From cbec4d7a9db25b07f4a596f5b8abfd7fff99131a Mon Sep 17 00:00:00 2001 From: Tung Date: Fri, 23 Aug 2019 15:49:10 +0700 Subject: [PATCH 1/3] chore: ignore history folder --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9c6d0024..70cf5c32 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,5 @@ neo4j-version test/tck/* !test/tck/.gitkeep + +.history \ No newline at end of file From 9425eec6ca7a04a85d11bcc1782734d57415075f Mon Sep 17 00:00:00 2001 From: Tung Date: Fri, 23 Aug 2019 15:54:40 +0700 Subject: [PATCH 2/3] test: add failed test --- test/unit/cypherTest.test.js | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/test/unit/cypherTest.test.js b/test/unit/cypherTest.test.js index 783865ef..68011c76 100644 --- a/test/unit/cypherTest.test.js +++ b/test/unit/cypherTest.test.js @@ -4,6 +4,10 @@ import { augmentedSchemaCypherTestRunner } from '../helpers/cypherTestHelpers'; +import { augmentSchema, augmentTypeDefs, cypherQuery } from '../../src'; +import { makeExecutableSchema } from 'graphql-tools'; +import { graphql } from 'graphql'; + const CYPHER_PARAMS = { userId: 'user-id' }; @@ -4454,3 +4458,84 @@ test('Handle @cypher field with parameterized value for field of input type argu augmentedSchemaCypherTestRunner(t, graphQLQuery, {}, expectedCypherQuery) ]); }); + +test('Cypher subquery filters with unfiltered parents', async t => { + const typeDefs = /* GraphQL */ ` + type A_B_Relation @relation(name: "A_TO_B") { + from: A + to: B + } + + type B_C_Relation @relation(name: "B_TO_C") { + from: B + to: C + active: Boolean! + } + + type A { + bArray: [A_B_Relation!]! + } + + type B { + cArray: [B_C_Relation!]! + } + + type C { + id: ID! + } + + type Query { + A: [A] + } + `; + + const graphqlQuery = /* GraphQL */ ` + { + A { + bArray { + B { + filteredCArray: cArray(filter: { active: true }) { + C { + id + } + } + } + } + } + } + `; + + const expectedCypherQuery = + 'MATCH (`a`:`A`) RETURN `a` {bArray: [(`a`)-[`a_bArray_relation`:`A_TO_B`]->(:`B`) | a_bArray_relation {B: head([(:`A`)-[`a_bArray_relation`]->(`a_bArray_B`:`B`) | a_bArray_B {cArray: [(`a_bArray_B`)-[`a_bArray_B_cArray_relation`:`B_TO_C`]->(:`C`) WHERE (`a_bArray_B_cArray_relation`.active = $1_filter.active) | a_bArray_B_cArray_relation {C: head([(:`B`)-[`a_bArray_B_cArray_relation`]->(`a_bArray_B_cArray_C`:`C`) | a_bArray_B_cArray_C { .id }]) }] }]) }] } AS `a`'; + const expectedCypherParams = { + '1_filter': { active: true }, + first: -1, + offset: 0 + }; + + const resolvers = { + Query: { + A(object, params, ctx, resolveInfo) { + const [query, queryParams] = cypherQuery(params, ctx, resolveInfo); + t.is(query, expectedCypherQuery); + t.deepEqual(queryParams, expectedCypherParams); + return []; + } + } + }; + + const schema = augmentSchema( + makeExecutableSchema({ + typeDefs: augmentTypeDefs(typeDefs), + resolvers + }), + { mutation: false } + ); + + // query the test schema with the test query, assertion is in the resolver + const resp = await graphql(schema, graphqlQuery); + + t.deepEqual(resp.data.A, []); + + return; +}); From 7ecd48d9e3c6e7d407dc38c1dfc4dd46c3ce7b00 Mon Sep 17 00:00:00 2001 From: Tung Date: Fri, 23 Aug 2019 15:57:00 +0700 Subject: [PATCH 3/3] fix: filtered child relation type of unfiltered parent --- src/translate.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/translate.js b/src/translate.js index 80c9b3ec..89c4243e 100644 --- a/src/translate.js +++ b/src/translate.js @@ -139,7 +139,10 @@ export const relationFieldOnNodeType = ({ const filterParamKey = `${tailParams.paramIndex}_filter`; const fieldArgumentParams = subSelection[1]; const filterParam = fieldArgumentParams[filterParamKey]; - if (filterParam) { + if ( + filterParam && + typeof serializedFilterParam[filterParamKey] !== 'undefined' + ) { subSelection[1][filterParamKey] = serializedFilterParam[filterParamKey]; } @@ -264,7 +267,10 @@ export const relationTypeFieldOnNodeType = ({ const filterParamKey = `${tailParams.paramIndex}_filter`; const fieldArgumentParams = subSelection[1]; const filterParam = fieldArgumentParams[filterParamKey]; - if (filterParam) { + if ( + filterParam && + typeof serializedFilterParam[filterParamKey] !== 'undefined' + ) { subSelection[1][filterParamKey] = serializedFilterParam[filterParamKey]; } @@ -426,7 +432,10 @@ const directedNodeTypeFieldOnRelationType = ({ const filterParamKey = `${tailParams.paramIndex}_filter`; const fieldArgumentParams = subSelection[1]; const filterParam = fieldArgumentParams[filterParamKey]; - if (filterParam) { + if ( + filterParam && + typeof serializedFilterParam[filterParamKey] !== 'undefined' + ) { subSelection[1][filterParamKey] = serializedFilterParam[filterParamKey]; } const whereClauses = [...temporalClauses, ...filterPredicates];