diff --git a/.changeset/orange-bats-add.md b/.changeset/orange-bats-add.md new file mode 100644 index 0000000000..717d1af76b --- /dev/null +++ b/.changeset/orange-bats-add.md @@ -0,0 +1,21 @@ +--- +"@neo4j/graphql": major +--- + +`@cypher` directive now requires the parameter `columnName`. + +This requires all cypher queries to be made with a valid alias that must be referred in this new parameter. + +For Example: + +**@neo4j/graphql@3** + +``` +@cypher(statement: "MATCH (i:Item) WHERE i.public=true RETURN i.name") +``` + +**@neo4j/graphql@4** + +``` +@cypher(statement: "MATCH (i:Item) WHERE i.public=true RETURN i.name as result", columnName: "result") +``` diff --git a/docs/contributing/DEVELOPING.md b/docs/contributing/DEVELOPING.md index 1abe8a5865..b596eb7c4f 100644 --- a/docs/contributing/DEVELOPING.md +++ b/docs/contributing/DEVELOPING.md @@ -113,6 +113,14 @@ run the following from `packages/graphql`: yarn test:tck ``` +### Verify TCK Tests + +You can run all the TCK tests against the database to check that the Cypher generated is valid. This can be done with the env variable `VERIFY_TCK` + +```bash +VERIFY_TCK yarn test:tck +``` + ### Testing using docker ```bash diff --git a/examples/neo-place/typedefs.graphql b/examples/neo-place/typedefs.graphql index c534811385..ee9a0bd7a4 100644 --- a/examples/neo-place/typedefs.graphql +++ b/examples/neo-place/typedefs.graphql @@ -12,6 +12,7 @@ type Query { ORDER BY p.position ASC RETURN collect(color) as canvas """ + columnName: "canvas" ) @auth(rules: [{ isAuthenticated: true }]) } diff --git a/examples/neo-push/server/src/gql/Blog.ts b/examples/neo-push/server/src/gql/Blog.ts index 5a02a02005..41f75f186c 100644 --- a/examples/neo-push/server/src/gql/Blog.ts +++ b/examples/neo-push/server/src/gql/Blog.ts @@ -14,6 +14,7 @@ export const typeDefs = gql` WITH creator IS NOT NULL AS isCreator RETURN isCreator """ + columnName: "isCreator" ) isAuthor: Boolean @cypher( @@ -22,6 +23,7 @@ export const typeDefs = gql` WITH author IS NOT NULL AS isAuthor RETURN isAuthor """ + columnName: "isAuthor" ) createdAt: DateTime @timestamp(operations: [CREATE]) updatedAt: DateTime @timestamp(operations: [UPDATE]) diff --git a/examples/neo-push/server/src/gql/Comment.ts b/examples/neo-push/server/src/gql/Comment.ts index 0c8cbdaf96..7a8085f896 100644 --- a/examples/neo-push/server/src/gql/Comment.ts +++ b/examples/neo-push/server/src/gql/Comment.ts @@ -21,6 +21,7 @@ export const typeDefs = gql` ) AS canDelete RETURN canDelete """ + columnName: "canDelete" ) createdAt: DateTime @timestamp(operations: [CREATE]) updatedAt: DateTime @timestamp(operations: [UPDATE]) diff --git a/examples/neo-push/server/src/gql/Post.ts b/examples/neo-push/server/src/gql/Post.ts index 7dbbf22754..6eaf6b18e6 100644 --- a/examples/neo-push/server/src/gql/Post.ts +++ b/examples/neo-push/server/src/gql/Post.ts @@ -22,6 +22,7 @@ export const typeDefs = gql` ) AS canEdit RETURN canEdit """ + columnName: "canEdit" ) canDelete: Boolean @cypher( @@ -35,6 +36,7 @@ export const typeDefs = gql` ) AS canDelete RETURN canDelete """ + columnName: "canDelete" ) createdAt: DateTime @timestamp(operations: [CREATE]) updatedAt: DateTime @timestamp(operations: [UPDATE]) diff --git a/examples/subscriptions/apollo_rabbitmq/server.js b/examples/subscriptions/apollo_rabbitmq/server.js index cde67aca0e..74384c1786 100644 --- a/examples/subscriptions/apollo_rabbitmq/server.js +++ b/examples/subscriptions/apollo_rabbitmq/server.js @@ -40,7 +40,7 @@ const plugin = new Neo4jGraphQLSubscriptionsAMQPPlugin({ }); //Alternatively, we can remove the AMQP server if we are only using a development server -// const plugin = new new Neo4jGraphQLSubscriptionsSingleInstancePlugin(); +// const plugin = new Neo4jGrapghQLSubscriptionsSingleInstancePlugin(); if (!process.argv[2]) throw new Error("Usage node server.js [port]"); diff --git a/packages/graphql/src/constants.ts b/packages/graphql/src/constants.ts index 19375a76d5..4a6b113775 100644 --- a/packages/graphql/src/constants.ts +++ b/packages/graphql/src/constants.ts @@ -22,12 +22,7 @@ const DEBUG_PREFIX = "@neo4j/graphql"; export const AUTH_FORBIDDEN_ERROR = "@neo4j/graphql/FORBIDDEN"; export const AUTH_UNAUTHENTICATED_ERROR = "@neo4j/graphql/UNAUTHENTICATED"; export const MIN_VERSIONS = [{ majorMinor: "4.3", neo4j: "4.3.2" }]; -export const REQUIRED_APOC_FUNCTIONS = [ - "apoc.util.validatePredicate", - "apoc.cypher.runFirstColumnSingle", - "apoc.cypher.runFirstColumnMany", - "apoc.date.convertFormat", -]; +export const REQUIRED_APOC_FUNCTIONS = ["apoc.util.validatePredicate", "apoc.date.convertFormat"]; export const REQUIRED_APOC_PROCEDURES = ["apoc.util.validate", "apoc.do.when", "apoc.cypher.doIt"]; export const DEBUG_ALL = `${DEBUG_PREFIX}:*`; export const DEBUG_AUTH = `${DEBUG_PREFIX}:auth`; diff --git a/packages/graphql/src/graphql/directives/cypher.ts b/packages/graphql/src/graphql/directives/cypher.ts index c60d8648c6..908a340605 100644 --- a/packages/graphql/src/graphql/directives/cypher.ts +++ b/packages/graphql/src/graphql/directives/cypher.ts @@ -31,9 +31,8 @@ export const cypherDirective = new GraphQLDirective({ type: new GraphQLNonNull(GraphQLString), }, columnName: { - description: - "[Experimental] Name of the returned variable from the Cypher statement, if provided, the query will be optimized to improve performance.", - type: GraphQLString, + description: "Name of the returned variable from the Cypher statement.", + type: new GraphQLNonNull(GraphQLString), }, }, }); diff --git a/packages/graphql/src/schema/make-augmented-schema.test.ts b/packages/graphql/src/schema/make-augmented-schema.test.ts index dffeb7b202..229b65867e 100644 --- a/packages/graphql/src/schema/make-augmented-schema.test.ts +++ b/packages/graphql/src/schema/make-augmented-schema.test.ts @@ -182,7 +182,7 @@ describe("makeAugmentedSchema", () => { } type Query { - movies: [Movie!]! @cypher(statement: "") + movies: [Movie!]! @cypher(statement: "RETURN 5 as a", columnName: "a") } `; @@ -225,7 +225,7 @@ describe("makeAugmentedSchema", () => { name: String } - interface ActedIn @cypher(statement: "RETURN rand()") { + interface ActedIn @cypher(statement: "RETURN rand() as rand", columnName: "rand") { screenTime: Int } `; @@ -282,7 +282,7 @@ describe("makeAugmentedSchema", () => { } interface ActedIn { - id: ID @cypher(statement: "RETURN id(this)") + id: ID @cypher(statement: "RETURN id(this) as id", columnName: "id") roles: [String] } `; diff --git a/packages/graphql/src/schema/validation/validate-document.test.ts b/packages/graphql/src/schema/validation/validate-document.test.ts index 5f85c2b051..cbbddf99cc 100644 --- a/packages/graphql/src/schema/validation/validate-document.test.ts +++ b/packages/graphql/src/schema/validation/validate-document.test.ts @@ -171,6 +171,7 @@ describe("validateDocument", () => { post.id = randomUUID() RETURN post """ + columnName: "post" ) } @@ -277,6 +278,7 @@ describe("validateDocument", () => { s.salaryReviewDate = salary.salaryReviewDate RETURN s """ + columnName: "s" ) mergeEmploymentRecords(employmentRecords: [EmpRecord]): [EmploymentRecord] @@ -303,6 +305,7 @@ describe("validateDocument", () => { MERGE (er)-[:PAYS_SALARY]->(s) RETURN er """ + columnName: "er" ) } `; @@ -319,7 +322,7 @@ describe("validateDocument", () => { } type Query { - nodes: [Test] @cypher(statement: "") + nodes: [Test] @cypher(statement: "", columnName: "") } `; @@ -374,10 +377,15 @@ describe("validateDocument", () => { } extend type Order { - subTotal: Float @cypher(statement: "MATCH (this)-[:CONTAINS]->(b:Book) RETURN sum(b.price)") + subTotal: Float + @cypher( + statement: "MATCH (this)-[:CONTAINS]->(b:Book) RETURN sum(b.price) as result" + columnName: "result" + ) shippingCost: Float @cypher( - statement: "MATCH (this)-[:SHIPS_TO]->(a:Address) RETURN round(0.01 * distance(a.location, Point({latitude: 40.7128, longitude: -74.0060})) / 1000, 2)" + statement: "MATCH (this)-[:SHIPS_TO]->(a:Address) RETURN round(0.01 * distance(a.location, Point({latitude: 40.7128, longitude: -74.0060})) / 1000, 2) as result" + columnName: "result" ) estimatedDelivery: DateTime @customResolver } @@ -389,6 +397,7 @@ describe("validateDocument", () => { recommended(limit: Int = 3): [Book] @cypher( statement: "MATCH (this)-[:PLACED]->(:Order)-[:CONTAINS]->(:Book)<-[:CONTAINS]-(:Order)<-[:PLACED]-(c:Customer) MATCH (c)-[:PLACED]->(:Order)-[:CONTAINS]->(rec:Book) WHERE NOT exists((this)-[:PLACED]->(:Order)-[:CONTAINS]->(rec)) RETURN rec LIMIT $limit" + columnName: "rec" ) } @@ -402,6 +411,7 @@ describe("validateDocument", () => { currentWeather: Weather @cypher( statement: "CALL apoc.load.json('https://www.7timer.info/bin/civil.php?lon=' + this.location.longitude + '&lat=' + this.location.latitude + '&ac=0&unit=metric&output=json&tzshift=0') YIELD value WITH value.dataseries[0] as weather RETURN {temperature: weather.temp2m, windSpeed: weather.wind10m.speed, windDirection: weather.wind10m.direction, precipitation: weather.prec_type, summary: weather.weather} AS conditions" + columnName: "conditions" ) } @@ -435,6 +445,7 @@ describe("validateDocument", () => { ORDER BY jaccard DESC RETURN b LIMIT 1 """ + columnName: "b" ) } @@ -467,6 +478,7 @@ describe("validateDocument", () => { MERGE (t)-[:ABOUT]->(s) RETURN s """ + columnName: "s" ) } @@ -477,6 +489,7 @@ describe("validateDocument", () => { CALL db.index.fulltext.queryNodes('bookIndex', $searchString+'~') YIELD node RETURN node """ + columnName: "node" ) } `; diff --git a/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts b/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts index 806d713660..1be8cfed8b 100644 --- a/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts +++ b/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts @@ -147,7 +147,6 @@ export function translateCypherDirectiveProjection({ } } - let customCypherClause: Cypher.Clause | undefined; const nodeRef = new Cypher.NamedNode(chainStr); // Null default argument values are not passed into the resolve tree therefore these are not being passed to @@ -161,23 +160,12 @@ export function translateCypherDirectiveProjection({ ); const extraArgs = { ...nullArgumentValues, ...field.args }; - if (!cypherField.columnName) { - const runCypherInApocClause = createCypherDirectiveApocProcedure({ - nodeRef, - expectMultipleValues, - context, - cypherField, - extraArgs, - }); - customCypherClause = new Cypher.Unwind([runCypherInApocClause, param]); - } else { - customCypherClause = createCypherDirectiveSubquery({ - cypherField, - nodeRef, - resultVariable: param, - extraArgs, - }); - } + const customCypherClause = createCypherDirectiveSubquery({ + cypherField, + nodeRef, + resultVariable: param, + extraArgs, + }); const unionExpression = hasUnionLabelsPredicate ? new Cypher.With("*").where(hasUnionLabelsPredicate) : undefined; @@ -210,40 +198,6 @@ export function translateCypherDirectiveProjection({ return res; } -function createCypherDirectiveApocProcedure({ - cypherField, - expectMultipleValues, - context, - nodeRef, - extraArgs, -}: { - cypherField: CypherField; - expectMultipleValues: boolean; - context: Context; - nodeRef: Cypher.Node; - extraArgs: Record; -}): Cypher.apoc.RunFirstColumn { - const rawApocParams = Object.entries(extraArgs); - - const apocParams: Record = rawApocParams.reduce((acc, [key, value]) => { - acc[key] = new Cypher.Param(value); - return acc; - }, {}); - - const apocParamsMap = new Cypher.Map({ - ...apocParams, - this: nodeRef, - ...(context.auth && { auth: new Cypher.NamedParam("auth") }), - ...(Boolean(context.cypherParams) && { cypherParams: new Cypher.NamedParam("cypherParams") }), - }); - const apocClause = new Cypher.apoc.RunFirstColumn( - cypherField.statement, - apocParamsMap, - Boolean(expectMultipleValues) - ); - return apocClause; -} - function createCypherDirectiveSubquery({ cypherField, nodeRef, diff --git a/packages/graphql/src/translate/translate-top-level-cypher.ts b/packages/graphql/src/translate/translate-top-level-cypher.ts index 0df6ed4d5e..14971a1a1e 100644 --- a/packages/graphql/src/translate/translate-top-level-cypher.ts +++ b/packages/graphql/src/translate/translate-top-level-cypher.ts @@ -158,18 +158,10 @@ export function translateTopLevelCypher({ const apocParamsStr = `{${apocParams.strs.length ? `${apocParams.strs.join(", ")}` : ""}}`; if (type === "Query") { - if (field.columnName) { - const experimentalCypherStatement = createCypherDirectiveSubquery({ - field, - }); - cypherStrs.push(...experimentalCypherStatement); - } else { - const legacyCypherStatement = createCypherDirectiveApocProcedure({ - field, - apocParams: apocParamsStr, - }); - cypherStrs.push(...legacyCypherStatement); - } + const cypherStatement = createCypherDirectiveSubquery({ + field, + }); + cypherStrs.push(...cypherStatement); } else { cypherStrs.push(` CALL apoc.cypher.doIt("${statement}", ${apocParamsStr}) YIELD value @@ -207,27 +199,6 @@ export function translateTopLevelCypher({ }).build(); } -function createCypherDirectiveApocProcedure({ - field, - apocParams, -}: { - field: CypherField; - apocParams: string; -}): string[] { - const isArray = field.typeMeta.array; - const expectMultipleValues = !field.isScalar && !field.isEnum && isArray; - const cypherStrs: string[] = []; - - if (expectMultipleValues) { - cypherStrs.push(`WITH apoc.cypher.runFirstColumnMany("${field.statement}", ${apocParams}) as x`); - } else { - cypherStrs.push(`WITH apoc.cypher.runFirstColumnSingle("${field.statement}", ${apocParams}) as x`); - } - - cypherStrs.push("UNWIND x as this\nWITH this"); - return cypherStrs; -} - function createCypherDirectiveSubquery({ field }: { field: CypherField }): string[] { const cypherStrs: string[] = []; cypherStrs.push("CALL {", field.statement, "}"); diff --git a/packages/graphql/tests/integration/connections/sort.int.test.ts b/packages/graphql/tests/integration/connections/sort.int.test.ts index 70119bc578..31daea2911 100644 --- a/packages/graphql/tests/integration/connections/sort.int.test.ts +++ b/packages/graphql/tests/integration/connections/sort.int.test.ts @@ -49,7 +49,7 @@ describe("connections sort", () => { title: String! runtime: Int! actors: [${Actor}!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") - numberOfActors: Int! @cypher(statement: "MATCH (actor:${Actor})-[:ACTED_IN]->(this) RETURN count(actor)") + numberOfActors: Int! @cypher(statement: "MATCH (actor:${Actor})-[:ACTED_IN]->(this) RETURN count(actor) as count", columnName: "count") } type ${Series} implements Production { @@ -66,8 +66,9 @@ describe("connections sort", () => { @cypher( statement: """ MATCH (this)-[r:ACTED_IN]->(:${Movie}) - RETURN sum(r.screenTime) - """ + RETURN sum(r.screenTime) as sum + """, + columnName: "sum" ) } interface ActedIn @relationshipProperties { diff --git a/packages/graphql/tests/integration/custom-resolvers.int.test.ts b/packages/graphql/tests/integration/custom-resolvers.int.test.ts index b112f7e9f6..1d2cac0233 100644 --- a/packages/graphql/tests/integration/custom-resolvers.int.test.ts +++ b/packages/graphql/tests/integration/custom-resolvers.int.test.ts @@ -293,8 +293,9 @@ describe("Custom Resolvers", () => { typeDefs = ` type Query { test: ${type}! @cypher(statement: """ - RETURN \\"${id}\\" - """) + RETURN "${id}" as id + """, + columnName: "id") } `; @@ -309,8 +310,8 @@ describe("Custom Resolvers", () => { typeDefs = ` type Query { test: ${type}! @cypher(statement: """ - RETURN ${int} - """) + RETURN ${int} as res + """, columnName: "res") } `; @@ -325,8 +326,8 @@ describe("Custom Resolvers", () => { typeDefs = ` type Query { test: ${type}! @cypher(statement: """ - RETURN ${float} - """) + RETURN ${float} as res + """, columnName: "res") } `; @@ -341,8 +342,8 @@ describe("Custom Resolvers", () => { typeDefs = ` type Query { test: ${type}! @cypher(statement: """ - RETURN ${bool} - """) + RETURN ${bool} as res + """, columnName: "res") } `; @@ -361,8 +362,8 @@ describe("Custom Resolvers", () => { type Query { test: Test! @cypher(statement: """ - RETURN {id: \\"${id}\\"} - """) + RETURN {id: "${id}"} as res + """, columnName: "res") } `; @@ -385,7 +386,7 @@ describe("Custom Resolvers", () => { test(id: ID!): Test! @cypher(statement: """ MATCH (n:Test {id: $id}) RETURN n - """) + """, columnName: "n") } `; @@ -461,8 +462,8 @@ describe("Custom Resolvers", () => { type Mutation { test(id: ID!): ID! @cypher(statement: """ - RETURN \\"${id}\\" + $id - """) + RETURN \\"${id}\\" + $id as res + """, columnName: "res") } `; @@ -502,8 +503,8 @@ describe("Custom Resolvers", () => { type Query { status: Status @cypher(statement: """ - RETURN 'COMPLETED' - """) + RETURN 'COMPLETED' as str + """, columnName: "str") } `; @@ -547,8 +548,8 @@ describe("Custom Resolvers", () => { type Trade { id: ID status: Status @cypher(statement: """ - RETURN 'COMPLETED' - """) + RETURN 'COMPLETED' as res + """, columnName: "res") } `; @@ -604,8 +605,9 @@ describe("Custom Resolvers", () => { type Type { id: ID strings: [String] @cypher(statement: """ - RETURN ['${string1}', '${string2}', '${string3}'] - """) + RETURN ['${string1}', '${string2}', '${string3}'] as arr + """, + columnName: "arr") } `; diff --git a/packages/graphql/tests/integration/cypher-params.int.test.ts b/packages/graphql/tests/integration/cypher-params.int.test.ts index 9a257caf0e..7171b32d07 100644 --- a/packages/graphql/tests/integration/cypher-params.int.test.ts +++ b/packages/graphql/tests/integration/cypher-params.int.test.ts @@ -45,7 +45,7 @@ describe("cypherParams", () => { } type Query { - id: String! @cypher(statement: "RETURN $cypherParams.id") + id: String! @cypher(statement: "RETURN $cypherParams.id AS id", columnName: "id") } `; @@ -88,7 +88,7 @@ describe("cypherParams", () => { type Movie { id: ID - cypherParams: CypherParams @cypher(statement: "RETURN $cypherParams") + cypherParams: CypherParams @cypher(statement: "RETURN $cypherParams AS result", columnName: "result") } `; @@ -153,7 +153,7 @@ describe("cypherParams", () => { } type Mutation { - id: String! @cypher(statement: "RETURN $cypherParams.id") + id: String! @cypher(statement: "RETURN $cypherParams.id AS id", columnName:"id") } `; diff --git a/packages/graphql/tests/integration/default-values.int.test.ts b/packages/graphql/tests/integration/default-values.int.test.ts index 90c4a1c3a3..298a8578cb 100644 --- a/packages/graphql/tests/integration/default-values.int.test.ts +++ b/packages/graphql/tests/integration/default-values.int.test.ts @@ -45,8 +45,9 @@ describe("Default values", () => { field(skip: Int = 100): Int @cypher( statement: """ - return $skip - """ + return $skip as s + """, + columnName: "s" ) } `; @@ -102,8 +103,9 @@ describe("Default values", () => { field(skip: Int = 100): Int @cypher( statement: """ - return $skip - """ + return $skip as s + """, + columnName: "s" ) } `; diff --git a/packages/graphql/tests/integration/deprecated/computed.int.test.ts b/packages/graphql/tests/integration/deprecated/computed.int.test.ts index bebc66cd54..d5a8efcc3d 100644 --- a/packages/graphql/tests/integration/deprecated/computed.int.test.ts +++ b/packages/graphql/tests/integration/deprecated/computed.int.test.ts @@ -171,8 +171,8 @@ describe("@computed directive", () => { const typeDefs = ` type User { id: ID! - firstName: String! @cypher(statement: "RETURN '${user.firstName}'") - lastName: String! @cypher(statement: "RETURN '${user.lastName}'") + firstName: String! @cypher(statement: "RETURN '${user.firstName}' as x", columnName: "x") + lastName: String! @cypher(statement: "RETURN '${user.lastName}' as x", columnName: "x") fullName: String @computed(from: ["firstName", "lastName"]) } `; diff --git a/packages/graphql/tests/integration/directives/auth/custom-cypher.int.test.ts b/packages/graphql/tests/integration/directives/auth/custom-cypher.int.test.ts index 6e86006834..5809c32b11 100644 --- a/packages/graphql/tests/integration/directives/auth/custom-cypher.int.test.ts +++ b/packages/graphql/tests/integration/directives/auth/custom-cypher.int.test.ts @@ -48,8 +48,8 @@ describe("should inject the auth into cypher directive", () => { const typeDefs = ` type Query { userId: ID @cypher(statement: """ - RETURN $auth.jwt.sub - """) + RETURN $auth.jwt.sub as res + """, columnName: "res") } `; @@ -88,8 +88,8 @@ describe("should inject the auth into cypher directive", () => { const typeDefs = ` type Query { userId: ID @cypher(statement: """ - RETURN $auth.jwt.sub - """) + RETURN $auth.jwt.sub as res + """, columnName: "res") } `; @@ -136,8 +136,8 @@ describe("should inject the auth into cypher directive", () => { type Mutation { userId: ID @cypher(statement: """ - RETURN $auth.jwt.sub - """) + RETURN $auth.jwt.sub as res + """, columnName: "res") } `; @@ -180,8 +180,8 @@ describe("should inject the auth into cypher directive", () => { type Mutation { userId: ID @cypher(statement: """ - RETURN $auth.jwt.sub - """) + RETURN $auth.jwt.sub as res + """, columnName: "res") } `; @@ -227,7 +227,7 @@ describe("should inject the auth into cypher directive", () => { userId: ID @cypher(statement: """ WITH $auth.jwt.sub as a RETURN a - """) + """, columnName: "a") } `; @@ -275,7 +275,7 @@ describe("should inject the auth into cypher directive", () => { userId: ID @cypher(statement: """ WITH $auth.jwt.sub as a RETURN a - """) + """, columnName: "a") } `; diff --git a/packages/graphql/tests/integration/directives/auth/is-authenticated.int.test.ts b/packages/graphql/tests/integration/directives/auth/is-authenticated.int.test.ts index da3ce8e64c..6cad857955 100644 --- a/packages/graphql/tests/integration/directives/auth/is-authenticated.int.test.ts +++ b/packages/graphql/tests/integration/directives/auth/is-authenticated.int.test.ts @@ -592,7 +592,7 @@ describe("auth/is-authenticated", () => { } type Query { - users: [${User}] @cypher(statement: "MATCH (u:${User}) RETURN u") @auth(rules: [{ isAuthenticated: true }]) + users: [${User}] @cypher(statement: "MATCH (u:${User}) RETURN u", columnName:"u") @auth(rules: [{ isAuthenticated: true }]) } `; @@ -635,7 +635,7 @@ describe("auth/is-authenticated", () => { } type Mutation { - createUser: ${User} @cypher(statement: "CREATE (u:${User}) RETURN u") @auth(rules: [{ isAuthenticated: true }]) + createUser: ${User} @cypher(statement: "CREATE (u:${User}) RETURN u", columnName: "u") @auth(rules: [{ isAuthenticated: true }]) } `; @@ -680,7 +680,7 @@ describe("auth/is-authenticated", () => { type ${User} { id: ID history: [${History}] - @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:${History}) RETURN h") + @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:${History}) RETURN h", columnName: "h") @auth(rules: [{ operations: [READ], isAuthenticated: true }]) } `; diff --git a/packages/graphql/tests/integration/directives/auth/roles.int.test.ts b/packages/graphql/tests/integration/directives/auth/roles.int.test.ts index 24b1de95c9..fca625baee 100644 --- a/packages/graphql/tests/integration/directives/auth/roles.int.test.ts +++ b/packages/graphql/tests/integration/directives/auth/roles.int.test.ts @@ -176,7 +176,7 @@ describe("auth/roles", () => { extend type ${typeUser} { history: [${typeHistory}] - @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:${typeHistory}) RETURN h") + @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:${typeHistory}) RETURN h", columnName: "h") @auth(rules: [{ operations: [READ], roles: ["super-admin"] }]) } `; @@ -984,7 +984,7 @@ describe("auth/roles", () => { } type Query { - ${typeUser.plural}: [${typeUser}] @cypher(statement: "MATCH (u:${typeUser}) RETURN u") @auth(rules: [{ roles: ["admin"] }]) + ${typeUser.plural}: [${typeUser}] @cypher(statement: "MATCH (u:${typeUser}) RETURN u", columnName: "u") @auth(rules: [{ roles: ["admin"] }]) } `; @@ -1030,7 +1030,7 @@ describe("auth/roles", () => { } type Mutation { - ${typeUser.operations.create}: ${typeUser} @cypher(statement: "CREATE (u:${typeUser}) RETURN u") @auth(rules: [{ roles: ["admin"] }]) + ${typeUser.operations.create}: ${typeUser} @cypher(statement: "CREATE (u:${typeUser}) RETURN u", columnName: "u") @auth(rules: [{ roles: ["admin"] }]) } `; @@ -1077,7 +1077,7 @@ describe("auth/roles", () => { type ${typeUser} { id: ID history: [${typeHistory}] - @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:${typeHistory}) RETURN h") + @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:${typeHistory}) RETURN h", columnName: "h") @auth(rules: [{ operations: [READ], roles: ["admin"] }]) } `; diff --git a/packages/graphql/tests/integration/directives/customResolver.int.test.ts b/packages/graphql/tests/integration/directives/customResolver.int.test.ts index 02f73cb920..8469553b56 100644 --- a/packages/graphql/tests/integration/directives/customResolver.int.test.ts +++ b/packages/graphql/tests/integration/directives/customResolver.int.test.ts @@ -165,8 +165,8 @@ describe("@customResolver directive", () => { const typeDefs = ` type ${testType.name} { id: ID! - firstName: String! @cypher(statement: "RETURN '${user.firstName}'") - lastName: String! @cypher(statement: "RETURN '${user.lastName}'") + firstName: String! @cypher(statement: "RETURN '${user.firstName}' as x", columnName: "x") + lastName: String! @cypher(statement: "RETURN '${user.lastName}' as x", columnName: "x") fullName: String @customResolver(requires: ["firstName", "lastName"]) } `; @@ -297,7 +297,7 @@ describe("@customResolver directive", () => { ${customResolverField}: String } `; - + const testResolver = () => "Some value"; const resolvers = { [interfaceType.name]: { diff --git a/packages/graphql/tests/integration/directives/cypher/cypher.int.test.ts b/packages/graphql/tests/integration/directives/cypher/cypher.int.test.ts index 373ead88e1..807e732156 100644 --- a/packages/graphql/tests/integration/directives/cypher/cypher.int.test.ts +++ b/packages/graphql/tests/integration/directives/cypher/cypher.int.test.ts @@ -79,7 +79,8 @@ describe("cypher", () => { statement: """ MATCH (m:${Movie} {title: $title}) RETURN m - """ + """, + columnName: "m" ) } `; @@ -150,7 +151,7 @@ describe("cypher", () => { customMovies(title: String!): [${Movie}] @cypher(statement: """ MATCH (m:${Movie} {title: $title}) RETURN m - """ + """, columnName: "m" ) } `; @@ -221,7 +222,7 @@ describe("cypher", () => { customMovies(title: String!): [${Movie}] @cypher(statement: """ MATCH (m:${Movie} {title: $title}) RETURN m - """) + """, columnName: "m") } `; @@ -306,7 +307,8 @@ describe("cypher", () => { MATCH (m:${Movie}) WHERE m.title in $titles RETURN m - """ + """, + columnName: "m" ) } `; @@ -404,7 +406,8 @@ describe("cypher", () => { MATCH (m:${Movie}) WHERE m.title = $title RETURN m - """ + """, + columnName: "m" ) } `; @@ -506,7 +509,8 @@ describe("cypher", () => { statement: """ MATCH (m:${Movie} {title: $title}) RETURN m - """ + """, + columnName: "m" ) } `; @@ -577,7 +581,8 @@ describe("cypher", () => { customMovies(title: String!): [${Movie}] @cypher(statement: """ MATCH (m:${Movie} {title: $title}) RETURN m - """) + """, + columnName: "m") } `; @@ -647,7 +652,8 @@ describe("cypher", () => { customMovies(title: String!): [${Movie}] @cypher(statement: """ MATCH (m:${Movie} {title: $title}) RETURN m - """) + """, + columnName: "m") } `; @@ -709,7 +715,7 @@ describe("cypher", () => { id: ID! preposition(caseName: String${ withDefaultValue ? "= null" : "" - }): String! @cypher(statement: "RETURN coalesce($caseName, '${defaultPreposition}')") + }): String! @cypher(statement: "RETURN coalesce($caseName, '${defaultPreposition}') as result", columnName: "result") } type Query { @@ -717,7 +723,8 @@ describe("cypher", () => { MATCH (town:Town {id:$id}) OPTIONAL MATCH (town)<-[:BELONGS_TO]-(destination:Destination) RETURN destination - """) + """, + columnName: "destination") } `; @@ -858,7 +865,8 @@ describe("cypher", () => { MATCH (this:User)-[:WROTE]->(wrote:Post) RETURN wrote LIMIT 5 - """ + """, + columnName: "wrote" ) } `; diff --git a/packages/graphql/tests/integration/find.int.test.ts b/packages/graphql/tests/integration/find.int.test.ts index bdb3b69692..48e8911a39 100644 --- a/packages/graphql/tests/integration/find.int.test.ts +++ b/packages/graphql/tests/integration/find.int.test.ts @@ -420,7 +420,8 @@ describe("find", () => { MATCH (a:Actor) WHERE a.id IN $actorIds RETURN a - """ + """, + columnName: "a" ) } `; diff --git a/packages/graphql/tests/integration/issues/1049.int.test.ts b/packages/graphql/tests/integration/issues/1049.int.test.ts index 6f67ba199e..8f778d0491 100644 --- a/packages/graphql/tests/integration/issues/1049.int.test.ts +++ b/packages/graphql/tests/integration/issues/1049.int.test.ts @@ -56,8 +56,9 @@ describe("https://github.com/neo4j/graphql/issues/1049", () => { @cypher( statement: """ MATCH (this)<-[:LIKES]-(:${Person.name})-[:LIKES]->(other:${Media.name}) - RETURN COLLECT(other { .*, __resolveType: apoc.coll.subtract(labels(other), ['Meda'])[0] }) - """ + RETURN COLLECT(other { .*, __resolveType: apoc.coll.subtract(labels(other), ['Meda'])[0] }) as x + """, + columnName: "x" ) } diff --git a/packages/graphql/tests/integration/issues/1364.int.test.ts b/packages/graphql/tests/integration/issues/1364.int.test.ts index 2c4c6d53f9..720b8400a0 100644 --- a/packages/graphql/tests/integration/issues/1364.int.test.ts +++ b/packages/graphql/tests/integration/issues/1364.int.test.ts @@ -59,15 +59,17 @@ describe("https://github.com/neo4j/graphql/issues/1364", () => { @cypher( statement: """ MATCH (this)-[:HAS_GENRE]->(genre:${testGenre.name}) - RETURN count(DISTINCT genre) - """ + RETURN count(DISTINCT genre) as c + """, + columnName: "c" ) totalActors: Int! @cypher( statement: """ MATCH (this)<-[:ACTED_IN]-(actor:${testActor.name}) - RETURN count(DISTINCT actor) - """ + RETURN count(DISTINCT actor) as c + """, + columnName: "c" ) } diff --git a/packages/graphql/tests/integration/issues/1528.int.test.ts b/packages/graphql/tests/integration/issues/1528.int.test.ts index 55e4b967a3..d287e04dbd 100644 --- a/packages/graphql/tests/integration/issues/1528.int.test.ts +++ b/packages/graphql/tests/integration/issues/1528.int.test.ts @@ -55,8 +55,9 @@ describe("https://github.com/neo4j/graphql/issues/1528", () => { @cypher( statement: """ MATCH (this)<-[:ACTED_IN]-(ac:${testPerson}) - RETURN count(ac) - """ + RETURN count(ac) as res + """, + columnName: "res" ) } diff --git a/packages/graphql/tests/integration/issues/1566.int.test.ts b/packages/graphql/tests/integration/issues/1566.int.test.ts index 08931a6f7d..3779eb915e 100644 --- a/packages/graphql/tests/integration/issues/1566.int.test.ts +++ b/packages/graphql/tests/integration/issues/1566.int.test.ts @@ -56,6 +56,7 @@ describe("https://github.com/neo4j/graphql/issues/1566", () => { Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag """ + columnName: "pag" ) hasFeedItems(limit: Int = 10, page: Int = 0): [FeedItem!]! @cypher( @@ -63,6 +64,7 @@ describe("https://github.com/neo4j/graphql/issues/1566", () => { Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag SKIP ($limit * $page) LIMIT $limit """ + columnName: "pag" ) } `; diff --git a/packages/graphql/tests/integration/issues/1735.int.test.ts b/packages/graphql/tests/integration/issues/1735.int.test.ts index 614275783b..97be716b5d 100644 --- a/packages/graphql/tests/integration/issues/1735.int.test.ts +++ b/packages/graphql/tests/integration/issues/1735.int.test.ts @@ -46,8 +46,8 @@ describe("https://github.com/neo4j/graphql/issues/1735", () => { leadActorsCount: Int! @cypher(statement:""" MATCH (this)<-[rel:ACTED_IN]-(a:${actorType.name}) WHERE rel.isLead = true - RETURN count(a) - """) + RETURN count(a) as result + """, columnName: "result") } type ${actorType.name} { diff --git a/packages/graphql/tests/integration/issues/1760.int.test.ts b/packages/graphql/tests/integration/issues/1760.int.test.ts index 79f817cf8e..48a5512d90 100644 --- a/packages/graphql/tests/integration/issues/1760.int.test.ts +++ b/packages/graphql/tests/integration/issues/1760.int.test.ts @@ -43,7 +43,8 @@ describe("https://github.com/neo4j/graphql/issues/1760", () => { @exclude(operations: [CREATE, UPDATE, DELETE]) { markets: [Market!]! @relationship(type: "HAS_MARKETS", direction: OUT) id: ID! @id(autogenerate: false) - relatedId: ID @cypher(statement: "MATCH (this)<-[:HAS_BASE]-(n:BaseObject) RETURN n.id") + relatedId: ID + @cypher(statement: "MATCH (this)<-[:HAS_BASE]-(n:BaseObject) RETURN n.id as res", columnName: "res") baseObject: BaseObject! @relationship(type: "HAS_BASE", direction: IN) current: Boolean! nameDetails: NameDetails @relationship(type: "HAS_NAME", direction: OUT) diff --git a/packages/graphql/tests/integration/issues/1848.int.test.ts b/packages/graphql/tests/integration/issues/1848.int.test.ts index 5c95c82465..22f1ecacd2 100644 --- a/packages/graphql/tests/integration/issues/1848.int.test.ts +++ b/packages/graphql/tests/integration/issues/1848.int.test.ts @@ -56,7 +56,8 @@ describe("https://github.com/neo4j/graphql/issues/1848", () => { @cypher( statement: """ Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag SKIP ($limit * $pageIndex) LIMIT $limit - """ + """, + columnName: "pag" ) } diff --git a/packages/graphql/tests/integration/issues/2068.int.test.ts b/packages/graphql/tests/integration/issues/2068.int.test.ts index a881764ade..c93d3c29e4 100644 --- a/packages/graphql/tests/integration/issues/2068.int.test.ts +++ b/packages/graphql/tests/integration/issues/2068.int.test.ts @@ -267,7 +267,8 @@ describe("https://github.com/neo4j/graphql/pull/2068", () => { statement: """ MATCH (m:${movieType.name} {title: $title}) RETURN m - """ + """, + columnName: "m" ) tvShows(title: String): [${movieType.name}] @@ -275,7 +276,8 @@ describe("https://github.com/neo4j/graphql/pull/2068", () => { statement: """ MATCH (t:${tvShowType.name} {title: $title}) RETURN t - """ + """, + columnName: "t" ) movieOrTVShow(title: String): [${movieOrTVShowType.name}] @@ -284,7 +286,8 @@ describe("https://github.com/neo4j/graphql/pull/2068", () => { MATCH (n) WHERE (n:${tvShowType.name} OR n:${movieType.name}) AND ($title IS NULL OR n.title = $title) RETURN n - """ + """, + columnName: "n" ) } @@ -299,14 +302,16 @@ describe("https://github.com/neo4j/graphql/pull/2068", () => { statement: """ MATCH (a:${actorType.name}) RETURN a - """ + """, + columnName: "a" ) topActor: ${actorType.name} @cypher( statement: """ MATCH (a:${actorType.name}) RETURN a - """ + """, + columnName: "a" ) } @@ -318,14 +323,16 @@ describe("https://github.com/neo4j/graphql/pull/2068", () => { statement: """ MATCH (a:${actorType.name}) RETURN a - """ + """, + columnName: "a" ) topActor: ${actorType.name} @cypher( statement: """ MATCH (a:${actorType.name}) RETURN a - """ + """, + columnName: "a" ) } `; diff --git a/packages/graphql/tests/integration/issues/2100.int.test.ts b/packages/graphql/tests/integration/issues/2100.int.test.ts index b12f21c654..97738b00b9 100644 --- a/packages/graphql/tests/integration/issues/2100.int.test.ts +++ b/packages/graphql/tests/integration/issues/2100.int.test.ts @@ -50,7 +50,8 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { statement: """ MATCH (this)<-[:PRESENT_AT_SERVICE|ABSENT_FROM_SERVICE]-(member:Member) RETURN COUNT(member) > 0 AS markedAttendance - """ + """, + columnName: "markedAttendance" ) serviceDate: ${TimeGraphType}! @relationship(type: "BUSSED_ON", direction: OUT) } @@ -72,6 +73,7 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { WITH DISTINCT records, date LIMIT $limit RETURN records ORDER BY date.date DESC """ + columnName: "records" ) } @@ -87,7 +89,8 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { statement: """ MATCH (this)<-[:PRESENT_AT_SERVICE|ABSENT_FROM_SERVICE]-(member:Member) RETURN COUNT(member) > 0 AS markedAttendance - """ + """, + columnName: "markedAttendance" ) serviceDate: ${TimeGraphType}! @relationship(type: "BUSSED_ON", direction: OUT) } diff --git a/packages/graphql/tests/integration/issues/2189.int.test.ts b/packages/graphql/tests/integration/issues/2189.int.test.ts index 6a46087b30..5881a0bff9 100644 --- a/packages/graphql/tests/integration/issues/2189.int.test.ts +++ b/packages/graphql/tests/integration/issues/2189.int.test.ts @@ -54,7 +54,8 @@ describe("https://github.com/neo4j/graphql/issues/2189", () => { OPTIONAL MATCH (this)<-[:TEST_RELATIONSHIP]-(t:${Test_Feedback}) RETURN t LIMIT 1 - """ + """, + columnName: "t" ) } type ${Test_Feedback} { diff --git a/packages/graphql/tests/integration/issues/2261.int.test.ts b/packages/graphql/tests/integration/issues/2261.int.test.ts index 606fc0af13..d58f57517f 100644 --- a/packages/graphql/tests/integration/issues/2261.int.test.ts +++ b/packages/graphql/tests/integration/issues/2261.int.test.ts @@ -52,13 +52,13 @@ describe("https://github.com/neo4j/graphql/issues/2261", () => { type ${ProgrammeItem} implements Product { id: ID! @id - uri: String! @cypher(statement: "RETURN 'example://programme-item/' + this.id") + uri: String! @cypher(statement: "RETURN 'example://programme-item/' + this.id as x", columnName: "x") editions: [${Edition}!]! @relationship(type: "HAS_EDITION", direction: OUT) } type ${Edition} { id: ID! @id - uri: String! @cypher(statement: "RETURN 'example://edition/' + this.id") + uri: String! @cypher(statement: "RETURN 'example://edition/' + this.id as x", columnName: "x") product: Product! @relationship(type: "HAS_EDITION", direction: IN) } `; diff --git a/packages/graphql/tests/integration/issues/227.int.test.ts b/packages/graphql/tests/integration/issues/227.int.test.ts index 3b66c37428..e2b4ee0b03 100644 --- a/packages/graphql/tests/integration/issues/227.int.test.ts +++ b/packages/graphql/tests/integration/issues/227.int.test.ts @@ -64,7 +64,8 @@ describe("https://github.com/neo4j/graphql/issues/227", () => { MATCH (town:Town {id:$id}) OPTIONAL MATCH (town)<-[:BELONGS_TO]-(member:Member) RETURN member - """) + """, + columnName: "member") } `; diff --git a/packages/graphql/tests/integration/issues/283.int.test.ts b/packages/graphql/tests/integration/issues/283.int.test.ts index 169254f291..7d462ee03f 100644 --- a/packages/graphql/tests/integration/issues/283.int.test.ts +++ b/packages/graphql/tests/integration/issues/283.int.test.ts @@ -40,6 +40,7 @@ describe("https://github.com/neo4j/graphql/issues/283", () => { post.id = randomUUID() RETURN post """ + columnName: "post" ) } diff --git a/packages/graphql/tests/integration/issues/315.int.test.ts b/packages/graphql/tests/integration/issues/315.int.test.ts index 837de970a0..8ec7b31c9b 100644 --- a/packages/graphql/tests/integration/issues/315.int.test.ts +++ b/packages/graphql/tests/integration/issues/315.int.test.ts @@ -58,6 +58,7 @@ describe("https://github.com/neo4j/graphql/issues/315", () => { } RETURN DISTINCT post AS result ORDER BY result.modifiedDate DESC """ + columnName: "result" ) } `; diff --git a/packages/graphql/tests/integration/issues/326.int.test.ts b/packages/graphql/tests/integration/issues/326.int.test.ts index f1917672d7..d2886ef664 100644 --- a/packages/graphql/tests/integration/issues/326.int.test.ts +++ b/packages/graphql/tests/integration/issues/326.int.test.ts @@ -51,9 +51,9 @@ describe("326", () => { getSelf: [User]! @cypher( statement: """ - MATCH (user:User { id: \\"${id}\\" }) + MATCH (user:User { id: "${id}" }) RETURN user - """ + """, columnName: "user" ) } @@ -117,7 +117,7 @@ describe("326", () => { statement: """ MATCH (user:User { id: \\"${id}\\" }) RETURN user - """ + """, columnName: "user" ) } diff --git a/packages/graphql/tests/integration/issues/350.int.test.ts b/packages/graphql/tests/integration/issues/350.int.test.ts index f662c26b45..6635697c51 100644 --- a/packages/graphql/tests/integration/issues/350.int.test.ts +++ b/packages/graphql/tests/integration/issues/350.int.test.ts @@ -51,7 +51,7 @@ describe("https://github.com/neo4j/graphql/issues/350", () => { flagged: Boolean! content: String! post: Post! @relationship(type: "HAS_COMMENT", direction: IN) - canEdit: Boolean! @cypher(statement: "RETURN false") + canEdit: Boolean! @cypher(statement: "RETURN false as res", columnName: "res") } `; diff --git a/packages/graphql/tests/integration/issues/369.int.test.ts b/packages/graphql/tests/integration/issues/369.int.test.ts index 430277fad6..2c84ea8fcd 100644 --- a/packages/graphql/tests/integration/issues/369.int.test.ts +++ b/packages/graphql/tests/integration/issues/369.int.test.ts @@ -57,6 +57,7 @@ describe("369", () => { statement: """ MATCH (d:Dato {uuid: $uuid}) RETURN d """ + columnName: "d" ) } `; @@ -141,6 +142,7 @@ describe("369", () => { statement: """ MATCH (d:Dato {uuid: $uuid}) RETURN d """ + columnName: "d" ) } `; diff --git a/packages/graphql/tests/integration/issues/387.int.test.ts b/packages/graphql/tests/integration/issues/387.int.test.ts index f39d0131bc..36e0322ce8 100644 --- a/packages/graphql/tests/integration/issues/387.int.test.ts +++ b/packages/graphql/tests/integration/issues/387.int.test.ts @@ -55,14 +55,16 @@ describe("https://github.com/neo4j/graphql/issues/387", () => { url: URL @cypher( statement: """ - return '${url}' - """ + return '${url}' as res + """, + columnName: "res" ) url_array: [URL] @cypher( statement: """ - return ['${url}', '${url}'] - """ + return ['${url}', '${url}'] as res + """, + columnName: "res" ) } `; @@ -116,14 +118,16 @@ describe("https://github.com/neo4j/graphql/issues/387", () => { url: URL @cypher( statement: """ - return '${url}' - """ + return '${url}' as x + """, + columnName: "x" ) url_array: [URL] @cypher( statement: """ - return ['${url}', '${url}'] - """ + return ['${url}', '${url}'] as x + """, + columnName: "x" ) } `; diff --git a/packages/graphql/tests/integration/issues/388.int.test.ts b/packages/graphql/tests/integration/issues/388.int.test.ts index bda002be45..bebf8ccf06 100644 --- a/packages/graphql/tests/integration/issues/388.int.test.ts +++ b/packages/graphql/tests/integration/issues/388.int.test.ts @@ -58,6 +58,7 @@ describe("https://github.com/neo4j/graphql/issues/388", () => { } RETURN DISTINCT post AS result ORDER BY result.modifiedDate DESC """ + columnName: "result" ) } `; diff --git a/packages/graphql/tests/integration/issues/487.int.test.ts b/packages/graphql/tests/integration/issues/487.int.test.ts index 73204f3e60..27616573c8 100644 --- a/packages/graphql/tests/integration/issues/487.int.test.ts +++ b/packages/graphql/tests/integration/issues/487.int.test.ts @@ -73,10 +73,11 @@ describe("https://github.com/neo4j/graphql/issues/487", () => { statement: """ MATCH (node) WHERE - \\"${typeBook.name}\\" IN labels(node) OR - \\"${typeMovie.name}\\" IN labels(node) + "${typeBook.name}" IN labels(node) OR + "${typeMovie.name}" IN labels(node) RETURN node - """ + """, + columnName: "node" ) } `; diff --git a/packages/graphql/tests/integration/issues/526.int.test.ts b/packages/graphql/tests/integration/issues/526.int.test.ts index f5dc0eac6a..eccf0fca46 100644 --- a/packages/graphql/tests/integration/issues/526.int.test.ts +++ b/packages/graphql/tests/integration/issues/526.int.test.ts @@ -47,6 +47,7 @@ describe("https://github.com/neo4j/graphql/issues/526 - Int Argument on Custom Q RETURN movie LIMIT $limit """ + columnName: "movie" ) } `; diff --git a/packages/graphql/tests/integration/issues/630.int.test.ts b/packages/graphql/tests/integration/issues/630.int.test.ts index 6e8ad8a000..128be7362b 100644 --- a/packages/graphql/tests/integration/issues/630.int.test.ts +++ b/packages/graphql/tests/integration/issues/630.int.test.ts @@ -45,7 +45,7 @@ describe("https://github.com/neo4j/graphql/issues/630", () => { type ${typeActor} { id: ID! name: String! - movies: [${typeMovie}!]! @cypher(statement: "MATCH (this)-[:ACTED_IN]->(m:${typeMovie}) RETURN m") + movies: [${typeMovie}!]! @cypher(statement: "MATCH (this)-[:ACTED_IN]->(m:${typeMovie}) RETURN m", columnName:"m") } type ${typeMovie} { diff --git a/packages/graphql/tests/integration/sort.int.test.ts b/packages/graphql/tests/integration/sort.int.test.ts index fbcfe5ad1c..84042597c0 100644 --- a/packages/graphql/tests/integration/sort.int.test.ts +++ b/packages/graphql/tests/integration/sort.int.test.ts @@ -49,7 +49,7 @@ describe("sort", () => { title: String! runtime: Int! actors: [${actorType}!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") - numberOfActors: Int! @cypher(statement: "MATCH (actor:${actorType})-[:ACTED_IN]->(this) RETURN count(actor)") + numberOfActors: Int! @cypher(statement: "MATCH (actor:${actorType})-[:ACTED_IN]->(this) RETURN count(actor) AS count", columnName: "count") } type ${seriesType} implements Production { @@ -66,8 +66,9 @@ describe("sort", () => { @cypher( statement: """ MATCH (this)-[r:ACTED_IN]->(:${movieType}) - RETURN sum(r.screenTime) - """ + RETURN sum(r.screenTime) AS sum + """, + columnName: "sum" ) } interface ActedIn @relationshipProperties { diff --git a/packages/graphql/tests/integration/types/bigint.int.test.ts b/packages/graphql/tests/integration/types/bigint.int.test.ts index da5f6d7454..31bfda489c 100644 --- a/packages/graphql/tests/integration/types/bigint.int.test.ts +++ b/packages/graphql/tests/integration/types/bigint.int.test.ts @@ -215,8 +215,8 @@ describe("BigInt", () => { type File { name: String! size: BigInt! @cypher(statement: """ - RETURN 9223372036854775807 - """) + RETURN 9223372036854775807 as result + """, columnName:"result") } `; diff --git a/packages/graphql/tests/integration/types/float.int.test.ts b/packages/graphql/tests/integration/types/float.int.test.ts index 0cbdbddd33..9c0fd56c75 100644 --- a/packages/graphql/tests/integration/types/float.int.test.ts +++ b/packages/graphql/tests/integration/types/float.int.test.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Driver} from "neo4j-driver"; +import type { Driver } from "neo4j-driver"; import { int } from "neo4j-driver"; import { graphql } from "graphql"; import { generate } from "randomstring"; @@ -188,7 +188,8 @@ describe("Float", () => { statement: """ CREATE (m:Movie {id: $id, float: $float, floats: $nested.floats}) RETURN m.float - """ + """, + columnName: "m.float" ) } `; @@ -241,8 +242,8 @@ describe("Float", () => { type Movie { id: String fakeFloat: Float! @cypher(statement: """ - RETURN 12345 - """) + RETURN 12345 as result + """, columnName: "result") } diff --git a/packages/graphql/tests/performance/graphql/cypher-directive.graphql b/packages/graphql/tests/performance/graphql/cypher-directive.graphql index 2f01cc4568..2d9bbd1e3f 100644 --- a/packages/graphql/tests/performance/graphql/cypher-directive.graphql +++ b/packages/graphql/tests/performance/graphql/cypher-directive.graphql @@ -7,13 +7,3 @@ query TopLevelCypherDirective { } } } - -query TopLevelCypherDirectiveWithColumnName { - experimentalCustomCypher { - name - born - movies { - title - } - } -} diff --git a/packages/graphql/tests/performance/performance.ts b/packages/graphql/tests/performance/performance.ts index a449d54d0e..498a1b1dd0 100644 --- a/packages/graphql/tests/performance/performance.ts +++ b/packages/graphql/tests/performance/performance.ts @@ -62,7 +62,8 @@ const typeDefs = gql` reviewers: [Person!]! @relationship(type: "REVIEWED", direction: IN) producers: [Person!]! @relationship(type: "PRODUCED", direction: IN) likedBy: [User!]! @relationship(type: "LIKES", direction: IN) - oneActorName: String @cypher(statement: "MATCH (this)<-[:ACTED_IN]-(a:Person) RETURN a.name") + oneActorName: String + @cypher(statement: "MATCH (this)<-[:ACTED_IN]-(a:Person) RETURN a.name AS name", columnName: "name") } type User { @@ -72,14 +73,6 @@ const typeDefs = gql` type Query { customCypher: [Person] - @cypher( - statement: """ - MATCH(m:Movie)--(p:Person) - WHERE m.released > 2000 - RETURN p - """ - ) - experimentalCustomCypher: [Person] @cypher( statement: """ MATCH(m:Movie)--(p:Person) diff --git a/packages/graphql/tests/schema/custom-mutations.test.ts b/packages/graphql/tests/schema/custom-mutations.test.ts index 920d8859ac..697568e267 100644 --- a/packages/graphql/tests/schema/custom-mutations.test.ts +++ b/packages/graphql/tests/schema/custom-mutations.test.ts @@ -35,12 +35,12 @@ describe("Custom-mutations", () => { type Query { testQuery(input: ExampleInput): String - testCypherQuery(input: ExampleInput): String @cypher(statement: "") + testCypherQuery(input: ExampleInput): String @cypher(statement: "", columnName: "") } type Mutation { testMutation(input: ExampleInput): String - testCypherMutation(input: ExampleInput): String @cypher(statement: "") + testCypherMutation(input: ExampleInput): String @cypher(statement: "", columnName: "") } type Subscription { diff --git a/packages/graphql/tests/schema/directives/cypher.test.ts b/packages/graphql/tests/schema/directives/cypher.test.ts index 634f728699..6c4ffeb0e2 100644 --- a/packages/graphql/tests/schema/directives/cypher.test.ts +++ b/packages/graphql/tests/schema/directives/cypher.test.ts @@ -38,6 +38,7 @@ describe("Cypher", () => { RETURN a LIMIT 1 """ + columnName: "a" ) } `; @@ -262,8 +263,9 @@ describe("Cypher", () => { @cypher( statement: """ MATCH (this)-[r:ACTED_IN]->(:Movie) - RETURN sum(r.screenTime) + RETURN sum(r.screenTime) as result """ + columnName: "result" ) } @@ -276,6 +278,7 @@ describe("Cypher", () => { RETURN a LIMIT 1 """ + columnName: "a" ) } `; diff --git a/packages/graphql/tests/schema/interfaces.test.ts b/packages/graphql/tests/schema/interfaces.test.ts index 2facca18ed..c5c13239ac 100644 --- a/packages/graphql/tests/schema/interfaces.test.ts +++ b/packages/graphql/tests/schema/interfaces.test.ts @@ -34,6 +34,7 @@ describe("Interfaces", () => { MATCH (m:Movie) RETURN m """ + columnName: "m" ) } @@ -47,6 +48,7 @@ describe("Interfaces", () => { MATCH (m:Movie) RETURN m """ + columnName: "m" ) } `; diff --git a/packages/graphql/tests/tck/alias.test.ts b/packages/graphql/tests/tck/alias.test.ts index 6adb38d159..bb4b626755 100644 --- a/packages/graphql/tests/tck/alias.test.ts +++ b/packages/graphql/tests/tck/alias.test.ts @@ -45,6 +45,7 @@ describe("Cypher Alias", () => { MATCH (m:Movie) RETURN m """ + columnName: "m" ) } `; @@ -90,23 +91,18 @@ describe("Cypher Alias", () => { } CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie) - RETURN m\\", { this: this, auth: $auth }) AS this_custom + CALL { + WITH this + WITH this AS this + MATCH (m:Movie) + RETURN m + } + WITH m AS this_custom RETURN collect(this_custom { aliasCustomId: this_custom.id }) AS this_custom } RETURN this { movieId: this.id, actors: this_actors, custom: this_custom } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": true, - \\"roles\\": [], - \\"jwt\\": { - \\"roles\\": [] - } - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); }); diff --git a/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/interface-relationships/interface-is-authenticated.test.ts b/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/interface-relationships/interface-is-authenticated.test.ts index 64953487c6..ec171c9392 100644 --- a/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/interface-relationships/interface-is-authenticated.test.ts +++ b/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/interface-relationships/interface-is-authenticated.test.ts @@ -71,7 +71,7 @@ describe("Cypher Auth isAuthenticated", () => { extend type User { history: [History] - @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h") + @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h", columnName: "h") @auth(rules: [{ operations: [READ], isAuthenticated: true }]) } `; diff --git a/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/is-authenticated.test.ts b/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/is-authenticated.test.ts index 227d7f99d3..7625201146 100644 --- a/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/is-authenticated.test.ts +++ b/packages/graphql/tests/tck/directives/auth/arguments/is-authenticated/is-authenticated.test.ts @@ -60,7 +60,7 @@ describe("Cypher Auth isAuthenticated", () => { extend type User { history: [History] - @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h") + @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h", columnName: "h") @auth(rules: [{ operations: [READ], isAuthenticated: true }]) } `; @@ -178,7 +178,12 @@ describe("Cypher Auth isAuthenticated", () => { CALL apoc.util.validate(NOT (apoc.util.validatePredicate(NOT ($auth.isAuthenticated = true), \\"@neo4j/graphql/UNAUTHENTICATED\\", [0])), \\"@neo4j/graphql/FORBIDDEN\\", [0]) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h\\", { this: this, auth: $auth }) AS this_history + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h + } + WITH h AS this_history RETURN collect(this_history { .url }) AS this_history } RETURN this { history: this_history } AS this" diff --git a/packages/graphql/tests/tck/directives/auth/arguments/roles/roles.test.ts b/packages/graphql/tests/tck/directives/auth/arguments/roles/roles.test.ts index 1a6ff92f03..a945e19172 100644 --- a/packages/graphql/tests/tck/directives/auth/arguments/roles/roles.test.ts +++ b/packages/graphql/tests/tck/directives/auth/arguments/roles/roles.test.ts @@ -66,7 +66,7 @@ describe("Cypher Auth Roles", () => { extend type User { history: [History] - @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h") + @cypher(statement: "MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h", columnName: "h") @auth(rules: [{ operations: [READ], roles: ["super-admin"] }]) } `; @@ -184,7 +184,12 @@ describe("Cypher Auth Roles", () => { CALL apoc.util.validate(NOT (any(auth_var1 IN [\\"super-admin\\"] WHERE any(auth_var0 IN $auth.roles WHERE auth_var0 = auth_var1))), \\"@neo4j/graphql/FORBIDDEN\\", [0]) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h\\", { this: this, auth: $auth }) AS this_history + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_HISTORY]->(h:History) RETURN h + } + WITH h AS this_history RETURN collect(this_history { .url }) AS this_history } RETURN this { history: this_history } AS this" diff --git a/packages/graphql/tests/tck/directives/cypher.test.ts b/packages/graphql/tests/tck/directives/cypher.test.ts index f78a824d84..b18a3b8597 100644 --- a/packages/graphql/tests/tck/directives/cypher.test.ts +++ b/packages/graphql/tests/tck/directives/cypher.test.ts @@ -38,6 +38,7 @@ describe("Cypher directive", () => { MATCH (m:Movie {title: $title}) RETURN m """ + columnName: "m" ) tvShows(title: String): [Movie] @@ -46,6 +47,7 @@ describe("Cypher directive", () => { MATCH (t:TVShow {title: $title}) RETURN t """ + columnName: "t" ) movieOrTVShow(title: String): [MovieOrTVShow] @@ -55,13 +57,15 @@ describe("Cypher directive", () => { WHERE (n:TVShow OR n:Movie) AND ($title IS NULL OR n.title = $title) RETURN n """ + columnName: "n" ) randomNumber: Int @cypher( statement: """ - RETURN rand() + RETURN rand() as res """ + columnName: "res" ) } @@ -77,6 +81,7 @@ describe("Cypher directive", () => { MATCH (a:Actor) RETURN a """ + columnName: "a" ) topActor: Actor @cypher( @@ -84,6 +89,7 @@ describe("Cypher directive", () => { MATCH (a:Actor) RETURN a """ + columnName: "a" ) } @@ -96,6 +102,7 @@ describe("Cypher directive", () => { MATCH (a:Actor) RETURN a """ + columnName: "a" ) topActor: Actor @cypher( @@ -103,6 +110,7 @@ describe("Cypher directive", () => { MATCH (a:Actor) RETURN a """ + columnName: "a" ) } `; @@ -134,21 +142,19 @@ describe("Cypher directive", () => { "MATCH (this:\`Movie\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this, auth: $auth }) AS this_topActor + CALL { + WITH this + WITH this AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_topActor RETURN head(collect(this_topActor { .name })) AS this_topActor } RETURN this { .title, topActor: this_topActor } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); test("Simple directive (primitive)", async () => { @@ -169,20 +175,18 @@ describe("Cypher directive", () => { "MATCH (this:\`Actor\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"RETURN rand()\\", { this: this, auth: $auth }) AS this_randomNumber + CALL { + WITH this + WITH this AS this + RETURN rand() as res + } + UNWIND res AS this_randomNumber RETURN head(collect(this_randomNumber)) AS this_randomNumber } RETURN this { randomNumber: this_randomNumber } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); test("LIMIT happens before custom Cypher if not sorting on the custom Cypher field", async () => { @@ -205,7 +209,12 @@ describe("Cypher directive", () => { LIMIT $param0 CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"RETURN rand()\\", { this: this, auth: $auth }) AS this_randomNumber + CALL { + WITH this + WITH this AS this + RETURN rand() as res + } + UNWIND res AS this_randomNumber RETURN head(collect(this_randomNumber)) AS this_randomNumber } RETURN this { randomNumber: this_randomNumber } AS this" @@ -216,10 +225,6 @@ describe("Cypher directive", () => { \\"param0\\": { \\"low\\": 10, \\"high\\": 0 - }, - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] } }" `); @@ -243,24 +248,25 @@ describe("Cypher directive", () => { "MATCH (this:\`Actor\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"RETURN rand()\\", { this: this, auth: $auth }) AS this_randomNumber + CALL { + WITH this + WITH this AS this + RETURN rand() as res + } + UNWIND res AS this_randomNumber RETURN head(collect(this_randomNumber)) AS this_randomNumber } WITH * ORDER BY this_randomNumber ASC - LIMIT $param1 + LIMIT $param0 RETURN this { randomNumber: this_randomNumber } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param1\\": { + \\"param0\\": { \\"low\\": 10, \\"high\\": 0 - }, - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] } }" `); @@ -290,12 +296,22 @@ describe("Cypher directive", () => { "MATCH (this:\`Movie\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this, auth: $auth }) AS this_topActor + CALL { + WITH this + WITH this AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_topActor CALL { WITH this_topActor - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie {title: $title}) - RETURN m\\", { title: $param1, this: this_topActor, auth: $auth }) AS this_topActor_movies + CALL { + WITH this_topActor + WITH this_topActor AS this + MATCH (m:Movie {title: $title}) + RETURN m + } + WITH m AS this_topActor_movies RETURN collect(this_topActor_movies { .title }) AS this_topActor_movies } RETURN head(collect(this_topActor { .name, movies: this_topActor_movies })) AS this_topActor @@ -305,11 +321,7 @@ describe("Cypher directive", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param1\\": \\"some title\\", - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } + \\"title\\": \\"some title\\" }" `); }); @@ -344,20 +356,40 @@ describe("Cypher directive", () => { "MATCH (this:\`Movie\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this, auth: $auth }) AS this_topActor + CALL { + WITH this + WITH this AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_topActor CALL { WITH this_topActor - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie {title: $title}) - RETURN m\\", { title: $param1, this: this_topActor, auth: $auth }) AS this_topActor_movies + CALL { + WITH this_topActor + WITH this_topActor AS this + MATCH (m:Movie {title: $title}) + RETURN m + } + WITH m AS this_topActor_movies CALL { WITH this_topActor_movies - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this_topActor_movies, auth: $auth }) AS this_topActor_movies_topActor + CALL { + WITH this_topActor_movies + WITH this_topActor_movies AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_topActor_movies_topActor CALL { WITH this_topActor_movies_topActor - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie {title: $title}) - RETURN m\\", { title: $param4, this: this_topActor_movies_topActor, auth: $auth }) AS this_topActor_movies_topActor_movies + CALL { + WITH this_topActor_movies_topActor + WITH this_topActor_movies_topActor AS this + MATCH (m:Movie {title: $title}) + RETURN m + } + WITH m AS this_topActor_movies_topActor_movies RETURN collect(this_topActor_movies_topActor_movies { .title }) AS this_topActor_movies_topActor_movies } RETURN head(collect(this_topActor_movies_topActor { .name, movies: this_topActor_movies_topActor_movies })) AS this_topActor_movies_topActor @@ -371,12 +403,7 @@ describe("Cypher directive", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param1\\": \\"some title\\", - \\"param4\\": \\"another title\\", - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } + \\"title\\": \\"another title\\" }" `); }); @@ -405,12 +432,22 @@ describe("Cypher directive", () => { "MATCH (this:\`Movie\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this, auth: $auth }) AS this_topActor + CALL { + WITH this + WITH this AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_topActor CALL { WITH this_topActor - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie {title: $title}) - RETURN m\\", { title: $param1, this: this_topActor, auth: $auth }) AS this_topActor_movies + CALL { + WITH this_topActor + WITH this_topActor AS this + MATCH (m:Movie {title: $title}) + RETURN m + } + WITH m AS this_topActor_movies RETURN collect(this_topActor_movies { .title }) AS this_topActor_movies } RETURN head(collect(this_topActor { .name, movies: this_topActor_movies })) AS this_topActor @@ -420,11 +457,7 @@ describe("Cypher directive", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param1\\": \\"some title\\", - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } + \\"title\\": \\"some title\\" }" `); }); @@ -466,29 +499,49 @@ describe("Cypher directive", () => { "MATCH (this:\`Actor\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (n) - WHERE (n:TVShow OR n:Movie) AND ($title IS NULL OR n.title = $title) - RETURN n\\", { title: $param0, this: this, auth: $auth }) AS this_movieOrTVShow + CALL { + WITH this + WITH this AS this + MATCH (n) + WHERE (n:TVShow OR n:Movie) AND ($title IS NULL OR n.title = $title) + RETURN n + } + WITH n AS this_movieOrTVShow WITH * WHERE (this_movieOrTVShow:\`Movie\` OR this_movieOrTVShow:\`TVShow\`) WITH *, this_movieOrTVShow AS this_movieOrTVShow_0 CALL { WITH this_movieOrTVShow_0 - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this_movieOrTVShow_0, auth: $auth }) AS this_movieOrTVShow_0_topActor + CALL { + WITH this_movieOrTVShow_0 + WITH this_movieOrTVShow_0 AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_movieOrTVShow_0_topActor RETURN head(collect(this_movieOrTVShow_0_topActor { .name, .year })) AS this_movieOrTVShow_0_topActor } CALL { WITH this_movieOrTVShow_0 - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (a:Actor) - RETURN a\\", { this: this_movieOrTVShow_0, auth: $auth }) AS this_movieOrTVShow_0_actors + CALL { + WITH this_movieOrTVShow_0 + WITH this_movieOrTVShow_0 AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_movieOrTVShow_0_actors RETURN collect(this_movieOrTVShow_0_actors { .name }) AS this_movieOrTVShow_0_actors } WITH *, this_movieOrTVShow AS this_movieOrTVShow_1 CALL { WITH this_movieOrTVShow_1 - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (a:Actor) - RETURN a\\", { this: this_movieOrTVShow_1, auth: $auth }) AS this_movieOrTVShow_1_topActor + CALL { + WITH this_movieOrTVShow_1 + WITH this_movieOrTVShow_1 AS this + MATCH (a:Actor) + RETURN a + } + WITH a AS this_movieOrTVShow_1_topActor RETURN head(collect(this_movieOrTVShow_1_topActor { .name })) AS this_movieOrTVShow_1_topActor } RETURN collect(CASE @@ -501,11 +554,7 @@ describe("Cypher directive", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": \\"some title\\", - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } + \\"title\\": \\"some title\\" }" `); }); @@ -530,9 +579,14 @@ describe("Cypher directive", () => { "MATCH (this:\`Actor\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (n) - WHERE (n:TVShow OR n:Movie) AND ($title IS NULL OR n.title = $title) - RETURN n\\", { title: $param0, this: this, auth: $auth }) AS this_movieOrTVShow + CALL { + WITH this + WITH this AS this + MATCH (n) + WHERE (n:TVShow OR n:Movie) AND ($title IS NULL OR n.title = $title) + RETURN n + } + WITH n AS this_movieOrTVShow WITH * WHERE (this_movieOrTVShow:\`Movie\` OR this_movieOrTVShow:\`TVShow\`) RETURN collect(CASE @@ -545,11 +599,7 @@ describe("Cypher directive", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": \\"some title\\", - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } + \\"title\\": \\"some title\\" }" `); }); @@ -573,7 +623,8 @@ describe("Cypher directive", () => { statement: """ MATCH (m:Movie {title: $title}) RETURN m - """ + """, + columnName: "m" ) } `; @@ -597,10 +648,11 @@ describe("Cypher directive", () => { }); expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "WITH apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie {title: $title}) - RETURN m\\", {auth: $auth, title: $title}) as x - UNWIND x as this - WITH this + "CALL { + MATCH (m:Movie {title: $title}) + RETURN m + } + WITH m as this CALL { WITH this MATCH (this_actors:\`Actor\`)-[this0:ACTED_IN]->(this) diff --git a/packages/graphql/tests/tck/issues/1139.test.ts b/packages/graphql/tests/tck/issues/1139.test.ts deleted file mode 100644 index 4a73c1399b..0000000000 --- a/packages/graphql/tests/tck/issues/1139.test.ts +++ /dev/null @@ -1,115 +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 { gql } from "apollo-server"; -import type { DocumentNode } from "graphql"; -import { Neo4jGraphQL } from "../../../src"; -import { formatCypher, translateQuery, formatParams } from "../utils/tck-test-utils"; - -describe("https://github.com/neo4j/graphql/issues/1139", () => { - let typeDefs: DocumentNode; - let neoSchema: Neo4jGraphQL; - - beforeAll(() => { - typeDefs = gql` - union PostMovieUser = Post | Movie | User - - type Post { - name: String - } - - type Movie { - name: String - } - - type User { - id: ID @id - updates: [PostMovieUser!]! - @cypher( - statement: """ - MATCH (this)-[a:WROTE]->(wrote:Post) - WHERE a.date_added IS NOT NULL - WITH COLLECT(wrote{ .*, date_added: a.date_added, typename: 'WROTE' }) as updates1, this - MATCH (this)-[a:FOLLOWS]->(umb) - WHERE (umb:User or umb:Movie or umb:Blog) AND a.date_added IS NOT NULL - WITH updates1 + COLLECT(umb{ .*, date_added: a.date_added, typename: 'FOLLOWED' }) as allUpdates - UNWIND allUpdates as update - RETURN update - ORDER BY update.date_added DESC - LIMIT 5 - """ - ) - } - `; - - neoSchema = new Neo4jGraphQL({ - typeDefs, - }); - }); - - test("Querying the __typename on a relationship with a union array type in cypher statement", async () => { - const query = gql` - query { - users(where: { id: "test-id" }) { - updates { - __typename - } - } - } - `; - - const result = await translateQuery(neoSchema, query, {}); - - expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this:\`User\`) - WHERE this.id = $param0 - CALL { - WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (this)-[a:WROTE]->(wrote:Post) - WHERE a.date_added IS NOT NULL - WITH COLLECT(wrote{ .*, date_added: a.date_added, typename: 'WROTE' }) as updates1, this - MATCH (this)-[a:FOLLOWS]->(umb) - WHERE (umb:User or umb:Movie or umb:Blog) AND a.date_added IS NOT NULL - WITH updates1 + COLLECT(umb{ .*, date_added: a.date_added, typename: 'FOLLOWED' }) as allUpdates - UNWIND allUpdates as update - RETURN update - ORDER BY update.date_added DESC - LIMIT 5\\", { this: this, auth: $auth }) AS this_updates - WITH * - WHERE (this_updates:\`Post\` OR this_updates:\`Movie\` OR this_updates:\`User\`) - RETURN collect(CASE - WHEN this_updates:\`Post\` THEN this_updates { __resolveType: \\"Post\\" } - WHEN this_updates:\`Movie\` THEN this_updates { __resolveType: \\"Movie\\" } - WHEN this_updates:\`User\` THEN this_updates { __resolveType: \\"User\\" } - END) AS this_updates - } - RETURN this { updates: this_updates } AS this" - `); - - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"param0\\": \\"test-id\\", - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } - }" - `); - }); -}); diff --git a/packages/graphql/tests/tck/issues/1364.test.ts b/packages/graphql/tests/tck/issues/1364.test.ts index 328702e454..956d3e0a47 100644 --- a/packages/graphql/tests/tck/issues/1364.test.ts +++ b/packages/graphql/tests/tck/issues/1364.test.ts @@ -46,15 +46,17 @@ describe("https://github.com/neo4j/graphql/issues/1364", () => { @cypher( statement: """ MATCH (this)-[:HAS_GENRE]->(genre:Genre) - RETURN count(DISTINCT genre) + RETURN count(DISTINCT genre) as result """ + columnName: "result" ) totalActors: Int! @cypher( statement: """ MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN count(DISTINCT actor) + RETURN count(DISTINCT actor) as result """ + columnName: "result" ) } @@ -65,8 +67,9 @@ describe("https://github.com/neo4j/graphql/issues/1364", () => { @cypher( statement: """ MATCH (this)<-[:HAS_GENRE]-(movie:Movie) - RETURN count(DISTINCT movie) + RETURN count(DISTINCT movie) as result """ + columnName: "result" ) } `; @@ -109,8 +112,13 @@ describe("https://github.com/neo4j/graphql/issues/1364", () => { ORDER BY this.title ASC CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)-[:HAS_GENRE]->(genre:Genre) - RETURN count(DISTINCT genre)\\", { this: this, auth: $auth }) AS this_totalGenres + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_GENRE]->(genre:Genre) + RETURN count(DISTINCT genre) as result + } + UNWIND result AS this_totalGenres RETURN head(collect(this_totalGenres)) AS this_totalGenres } WITH { node: this { .title, totalGenres: this_totalGenres } } AS edge, totalCount, this @@ -144,8 +152,13 @@ describe("https://github.com/neo4j/graphql/issues/1364", () => { WITH this, totalCount CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)-[:HAS_GENRE]->(genre:Genre) - RETURN count(DISTINCT genre)\\", { this: this, auth: $auth }) AS this_totalGenres + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_GENRE]->(genre:Genre) + RETURN count(DISTINCT genre) as result + } + UNWIND result AS this_totalGenres RETURN head(collect(this_totalGenres)) AS this_totalGenres } WITH * @@ -182,16 +195,26 @@ describe("https://github.com/neo4j/graphql/issues/1364", () => { WITH this, totalCount CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)-[:HAS_GENRE]->(genre:Genre) - RETURN count(DISTINCT genre)\\", { this: this, auth: $auth }) AS this_totalGenres + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_GENRE]->(genre:Genre) + RETURN count(DISTINCT genre) as result + } + UNWIND result AS this_totalGenres RETURN head(collect(this_totalGenres)) AS this_totalGenres } WITH * ORDER BY this_totalGenres ASC CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN count(DISTINCT actor)\\", { this: this, auth: $auth }) AS this_totalActors + CALL { + WITH this + WITH this AS this + MATCH (this)<-[:ACTED_IN]-(actor:Actor) + RETURN count(DISTINCT actor) as result + } + UNWIND result AS this_totalActors RETURN head(collect(this_totalActors)) AS this_totalActors } WITH { node: this { .title, totalGenres: this_totalGenres, totalActors: this_totalActors } } AS edge, totalCount, this diff --git a/packages/graphql/tests/tck/issues/1528.test.ts b/packages/graphql/tests/tck/issues/1528.test.ts index 38aadef274..81083dae6b 100644 --- a/packages/graphql/tests/tck/issues/1528.test.ts +++ b/packages/graphql/tests/tck/issues/1528.test.ts @@ -34,8 +34,9 @@ describe("https://github.com/neo4j/graphql/issues/1528", () => { @cypher( statement: """ MATCH (this)<-[:ACTED_IN]-(ac:Person) - RETURN count(ac) + RETURN count(ac) as res """ + columnName: "res" ) } @@ -84,8 +85,13 @@ describe("https://github.com/neo4j/graphql/issues/1528", () => { ORDER BY this_Movie.actorsCount DESC CALL { WITH this_Movie - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)<-[:ACTED_IN]-(ac:Person) - RETURN count(ac)\\", { this: this_Movie, auth: $auth }) AS this_Movie_actorsCount + CALL { + WITH this_Movie + WITH this_Movie AS this + MATCH (this)<-[:ACTED_IN]-(ac:Person) + RETURN count(ac) as res + } + UNWIND res AS this_Movie_actorsCount RETURN head(collect(this_Movie_actorsCount)) AS this_Movie_actorsCount } WITH { node: { title: this_Movie.title, actorsCount: this_Movie_actorsCount } } AS edge @@ -104,13 +110,6 @@ describe("https://github.com/neo4j/graphql/issues/1528", () => { RETURN this { moviesConnection: this_moviesConnection } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); }); diff --git a/packages/graphql/tests/tck/issues/1566.test.ts b/packages/graphql/tests/tck/issues/1566.test.ts index bf1fe1dd23..899cb3d3b3 100644 --- a/packages/graphql/tests/tck/issues/1566.test.ts +++ b/packages/graphql/tests/tck/issues/1566.test.ts @@ -50,6 +50,7 @@ describe("https://github.com/neo4j/graphql/issues/1566", () => { Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag SKIP ($limit * $pageIndex) LIMIT $limit """ + columnName: "pag" ) } `; @@ -84,8 +85,13 @@ describe("https://github.com/neo4j/graphql/issues/1566", () => { WHERE this.id = $param0 CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) - return pag SKIP ($limit * $pageIndex) LIMIT $limit\\", { limit: $param1, page: $param2, this: this, auth: $auth }) AS this_hasFeedItems + CALL { + WITH this + WITH this AS this + Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) + return pag SKIP ($limit * $pageIndex) LIMIT $limit + } + WITH pag AS this_hasFeedItems WITH * WHERE (this_hasFeedItems:\`Content\` OR this_hasFeedItems:\`Project\`) RETURN collect(CASE diff --git a/packages/graphql/tests/tck/issues/1760.test.ts b/packages/graphql/tests/tck/issues/1760.test.ts index cb26519c6f..35b89323fe 100644 --- a/packages/graphql/tests/tck/issues/1760.test.ts +++ b/packages/graphql/tests/tck/issues/1760.test.ts @@ -38,7 +38,8 @@ describe("https://github.com/neo4j/graphql/issues/1760", () => { @exclude(operations: [CREATE, UPDATE, DELETE]) { markets: [Market!]! @relationship(type: "HAS_MARKETS", direction: OUT) id: ID! @id(autogenerate: false) - relatedId: ID @cypher(statement: "MATCH (this)<-[:HAS_BASE]-(n:BaseObject) RETURN n.id") + relatedId: ID + @cypher(statement: "MATCH (this)<-[:HAS_BASE]-(n:BaseObject) RETURN n.id as res", columnName: "res") baseObject: BaseObject! @relationship(type: "HAS_BASE", direction: IN) current: Boolean! nameDetails: NameDetails @relationship(type: "HAS_NAME", direction: OUT) @@ -127,13 +128,18 @@ describe("https://github.com/neo4j/graphql/issues/1760", () => { WHERE (this.current = $param0 AND apoc.util.validatePredicate(NOT ((any(var1 IN [\\"ALL\\"] WHERE any(var0 IN $auth.roles WHERE var0 = var1)) AND apoc.util.validatePredicate(NOT ($auth.isAuthenticated = true), \\"@neo4j/graphql/UNAUTHENTICATED\\", [0]))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)<-[:HAS_BASE]-(n:BaseObject) RETURN n.id\\", { this: this, auth: $auth }) AS this_relatedId + CALL { + WITH this + WITH this AS this + MATCH (this)<-[:HAS_BASE]-(n:BaseObject) RETURN n.id as res + } + UNWIND res AS this_relatedId RETURN head(collect(this_relatedId)) AS this_relatedId } WITH * ORDER BY this_relatedId ASC - SKIP $param3 - LIMIT $param4 + SKIP $param2 + LIMIT $param3 CALL { WITH this MATCH (this)-[this_connection_nameDetailsConnectionthis0:HAS_NAME]->(this_NameDetails:\`NameDetails\`) @@ -176,11 +182,11 @@ describe("https://github.com/neo4j/graphql/issues/1760", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ \\"param0\\": true, - \\"param3\\": { + \\"param2\\": { \\"low\\": 0, \\"high\\": 0 }, - \\"param4\\": { + \\"param3\\": { \\"low\\": 50, \\"high\\": 0 }, diff --git a/packages/graphql/tests/tck/issues/1848.test.ts b/packages/graphql/tests/tck/issues/1848.test.ts index d22fa4993d..e3b7276f2f 100644 --- a/packages/graphql/tests/tck/issues/1848.test.ts +++ b/packages/graphql/tests/tck/issues/1848.test.ts @@ -56,6 +56,7 @@ describe("https://github.com/neo4j/graphql/issues/1848", () => { statement: """ Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag SKIP ($limit * $pageIndex) LIMIT $limit """ + columnName: "pag" ) } @@ -90,7 +91,12 @@ describe("https://github.com/neo4j/graphql/issues/1848", () => { "MATCH (this:\`Community\`:\`UNIVERSAL\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag SKIP ($limit * $pageIndex) LIMIT $limit\\", { limit: $param0, pageIndex: $param1, this: this, auth: $auth }) AS this_hasFeedItems + CALL { + WITH this + WITH this AS this + Match(this)-[:COMMUNITY_CONTENTPIECE_HASCONTENTPIECES|:COMMUNITY_PROJECT_HASASSOCIATEDPROJECTS]-(pag) return pag SKIP ($limit * $pageIndex) LIMIT $limit + } + WITH pag AS this_hasFeedItems WITH * WHERE ((this_hasFeedItems:\`ContentPiece\` AND this_hasFeedItems:\`UNIVERSAL\`) OR (this_hasFeedItems:\`Project\` AND this_hasFeedItems:\`UNIVERSAL\`)) RETURN collect(CASE @@ -103,17 +109,13 @@ describe("https://github.com/neo4j/graphql/issues/1848", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { + \\"limit\\": { \\"low\\": 10, \\"high\\": 0 }, - \\"param1\\": { + \\"pageIndex\\": { \\"low\\": 0, \\"high\\": 0 - }, - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] } }" `); diff --git a/packages/graphql/tests/tck/issues/2100.test.ts b/packages/graphql/tests/tck/issues/2100.test.ts index 7e1aa99b64..e2f0d55459 100644 --- a/packages/graphql/tests/tck/issues/2100.test.ts +++ b/packages/graphql/tests/tck/issues/2100.test.ts @@ -41,6 +41,7 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { MATCH (this)<-[:PRESENT_AT_SERVICE|ABSENT_FROM_SERVICE]-(member:Member) RETURN COUNT(member) > 0 AS markedAttendance """ + columnName: "markedAttendance" ) serviceDate: TimeGraph! @relationship(type: "BUSSED_ON", direction: OUT) } @@ -62,6 +63,7 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { WITH DISTINCT records, date LIMIT $limit RETURN records ORDER BY date.date DESC """ + columnName: "records" ) } @@ -78,6 +80,7 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { MATCH (this)<-[:PRESENT_AT_SERVICE|ABSENT_FROM_SERVICE]-(member:Member) RETURN COUNT(member) > 0 AS markedAttendance """ + columnName: "markedAttendance" ) serviceDate: TimeGraph! @relationship(type: "BUSSED_ON", direction: OUT) } @@ -115,13 +118,23 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { WHERE (this.id = $param0 AND apoc.util.validatePredicate(NOT (apoc.util.validatePredicate(NOT ($auth.isAuthenticated = true), \\"@neo4j/graphql/UNAUTHENTICATED\\", [0])), \\"@neo4j/graphql/FORBIDDEN\\", [0])) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (this)-[:HAS_HISTORY]->(:ServiceLog)-[:HAS_BUSSING]->(records:BussingRecord)-[:BUSSED_ON]->(date:TimeGraph) - WITH DISTINCT records, date LIMIT $limit - RETURN records ORDER BY date.date DESC\\", { limit: $param2, this: this, auth: $auth }) AS this_bussing + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_HISTORY]->(:ServiceLog)-[:HAS_BUSSING]->(records:BussingRecord)-[:BUSSED_ON]->(date:TimeGraph) + WITH DISTINCT records, date LIMIT $limit + RETURN records ORDER BY date.date DESC + } + WITH records AS this_bussing CALL { WITH this_bussing - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)<-[:PRESENT_AT_SERVICE|ABSENT_FROM_SERVICE]-(member:Member) - RETURN COUNT(member) > 0 AS markedAttendance\\", { this: this_bussing, auth: $auth }) AS this_bussing_markedAttendance + CALL { + WITH this_bussing + WITH this_bussing AS this + MATCH (this)<-[:PRESENT_AT_SERVICE|ABSENT_FROM_SERVICE]-(member:Member) + RETURN COUNT(member) > 0 AS markedAttendance + } + UNWIND markedAttendance AS this_bussing_markedAttendance RETURN head(collect(this_bussing_markedAttendance)) AS this_bussing_markedAttendance } CALL { @@ -139,7 +152,7 @@ describe("https://github.com/neo4j/graphql/issues/2100", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ \\"param0\\": \\"1\\", - \\"param2\\": { + \\"limit\\": { \\"low\\": 10, \\"high\\": 0 }, diff --git a/packages/graphql/tests/tck/issues/2581.test.ts b/packages/graphql/tests/tck/issues/2581.test.ts index a8d9b6ece3..ce09053653 100644 --- a/packages/graphql/tests/tck/issues/2581.test.ts +++ b/packages/graphql/tests/tck/issues/2581.test.ts @@ -58,7 +58,8 @@ describe("https://github.com/neo4j/graphql/issues/2581", () => { ) soldCopiesWithoutColumnName: Int @cypher( - statement: "OPTIONAL MATCH(sales:Sales) WHERE this.refID = sales.refID WITH count(sales) as result RETURN result as result" + statement: "OPTIONAL MATCH(sales:Sales) WHERE this.refID = sales.refID WITH count(sales) as result RETURN result as result", + columnName: "result" ) authors: [Author!]! @relationship(type: "AUTHORED_BOOK", direction: IN) } @@ -144,7 +145,12 @@ describe("https://github.com/neo4j/graphql/issues/2581", () => { WITH result AS this_mostRecentBook CALL { WITH this_mostRecentBook - UNWIND apoc.cypher.runFirstColumnSingle(\\"OPTIONAL MATCH(sales:Sales) WHERE this.refID = sales.refID WITH count(sales) as result RETURN result as result\\", { this: this_mostRecentBook, auth: $auth }) AS this_mostRecentBook_soldCopiesWithoutColumnName + CALL { + WITH this_mostRecentBook + WITH this_mostRecentBook AS this + OPTIONAL MATCH(sales:Sales) WHERE this.refID = sales.refID WITH count(sales) as result RETURN result as result + } + UNWIND result AS this_mostRecentBook_soldCopiesWithoutColumnName RETURN head(collect(this_mostRecentBook_soldCopiesWithoutColumnName)) AS this_mostRecentBook_soldCopiesWithoutColumnName } RETURN head(collect(this_mostRecentBook { .name, .year, soldCopiesWithoutColumnName: this_mostRecentBook_soldCopiesWithoutColumnName })) AS this_mostRecentBook @@ -152,13 +158,6 @@ describe("https://github.com/neo4j/graphql/issues/2581", () => { RETURN this { .name, mostRecentBook: this_mostRecentBook } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); }); diff --git a/packages/graphql/tests/tck/issues/387.test.ts b/packages/graphql/tests/tck/issues/387.test.ts index 9dfda7b989..5759be8631 100644 --- a/packages/graphql/tests/tck/issues/387.test.ts +++ b/packages/graphql/tests/tck/issues/387.test.ts @@ -36,26 +36,30 @@ describe("#387", () => { url_works: String @cypher( statement: """ - return '' + '' + return '' + '' as result """ + columnName: "result" ) url_fails: URL @cypher( statement: """ - return '' + '' + return '' + '' as result """ + columnName: "result" ) url_array_works: [String] @cypher( statement: """ - return ['' + ''] + return ['' + ''] as result """ + columnName: "result" ) url_array_fails: [URL] @cypher( statement: """ - return ['' + ''] + return ['' + ''] as result """ + columnName: "result" ) } `; @@ -87,34 +91,47 @@ describe("#387", () => { "MATCH (this:\`Place\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"return '' + ''\\", { this: this, auth: $auth }) AS this_url_works + CALL { + WITH this + WITH this AS this + return '' + '' as result + } + UNWIND result AS this_url_works RETURN head(collect(this_url_works)) AS this_url_works } CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"return '' + ''\\", { this: this, auth: $auth }) AS this_url_fails + CALL { + WITH this + WITH this AS this + return '' + '' as result + } + UNWIND result AS this_url_fails RETURN head(collect(this_url_fails)) AS this_url_fails } CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"return ['' + '']\\", { this: this, auth: $auth }) AS this_url_array_works + CALL { + WITH this + WITH this AS this + return ['' + ''] as result + } + UNWIND result AS this_url_array_works RETURN collect(this_url_array_works) AS this_url_array_works } CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"return ['' + '']\\", { this: this, auth: $auth }) AS this_url_array_fails + CALL { + WITH this + WITH this AS this + return ['' + ''] as result + } + UNWIND result AS this_url_array_fails RETURN collect(this_url_array_fails) AS this_url_array_fails } RETURN this { url_works: this_url_works, url_fails: this_url_fails, url_array_works: this_url_array_works, url_array_fails: this_url_array_fails } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); }); diff --git a/packages/graphql/tests/tck/issues/630.test.ts b/packages/graphql/tests/tck/issues/630.test.ts index 33a1168a3a..8c5a50fdda 100644 --- a/packages/graphql/tests/tck/issues/630.test.ts +++ b/packages/graphql/tests/tck/issues/630.test.ts @@ -37,6 +37,7 @@ describe("Cypher directive", () => { MATCH (m:Movie {title: $title}) RETURN m """ + columnName: "m" ) } @@ -75,8 +76,13 @@ describe("Cypher directive", () => { "MATCH (this:\`Actor\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnMany(\\"MATCH (m:Movie {title: $title}) - RETURN m\\", { title: NULL, this: this, auth: $auth }) AS this_movies + CALL { + WITH this + WITH this AS this + MATCH (m:Movie {title: $title}) + RETURN m + } + WITH m AS this_movies CALL { WITH this_movies MATCH (this_movies)<-[this_movies_connection_actorsConnectionthis0:ACTED_IN]-(this_movies_Actor:\`Actor\`) @@ -92,10 +98,7 @@ describe("Cypher directive", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"auth\\": { - \\"isAuthenticated\\": false, - \\"roles\\": [] - } + \\"title\\": null }" `); }); diff --git a/packages/graphql/tests/tck/sort.test.ts b/packages/graphql/tests/tck/sort.test.ts index 1a02f33d28..17b96eac61 100644 --- a/packages/graphql/tests/tck/sort.test.ts +++ b/packages/graphql/tests/tck/sort.test.ts @@ -39,8 +39,9 @@ describe("Cypher sort tests", () => { @cypher( statement: """ MATCH (this)-[:HAS_GENRE]->(genre:Genre) - RETURN count(DISTINCT genre) + RETURN count(DISTINCT genre) as result """ + columnName: "result" ) } @@ -51,8 +52,9 @@ describe("Cypher sort tests", () => { @cypher( statement: """ MATCH (this)<-[:HAS_GENRE]-(movie:Movie) - RETURN count(DISTINCT movie) + RETURN count(DISTINCT movie) as result """ + columnName: "result" ) } `; @@ -162,8 +164,13 @@ describe("Cypher sort tests", () => { "MATCH (this:\`Movie\`) CALL { WITH this - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)-[:HAS_GENRE]->(genre:Genre) - RETURN count(DISTINCT genre)\\", { this: this, auth: $auth }) AS this_totalGenres + CALL { + WITH this + WITH this AS this + MATCH (this)-[:HAS_GENRE]->(genre:Genre) + RETURN count(DISTINCT genre) as result + } + UNWIND result AS this_totalGenres RETURN head(collect(this_totalGenres)) AS this_totalGenres } WITH * @@ -171,17 +178,7 @@ describe("Cypher sort tests", () => { RETURN this { totalGenres: this_totalGenres } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": true, - \\"roles\\": [], - \\"jwt\\": { - \\"roles\\": [] - } - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); test("Multi Sort", async () => { @@ -339,8 +336,13 @@ describe("Cypher sort tests", () => { MATCH (this)-[this0:HAS_GENRE]->(this_genres:\`Genre\`) CALL { WITH this_genres - UNWIND apoc.cypher.runFirstColumnSingle(\\"MATCH (this)<-[:HAS_GENRE]-(movie:Movie) - RETURN count(DISTINCT movie)\\", { this: this_genres, auth: $auth }) AS this_genres_totalMovies + CALL { + WITH this_genres + WITH this_genres AS this + MATCH (this)<-[:HAS_GENRE]-(movie:Movie) + RETURN count(DISTINCT movie) as result + } + UNWIND result AS this_genres_totalMovies RETURN head(collect(this_genres_totalMovies)) AS this_genres_totalMovies } WITH this_genres { .name, totalMovies: this_genres_totalMovies } AS this_genres @@ -350,16 +352,6 @@ describe("Cypher sort tests", () => { RETURN this { genres: this_genres } AS this" `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"auth\\": { - \\"isAuthenticated\\": true, - \\"roles\\": [], - \\"jwt\\": { - \\"roles\\": [] - } - } - }" - `); + expect(formatParams(result.params)).toMatchInlineSnapshot(`"{}"`); }); });