diff --git a/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth-connection.int.test.ts b/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth-connection.int.test.ts deleted file mode 100644 index 1ef201dfbe..0000000000 --- a/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth-connection.int.test.ts +++ /dev/null @@ -1,380 +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 { TestHelper } from "../../../../../utils/tests-helper"; - -describe("Connection API - cypher directive filtering - relationship auth filter", () => { - const testHelper = new TestHelper(); - - afterEach(async () => { - await testHelper.close(); - }); - - test("relationship with auth filter on type PASS", async () => { - const Movie = testHelper.createUniqueType("Movie"); - const Actor = testHelper.createUniqueType("Actor"); - - const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(filter: [{ where: { node: { actors_SOME: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [${Actor}!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:${Actor}) - RETURN actor - """ - columnName: "actor" - ) - } - - type ${Actor} @node { - name: String - movies: [${Movie}!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:${Movie}) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = testHelper.createBearerToken("secret", { custom_value: "Keanu Reeves" }); - - await testHelper.initNeo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - await testHelper.executeCypher( - ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) - CREATE (a:${Actor} { name: "Keanu Reeves" }) - CREATE (a)-[:ACTED_IN]->(m) - CREATE (a)-[:ACTED_IN]->(m2) - CREATE (a)-[:ACTED_IN]->(m3) - CREATE (a2:${Actor} { name: "Carrie-Anne Moss" }) - CREATE (a2)-[:ACTED_IN]->(m) - CREATE (a2)-[:ACTED_IN]->(m2) - CREATE (a2)-[:ACTED_IN]->(m3) - CREATE (a3:${Actor} { name: "Jada Pinkett Smith" }) - CREATE (a3)-[:ACTED_IN]->(m2) - CREATE (a3)-[:ACTED_IN]->(m3) - `, - {} - ); - - const query = /* GraphQL */ ` - query { - ${Movie.operations.connection}( - where: { - title: "The Matrix" - } - ) { - edges { - node { - title - } - } - } - } - `; - - const gqlResult = await testHelper.executeGraphQLWithToken(query, token); - - expect(gqlResult.errors).toBeFalsy(); - expect(gqlResult?.data).toEqual({ - [Movie.operations.connection]: { - edges: expect.toIncludeSameMembers([ - { - node: { - title: "The Matrix", - }, - }, - ]), - }, - }); - }); - - test("relationship with auth filter on type FAIL", async () => { - const Movie = testHelper.createUniqueType("Movie"); - const Actor = testHelper.createUniqueType("Actor"); - - const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [${Actor}!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:${Actor}) - RETURN actor - """ - columnName: "actor" - ) - } - - type ${Actor} @node { - name: String - movies: [${Movie}!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:${Movie}) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = testHelper.createBearerToken("secret", { custom_value: "Something Incorrect" }); - - await testHelper.initNeo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - await testHelper.executeCypher( - ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) - CREATE (a:${Actor} { name: "Keanu Reeves" }) - CREATE (a)-[:ACTED_IN]->(m) - CREATE (a)-[:ACTED_IN]->(m2) - CREATE (a)-[:ACTED_IN]->(m3) - CREATE (a2:${Actor} { name: "Carrie-Anne Moss" }) - CREATE (a2)-[:ACTED_IN]->(m) - CREATE (a2)-[:ACTED_IN]->(m2) - CREATE (a2)-[:ACTED_IN]->(m3) - CREATE (a3:${Actor} { name: "Jada Pinkett Smith" }) - CREATE (a3)-[:ACTED_IN]->(m2) - CREATE (a3)-[:ACTED_IN]->(m3) - `, - {} - ); - - const query = /* GraphQL */ ` - query { - ${Movie.operations.connection}( - where: { - title: "The Matrix" - } - ) { - edges { - node { - title - } - } - } - } - `; - - const gqlResult = await testHelper.executeGraphQLWithToken(query, token); - - expect(gqlResult.errors).toBeFalsy(); - expect(gqlResult?.data).toEqual({ - [Movie.operations.connection]: { - edges: [], - }, - }); - }); - - test("relationship with auth validate on type PASS", async () => { - const Movie = testHelper.createUniqueType("Movie"); - const Actor = testHelper.createUniqueType("Actor"); - - const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [${Actor}!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:${Actor}) - RETURN actor - """ - columnName: "actor" - ) - } - - type ${Actor} @node { - name: String - movies: [${Movie}!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:${Movie}) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = testHelper.createBearerToken("secret", { custom_value: "Keanu Reeves" }); - - await testHelper.initNeo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - await testHelper.executeCypher( - ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) - CREATE (a:${Actor} { name: "Keanu Reeves" }) - CREATE (a)-[:ACTED_IN]->(m) - CREATE (a)-[:ACTED_IN]->(m2) - CREATE (a)-[:ACTED_IN]->(m3) - CREATE (a2:${Actor} { name: "Carrie-Anne Moss" }) - CREATE (a2)-[:ACTED_IN]->(m) - CREATE (a2)-[:ACTED_IN]->(m2) - CREATE (a2)-[:ACTED_IN]->(m3) - CREATE (a3:${Actor} { name: "Jada Pinkett Smith" }) - CREATE (a3)-[:ACTED_IN]->(m2) - CREATE (a3)-[:ACTED_IN]->(m3) - `, - {} - ); - - const query = /* GraphQL */ ` - query { - ${Movie.operations.connection}( - where: { - title: "The Matrix" - } - ) { - edges { - node { - title - } - } - } - } - `; - - const gqlResult = await testHelper.executeGraphQLWithToken(query, token); - - expect(gqlResult.errors).toBeFalsy(); - expect(gqlResult?.data).toEqual({ - [Movie.operations.connection]: { - edges: expect.toIncludeSameMembers([ - { - node: { - title: "The Matrix", - }, - }, - ]), - }, - }); - }); - - test("relationship with auth validate on type FAIL", async () => { - const Movie = testHelper.createUniqueType("Movie"); - const Actor = testHelper.createUniqueType("Actor"); - - const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [${Actor}!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:${Actor}) - RETURN actor - """ - columnName: "actor" - ) - } - - type ${Actor} @node { - name: String - movies: [${Movie}!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:${Movie}) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = testHelper.createBearerToken("secret", { custom_value: "Something Incorrect" }); - - await testHelper.initNeo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - await testHelper.executeCypher( - ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) - CREATE (a:${Actor} { name: "Keanu Reeves" }) - CREATE (a)-[:ACTED_IN]->(m) - CREATE (a)-[:ACTED_IN]->(m2) - CREATE (a)-[:ACTED_IN]->(m3) - CREATE (a2:${Actor} { name: "Carrie-Anne Moss" }) - CREATE (a2)-[:ACTED_IN]->(m) - CREATE (a2)-[:ACTED_IN]->(m2) - CREATE (a2)-[:ACTED_IN]->(m3) - CREATE (a3:${Actor} { name: "Jada Pinkett Smith" }) - CREATE (a3)-[:ACTED_IN]->(m2) - CREATE (a3)-[:ACTED_IN]->(m3) - `, - {} - ); - - const query = /* GraphQL */ ` - query { - ${Movie.operations.connection}( - where: { - title: "The Matrix" - } - ) { - edges { - node { - title - } - } - } - } - `; - - const gqlResult = await testHelper.executeGraphQLWithToken(query, token); - - expect(gqlResult.errors).toHaveLength(1); - expect(gqlResult.errors?.[0]?.message).toBe("Forbidden"); - }); -}); diff --git a/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.int.test.ts b/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.int.test.ts index 3dd60d463c..b39a19ed02 100644 --- a/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.int.test.ts +++ b/packages/graphql/tests/integration/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.int.test.ts @@ -19,7 +19,7 @@ import { TestHelper } from "../../../../../utils/tests-helper"; -describe("cypher directive filtering - relationship auth filter", () => { +describe("Connection API - cypher directive filtering - relationship auth filter", () => { const testHelper = new TestHelper(); afterEach(async () => { @@ -31,8 +31,9 @@ describe("cypher directive filtering - relationship auth filter", () => { const Actor = testHelper.createUniqueType("Actor"); const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { + type ${Movie} @node @authorization(filter: [{ where: { node: { actors_SOME: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [${Actor}!]! @cypher( statement: """ @@ -56,7 +57,7 @@ describe("cypher directive filtering - relationship auth filter", () => { } `; - const token = testHelper.createBearerToken("secret", { custom_value: "Keanu Reeves" }); + const token = testHelper.createBearerToken("secret", { custom_value: "Jada Pinkett Smith" }); await testHelper.initNeo4jGraphQL({ typeDefs, @@ -68,9 +69,9 @@ describe("cypher directive filtering - relationship auth filter", () => { }); await testHelper.executeCypher( ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) + CREATE (m:${Movie} { title: "The Matrix", rating: 10.0 }) + CREATE (m2:${Movie} { title: "The Matrix Reloaded", rating: 8.0 }) + CREATE (m3:${Movie} { title: "The Matrix Revolutions", rating: 6.0 }) CREATE (a:${Actor} { name: "Keanu Reeves" }) CREATE (a)-[:ACTED_IN]->(m) CREATE (a)-[:ACTED_IN]->(m2) @@ -88,12 +89,16 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}( + ${Movie.operations.connection}( where: { - title: "The Matrix" + rating_GT: 7.0 } ) { - title + edges { + node { + title + } + } } } `; @@ -102,11 +107,15 @@ describe("cypher directive filtering - relationship auth filter", () => { expect(gqlResult.errors).toBeFalsy(); expect(gqlResult?.data).toEqual({ - [Movie.plural]: expect.toIncludeSameMembers([ - { - title: "The Matrix", - }, - ]), + [Movie.operations.connection]: { + edges: expect.toIncludeSameMembers([ + { + node: { + title: "The Matrix Reloaded", + }, + }, + ]), + }, }); }); @@ -115,8 +124,9 @@ describe("cypher directive filtering - relationship auth filter", () => { const Actor = testHelper.createUniqueType("Actor"); const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { + type ${Movie} @node @authorization(filter: [{ where: { node: { actors_SOME: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [${Actor}!]! @cypher( statement: """ @@ -152,9 +162,9 @@ describe("cypher directive filtering - relationship auth filter", () => { }); await testHelper.executeCypher( ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) + CREATE (m:${Movie} { title: "The Matrix", rating: 10.0 }) + CREATE (m2:${Movie} { title: "The Matrix Reloaded", rating: 8.0 }) + CREATE (m3:${Movie} { title: "The Matrix Revolutions", rating: 6.0 }) CREATE (a:${Actor} { name: "Keanu Reeves" }) CREATE (a)-[:ACTED_IN]->(m) CREATE (a)-[:ACTED_IN]->(m2) @@ -172,12 +182,16 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}( + ${Movie.operations.connection}( where: { - title: "The Matrix" + rating_GT: 7.0 } ) { - title + edges { + node { + title + } + } } } `; @@ -185,8 +199,10 @@ describe("cypher directive filtering - relationship auth filter", () => { const gqlResult = await testHelper.executeGraphQLWithToken(query, token); expect(gqlResult.errors).toBeFalsy(); - expect(gqlResult.data).toEqual({ - [Movie.plural]: expect.toIncludeSameMembers([]), + expect(gqlResult?.data).toEqual({ + [Movie.operations.connection]: { + edges: [], + }, }); }); @@ -195,8 +211,9 @@ describe("cypher directive filtering - relationship auth filter", () => { const Actor = testHelper.createUniqueType("Actor"); const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { + type ${Movie} @node @authorization(validate: [{ where: { node: { actors_SOME: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [${Actor}!]! @cypher( statement: """ @@ -220,7 +237,7 @@ describe("cypher directive filtering - relationship auth filter", () => { } `; - const token = testHelper.createBearerToken("secret", { custom_value: "Keanu Reeves" }); + const token = testHelper.createBearerToken("secret", { custom_value: "Jada Pinkett Smith" }); await testHelper.initNeo4jGraphQL({ typeDefs, @@ -232,9 +249,9 @@ describe("cypher directive filtering - relationship auth filter", () => { }); await testHelper.executeCypher( ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) + CREATE (m:${Movie} { title: "The Matrix", rating: 10.0 }) + CREATE (m2:${Movie} { title: "The Matrix Reloaded", rating: 8.0 }) + CREATE (m3:${Movie} { title: "The Matrix Revolutions", rating: 6.0 }) CREATE (a:${Actor} { name: "Keanu Reeves" }) CREATE (a)-[:ACTED_IN]->(m) CREATE (a)-[:ACTED_IN]->(m2) @@ -252,12 +269,16 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}( + ${Movie.operations.connection}( where: { - title: "The Matrix" + rating_LT: 7.0 } ) { - title + edges { + node { + title + } + } } } `; @@ -266,11 +287,15 @@ describe("cypher directive filtering - relationship auth filter", () => { expect(gqlResult.errors).toBeFalsy(); expect(gqlResult?.data).toEqual({ - [Movie.plural]: expect.toIncludeSameMembers([ - { - title: "The Matrix", - }, - ]), + [Movie.operations.connection]: { + edges: expect.toIncludeSameMembers([ + { + node: { + title: "The Matrix Revolutions", + }, + }, + ]), + }, }); }); @@ -279,8 +304,9 @@ describe("cypher directive filtering - relationship auth filter", () => { const Actor = testHelper.createUniqueType("Actor"); const typeDefs = /* GraphQL */ ` - type ${Movie} @node @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { + type ${Movie} @node @authorization(validate: [{ where: { node: { actors_SOME: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [${Actor}!]! @cypher( statement: """ @@ -304,7 +330,7 @@ describe("cypher directive filtering - relationship auth filter", () => { } `; - const token = testHelper.createBearerToken("secret", { custom_value: "Something Incorrect" }); + const token = testHelper.createBearerToken("secret", { custom_value: "Jada Pinkett Smith" }); await testHelper.initNeo4jGraphQL({ typeDefs, @@ -316,9 +342,9 @@ describe("cypher directive filtering - relationship auth filter", () => { }); await testHelper.executeCypher( ` - CREATE (m:${Movie} { title: "The Matrix" }) - CREATE (m2:${Movie} { title: "The Matrix Reloaded" }) - CREATE (m3:${Movie} { title: "The Matrix Revolutions" }) + CREATE (m:${Movie} { title: "The Matrix", rating: 10.0 }) + CREATE (m2:${Movie} { title: "The Matrix Reloaded", rating: 8.0 }) + CREATE (m3:${Movie} { title: "The Matrix Revolutions", rating: 6.0 }) CREATE (a:${Actor} { name: "Keanu Reeves" }) CREATE (a)-[:ACTED_IN]->(m) CREATE (a)-[:ACTED_IN]->(m2) @@ -336,12 +362,16 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}( + ${Movie.operations.connection}( where: { - title: "The Matrix" + rating_GT: 7.0 } ) { - title + edges { + node { + title + } + } } } `; diff --git a/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth-connection.test.ts b/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth-connection.test.ts deleted file mode 100644 index f33caf28f5..0000000000 --- a/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth-connection.test.ts +++ /dev/null @@ -1,384 +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 { Neo4jGraphQL } from "../../../../../../src"; -import { createBearerToken } from "../../../../../utils/create-bearer-token"; -import { formatCypher, formatParams, translateQuery } from "../../../../utils/tck-test-utils"; - -describe("Connection API - cypher directive filtering - relationship auth filter", () => { - test("relationship with auth filter on type PASS", async () => { - const typeDefs = /* GraphQL */ ` - type Movie @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [Actor!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - """ - columnName: "actor" - ) - } - - type Actor @node { - name: String - movies: [Movie!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:Movie) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = createBearerToken("secret", { custom_value: "Keanu Reeves" }); - - const neoSchema: Neo4jGraphQL = new Neo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - - const query = /* GraphQL */ ` - query { - moviesConnection(where: { title: "The Matrix" }) { - edges { - node { - title - } - } - } - } - `; - - const result = await translateQuery(neoSchema, query, { token }); - - expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this0:Movie) - CALL { - WITH this0 - CALL { - WITH this0 - WITH this0 AS this - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - } - WITH actor AS this1 - RETURN collect(this1) AS this2 - } - WITH * - WHERE (this0.title = $param0 AND ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value)))) - WITH collect({ node: this0 }) AS edges - WITH edges, size(edges) AS totalCount - CALL { - WITH edges - UNWIND edges AS edge - WITH edge.node AS this0 - RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 - } - RETURN { edges: var4, totalCount: totalCount } AS this" - `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"param0\\": \\"The Matrix\\", - \\"isAuthenticated\\": true, - \\"jwt\\": { - \\"roles\\": [], - \\"custom_value\\": \\"Keanu Reeves\\" - } - }" - `); - }); - - test("relationship with auth filter on type FAIL", async () => { - const typeDefs = /* GraphQL */ ` - type Movie @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [Actor!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - """ - columnName: "actor" - ) - } - - type Actor @node { - name: String - movies: [Movie!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:Movie) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = createBearerToken("secret", { custom_value: "Something Incorrect" }); - - const neoSchema: Neo4jGraphQL = new Neo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - - const query = /* GraphQL */ ` - query { - moviesConnection(where: { title: "The Matrix" }) { - edges { - node { - title - } - } - } - } - `; - - const result = await translateQuery(neoSchema, query, { token }); - - expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this0:Movie) - CALL { - WITH this0 - CALL { - WITH this0 - WITH this0 AS this - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - } - WITH actor AS this1 - RETURN collect(this1) AS this2 - } - WITH * - WHERE (this0.title = $param0 AND ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value)))) - WITH collect({ node: this0 }) AS edges - WITH edges, size(edges) AS totalCount - CALL { - WITH edges - UNWIND edges AS edge - WITH edge.node AS this0 - RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 - } - RETURN { edges: var4, totalCount: totalCount } AS this" - `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"param0\\": \\"The Matrix\\", - \\"isAuthenticated\\": true, - \\"jwt\\": { - \\"roles\\": [], - \\"custom_value\\": \\"Something Incorrect\\" - } - }" - `); - }); - - test("relationship with auth validate on type PASS", async () => { - const typeDefs = /* GraphQL */ ` - type Movie - @node - @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [Actor!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - """ - columnName: "actor" - ) - } - - type Actor @node { - name: String - movies: [Movie!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:Movie) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = createBearerToken("secret", { custom_value: "Keanu Reeves" }); - - const neoSchema: Neo4jGraphQL = new Neo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - - const query = /* GraphQL */ ` - query { - moviesConnection(where: { title: "The Matrix" }) { - edges { - node { - title - } - } - } - } - `; - - const result = await translateQuery(neoSchema, query, { token }); - - expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this0:Movie) - CALL { - WITH this0 - CALL { - WITH this0 - WITH this0 AS this - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - } - WITH actor AS this1 - RETURN collect(this1) AS this2 - } - WITH * - WHERE (this0.title = $param0 AND apoc.util.validatePredicate(NOT ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) - WITH collect({ node: this0 }) AS edges - WITH edges, size(edges) AS totalCount - CALL { - WITH edges - UNWIND edges AS edge - WITH edge.node AS this0 - RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 - } - RETURN { edges: var4, totalCount: totalCount } AS this" - `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"param0\\": \\"The Matrix\\", - \\"isAuthenticated\\": true, - \\"jwt\\": { - \\"roles\\": [], - \\"custom_value\\": \\"Keanu Reeves\\" - } - }" - `); - }); - - test("relationship with auth validate on type FAIL", async () => { - const typeDefs = /* GraphQL */ ` - type Movie - @node - @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { - title: String - actors: [Actor!]! - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - """ - columnName: "actor" - ) - } - - type Actor @node { - name: String - movies: [Movie!]! - @cypher( - statement: """ - MATCH (this)-[:ACTED_IN]->(movie:Movie) - RETURN movie - """ - columnName: "movie" - ) - } - `; - - const token = createBearerToken("secret", { custom_value: "Something Incorrect" }); - - const neoSchema: Neo4jGraphQL = new Neo4jGraphQL({ - typeDefs, - features: { - authorization: { - key: "secret", - }, - }, - }); - - const query = /* GraphQL */ ` - query { - moviesConnection(where: { title: "The Matrix" }) { - edges { - node { - title - } - } - } - } - `; - - const result = await translateQuery(neoSchema, query, { token }); - - expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this0:Movie) - CALL { - WITH this0 - CALL { - WITH this0 - WITH this0 AS this - MATCH (this)<-[:ACTED_IN]-(actor:Actor) - RETURN actor - } - WITH actor AS this1 - RETURN collect(this1) AS this2 - } - WITH * - WHERE (this0.title = $param0 AND apoc.util.validatePredicate(NOT ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) - WITH collect({ node: this0 }) AS edges - WITH edges, size(edges) AS totalCount - CALL { - WITH edges - UNWIND edges AS edge - WITH edge.node AS this0 - RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 - } - RETURN { edges: var4, totalCount: totalCount } AS this" - `); - expect(formatParams(result.params)).toMatchInlineSnapshot(` - "{ - \\"param0\\": \\"The Matrix\\", - \\"isAuthenticated\\": true, - \\"jwt\\": { - \\"roles\\": [], - \\"custom_value\\": \\"Something Incorrect\\" - } - }" - `); - }); -}); diff --git a/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.test.ts b/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.test.ts index 1975987913..13b383419b 100644 --- a/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.test.ts +++ b/packages/graphql/tests/tck/directives/cypher/filtering/relationships/cypher-filtering-relationship-auth.test.ts @@ -21,11 +21,12 @@ import { Neo4jGraphQL } from "../../../../../../src"; import { createBearerToken } from "../../../../../utils/create-bearer-token"; import { formatCypher, formatParams, translateQuery } from "../../../../utils/tck-test-utils"; -describe("cypher directive filtering - relationship auth filter", () => { +describe("Connection API - cypher directive filtering - relationship auth filter", () => { test("relationship with auth filter on type PASS", async () => { const typeDefs = /* GraphQL */ ` type Movie @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [Actor!]! @cypher( statement: """ @@ -62,8 +63,12 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - movies(where: { title: "The Matrix" }) { - title + moviesConnection(where: { rating_LT: 7.0 }) { + edges { + node { + title + } + } } } `; @@ -71,25 +76,33 @@ describe("cypher directive filtering - relationship auth filter", () => { const result = await translateQuery(neoSchema, query, { token }); expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this:Movie) + "MATCH (this0:Movie) CALL { - WITH this + WITH this0 CALL { - WITH this - WITH this AS this + WITH this0 + WITH this0 AS this MATCH (this)<-[:ACTED_IN]-(actor:Actor) RETURN actor } - WITH actor AS this0 - RETURN collect(this0) AS this1 + WITH actor AS this1 + RETURN collect(this1) AS this2 } WITH * - WHERE (this.title = $param0 AND ($isAuthenticated = true AND any(this2 IN this1 WHERE ($jwt.custom_value IS NOT NULL AND this2.name = $jwt.custom_value)))) - RETURN this { .title } AS this" + WHERE (this0.rating < $param0 AND ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value)))) + WITH collect({ node: this0 }) AS edges + WITH edges, size(edges) AS totalCount + CALL { + WITH edges + UNWIND edges AS edge + WITH edge.node AS this0 + RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 + } + RETURN { edges: var4, totalCount: totalCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": \\"The Matrix\\", + \\"param0\\": 7, \\"isAuthenticated\\": true, \\"jwt\\": { \\"roles\\": [], @@ -103,6 +116,7 @@ describe("cypher directive filtering - relationship auth filter", () => { const typeDefs = /* GraphQL */ ` type Movie @node @authorization(filter: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [Actor!]! @cypher( statement: """ @@ -139,8 +153,12 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - movies(where: { title: "The Matrix" }) { - title + moviesConnection(where: { rating_LT: 7.0 }) { + edges { + node { + title + } + } } } `; @@ -148,25 +166,33 @@ describe("cypher directive filtering - relationship auth filter", () => { const result = await translateQuery(neoSchema, query, { token }); expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this:Movie) + "MATCH (this0:Movie) CALL { - WITH this + WITH this0 CALL { - WITH this - WITH this AS this + WITH this0 + WITH this0 AS this MATCH (this)<-[:ACTED_IN]-(actor:Actor) RETURN actor } - WITH actor AS this0 - RETURN collect(this0) AS this1 + WITH actor AS this1 + RETURN collect(this1) AS this2 } WITH * - WHERE (this.title = $param0 AND ($isAuthenticated = true AND any(this2 IN this1 WHERE ($jwt.custom_value IS NOT NULL AND this2.name = $jwt.custom_value)))) - RETURN this { .title } AS this" + WHERE (this0.rating < $param0 AND ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value)))) + WITH collect({ node: this0 }) AS edges + WITH edges, size(edges) AS totalCount + CALL { + WITH edges + UNWIND edges AS edge + WITH edge.node AS this0 + RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 + } + RETURN { edges: var4, totalCount: totalCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": \\"The Matrix\\", + \\"param0\\": 7, \\"isAuthenticated\\": true, \\"jwt\\": { \\"roles\\": [], @@ -182,6 +208,7 @@ describe("cypher directive filtering - relationship auth filter", () => { @node @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [Actor!]! @cypher( statement: """ @@ -218,8 +245,12 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - movies(where: { title: "The Matrix" }) { - title + moviesConnection(where: { rating_LT: 7.0 }) { + edges { + node { + title + } + } } } `; @@ -227,25 +258,33 @@ describe("cypher directive filtering - relationship auth filter", () => { const result = await translateQuery(neoSchema, query, { token }); expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this:Movie) + "MATCH (this0:Movie) CALL { - WITH this + WITH this0 CALL { - WITH this - WITH this AS this + WITH this0 + WITH this0 AS this MATCH (this)<-[:ACTED_IN]-(actor:Actor) RETURN actor } - WITH actor AS this0 - RETURN collect(this0) AS this1 + WITH actor AS this1 + RETURN collect(this1) AS this2 } WITH * - WHERE (this.title = $param0 AND apoc.util.validatePredicate(NOT ($isAuthenticated = true AND any(this2 IN this1 WHERE ($jwt.custom_value IS NOT NULL AND this2.name = $jwt.custom_value))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) - RETURN this { .title } AS this" + WHERE (this0.rating < $param0 AND apoc.util.validatePredicate(NOT ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) + WITH collect({ node: this0 }) AS edges + WITH edges, size(edges) AS totalCount + CALL { + WITH edges + UNWIND edges AS edge + WITH edge.node AS this0 + RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 + } + RETURN { edges: var4, totalCount: totalCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": \\"The Matrix\\", + \\"param0\\": 7, \\"isAuthenticated\\": true, \\"jwt\\": { \\"roles\\": [], @@ -261,6 +300,7 @@ describe("cypher directive filtering - relationship auth filter", () => { @node @authorization(validate: [{ where: { node: { actors: { name: "$jwt.custom_value" } } } }]) { title: String + rating: Float actors: [Actor!]! @cypher( statement: """ @@ -297,8 +337,12 @@ describe("cypher directive filtering - relationship auth filter", () => { const query = /* GraphQL */ ` query { - movies(where: { title: "The Matrix" }) { - title + moviesConnection(where: { rating_GT: 7.0 }) { + edges { + node { + title + } + } } } `; @@ -306,25 +350,33 @@ describe("cypher directive filtering - relationship auth filter", () => { const result = await translateQuery(neoSchema, query, { token }); expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` - "MATCH (this:Movie) + "MATCH (this0:Movie) CALL { - WITH this + WITH this0 CALL { - WITH this - WITH this AS this + WITH this0 + WITH this0 AS this MATCH (this)<-[:ACTED_IN]-(actor:Actor) RETURN actor } - WITH actor AS this0 - RETURN collect(this0) AS this1 + WITH actor AS this1 + RETURN collect(this1) AS this2 } WITH * - WHERE (this.title = $param0 AND apoc.util.validatePredicate(NOT ($isAuthenticated = true AND any(this2 IN this1 WHERE ($jwt.custom_value IS NOT NULL AND this2.name = $jwt.custom_value))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) - RETURN this { .title } AS this" + WHERE (this0.rating > $param0 AND apoc.util.validatePredicate(NOT ($isAuthenticated = true AND any(this3 IN this2 WHERE ($jwt.custom_value IS NOT NULL AND this3.name = $jwt.custom_value))), \\"@neo4j/graphql/FORBIDDEN\\", [0])) + WITH collect({ node: this0 }) AS edges + WITH edges, size(edges) AS totalCount + CALL { + WITH edges + UNWIND edges AS edge + WITH edge.node AS this0 + RETURN collect({ node: { title: this0.title, __resolveType: \\"Movie\\" } }) AS var4 + } + RETURN { edges: var4, totalCount: totalCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": \\"The Matrix\\", + \\"param0\\": 7, \\"isAuthenticated\\": true, \\"jwt\\": { \\"roles\\": [],