diff --git a/modules/ROOT/pages/migration/v4-migration/authorization.adoc b/modules/ROOT/pages/migration/v4-migration/authorization.adoc index 27146cac..1666054d 100644 --- a/modules/ROOT/pages/migration/v4-migration/authorization.adoc +++ b/modules/ROOT/pages/migration/v4-migration/authorization.adoc @@ -1,6 +1,6 @@ = Authentication and Authorization -The largest breaking change in version 4.0.0 is the removal of the `@auth` directive, which requires a migration to the new `@authentication` and `@authorization` directives. +The largest breaking change in version 4.0.0 is the removal of the `@auth` directive, which requires a migration to the new `@authentication`, `@authorization` and `@subscriptionsAuthorization` directives. == Instantiation @@ -12,7 +12,9 @@ You should uninstall the previous plugin: npm uninstall @neo4j/graphql-plugin-auth ---- -Then, given an example of instantiation using a basic secret with the plugin: +=== Symmetric secret + +Given an example of instantiation using a symmetric secret with the plugin: [source, typescript, indent=0] ---- @@ -40,6 +42,38 @@ new Neo4jGraphQL({ }) ---- +=== JWKS endpoint + +When using a JWKS endpoint, an example of how this might be configured currently is: + +[source, typescript, indent=0] +---- +new Neo4jGraphQL({ + typeDefs, + plugins: { + auth: new Neo4jGraphQLAuthJWKSPlugin({ + jwksEndpoint: "https://YOUR_DOMAIN/well-known/jwks.json", + }), + } +}) +---- + +In version 4.0.0, delete the import of `Neo4jGraphQLAuthJWKSPlugin`, and change the instantiation to: + +[source, typescript, indent=0] +---- +new Neo4jGraphQL({ + typeDefs, + features: { + authorization: { + key: { + url: "https://YOUR_DOMAIN/well-known/jwks.json", + }, + } + } +}) +---- + == Server Previously, you could pass in the entire request object and the library would find the `Authorization` header: diff --git a/modules/ROOT/pages/migration/v4-migration/index.adoc b/modules/ROOT/pages/migration/v4-migration/index.adoc index b9ebd3a0..4baa3148 100644 --- a/modules/ROOT/pages/migration/v4-migration/index.adoc +++ b/modules/ROOT/pages/migration/v4-migration/index.adoc @@ -1,9 +1,6 @@ [[v4-migration]] - = 4.0.0 Migration -NOTE: Version 4.0.0 of the library has not yet been released. However, we recommend making these changes early in order to avoid issues in the future. - This document lists all breaking changes from version 3.x.y to 4.0.0 and how to update. == How to upgrade @@ -16,10 +13,120 @@ npm update @neo4j/graphql == Constructor arguments -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. +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. + +=== Removal of `config` + +==== `debug` + +The programmatic toggle for debug logging has been moved from `config.enableDebug` to simply `debug`. + +An example of `enableDebug`: + +[source, javascript, indent=0] +---- +const { Neo4jGraphQL } = require("@neo4j/graphql"); +const neo4j = require("neo4j-driver"); +const { ApolloServer } = require("apollo-server"); + +const typeDefs = ` + type Movie { + title: String! + } +`; + +const driver = neo4j.driver( + "bolt://localhost:7687", + neo4j.auth.basic("neo4j", "password") +); + +const neoSchema = new Neo4jGraphQL({ + typeDefs, + driver, + config: { + enableDebug: true, + } +}); +---- + +This now becomes: + +[source, javascript, indent=0] +---- +const { Neo4jGraphQL } = require("@neo4j/graphql"); +const neo4j = require("neo4j-driver"); +const { ApolloServer } = require("apollo-server"); + +const typeDefs = ` + type Movie { + title: String! + } +`; + +const driver = neo4j.driver( + "bolt://localhost:7687", + neo4j.auth.basic("neo4j", "password") +); + +const neoSchema = new Neo4jGraphQL({ + typeDefs, + driver, + debug: true, +}); +---- + +==== `driverConfig` moved to context + +Session configuration is now available only in the context under the `sessionConfig` key. + +This was previously `driverConfig`, available in both the constructor and in the context: + +[source, javascript, indent=0] +---- +const neoSchema = new Neo4jGraphQL({ + typeDefs, + config: { + driverConfig: { + database: "different-db" + }, + }, +}) +---- + +The new `sessionConfig` key is only available in the context: + +[source, javascript, indent=0] +---- +import { ApolloServer } from '@apollo/server'; +import { startStandaloneServer } from '@apollo/server/standalone'; +import { Neo4jGraphQL } from "@neo4j/graphql"; +import neo4j from "neo4j-driver"; + +const typeDefs = `#graphql + type User { + name: String + } +`; + +const driver = neo4j.driver( + "bolt://localhost:7687", + neo4j.auth.basic("neo4j", "password") +); + +const neoSchema = new Neo4jGraphQL({ typeDefs, driver }); + +const server = new ApolloServer({ + schema: await neoSchema.getSchema(), +}); + +await startStandaloneServer(server, { + context: async ({ req }) => ({ sessionConfig: { database: "my-database" }}), +}); +---- -=== config.enableRegex replaced by `MATCHES` in features.filters +The `bookmarks` key has been removed because it is no longer needed with the bookmark manager of the newer driver. + +==== `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. @@ -42,6 +149,81 @@ neoSchema = new Neo4jGraphQL({ }); ---- +==== `queryOptions` moved to the context + +If you had a need to pass in Cypher query options for query tuning, this interface has been changed. + +The config option `queryOptions` has now become `cypherQueryOptions` inside the context function, and it now accepts simple strings instead of enums. + +The following is an example before the change: + +[source, javascript, indent=0] +---- +const { Neo4jGraphQL, CypherRuntime } = require("@neo4j/graphql"); +const { ApolloServer } = require("apollo-server"); + +const typeDefs = ` + type Movie { + title: String! + } +`; + +const neoSchema = new Neo4jGraphQL({ + typeDefs, + config: { + queryOptions: { + runtime: CypherRuntime.INTERPRETED, + }, + }, +}); +---- + +This is what is required after the change: + +[source, javascript, indent=0] +---- +const { Neo4jGraphQL } = require("@neo4j/graphql"); +const { ApolloServer } = require("apollo-server"); + +const typeDefs = ` + type Movie { + title: String! + } +`; + +const neoSchema = new Neo4jGraphQL({ + typeDefs, +}); + +const server = new ApolloServer({ + schema: await neoSchema.getSchema(), +}); + +await startStandaloneServer(server, { + context: async ({ req }) => ({ cypherQueryOptions: { runtime: "interpreted" }}), +}); +---- + +This reflects the fact that the Cypher query options are set on a per-request basis. + +[[startup-validation]] +==== `skipValidateTypeDefs` + +The argument `skipValidateTypeDefs` has been moved to the top-level of the constructor input and renamed `validate`, which defaults to `true`. + +To disable type definition validation, the following config option should be used: + +[source, javascript, indent=0] +---- +const neoSchema = new Neo4jGraphQL({ + typeDefs, + validate: false, +}) +---- + +If you started using the `config.startupValidation` option, this has also been rolled into the same `validate` setting for simplicity. +The `resolvers` option of this is now just a warning, and `noDuplicateRelationshipFields` is now a mandatory check rolled into `validate`. + [subscriptions-options] === Subscription options @@ -152,6 +334,7 @@ const subscriptionsEngine = new Neo4jGraphQLAMQPSubscriptionsEngine({ ---- ==== Custom Subscription Plugins + The underlying subscription system has not changed. Custom behavior can be implemented the same way, by creating a class implementing the interface described in xref::subscriptions/engines.adoc#custom-subscription[Subscriptions Engines]. @@ -161,23 +344,15 @@ However, if using TypeScript, the exported interface to implement these classes We have renamed a number of directives and their arguments, in order to make using `@neo4j/graphql` more intuitive. -=== `@queryOptions` removed and `limit` argument moved to `@limit` - -If you were using the `@queryOptions` directive to configure the default and max values for limiting the data returned by queries, for instance: - -[source, graphql, indent=0] ----- -type Record @queryOptions(limit: { default: 10, max: 100 }) { - id: ID! -} ----- +=== `@alias` values are now automatically escaped -This is now achieved by using the `@limit` directive: +Properties in the alias directive automatically escaped using backticks. If you were using backticks in the `property` argument of your `@alias` directives, you should now remove the escape strings as this is covered by the library. [source, graphql, indent=0] ---- -type Record @limit(default: 10, max: 100) { - id: ID! +type User { + id: ID! @id + username: String! @alias(property: "dbUserName") } ---- @@ -351,87 +526,51 @@ type User { } ---- -[plural-migration] -=== `plural` argument removed from `@node` and replaced with `@plural` +=== `@cypher` changes +The default behaviour of the `@cypher` directive regarding the translation will change: Instead of using https://neo4j.com/labs/apoc/4.0/overview/apoc.cypher/apoc.cypher.runFirstColumnMany/[apoc.cypher.runFirstColumnMany] it will directly wrap the query within a `CALL { }` subquery. This behvaiour has proven to be much more performant for the same queries, however, it may lead to unexpected changes, mainly when using Neo4j 5.x, where the subqueries need to be _aliased_. -How a type name is pluralised has nothing to do with nodes in the database. As a result, having a `plural` argument on the `@node` directive did not make sense. -As a result, the `plural` argument of `@node` has been removed and replaced with a new `@plural` directive. The `@plural` directive takes the pluralised type name using the `value` argument. +On top of that, to improve performance, it is recommended to pass the returned alias in the property `columnName`, to ensure the subquery is properly integrated into the larger query. -This means that the following type definition is invalid: +For example: +The graphql query: [source, graphql, indent=0] ---- -type Tech @node(label: "TechDB", plural: "Techs") { - name: String +type query { + test: String! @cypher(statement: "RETURN 'hello'") } ---- -It would need to be updated to use the new directive as below: - -[source, graphql, indent=0] +Would get translated to: +[source,cypher, indent=0] ---- -type Tech @node(label: "TechDB") @plural(value: "Techs") { - name: String +CALL { + RETURN 'hello' } +WITH 'hello' AS this +RETURN this ---- -[label-migration] -=== `label` and `additionalLabels` arguments removed from `@node` and replaced with new argument `labels` - -There is no concept of a "main label" in the Neo4j database. As such, keeping these two separate arguments causes a disconnect between the database and the GraphQL library. -As a result, the `label` and `additionalLabels` arguments have been condensed into a single argument `labels` which will accept a list of string labels that used when a node of the given GraphQL type is created. -Please note that defining `labels` means you take control of the database labels of the node. Indexes and constraints in Neo4j only support a single label, for which the first element of the `labels` argument will be used. - -The equivalent of using just the `label` argument is now a list with a single value: +Which is invalid in Neo4j 5.x. +To fix it we just need to ensure the `RETURN` elements are aliased: [source, graphql, indent=0] ---- -type Tech @node(label: "TechDB") { - name: String -} -# becomes -type Tech @node(labels: ["TechDB"]) { - name: String +type query { + test: String! @cypher(statement: "RETURN 'hello' as result") } ---- -When creating the equivalent of using just the `additionalLabels` argument now requires the first value in the list to be the GraphQL type name: +This will be a breaking change, but this new behaviour can be used, as an experimental option with the `columnName` flag in the `@cypher` directive: [source, graphql, indent=0] ---- -type Tech @node(additionalLabels: ["TechDB"]) { - name: String -} -# becomes -type Tech @node(labels: ["Tech", "TechDB"]) { - name: String +type query { + test: String! @cypher(statement: "RETURN 'hello' as result", columnName: "result") } ---- -The equivalent of using both deprecated arguments is a list with all the values concatenated: - -[source, graphql, indent=0] ----- -type Tech @node(label: "TechDB", additionalLabels: ["AwesomeTech"]) { - name: String -} -# becomes -type Tech @node(labels: ["TechDB", "AwesomeTech"]) { - name: String -} ----- - -As before, providing none of these arguments results in the node label being the same as the GraphQL type name. - -Please note the implications on constraints. -In the following example, a unique constraint will be asserted for the label `Tech` and the property `name`: - -[source, graphql, indent=0] ----- -type Tech @node(labels: ["Tech", "TechDB"]) { - name: String @unique -} ----- +Additionally, escaping strings is no longer needed. [full-text-migration] === `@fulltext` changes @@ -592,130 +731,142 @@ type Query { } ---- -=== `@cypher` changes -The default behaviour of the `@cypher` directive regarding the translation will change: Instead of using https://neo4j.com/labs/apoc/4.0/overview/apoc.cypher/apoc.cypher.runFirstColumnMany/[apoc.cypher.runFirstColumnMany] it will directly wrap the query within a `CALL { }` subquery. This behvaiour has proven to be much more performant for the same queries, however, it may lead to unexpected changes, mainly when using Neo4j 5.x, where the subqueries need to be _aliased_. +=== `@id` changes -On top of that, to improve performance, it is recommended to pass the returned alias in the property `columnName`, to ensure the subquery is properly integrated into the larger query. +The `@id` directive has been completely pared back in version 4.0.0, with _all_ of its arguments removed. +This has been done to reduce the number of features that this directive was used to toggle, and to ensure that its behaviour is consistent no matter where it is used. -For example: +==== `autogenerate` + +The default value of `autogenerate` was `true`. If this was set to `false`, the `@id` directive was almost a no-op only used to manage a unique node property constraint. Use the `@unique` directive instead. + +==== `global` + +The `global` argument was used to configure the field that would form the global node identifier for Relay. + +This functionality has been moved into its own directive, `@relayId`. The use of `@relayId` will ensure a unique node property constraint for the field. + +==== `unique` + +The `@id` directive used to also manage unique node property constraints for a field. This functionality has now been removed, use the `@unique` directive in combination with `@id` if you want the field to be backed by a constraint. + +=== `@node` changes + +[plural-migration] +==== `plural` argument removed from `@node` and replaced with `@plural` + +How a type name is pluralised has nothing to do with nodes in the database. As a result, having a `plural` argument on the `@node` directive did not make sense. +As a result, the `plural` argument of `@node` has been removed and replaced with a new `@plural` directive. The `@plural` directive takes the pluralised type name using the `value` argument. + +This means that the following type definition is invalid: -The graphql query: [source, graphql, indent=0] ---- -type query { - test: String! @cypher(statement: "RETURN 'hello'") +type Tech @node(label: "TechDB", plural: "Techs") { + name: String } ---- -Would get translated to: -[source,cypher, indent=0] +It would need to be updated to use the new directive as below: + +[source, graphql, indent=0] ---- -CALL { - RETURN 'hello' +type Tech @node(label: "TechDB") @plural(value: "Techs") { + name: String } -WITH 'hello' AS this -RETURN this ---- -Which is invalid in Neo4j 5.x. +[label-migration] +==== `label` and `additionalLabels` arguments removed from `@node` and replaced with new argument `labels` + +There is no concept of a "main label" in the Neo4j database. As such, keeping these two separate arguments causes a disconnect between the database and the GraphQL library. +As a result, the `label` and `additionalLabels` arguments have been condensed into a single argument `labels` which will accept a list of string labels that used when a node of the given GraphQL type is created. +Please note that defining `labels` means you take control of the database labels of the node. Indexes and constraints in Neo4j only support a single label, for which the first element of the `labels` argument will be used. + +The equivalent of using just the `label` argument is now a list with a single value: -To fix it we just need to ensure the `RETURN` elements are aliased: [source, graphql, indent=0] ---- -type query { - test: String! @cypher(statement: "RETURN 'hello' as result") +type Tech @node(label: "TechDB") { + name: String +} +# becomes +type Tech @node(labels: ["TechDB"]) { + name: String } ---- -This will be a breaking change, but this new behaviour can be used, as an experimental option with the `columnName` flag in the `@cypher` directive: +When creating the equivalent of using just the `additionalLabels` argument now requires the first value in the list to be the GraphQL type name: [source, graphql, indent=0] ---- -type query { - test: String! @cypher(statement: "RETURN 'hello' as result", columnName: "result") +type Tech @node(additionalLabels: ["TechDB"]) { + name: String +} +# becomes +type Tech @node(labels: ["Tech", "TechDB"]) { + name: String } ---- -Additionally, escaping strings is no longer needed. - -=== Mandatory `@relationshipProperties` - -Upcoming changes to interfaces require us to distinguish between interfaces that are used to specify relationship properties, and others. Therefore, the `@relationshipProperties` directive is now required on all relationship property interfaces. -If it is not included, an error will be thrown. - -As a result, in version 4.0.0, the following type definitions are invalid: - -=== Relationship types are now automatically escaped - -Relationship types are now automatically escaped. If you have previously escaped your relationship types, you should now remove the escape strings as this is covered by the library. +The equivalent of using both deprecated arguments is a list with all the values concatenated: [source, graphql, indent=0] ---- -type Person { - name: String! - movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") -} - -type Movie { - title: String! - actors: [Person!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") +type Tech @node(label: "TechDB", additionalLabels: ["AwesomeTech"]) { + name: String } - -interface ActedIn { - screenTime: Int! +# becomes +type Tech @node(labels: ["TechDB", "AwesomeTech"]) { + name: String } ---- -=== Properties in the alias directive are now automatically escaped +As before, providing none of these arguments results in the node label being the same as the GraphQL type name. -Properties in the alias directive automatically escaped using backticks. If you were using backticks in the `property` argument of your `@alias` directives, you should now remove the escape strings as this is covered by the library. +Please note the implications on constraints. +In the following example, a unique constraint will be asserted for the label `Tech` and the property `name`: [source, graphql, indent=0] ---- -type User { - id: ID! @id - username: String! @alias(property: "dbUserName") +type Tech @node(labels: ["Tech", "TechDB"]) { + name: String @unique } ---- -=== Duplicate relationship fields are now checked for - -It was possible to define schemas with types that have multiple relationship fields connected by the same type of relationships. Instances of this scenario are now detected during schema generation and an error is thrown so developers are informed to remedy the type definitions. +=== `@queryOptions` removed and `limit` argument moved to `@limit` -An example of what is now considered invalid with these checks: +If you were using the `@queryOptions` directive to configure the default and max values for limiting the data returned by queries, for instance: [source, graphql, indent=0] ---- -type Team { - player1: Person! @relationship(type: "PLAYS_IN", direction: IN) - player2: Person! @relationship(type: "PLAYS_IN", direction: IN) - backupPlayers: [Person!]! @relationship(type: "PLAYS_IN", direction: IN) -} - -type Person { - teams: [Team!]! @relationship(type: "PLAYS_IN", direction: OUT) +type Record @queryOptions(limit: { default: 10, max: 100 }) { + id: ID! } ---- -In this example, there are multiple fields in the `Team` type which have the same `Person` type, the same `@relationship` type and ("PLAYS_IN") direction (IN). This is an issue when returning data from the database, as there would be no difference between `player1`, `player2` and `backupPlayers`. Selecting these fields would then return the same data. - -These checks can be disabled by disabling all validation in the library, however, this is not recommended unless in production with 100% confidence of type definitions input. +This is now achieved by using the `@limit` directive: -[source, javascript, indent=0] +[source, graphql, indent=0] ---- -const neoSchema = new Neo4jGraphQL({ - typeDefs, - validate: false, -}); +type Record @limit(default: 10, max: 100) { + id: ID! +} ---- [relationship-aggregate] === `@relationship` changes +==== Relationship types are now automatically escaped + +Relationship types are now automatically escaped. If you have previously escaped your relationship types using backticks, you must now remove these as this is covered by the library. + +==== `aggregate` argument + In version 4.0.0, the default value of the aggregate argument will be false. This means that aggregation operation fields will no longer be generated by default when a relationship is defined using the `@relationship` directive. -For instance, the following type definitions +For instance, given the following type definitions: [source, graphql, indent=0] ---- @@ -729,9 +880,9 @@ type Actor { } ---- -will no longer generate `actedInAggregate` for the type `Actor`. +These will no longer generate `actedInAggregate` for the type `Actor`. -To enable it back, explicitly set the aggregate argument as `true`: +To enable it, explicitly set the aggregate argument as `true`: [source, graphql, indent=0] ---- @@ -745,208 +896,92 @@ type Actor { } ---- -== Miscellaneous changes - -[[startup-validation]] -=== Startup validation - -The argument `config.skipValidateTypeDefs` has been moved to the top-level of the constructor input and renamed `validate`, which defaults to `true`. - -To disable type definition validation, the following config option should be used: - -[source, javascript, indent=0] ----- -const neoSchema = new Neo4jGraphQL({ - typeDefs, - validate: false, -}) ----- - -If you started using the `config.startupValidation` option, this has also been rolled into the same `validate` setting for simplicity. -The `resolvers` option of this is now just a warning, and `noDuplicateRelationshipFields` is now a mandatory check rolled into `validate`. - -[[opt-in-aggregation]] -=== Opt-in Aggregation +=== `@relationshipProperties` now mandatory -Aggregation operations are no longer generated by default. -They can be enabled case by case using the directives xref::reference/directives/schema-configuration/type-configuration.adoc#_query[`@query`] and xref::reference/directives/schema-configuration/field-configuration.adoc#_relationship[`@relationship`]. +Upcoming changes to interfaces require us to distinguish between interfaces that are used to specify relationship properties, and others. Therefore, the `@relationshipProperties` directive is now required on all relationship property interfaces. +If it is not included, an error will be thrown. -You can enable the operation fields `actorsAggregate` and `actedInAggregate` like this: +As a result, in version 4.0.0, the following type definitions are invalid: [source, graphql, indent=0] ---- +type Person { + name: String! + movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") +} + type Movie { title: String! + actors: [Person!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } -type Actor @query(aggregate: true) { - name: String! - actedIn: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, aggregate: true) +interface ActedIn { + screenTime: Int! } ---- -=== Cypher query options - -If you had a need to pass in Cypher query options for query tuning, this interface has been changed. - -The config option `queryOptions` has now become `cypherQueryOptions` inside the context function, and it now accepts simple strings instead of enums. - -The following is an example before the change: +`ActedIn` must be decorated with `@relationshipProperties`: -[source, javascript, indent=0] +[source, graphql, indent=0] ---- -const { Neo4jGraphQL, CypherRuntime } = require("@neo4j/graphql"); -const { ApolloServer } = require("apollo-server"); - -const typeDefs = ` - type Movie { - title: String! - } -`; - -const neoSchema = new Neo4jGraphQL({ - typeDefs, - config: { - queryOptions: { - runtime: CypherRuntime.INTERPRETED, - }, - }, -}); +interface ActedIn @relationshipProperties { + screenTime: Int! +} ---- -This is what is required after the change: - -[source, javascript, indent=0] ----- -const { Neo4jGraphQL } = require("@neo4j/graphql"); -const { ApolloServer } = require("apollo-server"); +== Miscellaneous changes -const typeDefs = ` - type Movie { - title: String! - } -`; +=== Duplicate relationship fields are now checked for -const neoSchema = new Neo4jGraphQL({ - typeDefs, -}); +It was possible to define schemas with types that have multiple relationship fields connected by the same type of relationships. Instances of this scenario are now detected during schema generation and an error is thrown so developers are informed to remedy the type definitions. -const server = new ApolloServer({ - schema: await neoSchema.getSchema(), -}); +An example of what is now considered invalid with these checks: -await startStandaloneServer(server, { - context: async ({ req }) => ({ cypherQueryOptions: { runtime: "interpreted" }}), -}); +[source, graphql, indent=0] ---- +type Team { + player1: Person! @relationship(type: "PLAYS_IN", direction: IN) + player2: Person! @relationship(type: "PLAYS_IN", direction: IN) + backupPlayers: [Person!]! @relationship(type: "PLAYS_IN", direction: IN) +} -This reflects the fact that the Cypher query options are set on a per-request basis. - -=== Session configuration +type Person { + teams: [Team!]! @relationship(type: "PLAYS_IN", direction: OUT) +} +---- -Session configuration is now available only in the context under the `sessionConfig` key. +In this example, there are multiple fields in the `Team` type which have the same `Person` type, the same `@relationship` type and ("PLAYS_IN") direction (IN). This is an issue when returning data from the database, as there would be no difference between `player1`, `player2` and `backupPlayers`. Selecting these fields would then return the same data. -This was previously `driverConfig`, available in both the constructor and in the context: +These checks can be disabled by disabling all validation in the library, however, this is not recommended unless in production with 100% confidence of type definitions input. [source, javascript, indent=0] ---- const neoSchema = new Neo4jGraphQL({ typeDefs, - config: { - driverConfig: { - database: "different-db" - }, - }, -}) ----- - -The new `sessionConfig` key is only available in the context: - -[source, javascript, indent=0] ----- -import { ApolloServer } from '@apollo/server'; -import { startStandaloneServer } from '@apollo/server/standalone'; -import { Neo4jGraphQL } from "@neo4j/graphql"; -import neo4j from "neo4j-driver"; - -const typeDefs = `#graphql - type User { - name: String - } -`; - -const driver = neo4j.driver( - "bolt://localhost:7687", - neo4j.auth.basic("neo4j", "password") -); - -const neoSchema = new Neo4jGraphQL({ typeDefs, driver }); - -const server = new ApolloServer({ - schema: await neoSchema.getSchema(), -}); - -await startStandaloneServer(server, { - context: async ({ req }) => ({ sessionConfig: { database: "my-database" }}), + validate: false, }); ---- -The `bookmarks` key has been removed because it is no longer needed with the bookmark manager of the newer driver. - -=== Debug logging - -The programmatic toggle for debug logging has been moved from `config.enableDebug` to simply `debug`. - -An example of `enableDebug`: - -[source, javascript, indent=0] ----- -const { Neo4jGraphQL } = require("@neo4j/graphql"); -const neo4j = require("neo4j-driver"); -const { ApolloServer } = require("apollo-server"); +[[opt-in-aggregation]] +=== Opt-in Aggregation -const typeDefs = ` - type Movie { - title: String! - } -`; +Aggregation operations are no longer generated by default. +They can be enabled case by case using the directives xref::reference/directives/schema-configuration/type-configuration.adoc#_query[`@query`] and xref::reference/directives/schema-configuration/field-configuration.adoc#_relationship[`@relationship`]. -const driver = neo4j.driver( - "bolt://localhost:7687", - neo4j.auth.basic("neo4j", "password") -); +You can enable the operation fields `actorsAggregate` and `actedInAggregate` like this: -const neoSchema = new Neo4jGraphQL({ - typeDefs, - driver, - config: { - enableDebug: true, - } -}); +[source, graphql, indent=0] ---- +type Movie { + title: String! +} -This now becomes: - -[source, javascript, indent=0] +type Actor @query(aggregate: true) { + name: String! + actedIn: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, aggregate: true) +} ---- -const { Neo4jGraphQL } = require("@neo4j/graphql"); -const neo4j = require("neo4j-driver"); -const { ApolloServer } = require("apollo-server"); -const typeDefs = ` - type Movie { - title: String! - } -`; +=== `cypherParams` -const driver = neo4j.driver( - "bolt://localhost:7687", - neo4j.auth.basic("neo4j", "password") -); - -const neoSchema = new Neo4jGraphQL({ - typeDefs, - driver, - debug: true, -}); ----- \ No newline at end of file +`cypherParams` is available in the context to provide the ability to pass arbitrary parameters to a custom Cypher query. This functionality remains in 4.0.0, but you no longer have to use the `$cypherParams` prefix to reference these parameters. diff --git a/modules/ROOT/pages/reference/directives/index.adoc b/modules/ROOT/pages/reference/directives/index.adoc index fd734f31..1bebcef2 100644 --- a/modules/ROOT/pages/reference/directives/index.adoc +++ b/modules/ROOT/pages/reference/directives/index.adoc @@ -125,6 +125,10 @@ Can only be used on interfaces, as per its definition: directive @relationshipProperties on INTERFACE ---- +== `@relayId` + +The `@relayId` directive can be used on object type fields, to flag which field should be used as the global node identifier for Relay. Can be used once per type. The use of the `@relayId` directive ensures a unique node property constraint for the field. + == `@selectable` The `@selectable` directive sets the availability of fields on queries and aggregations.