diff --git a/packages/graphql/src/classes/Error.ts b/packages/graphql/src/classes/Error.ts index 3bdd62f0f9..e2e81ce339 100644 --- a/packages/graphql/src/classes/Error.ts +++ b/packages/graphql/src/classes/Error.ts @@ -60,16 +60,6 @@ export class Neo4jGraphQLConstraintValidationError extends Neo4jGraphQLError { } } -export class Neo4jGraphQLRelationshipValidationError extends Neo4jGraphQLError { - readonly name; - - constructor(message: string) { - super(message); - - Object.defineProperty(this, "name", { value: "Neo4jGraphQLRelationshipValidationError" }); - } -} - export class Neo4jGraphQLCypherBuilderError extends Neo4jGraphQLError { readonly name; diff --git a/packages/graphql/src/constants.ts b/packages/graphql/src/constants.ts index 5efdf3b18d..eb01106793 100644 --- a/packages/graphql/src/constants.ts +++ b/packages/graphql/src/constants.ts @@ -21,7 +21,6 @@ const DEBUG_PREFIX = "@neo4j/graphql"; export const AUTH_FORBIDDEN_ERROR = "@neo4j/graphql/FORBIDDEN"; export const AUTH_UNAUTHENTICATED_ERROR = "@neo4j/graphql/UNAUTHENTICATED"; -export const RELATIONSHIP_REQUIREMENT_PREFIX = "@neo4j/graphql/RELATIONSHIP-REQUIRED"; export const MIN_VERSIONS = [ { majorMinor: "4.1", neo4j: "4.1.5" }, { majorMinor: "4.2", neo4j: "4.2.9" }, diff --git a/packages/graphql/src/schema/get-field-type-meta.ts b/packages/graphql/src/schema/get-field-type-meta.ts index 0f7c949439..1409f924f7 100644 --- a/packages/graphql/src/schema/get-field-type-meta.ts +++ b/packages/graphql/src/schema/get-field-type-meta.ts @@ -70,7 +70,6 @@ function getFieldTypeMeta(field: FieldDefinitionNode | InputValueDefinitionNode) required, pretty, arrayTypePretty, - arrayTypeRequired, }; const isPoint = ["Point", "CartesianPoint"].includes(name); diff --git a/packages/graphql/src/translate/create-create-and-params.ts b/packages/graphql/src/translate/create-create-and-params.ts index 175014606c..e596e1cbc1 100644 --- a/packages/graphql/src/translate/create-create-and-params.ts +++ b/packages/graphql/src/translate/create-create-and-params.ts @@ -24,7 +24,6 @@ import createAuthAndParams from "./create-auth-and-params"; import { AUTH_FORBIDDEN_ERROR } from "../constants"; import createSetRelationshipPropertiesAndParams from "./create-set-relationship-properties-and-params"; import mapToDbProperty from "../utils/map-to-db-property"; -import createRelationshipValidationStr from "./create-relationship-validation-str"; import { createConnectOrCreateAndParams } from "./connect-or-create/create-connect-or-create-and-params"; interface Res { @@ -260,12 +259,6 @@ function createCreateAndParams({ creates.push(`CALL apoc.util.validate(NOT(${meta.authStrs.join(" AND ")}), ${forbiddenString}, [0])`); } - const relationshipValidationStr = createRelationshipValidationStr({ node, context, varName }); - if (relationshipValidationStr) { - creates.push(`WITH ${withVars.join(", ")}`); - creates.push(relationshipValidationStr); - } - return [creates.join("\n"), params]; } diff --git a/packages/graphql/src/translate/create-relationship-validation-str.ts b/packages/graphql/src/translate/create-relationship-validation-str.ts deleted file mode 100644 index 3e0c0deba2..0000000000 --- a/packages/graphql/src/translate/create-relationship-validation-str.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Node } from "../classes"; -import { RELATIONSHIP_REQUIREMENT_PREFIX } from "../constants"; -import { Context } from "../types"; - -function createRelationshipValidationStr({ - node, - context, - varName, -}: { - node: Node; - context: Context; - varName: string; -}): string { - let relationshipValidationStr = ""; - - const nonNullRelationFields = node.relationFields.filter((field) => { - const isRequired = field.typeMeta.required; - const isArrayTypeRequired = field.typeMeta.arrayTypeRequired; - const isArray = field.typeMeta.array; - const isNotUnionOrInterface = Boolean(field.union) || Boolean(field.interface); - - if (isArray) { - return isArrayTypeRequired && !isNotUnionOrInterface; - } - - return isRequired && !isNotUnionOrInterface; - }); - - if (nonNullRelationFields.length) { - const nonNullPredicates = nonNullRelationFields.map((field) => { - const inStr = field.direction === "IN" ? "<-" : "-"; - const outStr = field.direction === "OUT" ? "->" : "-"; - const relTypeStr = `[:${field.type}]`; - const toNode = context.neoSchema.nodes.find((n) => n.name === field.typeMeta.name) as Node; - const exitsStr = `EXISTS((${varName})${inStr}${relTypeStr}${outStr}(${toNode.getLabelString(context)}))`; - - return `apoc.util.validatePredicate(NOT(${exitsStr}), '${RELATIONSHIP_REQUIREMENT_PREFIX}${node.name}.${field.fieldName} required', [0])`; - }); - - relationshipValidationStr = `CALL apoc.util.validate(NOT(${nonNullPredicates.join( - " AND " - )}), '${RELATIONSHIP_REQUIREMENT_PREFIX}', [0])`; - } - - return relationshipValidationStr; -} - -export default createRelationshipValidationStr; diff --git a/packages/graphql/src/translate/create-update-and-params.ts b/packages/graphql/src/translate/create-update-and-params.ts index 67ffa60491..bd3923f20e 100644 --- a/packages/graphql/src/translate/create-update-and-params.ts +++ b/packages/graphql/src/translate/create-update-and-params.ts @@ -30,7 +30,6 @@ import createSetRelationshipProperties from "./create-set-relationship-propertie import createConnectionWhereAndParams from "./where/create-connection-where-and-params"; import mapToDbProperty from "../utils/map-to-db-property"; import { createConnectOrCreateAndParams } from "./connect-or-create/create-connect-or-create-and-params"; -import createRelationshipValidationStr from "./create-relationship-validation-str"; import { wrapInCall } from "./utils/wrap-in-call"; interface Res { @@ -54,7 +53,6 @@ function createUpdateAndParams({ withVars, context, parameterPrefix, - fromTopLevel, }: { parentVar: string; updateInput: any; @@ -65,7 +63,6 @@ function createUpdateAndParams({ insideDoWhen?: boolean; context: Context; parameterPrefix: string; - fromTopLevel?: boolean; }): [string, any] { let hasAppliedTimeStamps = false; @@ -528,7 +525,6 @@ function createUpdateAndParams({ let preAuthStr = ""; let postAuthStr = ""; - const relationshipValidationStr = !fromTopLevel ? createRelationshipValidationStr({ node, context, varName }) : ""; const forbiddenString = insideDoWhen ? `\\"${AUTH_FORBIDDEN_ERROR}\\"` : `"${AUTH_FORBIDDEN_ERROR}"`; @@ -542,15 +538,9 @@ function createUpdateAndParams({ postAuthStr = `${withStr}\n${apocStr}`; } - return [ - [ - preAuthStr, - ...strs, - postAuthStr, - ...(relationshipValidationStr ? [withStr, relationshipValidationStr] : []), - ].join("\n"), - params, - ]; + const str = `${preAuthStr}\n${strs.join("\n")}\n${postAuthStr}`; + + return [str, params]; } export default createUpdateAndParams; diff --git a/packages/graphql/src/translate/translate-update.ts b/packages/graphql/src/translate/translate-update.ts index e7be93b410..dd310c3d2b 100644 --- a/packages/graphql/src/translate/translate-update.ts +++ b/packages/graphql/src/translate/translate-update.ts @@ -30,7 +30,6 @@ import createConnectionAndParams from "./connection/create-connection-and-params import createSetRelationshipPropertiesAndParams from "./create-set-relationship-properties-and-params"; import createInterfaceProjectionAndParams from "./create-interface-projection-and-params"; import translateTopLevelMatch from "./translate-top-level-match"; -import createRelationshipValidationStr from "./create-relationship-validation-str"; import { createConnectOrCreateAndParams } from "./connect-or-create/create-connect-or-create-and-params"; function translateUpdate({ node, context }: { node: Node; context: Context }): [string, any] { @@ -77,7 +76,6 @@ function translateUpdate({ node, context }: { node: Node; context: Context }): [ parentVar: varName, withVars: [varName], parameterPrefix: `${resolveTree.name}.args.update`, - fromTopLevel: true, }); [updateStr] = updateAndParams; cypherParams = { @@ -385,8 +383,6 @@ function translateUpdate({ node, context }: { node: Node; context: Context }): [ } } - const relationshipValidationStr = createRelationshipValidationStr({ node, context, varName }); - const returnStatement = nodeProjection ? `RETURN ${varName} ${projStr} AS ${varName}` : `RETURN 'Query cannot conclude with CALL'`; @@ -400,7 +396,6 @@ function translateUpdate({ node, context }: { node: Node; context: Context }): [ deleteStr, ...(connectionStrs.length || projAuth ? [`WITH ${varName}`] : []), // When FOREACH is the last line of update 'Neo4jError: WITH is required between FOREACH and CALL' ...(projAuth ? [projAuth] : []), - ...(relationshipValidationStr ? [`WITH ${varName}`, relationshipValidationStr] : []), ...connectionStrs, ...interfaceStrs, returnStatement, diff --git a/packages/graphql/src/types.ts b/packages/graphql/src/types.ts index 9e3eb1ba43..7b7102fb9f 100644 --- a/packages/graphql/src/types.ts +++ b/packages/graphql/src/types.ts @@ -98,7 +98,6 @@ export interface TypeMeta { pretty: string; }; }; - arrayTypeRequired?: boolean; } export interface Unique { diff --git a/packages/graphql/src/utils/execute.ts b/packages/graphql/src/utils/execute.ts index 3bbaf4af66..d519c0df31 100644 --- a/packages/graphql/src/utils/execute.ts +++ b/packages/graphql/src/utils/execute.ts @@ -23,14 +23,8 @@ import { Neo4jGraphQLForbiddenError, Neo4jGraphQLAuthenticationError, Neo4jGraphQLConstraintValidationError, - Neo4jGraphQLRelationshipValidationError, } from "../classes"; -import { - AUTH_FORBIDDEN_ERROR, - AUTH_UNAUTHENTICATED_ERROR, - DEBUG_EXECUTE, - RELATIONSHIP_REQUIREMENT_PREFIX, -} from "../constants"; +import { AUTH_FORBIDDEN_ERROR, AUTH_UNAUTHENTICATED_ERROR, DEBUG_EXECUTE } from "../constants"; import createAuthParam from "../translate/create-auth-param"; import { Context, DriverConfig } from "../types"; import environment from "../environment"; @@ -127,11 +121,6 @@ async function execute(input: { throw new Neo4jGraphQLAuthenticationError("Unauthenticated"); } - if (error.message.includes(`Caused by: java.lang.RuntimeException: ${RELATIONSHIP_REQUIREMENT_PREFIX}`)) { - const [, message] = error.message.split(RELATIONSHIP_REQUIREMENT_PREFIX); - throw new Neo4jGraphQLRelationshipValidationError(message); - } - if (error.code === "Neo.ClientError.Schema.ConstraintValidationFailed") { throw new Neo4jGraphQLConstraintValidationError("Constraint validation failed"); } diff --git a/packages/graphql/tests/integration/interface-relationships/create/create.int.test.ts b/packages/graphql/tests/integration/interface-relationships/create/create.int.test.ts index fbca1a8211..e2c5bbadc7 100644 --- a/packages/graphql/tests/integration/interface-relationships/create/create.int.test.ts +++ b/packages/graphql/tests/integration/interface-relationships/create/create.int.test.ts @@ -35,24 +35,24 @@ describe("interface relationships", () => { const typeDefs = gql` type Episode { runtime: Int! - series: Series @relationship(type: "HAS_EPISODE", direction: IN) + series: Series! @relationship(type: "HAS_EPISODE", direction: IN) } interface Production { title: String! - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Movie implements Production { title: String! runtime: Int! - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Series implements Production { title: String! - episodes: [Episode] @relationship(type: "HAS_EPISODE", direction: OUT) - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + episodes: [Episode!]! @relationship(type: "HAS_EPISODE", direction: OUT) + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } interface ActedIn @relationshipProperties { @@ -61,7 +61,7 @@ describe("interface relationships", () => { type Actor { name: String! - actedIn: [Production] @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") + actedIn: [Production!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") } `; diff --git a/packages/graphql/tests/integration/interface-relationships/update/create.int.test.ts b/packages/graphql/tests/integration/interface-relationships/update/create.int.test.ts index 4655ad617d..d4e3e8cf71 100644 --- a/packages/graphql/tests/integration/interface-relationships/update/create.int.test.ts +++ b/packages/graphql/tests/integration/interface-relationships/update/create.int.test.ts @@ -34,34 +34,34 @@ describe("interface relationships", () => { const typeDefs = gql` type Episode { - runtime: Int - series: Series @relationship(type: "HAS_EPISODE", direction: IN) + runtime: Int! + series: Series! @relationship(type: "HAS_EPISODE", direction: IN) } interface Production { - title: String - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + title: String! + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Movie implements Production { - title: String - runtime: Int - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + title: String! + runtime: Int! + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Series implements Production { - title: String - episodes: [Episode] @relationship(type: "HAS_EPISODE", direction: OUT) - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + title: String! + episodes: [Episode!]! @relationship(type: "HAS_EPISODE", direction: OUT) + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } interface ActedIn @relationshipProperties { - screenTime: Int + screenTime: Int! } type Actor { - name: String - actedIn: [Production] @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") + name: String! + actedIn: [Production!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") } `; diff --git a/packages/graphql/tests/integration/interface-relationships/update/update.int.test.ts b/packages/graphql/tests/integration/interface-relationships/update/update.int.test.ts index e44911091f..ae50dabd70 100644 --- a/packages/graphql/tests/integration/interface-relationships/update/update.int.test.ts +++ b/packages/graphql/tests/integration/interface-relationships/update/update.int.test.ts @@ -35,24 +35,24 @@ describe("interface relationships", () => { const typeDefs = gql` type Episode { runtime: Int! - series: Series @relationship(type: "HAS_EPISODE", direction: IN) + series: Series! @relationship(type: "HAS_EPISODE", direction: IN) } interface Production { title: String! - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Movie implements Production { title: String! runtime: Int! - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Series implements Production { title: String! - episodes: [Episode] @relationship(type: "HAS_EPISODE", direction: OUT) - actors: [Actor] @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") + episodes: [Episode!]! @relationship(type: "HAS_EPISODE", direction: OUT) + actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } interface ActedIn @relationshipProperties { @@ -61,7 +61,7 @@ describe("interface relationships", () => { type Actor { name: String! - actedIn: [Production] @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") + actedIn: [Production!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn") } `; diff --git a/packages/graphql/tests/integration/issues/247.int.test.ts b/packages/graphql/tests/integration/issues/247.int.test.ts index 4f128917b0..9c462f5122 100644 --- a/packages/graphql/tests/integration/issues/247.int.test.ts +++ b/packages/graphql/tests/integration/issues/247.int.test.ts @@ -39,12 +39,12 @@ describe("https://github.com/neo4j/graphql/issues/247", () => { const typeDefs = gql` type Movie { title: String! - owners: [User] @relationship(type: "OWNS", direction: IN) + owners: [User!]! @relationship(type: "OWNS", direction: IN) } type User { name: String! - movies: [Movie] @relationship(type: "OWNS", direction: OUT) + movies: [Movie!]! @relationship(type: "OWNS", direction: OUT) } `; diff --git a/packages/graphql/tests/integration/issues/315.int.test.ts b/packages/graphql/tests/integration/issues/315.int.test.ts index f91d790cdf..ab69628c0e 100644 --- a/packages/graphql/tests/integration/issues/315.int.test.ts +++ b/packages/graphql/tests/integration/issues/315.int.test.ts @@ -36,8 +36,8 @@ describe("https://github.com/neo4j/graphql/issues/315", () => { type User { id: ID! - friends: [User] @relationship(type: "HAS_FRIEND", direction: OUT) - posts: [Post] @relationship(type: "HAS_POST", direction: OUT) + friends: [User!]! @relationship(type: "HAS_FRIEND", direction: OUT) + posts: [Post!]! @relationship(type: "HAS_POST", direction: OUT) } type Query { diff --git a/packages/graphql/tests/integration/issues/388.int.test.ts b/packages/graphql/tests/integration/issues/388.int.test.ts index 434e183902..4949270ff6 100644 --- a/packages/graphql/tests/integration/issues/388.int.test.ts +++ b/packages/graphql/tests/integration/issues/388.int.test.ts @@ -36,8 +36,8 @@ describe("https://github.com/neo4j/graphql/issues/388", () => { type User { id: ID! - friends: [User] @relationship(type: "HAS_FRIEND", direction: OUT) - posts: [Post] @relationship(type: "HAS_POST", direction: OUT) + friends: [User!]! @relationship(type: "HAS_FRIEND", direction: OUT) + posts: [Post!]! @relationship(type: "HAS_POST", direction: OUT) } type Query { diff --git a/packages/graphql/tests/integration/issues/440.int.test.ts b/packages/graphql/tests/integration/issues/440.int.test.ts index 97bc01a972..df8be61ee6 100644 --- a/packages/graphql/tests/integration/issues/440.int.test.ts +++ b/packages/graphql/tests/integration/issues/440.int.test.ts @@ -29,12 +29,12 @@ describe("https://github.com/neo4j/graphql/issues/440", () => { const typeDefs = gql` type Video { id: ID! @id(autogenerate: false) - categories: [Category] @relationship(type: "IS_CATEGORIZED_AS", direction: OUT) + categories: [Category!]! @relationship(type: "IS_CATEGORIZED_AS", direction: OUT) } type Category { id: ID! @id(autogenerate: false) - videos: [Video] @relationship(type: "IS_CATEGORIZED_AS", direction: IN) + videos: [Video!]! @relationship(type: "IS_CATEGORIZED_AS", direction: IN) } `; diff --git a/packages/graphql/tests/integration/issues/549.int.test.ts b/packages/graphql/tests/integration/issues/549.int.test.ts deleted file mode 100644 index 839245ae59..0000000000 --- a/packages/graphql/tests/integration/issues/549.int.test.ts +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Driver } from "neo4j-driver"; -import { graphql } from "graphql"; -import { gql } from "apollo-server"; -import { generate } from "randomstring"; -import neo4j from "../neo4j"; -import { Neo4jGraphQL } from "../../../src/classes"; - -describe("https://github.com/neo4j/graphql/issues/549", () => { - let driver: Driver; - - beforeAll(async () => { - driver = await neo4j(); - }); - - afterAll(async () => { - await driver.close(); - }); - - test("should throw error when creating a node without a (single) relationship", async () => { - const typeDefs = gql` - type Director { - id: ID! - } - - type Movie { - id: ID! - director: Director! @relationship(type: "DIRECTED", direction: IN) - } - `; - - const neoSchema = new Neo4jGraphQL({ typeDefs }); - - const movieId = generate({ - charset: "alphabetic", - }); - - const mutation = ` - mutation { - createMovies(input: [{id: "${movieId}"}]) { - info { - nodesCreated - } - } - } - `; - - const result = await graphql({ - schema: neoSchema.schema, - source: mutation, - contextValue: { driver }, - }); - - expect(result.errors).toBeTruthy(); - expect((result.errors as any[])[0].message).toEqual("Movie.director required"); - }); - - test("should throw error when creating a node without a (array) relationship", async () => { - const typeDefs = gql` - type Director { - id: ID! - } - - type Movie { - id: ID! - directors: [Director!] @relationship(type: "DIRECTED", direction: IN) - } - `; - - const neoSchema = new Neo4jGraphQL({ typeDefs }); - - const movieId = generate({ - charset: "alphabetic", - }); - - const mutation = ` - mutation { - createMovies(input: [{id: "${movieId}"}]) { - info { - nodesCreated - } - } - } - `; - - const result = await graphql({ - schema: neoSchema.schema, - source: mutation, - contextValue: { driver }, - }); - - expect(result.errors).toBeTruthy(); - expect((result.errors as any[])[0].message).toEqual("Movie.directors required"); - }); - - test("should throw error when updating a node (top level) without a (single) relationship", async () => { - const session = driver.session(); - - const typeDefs = gql` - type Director { - id: ID! - } - - type Movie { - id: ID! - director: Director! @relationship(type: "DIRECTED", direction: IN) - } - `; - - const neoSchema = new Neo4jGraphQL({ typeDefs }); - - const movieId = generate({ - charset: "alphabetic", - }); - - const mutation = ` - mutation { - updateMovies(where: {id: "${movieId}"}, update: { id: "${movieId}" }) { - info { - nodesCreated - } - } - } - `; - - try { - await session.run(` - CREATE (:Movie {id: "${movieId}"}) - `); - - const result = await graphql({ - schema: neoSchema.schema, - source: mutation, - contextValue: { driver }, - }); - - expect(result.errors).toBeTruthy(); - expect((result.errors as any[])[0].message).toEqual("Movie.director required"); - } finally { - await session.close(); - } - }); - - test("should throw error when updating a node (top level) without a (array) relationship", async () => { - const session = driver.session(); - - const typeDefs = gql` - type Director { - id: ID! - } - - type Movie { - id: ID! - directors: [Director!] @relationship(type: "DIRECTED", direction: IN) - } - `; - - const neoSchema = new Neo4jGraphQL({ typeDefs }); - - const movieId = generate({ - charset: "alphabetic", - }); - - const mutation = ` - mutation { - updateMovies(where: {id: "${movieId}"}, update: { id: "${movieId}" }) { - info { - nodesCreated - } - } - } - `; - - try { - await session.run(` - CREATE (:Movie {id: "${movieId}"}) - `); - - const result = await graphql({ - schema: neoSchema.schema, - source: mutation, - contextValue: { driver }, - }); - - expect(result.errors).toBeTruthy(); - expect((result.errors as any[])[0].message).toEqual("Movie.directors required"); - } finally { - await session.close(); - } - }); - - test("should throw error when updating a node (field level) without a (single) relationship", async () => { - const session = driver.session(); - - const typeDefs = gql` - type Director { - id: ID! - directed: [Movie!] @relationship(type: "DIRECTED", direction: OUT) - } - - type Movie { - id: ID! - director: Director! @relationship(type: "DIRECTED", direction: IN) - } - `; - - const neoSchema = new Neo4jGraphQL({ typeDefs }); - - const movieId = generate({ - charset: "alphabetic", - }); - - const directorId = generate({ - charset: "alphabetic", - }); - - const mutation = ` - mutation { - updateDirectors( - where: { id: "${directorId}" }, - update: { - directed: { - update: { ## <---------------------------------------- 👀 The test is making sure the validation gets called here - node: { - director: { - disconnect: { - where: { - node: { - id: "${directorId}" - } - } - } - } - } - } - } - } - ) { - info { - nodesCreated - } - } - } - `; - - try { - await session.run(` - CREATE (:Director {id: "${directorId}"})-[:DIRECTED]->(:Movie {id: "${movieId}"}) - `); - - const result = await graphql({ - schema: neoSchema.schema, - source: mutation, - contextValue: { driver }, - }); - - expect(result.errors).toBeTruthy(); - expect((result.errors as any[])[0].message).toEqual("Movie.director required"); - } finally { - await session.close(); - } - }); - - test("should throw error when updating a node (field level) without a (array) relationship", async () => { - const session = driver.session(); - - const typeDefs = gql` - type Director { - id: ID! - directed: [Movie!] @relationship(type: "DIRECTED", direction: OUT) - } - - type Movie { - id: ID! - directors: [Director!]! @relationship(type: "DIRECTED", direction: IN) - } - `; - - const neoSchema = new Neo4jGraphQL({ typeDefs }); - - const movieId = generate({ - charset: "alphabetic", - }); - - const directorId = generate({ - charset: "alphabetic", - }); - - const mutation = ` - mutation { - updateDirectors( - where: { id: "${directorId}" }, - update: { - directed: { - update: { ## <---------------------------------------- 👀 The test is making sure the validation gets called here - node: { - directors: { - disconnect: { - where: { - node: { - id: "${directorId}" - } - } - } - } - } - } - } - } - ) { - info { - nodesCreated - } - } - } - `; - - try { - await session.run(` - CREATE (:Director {id: "${directorId}"})-[:DIRECTED]->(:Movie {id: "${movieId}"}) - `); - - const result = await graphql({ - schema: neoSchema.schema, - source: mutation, - contextValue: { driver }, - }); - - expect(result.errors).toBeTruthy(); - expect((result.errors as any[])[0].message).toEqual("Movie.directors required"); - } finally { - await session.close(); - } - }); -}); diff --git a/packages/graphql/tests/integration/issues/572.int.test.ts b/packages/graphql/tests/integration/issues/572.int.test.ts new file mode 100644 index 0000000000..853ea971e2 --- /dev/null +++ b/packages/graphql/tests/integration/issues/572.int.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import pluralize from "pluralize"; +import { Driver } from "neo4j-driver"; +import { graphql } from "graphql"; +import { gql } from "apollo-server"; +import neo4j from "../neo4j"; +import { Neo4jGraphQL } from "../../../src/classes"; +import { generateUniqueType } from "../../../src/utils/test/graphql-types"; + +describe("Revert https://github.com/neo4j/graphql/pull/572", () => { + let driver: Driver; + + beforeAll(async () => { + driver = await neo4j(); + }); + + afterAll(async () => { + await driver.close(); + }); + + test("should create user without related friend in many-to-many relationship", async () => { + const user = generateUniqueType("User"); + + const typeDefs = gql` + type ${user.name} { + name: String! + friends: [${user.name}!]! @relationship(type: "FRIENDS_WITH", direction: OUT) + } + `; + + const neoSchema = new Neo4jGraphQL({ typeDefs }); + + const query = ` + mutation { + create${pluralize(user.name)}(input: { name: "Ford" }) { + info { + nodesCreated + } + } + } + `; + + const gqlResult = await graphql({ + schema: neoSchema.schema, + source: query, + contextValue: { driver }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect(gqlResult.data).toEqual({ + [`create${pluralize(user.name)}`]: { + info: { + nodesCreated: 1, + }, + }, + }); + }); +}); diff --git a/packages/graphql/tests/integration/relationship-properties/create.int.test.ts b/packages/graphql/tests/integration/relationship-properties/create.int.test.ts index 77b7b867aa..ee7858656f 100644 --- a/packages/graphql/tests/integration/relationship-properties/create.int.test.ts +++ b/packages/graphql/tests/integration/relationship-properties/create.int.test.ts @@ -39,12 +39,12 @@ describe("Relationship properties - create", () => { const typeDefs = gql` type Movie { title: String! - actors: [Actor] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) + actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) } type Actor { name: String! - movies: [Movie] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) + movies: [Movie!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) } interface ActedIn { diff --git a/packages/graphql/tests/integration/relationship-properties/delete.int.test.ts b/packages/graphql/tests/integration/relationship-properties/delete.int.test.ts index 06978f2b6d..91869c08ce 100644 --- a/packages/graphql/tests/integration/relationship-properties/delete.int.test.ts +++ b/packages/graphql/tests/integration/relationship-properties/delete.int.test.ts @@ -39,12 +39,12 @@ describe("Relationship properties - delete", () => { const typeDefs = gql` type Movie { title: String! - actors: [Actor] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) + actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) } type Actor { name: String! - movies: [Movie] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) + movies: [Movie!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) } interface ActedIn { diff --git a/packages/graphql/tests/integration/relationship-properties/disconnect.int.test.ts b/packages/graphql/tests/integration/relationship-properties/disconnect.int.test.ts index eeb22b9e83..a638920cc7 100644 --- a/packages/graphql/tests/integration/relationship-properties/disconnect.int.test.ts +++ b/packages/graphql/tests/integration/relationship-properties/disconnect.int.test.ts @@ -39,12 +39,12 @@ describe("Relationship properties - disconnect", () => { const typeDefs = gql` type Movie { title: String! - actors: [Actor] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) + actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) } type Actor { name: String! - movies: [Movie] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) + movies: [Movie!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) } interface ActedIn { diff --git a/packages/graphql/tests/integration/relationship-properties/update.int.test.ts b/packages/graphql/tests/integration/relationship-properties/update.int.test.ts index 6edec8a913..40bd6f22ae 100644 --- a/packages/graphql/tests/integration/relationship-properties/update.int.test.ts +++ b/packages/graphql/tests/integration/relationship-properties/update.int.test.ts @@ -30,12 +30,12 @@ describe("Relationship properties - update", () => { const typeDefs = gql` type Movie { title: String! - actors: [Actor] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) + actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN) } type Actor { name: String! - movies: [Movie] @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) + movies: [Movie!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT) } interface ActedIn { diff --git a/packages/graphql/tests/tck/tck-test-files/connections/connect-or-create/connect-or-create.test.ts b/packages/graphql/tests/tck/tck-test-files/connections/connect-or-create/connect-or-create.test.ts index f9701f5790..0b71bf475d 100644 --- a/packages/graphql/tests/tck/tck-test-files/connections/connect-or-create/connect-or-create.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/connections/connect-or-create/connect-or-create.test.ts @@ -91,8 +91,6 @@ describe("Create or connect", () => { ON CREATE SET this0_relationship_this0_movies_connectOrCreate0.screentime = $this0_relationship_this0_movies_connectOrCreate0_on_create_screentime - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)-[:ACTED_IN]->(:Movie))), '@neo4j/graphql/RELATIONSHIP-REQUIREDActor.movies required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } RETURN @@ -156,8 +154,6 @@ describe("Create or connect", () => { this_relationship_this_movies0_connectOrCreate0.screentime = $this_relationship_this_movies0_connectOrCreate0_on_create_screentime RETURN COUNT(*) } - WITH this - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this)-[:ACTED_IN]->(:Movie))), '@neo4j/graphql/RELATIONSHIP-REQUIREDActor.movies required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this { .name } AS this" `); diff --git a/packages/graphql/tests/tck/tck-test-files/connections/projections/create.test.ts b/packages/graphql/tests/tck/tck-test-files/connections/projections/create.test.ts index b921981567..40d66333f2 100644 --- a/packages/graphql/tests/tck/tck-test-files/connections/projections/create.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/connections/projections/create.test.ts @@ -79,8 +79,6 @@ describe("Cypher -> Connections -> Projections -> Create", () => { "CALL { CREATE (this0:Movie) SET this0.title = $this0_title - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } CALL { @@ -128,15 +126,11 @@ describe("Cypher -> Connections -> Projections -> Create", () => { "CALL { CREATE (this0:Movie) SET this0.title = $this0_title - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } CALL { CREATE (this1:Movie) SET this1.title = $this1_title - WITH this1 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this1)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this1 } CALL { @@ -192,15 +186,11 @@ describe("Cypher -> Connections -> Projections -> Create", () => { "CALL { CREATE (this0:Movie) SET this0.title = $this0_title - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } CALL { CREATE (this1:Movie) SET this1.title = $this1_title - WITH this1 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this1)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this1 } CALL { diff --git a/packages/graphql/tests/tck/tck-test-files/connections/projections/update.test.ts b/packages/graphql/tests/tck/tck-test-files/connections/projections/update.test.ts index 2a45e3e0ee..c1f982433a 100644 --- a/packages/graphql/tests/tck/tck-test-files/connections/projections/update.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/connections/projections/update.test.ts @@ -79,8 +79,6 @@ describe("Cypher -> Connections -> Projections -> Update", () => { "MATCH (this:Movie) WHERE this.title = $this_title WITH this - WITH this - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) CALL { WITH this MATCH (this)<-[this_acted_in_relationship:ACTED_IN]-(this_actor:Actor) diff --git a/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/connect.test.ts b/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/connect.test.ts index 3c6b435749..bf88990089 100644 --- a/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/connect.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/connect.test.ts @@ -91,8 +91,6 @@ describe("Relationship Properties Connect Cypher", () => { ) RETURN count(*) } - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } CALL { @@ -164,8 +162,6 @@ describe("Relationship Properties Connect Cypher", () => { ) RETURN count(*) } - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } CALL { @@ -230,8 +226,6 @@ describe("Relationship Properties Connect Cypher", () => { RETURN count(*) } WITH this - WITH this - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) CALL { WITH this MATCH (this)<-[this_acted_in_relationship:ACTED_IN]-(this_actor:Actor) @@ -296,8 +290,6 @@ describe("Relationship Properties Connect Cypher", () => { RETURN count(*) } WITH this - WITH this - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) CALL { WITH this MATCH (this)<-[this_acted_in_relationship:ACTED_IN]-(this_actor:Actor) diff --git a/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/create.test.ts b/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/create.test.ts index a62938b30a..b4c5c4df06 100644 --- a/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/create.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/create.test.ts @@ -89,12 +89,8 @@ describe("Relationship Properties Create Cypher", () => { WITH this0 CREATE (this0_actors0_node:Actor) SET this0_actors0_node.name = $this0_actors0_node_name - WITH this0, this0_actors0_node - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0_actors0_node)-[:ACTED_IN]->(:Movie))), '@neo4j/graphql/RELATIONSHIP-REQUIREDActor.movies required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) MERGE (this0)<-[this0_actors0_relationship:ACTED_IN]-(this0_actors0_node) SET this0_actors0_relationship.screenTime = $this0_actors0_relationship_screenTime - WITH this0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this0 } CALL { diff --git a/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/update.test.ts b/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/update.test.ts index 7d5b8394fe..0150b48572 100644 --- a/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/update.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/connections/relationship_properties/update.test.ts @@ -83,8 +83,6 @@ describe("Cypher -> Connections -> Relationship Properties -> Update", () => { RETURN count(*) \\", \\"\\", {this_acted_in0_relationship:this_acted_in0_relationship, updateMovies: $updateMovies}) YIELD value as this_acted_in0_relationship_actors0_edge - WITH this - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this { .title } AS this" `); @@ -152,8 +150,6 @@ describe("Cypher -> Connections -> Relationship Properties -> Update", () => { WHERE this_actors0.name = $updateMovies.args.update.actors[0].where.node.name CALL apoc.do.when(this_actors0 IS NOT NULL, \\" SET this_actors0.name = $this_update_actors0_name - WITH this, this_actors0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actors0)-[:ACTED_IN]->(:Movie))), '@neo4j/graphql/RELATIONSHIP-REQUIREDActor.movies required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateMovies: $updateMovies, this_actors0:this_actors0, auth:$auth,this_update_actors0_name:$this_update_actors0_name}) YIELD value as _ @@ -162,8 +158,6 @@ describe("Cypher -> Connections -> Relationship Properties -> Update", () => { RETURN count(*) \\", \\"\\", {this_acted_in0_relationship:this_acted_in0_relationship, updateMovies: $updateMovies}) YIELD value as this_acted_in0_relationship_actors0_edge - WITH this - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN this { .title } AS this" `); diff --git a/packages/graphql/tests/tck/tck-test-files/interface-relationships/update/update.test.ts b/packages/graphql/tests/tck/tck-test-files/interface-relationships/update/update.test.ts index 8e049328b7..cc8685e2ec 100644 --- a/packages/graphql/tests/tck/tck-test-files/interface-relationships/update/update.test.ts +++ b/packages/graphql/tests/tck/tck-test-files/interface-relationships/update/update.test.ts @@ -92,8 +92,6 @@ describe("Interface Relationships - Update update", () => { WHERE this_actedIn0.title = $updateActors.args.update.actedIn[0].where.node.title CALL apoc.do.when(this_actedIn0 IS NOT NULL, \\" SET this_actedIn0.title = $this_update_actedIn0_title - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_title:$this_update_actedIn0_title}) YIELD value as _ @@ -104,8 +102,6 @@ describe("Interface Relationships - Update update", () => { WHERE this_actedIn0.title = $updateActors.args.update.actedIn[0].where.node.title CALL apoc.do.when(this_actedIn0 IS NOT NULL, \\" SET this_actedIn0.title = $this_update_actedIn0_title - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDSeries.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_title:$this_update_actedIn0_title}) YIELD value as _ @@ -186,8 +182,6 @@ describe("Interface Relationships - Update update", () => { RETURN count(*) \\\\\\", \\\\\\"\\\\\\", {this:this, this_actedIn0:this_actedIn0, updateActors: $updateActors, this_actedIn0_actors0:this_actedIn0_actors0, auth:$auth,this_update_actedIn0_actors0_name:$this_update_actedIn0_actors0_name}) YIELD value as _ - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_actors0_name:$this_update_actedIn0_actors0_name}) YIELD value as _ @@ -204,8 +198,6 @@ describe("Interface Relationships - Update update", () => { RETURN count(*) \\\\\\", \\\\\\"\\\\\\", {this:this, this_actedIn0:this_actedIn0, updateActors: $updateActors, this_actedIn0_actors0:this_actedIn0_actors0, auth:$auth,this_update_actedIn0_actors0_name:$this_update_actedIn0_actors0_name}) YIELD value as _ - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDSeries.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_actors0_name:$this_update_actedIn0_actors0_name}) YIELD value as _ @@ -290,16 +282,12 @@ describe("Interface Relationships - Update update", () => { WHERE this_actedIn0.title = $updateActors.args.update.actedIn[0].where.node.title CALL apoc.do.when(this_actedIn0 IS NOT NULL, \\" WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) - WITH this, this_actedIn0 OPTIONAL MATCH (this_actedIn0)<-[this_actedIn0_acted_in0_relationship:ACTED_IN]-(this_actedIn0_actors0:Actor) CALL apoc.do.when(this_actedIn0_actors0 IS NOT NULL, \\\\\\" SET this_actedIn0_actors0.name = $this_update_actedIn0_on_Movie_actors0_name RETURN count(*) \\\\\\", \\\\\\"\\\\\\", {this:this, this_actedIn0:this_actedIn0, updateActors: $updateActors, this_actedIn0_actors0:this_actedIn0_actors0, auth:$auth,this_update_actedIn0_on_Movie_actors0_name:$this_update_actedIn0_on_Movie_actors0_name}) YIELD value as _ - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_on_Movie_actors0_name:$this_update_actedIn0_on_Movie_actors0_name}) YIELD value as _ @@ -309,8 +297,6 @@ describe("Interface Relationships - Update update", () => { OPTIONAL MATCH (this)-[this_acted_in0_relationship:ACTED_IN]->(this_actedIn0:Series) WHERE this_actedIn0.title = $updateActors.args.update.actedIn[0].where.node.title CALL apoc.do.when(this_actedIn0 IS NOT NULL, \\" - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDSeries.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth}) YIELD value as _ @@ -402,16 +388,12 @@ describe("Interface Relationships - Update update", () => { WHERE this_actedIn0.title = $updateActors.args.update.actedIn[0].where.node.title CALL apoc.do.when(this_actedIn0 IS NOT NULL, \\" WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) - WITH this, this_actedIn0 OPTIONAL MATCH (this_actedIn0)<-[this_actedIn0_acted_in0_relationship:ACTED_IN]-(this_actedIn0_actors0:Actor) CALL apoc.do.when(this_actedIn0_actors0 IS NOT NULL, \\\\\\" SET this_actedIn0_actors0.name = $this_update_actedIn0_on_Movie_actors0_name RETURN count(*) \\\\\\", \\\\\\"\\\\\\", {this:this, this_actedIn0:this_actedIn0, updateActors: $updateActors, this_actedIn0_actors0:this_actedIn0_actors0, auth:$auth,this_update_actedIn0_on_Movie_actors0_name:$this_update_actedIn0_on_Movie_actors0_name}) YIELD value as _ - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_on_Movie_actors0_name:$this_update_actedIn0_on_Movie_actors0_name}) YIELD value as _ @@ -428,8 +410,6 @@ describe("Interface Relationships - Update update", () => { RETURN count(*) \\\\\\", \\\\\\"\\\\\\", {this:this, this_actedIn0:this_actedIn0, updateActors: $updateActors, this_actedIn0_actors0:this_actedIn0_actors0, auth:$auth,this_update_actedIn0_actors0_name:$this_update_actedIn0_actors0_name}) YIELD value as _ - WITH this, this_actedIn0 - CALL apoc.util.validate(NOT(apoc.util.validatePredicate(NOT(EXISTS((this_actedIn0)<-[:ACTED_IN]-(:Actor))), '@neo4j/graphql/RELATIONSHIP-REQUIREDSeries.actors required', [0])), '@neo4j/graphql/RELATIONSHIP-REQUIRED', [0]) RETURN count(*) \\", \\"\\", {this:this, updateActors: $updateActors, this_actedIn0:this_actedIn0, auth:$auth,this_update_actedIn0_actors0_name:$this_update_actedIn0_actors0_name}) YIELD value as _