From cd3bbdbd55d728b547de45531cf277c88e417c1c Mon Sep 17 00:00:00 2001 From: Jesse Snyder Date: Mon, 1 Jun 2020 16:29:10 -0600 Subject: [PATCH 1/3] adds case insensitive searching --- package-lock.json | 5 ++--- src/augment/input-values.js | 1 + src/translate.js | 30 +++++++++++++++++++++++--- test/helpers/testSchema.js | 9 ++++++-- test/unit/augmentSchemaTest.test.js | 33 +++++++++++++++++++++++++++++ test/unit/cypherTest.test.js | 16 ++++++++++++++ 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index de5e54d5..2295fe29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "neo4j-graphql-js", - "version": "2.14.1-alpha.2", + "version": "2.14.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4714,8 +4714,7 @@ "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "1" } }, "readable-stream": { diff --git a/src/augment/input-values.js b/src/augment/input-values.js index 6c8ae59e..3865a460 100644 --- a/src/augment/input-values.js +++ b/src/augment/input-values.js @@ -408,6 +408,7 @@ const buildPropertyFilters = ({ 'in', 'not_in', 'contains', + 'contains_i', 'not_contains', 'starts_with', 'not_starts_with', diff --git a/src/translate.js b/src/translate.js index f806d79a..842b3825 100644 --- a/src/translate.js +++ b/src/translate.js @@ -2447,9 +2447,12 @@ const translateFilterArgument = ({ innerSchemaType = schema.getType(typeName); } // build path for parameter data for current filter field - const parameterPath = `${ - parentParamPath ? parentParamPath : filterParam - }.${fieldName}`; + const parameterPath = buildParamaterPathExpression({ + parentParamPath, + filterParam, + fieldName, + filterOperationType + }); // short-circuit evaluation: predicate used to skip a field // if processing a list of objects that possibly contain different arguments const nullFieldPredicate = decideNullSkippingPredicate({ @@ -2504,6 +2507,7 @@ const parseFilterArgumentName = fieldName => { '_in', '_not_in', '_contains', + '_contains_i', '_not_contains', '_starts_with', '_not_starts_with', @@ -2555,6 +2559,24 @@ const parseFilterArgumentName = fieldName => { }; }; +const buildParamaterPathExpression = ({ + parentParamPath, + filterParam, + fieldName, + filterOperationType +}) => { + // build path for parameter data for current filter field + const parameterPath = `${ + parentParamPath ? parentParamPath : filterParam + }.${fieldName}`; + // may need to call expression on path value depending on filter type + if (filterOperationType.slice(-2) === '_i') { + // case insensitive + return `toLower(${parameterPath})`; + } + return parameterPath; +}; + const translateScalarFilter = ({ isListFilterArgument, filterOperationField, @@ -2638,6 +2660,8 @@ const buildOperatorExpression = ({ return `NOT ${propertyPath} IN`; case 'contains': return `${propertyPath} CONTAINS`; + case 'contains_i': + return `toLower(${propertyPath}) CONTAINS`; case 'not_contains': return `NOT ${propertyPath} CONTAINS`; case 'starts_with': diff --git a/test/helpers/testSchema.js b/test/helpers/testSchema.js index cacf925d..c7cd962e 100644 --- a/test/helpers/testSchema.js +++ b/test/helpers/testSchema.js @@ -55,7 +55,7 @@ export const testSchema = ` releases: [DateTime] customField: String @neo4j_ignore } - + extend type Movie { currentUserId(strArg: String): String @cypher( @@ -112,6 +112,7 @@ export const testSchema = ` userId_in: [ID!] userId_not_in: [ID!] userId_contains: ID + userId_contains_i: ID userId_not_contains: ID userId_starts_with: ID userId_not_starts_with: ID @@ -122,6 +123,7 @@ export const testSchema = ` name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -403,6 +405,7 @@ export const testSchema = ` id_in: [ID!] id_not_in: [ID!] id_contains: ID + id_contains_i: ID id_not_contains: ID id_starts_with: ID id_not_starts_with: ID @@ -413,6 +416,7 @@ export const testSchema = ` type_in: [String!] type_not_in: [String!] type_contains: String + type_contains_i: String type_not_contains: String type_starts_with: String type_not_starts_with: String @@ -423,6 +427,7 @@ export const testSchema = ` make_in: [String!] make_not_in: [String!] make_contains: String + make_contains_i: String make_not_contains: String make_starts_with: String make_not_starts_with: String @@ -529,7 +534,7 @@ export const testSchema = ` query: QueryA subscription: SubscriptionC } - + extend schema { mutation: Mutation } diff --git a/test/unit/augmentSchemaTest.test.js b/test/unit/augmentSchemaTest.test.js index 58e3ae71..733f219b 100644 --- a/test/unit/augmentSchemaTest.test.js +++ b/test/unit/augmentSchemaTest.test.js @@ -311,6 +311,7 @@ test.cb('Test augmented schema', t => { movieId_in: [ID!] movieId_not_in: [ID!] movieId_contains: ID + movieId_contains_i: ID movieId_not_contains: ID movieId_starts_with: ID movieId_not_starts_with: ID @@ -321,6 +322,7 @@ test.cb('Test augmented schema', t => { title_in: [String!] title_not_in: [String!] title_contains: String + title_contains_i: String title_not_contains: String title_starts_with: String title_not_starts_with: String @@ -331,6 +333,7 @@ test.cb('Test augmented schema', t => { someprefix_title_with_underscores_in: [String!] someprefix_title_with_underscores_not_in: [String!] someprefix_title_with_underscores_contains: String + someprefix_title_with_underscores_contains_i: String someprefix_title_with_underscores_not_contains: String someprefix_title_with_underscores_starts_with: String someprefix_title_with_underscores_not_starts_with: String @@ -357,6 +360,7 @@ test.cb('Test augmented schema', t => { plot_in: [String!] plot_not_in: [String!] plot_contains: String + plot_contains_i: String plot_not_contains: String plot_starts_with: String plot_not_starts_with: String @@ -367,6 +371,7 @@ test.cb('Test augmented schema', t => { poster_in: [String!] poster_not_in: [String!] poster_contains: String + poster_contains_i: String poster_not_contains: String poster_starts_with: String poster_not_starts_with: String @@ -436,6 +441,7 @@ test.cb('Test augmented schema', t => { extensionScalar_in: [String!] extensionScalar_not_in: [String!] extensionScalar_contains: String + extensionScalar_contains_i: String extensionScalar_not_contains: String extensionScalar_starts_with: String extensionScalar_not_starts_with: String @@ -459,6 +465,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -482,6 +489,7 @@ test.cb('Test augmented schema', t => { userId_in: [ID!] userId_not_in: [ID!] userId_contains: ID + userId_contains_i: ID userId_not_contains: ID userId_starts_with: ID userId_not_starts_with: ID @@ -492,6 +500,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -518,6 +527,7 @@ test.cb('Test augmented schema', t => { extensionScalar_in: [String!] extensionScalar_not_in: [String!] extensionScalar_contains: String + extensionScalar_contains_i: String extensionScalar_not_contains: String extensionScalar_starts_with: String extensionScalar_not_starts_with: String @@ -533,6 +543,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -650,6 +661,7 @@ test.cb('Test augmented schema', t => { userId_in: [ID!] userId_not_in: [ID!] userId_contains: ID + userId_contains_i: ID userId_not_contains: ID userId_starts_with: ID userId_not_starts_with: ID @@ -660,6 +672,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -694,6 +707,7 @@ test.cb('Test augmented schema', t => { extensionScalar_in: [String!] extensionScalar_not_in: [String!] extensionScalar_contains: String + extensionScalar_contains_i: String extensionScalar_not_contains: String extensionScalar_starts_with: String extensionScalar_not_starts_with: String @@ -1251,6 +1265,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -1284,6 +1299,7 @@ test.cb('Test augmented schema', t => { userId_in: [ID!] userId_not_in: [ID!] userId_contains: ID + userId_contains_i: ID userId_not_contains: ID userId_starts_with: ID userId_not_starts_with: ID @@ -1294,6 +1310,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -1336,6 +1353,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -1446,6 +1464,7 @@ test.cb('Test augmented schema', t => { id_in: [ID!] id_not_in: [ID!] id_contains: ID + id_contains_i: ID id_not_contains: ID id_starts_with: ID id_not_starts_with: ID @@ -1456,6 +1475,7 @@ test.cb('Test augmented schema', t => { type_in: [String!] type_not_in: [String!] type_contains: String + type_contains_i: String type_not_contains: String type_starts_with: String type_not_starts_with: String @@ -1466,6 +1486,7 @@ test.cb('Test augmented schema', t => { make_in: [String!] make_not_in: [String!] make_contains: String + make_contains_i: String make_not_contains: String make_starts_with: String make_not_starts_with: String @@ -1532,6 +1553,7 @@ test.cb('Test augmented schema', t => { id_in: [ID!] id_not_in: [ID!] id_contains: ID + id_contains_i: ID id_not_contains: ID id_starts_with: ID id_not_starts_with: ID @@ -1542,6 +1564,7 @@ test.cb('Test augmented schema', t => { type_in: [String!] type_not_in: [String!] type_contains: String + type_contains_i: String type_not_contains: String type_starts_with: String type_not_starts_with: String @@ -1552,6 +1575,7 @@ test.cb('Test augmented schema', t => { make_in: [String!] make_not_in: [String!] make_contains: String + make_contains_i: String make_not_contains: String make_starts_with: String make_not_starts_with: String @@ -1570,6 +1594,7 @@ test.cb('Test augmented schema', t => { smell_in: [String!] smell_not_in: [String!] smell_contains: String + smell_contains_i: String smell_not_contains: String smell_starts_with: String smell_not_starts_with: String @@ -1628,6 +1653,7 @@ test.cb('Test augmented schema', t => { id_in: [ID!] id_not_in: [ID!] id_contains: ID + id_contains_i: ID id_not_contains: ID id_starts_with: ID id_not_starts_with: ID @@ -1638,6 +1664,7 @@ test.cb('Test augmented schema', t => { type_in: [String!] type_not_in: [String!] type_contains: String + type_contains_i: String type_not_contains: String type_starts_with: String type_not_starts_with: String @@ -1648,6 +1675,7 @@ test.cb('Test augmented schema', t => { make_in: [String!] make_not_in: [String!] make_contains: String + make_contains_i: String make_not_contains: String make_starts_with: String make_not_starts_with: String @@ -1712,6 +1740,7 @@ test.cb('Test augmented schema', t => { userId_in: [ID!] userId_not_in: [ID!] userId_contains: ID + userId_contains_i: ID userId_not_contains: ID userId_starts_with: ID userId_not_starts_with: ID @@ -1722,6 +1751,7 @@ test.cb('Test augmented schema', t => { name_in: [String!] name_not_in: [String!] name_contains: String + name_contains_i: String name_not_contains: String name_starts_with: String name_not_starts_with: String @@ -1748,6 +1778,7 @@ test.cb('Test augmented schema', t => { extensionScalar_in: [String!] extensionScalar_not_in: [String!] extensionScalar_contains: String + extensionScalar_contains_i: String extensionScalar_not_contains: String extensionScalar_starts_with: String extensionScalar_not_starts_with: String @@ -1792,6 +1823,7 @@ test.cb('Test augmented schema', t => { id_in: [ID!] id_not_in: [ID!] id_contains: ID + id_contains_i: ID id_not_contains: ID id_starts_with: ID id_not_starts_with: ID @@ -3044,6 +3076,7 @@ test.cb('Test augmented schema', t => { userId_in: [String!] userId_not_in: [String!] userId_contains: String + userId_contains_i: String userId_not_contains: String userId_starts_with: String userId_not_starts_with: String diff --git a/test/unit/cypherTest.test.js b/test/unit/cypherTest.test.js index bd602cb6..cd7ec202 100644 --- a/test/unit/cypherTest.test.js +++ b/test/unit/cypherTest.test.js @@ -524,6 +524,22 @@ test('Cypher subquery filters', t => { ]); }); +test('cypher query filters with case insensitive filter', t => { + const graphQLQuery = ` + { + Movie(filter: {title_contains_i: "river"}) { + title + } + } + `, + expectedCypherQuery = `MATCH (\`movie\`:\`Movie\`:\`u_user-id\`:\`newMovieLabel\`) WHERE (toLower(\`movie\`.title) CONTAINS toLower($filter.title_contains_i)) RETURN \`movie\` { .title } AS \`movie\``; + + t.plan(1); + return Promise.all([ + augmentedSchemaCypherTestRunner(t, graphQLQuery, {}, expectedCypherQuery) + ]); +}); + test('cypher subquery preserves case through filters', t => { const graphQLQuery = ` { From 5d14577d0e8552b11d12582ed8d53f2abdd85e7f Mon Sep 17 00:00:00 2001 From: Jesse Snyder Date: Tue, 2 Jun 2020 11:16:43 -0600 Subject: [PATCH 2/3] worth a shot --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 803df63f..88ce0cf3 100755 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "babel src --presets @babel/preset-env --out-dir dist", "build-with-sourcemaps": "babel src --presets @babel/preset-env --out-dir dist --source-maps", "precommit": "lint-staged", - "prepare": "npm run build", + "prepare": "yarn run build", "test": "nyc --reporter=lcov ava test/unit/**.test.js --verbose", "parse-tck": "babel-node test/helpers/tck/parseTck.js", "test-tck": "nyc ava --fail-fast test/unit/filterTests.test.js", From e860f5f130817b27595f3ebc6d453021d5eaa82a Mon Sep 17 00:00:00 2001 From: Jesse Snyder Date: Tue, 2 Jun 2020 11:19:07 -0600 Subject: [PATCH 3/3] idk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 88ce0cf3..803df63f 100755 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "babel src --presets @babel/preset-env --out-dir dist", "build-with-sourcemaps": "babel src --presets @babel/preset-env --out-dir dist --source-maps", "precommit": "lint-staged", - "prepare": "yarn run build", + "prepare": "npm run build", "test": "nyc --reporter=lcov ava test/unit/**.test.js --verbose", "parse-tck": "babel-node test/helpers/tck/parseTck.js", "test-tck": "nyc ava --fail-fast test/unit/filterTests.test.js",