diff --git a/.changeset/wicked-ties-burn.md b/.changeset/wicked-ties-burn.md new file mode 100644 index 0000000000..6aad160c92 --- /dev/null +++ b/.changeset/wicked-ties-burn.md @@ -0,0 +1,5 @@ +--- +"@neo4j/graphql": major +--- + +`enableRegex` has been removed and replaced with `MATCHES` filters in the features configuration object. See the migration guide for more information: https://neo4j.com/docs/graphql-manual/current/guides/v4-migration diff --git a/docs/modules/ROOT/pages/api-reference/neo4jgraphql.adoc b/docs/modules/ROOT/pages/api-reference/neo4jgraphql.adoc index ed4204515f..b28d9c70d8 100644 --- a/docs/modules/ROOT/pages/api-reference/neo4jgraphql.adoc +++ b/docs/modules/ROOT/pages/api-reference/neo4jgraphql.adoc @@ -56,11 +56,6 @@ Accepts all of the options from https://www.graphql-tools.com/docs/generate-sche Type: xref::api-reference/neo4jgraphql.adoc#api-reference-neo4jgraphql-input-neo4jgraphqlconfig-driverconfig[`DriverConfig`] |Additional driver configuration options. -|`enableRegex` + - + - Type: `boolean` -|Whether to enable RegEx filters, see xref::filtering.adoc#filtering-regex[RegEx matching] for more information. - |`queryOptions` + + Type: xref::api-reference/neo4jgraphql.adoc#api-reference-neo4jgraphql-input-neo4jgraphqlconfig-cypherqueryoptions[`CypherQueryOptions`] diff --git a/docs/modules/ROOT/pages/filtering.adoc b/docs/modules/ROOT/pages/filtering.adoc index 631608e9e7..2184af0e20 100644 --- a/docs/modules/ROOT/pages/filtering.adoc +++ b/docs/modules/ROOT/pages/filtering.adoc @@ -127,9 +127,6 @@ const features = { const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver }); ---- - -Previously to enable to this filter the config option `enableRegex` was used, it has been deprecated. Use the `features` configuration object as described here, as the `enableRegex` will be removed in the future. - > The nature of RegEx matching means that on an unprotected API, this could potentially be used to execute a ReDoS attack (https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) against the backing Neo4j database. === Array comparison diff --git a/docs/modules/ROOT/pages/guides/v4-migration/index.adoc b/docs/modules/ROOT/pages/guides/v4-migration/index.adoc index 2fe060bead..f3bb7ca24e 100644 --- a/docs/modules/ROOT/pages/guides/v4-migration/index.adoc +++ b/docs/modules/ROOT/pages/guides/v4-migration/index.adoc @@ -19,6 +19,29 @@ npm update @neo4j/graphql If you were passing any arguments from https://the-guild.dev/graphql/tools/docs/api/interfaces/schema_src.iexecutableschemadefinition[`IExecutableSchemaDefinition`] into the library other than `typeDefs` and `resolvers`, these are no longer supported. +=== config.enableRegex replaced by `MATCHES` in features.filters + +`config.enableRegex` has been replaced by `MATCHES` in features.filters. With this change comes more granularity in the feature configuration. You can now enable the `MATCHES` filter on `String` and `ID` fields separately. + +A direct replacement of the `enableRegex: true` configuration would be as follows: + +[source, javascript, indent=0] +---- +neoSchema = new Neo4jGraphQL({ + typeDefs, + features: { + filters: { + String: { + MATCHES: true, + }, + ID: { + MATCHES: true, + }, + }, + }, +}); +---- + == Updated Directives We have renamed a number of directives and their arguments, in order to make using `@neo4j/graphql` more intuitive. @@ -577,7 +600,6 @@ const neoSchema = new Neo4jGraphQL({ }); ---- - == Miscellaneous changes [[startup-validation]] diff --git a/packages/graphql/src/classes/Neo4jGraphQL.ts b/packages/graphql/src/classes/Neo4jGraphQL.ts index c76a10e790..2a1b2d03b1 100644 --- a/packages/graphql/src/classes/Neo4jGraphQL.ts +++ b/packages/graphql/src/classes/Neo4jGraphQL.ts @@ -54,12 +54,6 @@ import { validateDocument } from "../schema/validation"; export interface Neo4jGraphQLConfig { driverConfig?: DriverConfig; - /** - * @deprecated This argument has been deprecated and will be removed in v4.0.0. - * Please use features.filters instead. More information can be found at - * https://neo4j.com/docs/graphql-manual/current/guides/v4-migration/#features - */ - enableRegex?: boolean; enableDebug?: boolean; /** * @deprecated This argument has been deprecated and will be removed in v4.0.0. @@ -334,7 +328,6 @@ class Neo4jGraphQL { const { nodes, relationships, typeDefs, resolvers } = makeAugmentedSchema(document, { features: this.features, - enableRegex: this.config?.enableRegex, validateResolvers: validationConfig.validateResolvers, generateSubscriptions: Boolean(this.plugins?.subscriptions), callbacks: this.features?.populatedBy?.callbacks ?? this.config.callbacks, @@ -372,7 +365,6 @@ class Neo4jGraphQL { const { nodes, relationships, typeDefs, resolvers } = makeAugmentedSchema(document, { features: this.features, - enableRegex: this.config?.enableRegex, validateResolvers: validationConfig.validateResolvers, generateSubscriptions: Boolean(this.plugins?.subscriptions), callbacks: this.features?.populatedBy?.callbacks ?? this.config.callbacks, diff --git a/packages/graphql/src/schema/get-where-fields.ts b/packages/graphql/src/schema/get-where-fields.ts index 9256a32d99..5a5f4fe3b7 100644 --- a/packages/graphql/src/schema/get-where-fields.ts +++ b/packages/graphql/src/schema/get-where-fields.ts @@ -39,13 +39,11 @@ interface Fields { function getWhereFields({ typeName, fields, - enableRegex, isInterface, features, }: { typeName: string; fields: Fields; - enableRegex?: boolean; isInterface?: boolean; features?: Neo4jFeaturesSettings; }): { [k: string]: string } { @@ -126,30 +124,25 @@ function getWhereFields({ } if (["String", "ID"].includes(f.typeMeta.name)) { - const matchesSetting: boolean | undefined = features?.filters?.[f.typeMeta.name]?.MATCHES; - if (matchesSetting !== undefined) { - if (matchesSetting === true) { - res[`${f.fieldName}_MATCHES`] = { type: "String", directives: deprecatedDirectives }; - } - } else if (enableRegex) { - // TODO: This is deprecated. To be removed in 4.0.0. - res[`${f.fieldName}_MATCHES`] = { type: "String", directives: deprecatedDirectives }; - } - - const stringWhereOperators = ["_CONTAINS", "_STARTS_WITH", "_ENDS_WITH"]; + const stringWhereOperators: Array<{ comparator: string; typeName: string }> = [ + { comparator: "_CONTAINS", typeName: f.typeMeta.name }, + { comparator: "_STARTS_WITH", typeName: f.typeMeta.name }, + { comparator: "_ENDS_WITH", typeName: f.typeMeta.name }, + ]; const stringWhereOperatorsNegate = ["_NOT_CONTAINS", "_NOT_STARTS_WITH", "_NOT_ENDS_WITH"]; - Object.entries(features?.filters?.String || {}).forEach(([filter, enabled]) => { - if (filter === "MATCHES") { - return; - } + Object.entries(features?.filters?.[f.typeMeta.name] || {}).forEach(([filter, enabled]) => { if (enabled) { - stringWhereOperators.push(`_${filter}`); + if (filter === "MATCHES") { + stringWhereOperators.push({ comparator: `_${filter}`, typeName: "String" }); + } else { + stringWhereOperators.push({ comparator: `_${filter}`, typeName: f.typeMeta.name }); + } } }); - stringWhereOperators.forEach((comparator) => { - res[`${f.fieldName}${comparator}`] = { type: f.typeMeta.name, directives: deprecatedDirectives }; + stringWhereOperators.forEach(({ comparator, typeName }) => { + res[`${f.fieldName}${comparator}`] = { type: typeName, directives: deprecatedDirectives }; }); stringWhereOperatorsNegate.forEach((comparator) => { diff --git a/packages/graphql/src/schema/make-augmented-schema.test.ts b/packages/graphql/src/schema/make-augmented-schema.test.ts index 2bda66e401..7357805f8c 100644 --- a/packages/graphql/src/schema/make-augmented-schema.test.ts +++ b/packages/graphql/src/schema/make-augmented-schema.test.ts @@ -151,29 +151,6 @@ describe("makeAugmentedSchema", () => { expect(matchesField).toBeUndefined(); }); - test("should add the MATCHES filter when NEO4J_GRAPHQL_ENABLE_REGEX is set", () => { - const typeDefs = gql` - type User { - name: String - } - `; - - const neoSchema = makeAugmentedSchema(typeDefs, { - enableRegex: true, - validateResolvers: true, - }); - - const document = neoSchema.typeDefs; - - const nodeWhereInput = document.definitions.find( - (x) => x.kind === "InputObjectTypeDefinition" && x.name.value === "UserWhere" - ) as InputObjectTypeDefinitionNode; - - const matchesField = nodeWhereInput.fields?.find((x) => x.name.value.endsWith("_MATCHES")); - - expect(matchesField).toBeDefined(); - }); - test("should add the name_MATCHES filter when Features.Filters.String.MATCHES is set", () => { const typeDefs = gql` type User { diff --git a/packages/graphql/src/schema/make-augmented-schema.ts b/packages/graphql/src/schema/make-augmented-schema.ts index c9381bdcbf..78c5fe85e2 100644 --- a/packages/graphql/src/schema/make-augmented-schema.ts +++ b/packages/graphql/src/schema/make-augmented-schema.ts @@ -90,7 +90,6 @@ function makeAugmentedSchema( document: DocumentNode, { features, - enableRegex, validateResolvers, generateSubscriptions, callbacks, @@ -98,7 +97,6 @@ function makeAugmentedSchema( subgraph, }: { features?: Neo4jFeaturesSettings; - enableRegex?: boolean; validateResolvers: boolean; generateSubscriptions?: boolean; callbacks?: Neo4jGraphQLCallbacks; @@ -269,7 +267,6 @@ function makeAugmentedSchema( pointFields: relFields.pointFields, primitiveFields: relFields.primitiveFields, }, - enableRegex, features, }); @@ -374,7 +371,6 @@ function makeAugmentedSchema( pointFields: interfaceFields.pointFields, primitiveFields: interfaceFields.primitiveFields, }, - enableRegex, isInterface: true, features, }); @@ -622,7 +618,6 @@ function makeAugmentedSchema( const queryFields = getWhereFields({ typeName: node.name, - enableRegex, fields: { temporalFields: node.temporalFields, enumFields: node.enumFields, diff --git a/packages/graphql/tests/tck/directives/customResolver.test.ts b/packages/graphql/tests/tck/directives/customResolver.test.ts index b806102d0d..b3e15b65f5 100644 --- a/packages/graphql/tests/tck/directives/customResolver.test.ts +++ b/packages/graphql/tests/tck/directives/customResolver.test.ts @@ -160,7 +160,6 @@ describe("@customResolver directive", () => { neoSchema = new Neo4jGraphQL({ typeDefs, resolvers, - config: { enableRegex: true }, }); }); @@ -242,7 +241,6 @@ describe("@customResolver directive", () => { neoSchema = new Neo4jGraphQL({ typeDefs, resolvers, - config: { enableRegex: true }, }); }); @@ -419,7 +417,6 @@ describe("@customResolver directive", () => { neoSchema = new Neo4jGraphQL({ typeDefs, resolvers, - config: { enableRegex: true }, }); }); @@ -612,7 +609,6 @@ describe("@customResolver directive", () => { neoSchema = new Neo4jGraphQL({ typeDefs, resolvers, - config: { enableRegex: true }, }); });