diff --git a/.changeset/flat-cows-impress.md b/.changeset/flat-cows-impress.md new file mode 100644 index 0000000000..f18c2ca5c1 --- /dev/null +++ b/.changeset/flat-cows-impress.md @@ -0,0 +1,5 @@ +--- +"@neo4j/graphql": patch +--- + +Fixed #2713 - missing checks for connection not NONE when filtering by connection_ALL diff --git a/.changeset/hip-coats-taste.md b/.changeset/hip-coats-taste.md new file mode 100644 index 0000000000..c0d725bf2b --- /dev/null +++ b/.changeset/hip-coats-taste.md @@ -0,0 +1,5 @@ +--- +"@neo4j/graphql": patch +--- + +Fixed #2708 - invalid cypher when using an aggregation filter within a relationship filter diff --git a/.changeset/new-games-buy.md b/.changeset/new-games-buy.md new file mode 100644 index 0000000000..a99a2a4b23 --- /dev/null +++ b/.changeset/new-games-buy.md @@ -0,0 +1,5 @@ +--- +"@neo4j/graphql": patch +--- + +Fixes #2670 - invalid cypher when using an aggregation filter within a connection filter diff --git a/.github/workflows/reusable-toolbox-tests.yml b/.github/workflows/reusable-toolbox-tests.yml index 4650589548..3662c44c5f 100644 --- a/.github/workflows/reusable-toolbox-tests.yml +++ b/.github/workflows/reusable-toolbox-tests.yml @@ -20,17 +20,6 @@ jobs: steps: - name: Check out repository code uses: actions/checkout@v3 - - name: Update system (Ubuntu) - run: | - # use apt-spy2 to select closest apt mirror, - # which helps avoid connectivity issues in Azure; - # see https://github.com/actions/virtual-environments/issues/675 - sudo gem install apt-spy2 - sudo apt-spy2 check - sudo apt-spy2 fix --commit - # need to run apt-get update after running apt-spy2 fix - sudo apt-get -o Acquire::Retries=3 update - # end of apt-spy2 workaround - uses: actions/setup-node@v3 with: node-version: lts/* diff --git a/packages/graphql/src/schema/resolvers/query/read.ts b/packages/graphql/src/schema/resolvers/query/read.ts index 76d8aee4f9..0167316be2 100644 --- a/packages/graphql/src/schema/resolvers/query/read.ts +++ b/packages/graphql/src/schema/resolvers/query/read.ts @@ -26,7 +26,6 @@ import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; import { fulltextArgDeprecationMessage } from "../../../schema/augment/fulltext"; export function findResolver({ node }: { node: Node }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { const context = _context as Context; context.resolveTree = getNeo4jResolveTree(info, { args }); @@ -41,7 +40,7 @@ export function findResolver({ node }: { node: Node }) { return executeResult.records.map((x) => x.this); } - + return { type: `[${node.name}!]!`, resolve, diff --git a/packages/graphql/src/translate/create-aggregate-where-and-params.ts b/packages/graphql/src/translate/create-aggregate-where-and-params.ts index c24b96d796..92257d2225 100644 --- a/packages/graphql/src/translate/create-aggregate-where-and-params.ts +++ b/packages/graphql/src/translate/create-aggregate-where-and-params.ts @@ -19,8 +19,8 @@ import Cypher from "@neo4j/cypher-builder"; import type { Node, Relationship } from "../classes"; -import type { RelationField, Context, GraphQLWhereArg } from "../types"; -import { aggregationFieldRegEx, AggregationFieldRegexGroups, whereRegEx } from "./where/utils"; +import type { RelationField, Context, GraphQLWhereArg, PredicateReturn } from "../types"; +import { aggregationFieldRegEx, AggregationFieldRegexGroups, ListPredicate, whereRegEx } from "./where/utils"; import { createBaseOperation } from "./where/property-operations/create-comparison-operation"; import { NODE_OR_EDGE_KEYS, LOGICAL_OPERATORS, AGGREGATION_AGGREGATE_COUNT_OPERATORS } from "../constants"; import mapToDbProperty from "../utils/map-to-db-property"; @@ -42,6 +42,7 @@ export type AggregateWhereInput = { type AggregateWhereReturn = { returnProjections: ("*" | Cypher.ProjectionColumn)[]; predicates: Cypher.Predicate[]; + returnVariables: Cypher.Variable[]; }; export function aggregatePreComputedWhereFields( @@ -49,11 +50,9 @@ export function aggregatePreComputedWhereFields( relationField: RelationField, relationship: Relationship | undefined, context: Context, - matchNode: Cypher.Variable -): { - predicate: Cypher.Predicate | undefined; - preComputedSubquery: Cypher.Call; -} { + matchNode: Cypher.Variable, + listPredicateStr?: ListPredicate +): PredicateReturn { const refNode = context.nodes.find((x) => x.name === relationField.typeMeta.name) as Node; const direction = relationField.direction; const aggregationTarget = new Cypher.Node({ labels: refNode.getLabels(context) }); @@ -62,22 +61,40 @@ export function aggregatePreComputedWhereFields( target: aggregationTarget, type: relationField.type, }); + let matchPattern = cypherRelation.pattern({ source: { labels: false } }); if (direction === "IN") { cypherRelation.reverse(); + matchPattern = cypherRelation.pattern({ target: { labels: false } }); } - const matchQuery = new Cypher.Match(cypherRelation); - const { returnProjections, predicates } = aggregateWhere( + const matchQuery = new Cypher.Match(matchPattern); + const { returnProjections, predicates, returnVariables } = aggregateWhere( value as AggregateWhereInput, refNode, relationship, aggregationTarget, - cypherRelation + cypherRelation, + listPredicateStr ); matchQuery.return(...returnProjections); const subquery = new Cypher.Call(matchQuery).innerWith(matchNode); + + // The return values are needed when performing SOME/NONE/ALL/SINGLE operations as they need to be aggregated to perform comparisons + if (listPredicateStr) { + return { + predicate: Cypher.and(...predicates), + // Cypher.concat is used because this is passed to createWherePredicate which expects a Cypher.CompositeClause + preComputedSubqueries: Cypher.concat(subquery), + requiredVariables: [], + aggregatingVariables: returnVariables, + }; + } + return { predicate: Cypher.and(...predicates), - preComputedSubquery: subquery, + // Cypher.concat is used because this is passed to createWherePredicate which expects a Cypher.CompositeClause + preComputedSubqueries: Cypher.concat(subquery), + requiredVariables: returnVariables, + aggregatingVariables: [], }; } @@ -86,40 +103,53 @@ export function aggregateWhere( refNode: Node, relationship: Relationship | undefined, aggregationTarget: Cypher.Node, - cypherRelation: Cypher.Relationship + cypherRelation: Cypher.Relationship, + listPredicateStr?: ListPredicate ): AggregateWhereReturn { const returnProjections: ("*" | Cypher.ProjectionColumn)[] = []; const predicates: Cypher.Predicate[] = []; + const returnVariables: Cypher.Variable[] = []; Object.entries(aggregateWhereInput).forEach(([key, value]) => { if (AGGREGATION_AGGREGATE_COUNT_OPERATORS.includes(key)) { - const { returnProjection: innerReturnProjection, predicate: innerPredicate } = - createCountPredicateAndProjection(aggregationTarget, key, value); + const { + returnProjection: innerReturnProjection, + predicate: innerPredicate, + returnVariable: innerReturnVariable, + } = createCountPredicateAndProjection(aggregationTarget, key, value, listPredicateStr); returnProjections.push(innerReturnProjection); - predicates.push(innerPredicate); + if (innerPredicate) predicates.push(innerPredicate); + returnVariables.push(innerReturnVariable); } else if (NODE_OR_EDGE_KEYS.includes(key)) { const target = key === "edge" ? cypherRelation : aggregationTarget; const refNodeOrRelation = key === "edge" ? relationship : refNode; if (!refNodeOrRelation) throw new Error(`Edge filter ${key} on undefined relationship`); - const { returnProjections: innerReturnProjections, predicates: innerPredicates } = aggregateEntityWhere( - value, - refNodeOrRelation, - target - ); + const { + returnProjections: innerReturnProjections, + predicates: innerPredicates, + returnVariables: innerReturnVariables, + } = aggregateEntityWhere(value, refNodeOrRelation, target, listPredicateStr); returnProjections.push(...innerReturnProjections); predicates.push(...innerPredicates); + returnVariables.push(...innerReturnVariables); } else if (LOGICAL_OPERATORS.includes(key)) { const logicalOperator = key === "AND" ? Cypher.and : Cypher.or; const logicalPredicates: Cypher.Predicate[] = []; value.forEach((whereInput) => { - const { returnProjections: innerReturnProjections, predicates: innerPredicates } = aggregateWhere( + const { + returnProjections: innerReturnProjections, + predicates: innerPredicates, + returnVariables: innerReturnVariables, + } = aggregateWhere( whereInput, refNode, relationship, aggregationTarget, - cypherRelation + cypherRelation, + listPredicateStr ); returnProjections.push(...innerReturnProjections); logicalPredicates.push(...innerPredicates); + returnVariables.push(...innerReturnVariables); }); predicates.push(logicalOperator(...logicalPredicates)); } @@ -127,16 +157,19 @@ export function aggregateWhere( return { returnProjections, predicates, + returnVariables, }; } function createCountPredicateAndProjection( aggregationTarget: Cypher.Node, filterKey: string, - filterValue: number + filterValue: number, + listPredicateStr?: ListPredicate ): { returnProjection: "*" | Cypher.ProjectionColumn; - predicate: Cypher.Predicate; + predicate: Cypher.Predicate | undefined; + returnVariable: Cypher.Variable; } { const paramName = new Cypher.Param(filterValue); const count = Cypher.count(aggregationTarget); @@ -147,43 +180,50 @@ function createCountPredicateAndProjection( param: paramName, }); const operationVar = new Cypher.Variable(); + return { returnProjection: [operation, operationVar], - predicate: Cypher.eq(operationVar, new Cypher.Literal(true)), + predicate: getReturnValuePredicate(operationVar, listPredicateStr), + returnVariable: operationVar, }; } function aggregateEntityWhere( aggregateEntityWhereInput: WhereFilter, refNodeOrRelation: Node | Relationship, - target: Cypher.Node | Cypher.Relationship + target: Cypher.Node | Cypher.Relationship, + listPredicateStr?: ListPredicate ): AggregateWhereReturn { const returnProjections: ("*" | Cypher.ProjectionColumn)[] = []; const predicates: Cypher.Predicate[] = []; + const returnVariables: Cypher.Variable[] = []; Object.entries(aggregateEntityWhereInput).forEach(([key, value]) => { if (LOGICAL_OPERATORS.includes(key)) { const logicalOperator = key === "AND" ? Cypher.and : Cypher.or; const logicalPredicates: Cypher.Predicate[] = []; value.forEach((whereInput) => { - const { returnProjections: innerReturnProjections, predicates: innerPredicates } = aggregateEntityWhere( - whereInput, - refNodeOrRelation, - target - ); + const { + returnProjections: innerReturnProjections, + predicates: innerPredicates, + returnVariables: innerReturnVariables, + } = aggregateEntityWhere(whereInput, refNodeOrRelation, target, listPredicateStr); returnProjections.push(...innerReturnProjections); logicalPredicates.push(...innerPredicates); + returnVariables.push(...innerReturnVariables); }); predicates.push(logicalOperator(...logicalPredicates)); } else { const operation = createEntityOperation(refNodeOrRelation, target, key, value); const operationVar = new Cypher.Variable(); returnProjections.push([operation, operationVar]); - predicates.push(Cypher.eq(operationVar, new Cypher.Literal(true))); + predicates.push(getReturnValuePredicate(operationVar, listPredicateStr)); + returnVariables.push(operationVar); } }); return { returnProjections, predicates, + returnVariables, }; } @@ -247,3 +287,24 @@ function getAggregateOperation( throw new Error(`Invalid operator ${aggregationOperator}`); } } + +function getReturnValuePredicate(operationVar: Cypher.Variable, listPredicateStr?: ListPredicate) { + switch (listPredicateStr) { + case "all": { + const listVar = new Cypher.Variable(); + return Cypher.all(listVar, operationVar, Cypher.eq(listVar, new Cypher.Literal(true))); + } + case "single": { + const listVar = new Cypher.Variable(); + return Cypher.single(listVar, operationVar, Cypher.eq(listVar, new Cypher.Literal(true))); + } + case "not": + case "none": + case "any": { + return Cypher.in(new Cypher.Literal(true), operationVar); + } + default: { + return Cypher.eq(operationVar, new Cypher.Literal(true)); + } + } +} diff --git a/packages/graphql/src/translate/create-connect-and-params.test.ts b/packages/graphql/src/translate/create-connect-and-params.test.ts index b7835818f5..f221fa0141 100644 --- a/packages/graphql/src/translate/create-connect-and-params.test.ts +++ b/packages/graphql/src/translate/create-connect-and-params.test.ts @@ -126,21 +126,6 @@ describe("createConnectAndParams", () => { } RETURN count(*) AS _ } - WITH this, this0_node, this0_node_similarMovies0_node - CALL { - WITH this0_node - MATCH (this0_node)-[this0_node_similarMovies_Movie_unique:SIMILAR]->(other:Movie) - WITH count(this0_node_similarMovies_Movie_unique) as c, other - CALL apoc.util.validate(NOT (c = 1), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.similarMovies required exactly once for a specific Movie', [0]) - RETURN collect(c) AS this0_node_similarMovies_Movie_unique_ignored - } - CALL { - WITH this0_node_similarMovies0_node - MATCH (this0_node_similarMovies0_node)-[this0_node_similarMovies0_node_similarMovies_Movie_unique:SIMILAR]->(other:Movie) - WITH count(this0_node_similarMovies0_node_similarMovies_Movie_unique) as c, other - CALL apoc.util.validate(NOT (c = 1), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.similarMovies required exactly once for a specific Movie', [0]) - RETURN collect(c) AS this0_node_similarMovies0_node_similarMovies_Movie_unique_ignored - } WITH this, this0_node, this0_node_similarMovies0_node RETURN count(*) AS connect_this0_node_similarMovies_Movie } diff --git a/packages/graphql/src/translate/create-connect-and-params.ts b/packages/graphql/src/translate/create-connect-and-params.ts index 4297baf695..cc737ed6f2 100644 --- a/packages/graphql/src/translate/create-connect-and-params.ts +++ b/packages/graphql/src/translate/create-connect-and-params.ts @@ -320,7 +320,7 @@ function createConnectAndParams({ node: mi[0], context, varName: mi[1], - relationshipFieldNotOverwritable: relationField.fieldName, + ...(isOverwriteNotAllowed && { relationshipFieldNotOverwritable: relationField.fieldName }), }); if (relValidationStr) { relValidationStrs.push(relValidationStr); diff --git a/packages/graphql/src/translate/where/create-where-and-params.ts b/packages/graphql/src/translate/where/create-where-and-params.ts index c1ee7d6179..9ae07555b0 100644 --- a/packages/graphql/src/translate/where/create-where-and-params.ts +++ b/packages/graphql/src/translate/where/create-where-and-params.ts @@ -53,7 +53,6 @@ export default function createWhereAndParams({ const whereCypher = new Cypher.RawCypher((env: Cypher.Environment) => { preComputedWhereFieldsResult = preComputedSubqueries?.getCypher(env) || ""; const cypher = wherePredicate?.getCypher(env) || ""; - return [cypher, {}]; }); diff --git a/packages/graphql/src/translate/where/create-where-predicate.ts b/packages/graphql/src/translate/where/create-where-predicate.ts index cad98076a3..a5386af05f 100644 --- a/packages/graphql/src/translate/where/create-where-predicate.ts +++ b/packages/graphql/src/translate/where/create-where-predicate.ts @@ -17,12 +17,13 @@ * limitations under the License. */ -import type { GraphQLWhereArg, Context } from "../../types"; +import type { GraphQLWhereArg, Context, PredicateReturn } from "../../types"; import type { GraphElement } from "../../classes"; import Cypher from "@neo4j/cypher-builder"; // Recursive function import { createPropertyWhere } from "./property-operations/create-property-where"; +import type { ListPredicate } from "./utils"; type WhereOperators = "OR" | "AND"; @@ -36,41 +37,66 @@ export function createWherePredicate({ whereInput, context, element, + listPredicateStr, }: { targetElement: Cypher.Variable; whereInput: GraphQLWhereArg; context: Context; element: GraphElement; -}): { predicate: Cypher.Predicate | undefined; preComputedSubqueries?: Cypher.CompositeClause | undefined } { + listPredicateStr?: ListPredicate; +}): PredicateReturn { const whereFields = Object.entries(whereInput); - const predicates: Cypher.Predicate[] = []; + const requiredVariables: Cypher.Variable[] = []; + const aggregatingVariables: Cypher.Variable[] = []; let subqueries: Cypher.CompositeClause | undefined; whereFields.forEach(([key, value]) => { if (isWhereOperator(key)) { - const { predicate, preComputedSubqueries } = createNestedPredicate({ + const { + predicate, + preComputedSubqueries, + requiredVariables: innerRequiredVariables, + aggregatingVariables: innerAggregatingVariables, + } = createNestedPredicate({ key, element, targetElement, context, value, + listPredicateStr, + requiredVariables, }); if (predicate) { predicates.push(predicate); + requiredVariables.push(...innerRequiredVariables); + aggregatingVariables.push(...innerAggregatingVariables); if (preComputedSubqueries && !preComputedSubqueries.empty) subqueries = Cypher.concat(subqueries, preComputedSubqueries); } return; } - const { predicate, preComputedSubquery } = createPropertyWhere({ key, value, element, targetElement, context }); + const { + predicate, + preComputedSubqueries, + requiredVariables: innerRequiredVariables, + aggregatingVariables: innerAggregatingVariables, + } = createPropertyWhere({ key, value, element, targetElement, context, listPredicateStr, requiredVariables }); if (predicate) { predicates.push(predicate); - if (preComputedSubquery) subqueries = Cypher.concat(subqueries, preComputedSubquery); + requiredVariables.push(...innerRequiredVariables); + aggregatingVariables.push(...innerAggregatingVariables); + if (preComputedSubqueries && !preComputedSubqueries.empty) + subqueries = Cypher.concat(subqueries, preComputedSubqueries); return; } }); // Implicit AND - return { predicate: Cypher.and(...predicates), preComputedSubqueries: subqueries }; + return { + predicate: Cypher.and(...predicates), + preComputedSubqueries: subqueries, + requiredVariables, + aggregatingVariables, + }; } function createNestedPredicate({ @@ -79,30 +105,53 @@ function createNestedPredicate({ targetElement, context, value, + listPredicateStr, + requiredVariables, }: { key: WhereOperators; value: Array; element: GraphElement; targetElement: Cypher.Variable; context: Context; -}): { predicate: Cypher.Predicate | undefined; preComputedSubqueries?: Cypher.CompositeClause | undefined } { + listPredicateStr?: ListPredicate; + requiredVariables: Cypher.Variable[]; +}): PredicateReturn { const nested: Cypher.Predicate[] = []; + const aggregatingVariables: Cypher.Variable[] = []; let subqueries: Cypher.CompositeClause | undefined; value.forEach((v) => { - const { predicate, preComputedSubqueries } = createWherePredicate({ + const { + predicate, + preComputedSubqueries, + requiredVariables: innerReturnVariables, + aggregatingVariables: innerAggregatingVariables, + } = createWherePredicate({ whereInput: v, element, targetElement, context, + listPredicateStr, }); if (predicate) { nested.push(predicate); } + requiredVariables.push(...innerReturnVariables); + aggregatingVariables.push(...innerAggregatingVariables); if (preComputedSubqueries && !preComputedSubqueries.empty) subqueries = Cypher.concat(subqueries, preComputedSubqueries); }); if (key === "OR") { - return { predicate: Cypher.or(...nested), preComputedSubqueries: subqueries }; + return { + predicate: Cypher.or(...nested), + preComputedSubqueries: subqueries, + requiredVariables, + aggregatingVariables, + }; } - return { predicate: Cypher.and(...nested), preComputedSubqueries: subqueries }; + return { + predicate: Cypher.and(...nested), + preComputedSubqueries: subqueries, + requiredVariables, + aggregatingVariables, + }; } diff --git a/packages/graphql/src/translate/where/list-predicate-to-clause.ts b/packages/graphql/src/translate/where/list-predicate-to-clause.ts deleted file mode 100644 index d33b6c2805..0000000000 --- a/packages/graphql/src/translate/where/list-predicate-to-clause.ts +++ /dev/null @@ -1,46 +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 type { ListPredicate } from "./utils"; - -export function listPredicateToClause(listPredicate: ListPredicate, matchPattern: string, where: string): string { - let clause: string; - - switch (listPredicate) { - case "all": - // This one is not as expressive as we would like - // ALL == NOT ANY WHERE NOT - clause = `NOT EXISTS { ${matchPattern} WHERE NOT ${where} }`; - break; - case "any": - clause = `EXISTS { ${matchPattern} WHERE ${where} }`; - break; - case "none": - clause = `NOT EXISTS { ${matchPattern} WHERE ${where} }`; - break; - case "single": - // Sadly no expressive way to check for single match - clause = `size([${matchPattern} WHERE ${where} | 1]) = 1`; - break; - default: - throw new Error(`Unknown predicate ${listPredicate}`); - } - - return clause; -} diff --git a/packages/graphql/src/translate/where/list-predicate-to-size-function.ts b/packages/graphql/src/translate/where/list-predicate-to-size-function.ts deleted file mode 100644 index 207ef061cb..0000000000 --- a/packages/graphql/src/translate/where/list-predicate-to-size-function.ts +++ /dev/null @@ -1,45 +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 type { ListPredicate } from "./utils"; - -// TODO: Temporary function whilst filtering is performed in projections -// To be superseded by list-predicate-to-clause.ts when moved to subqueries -export function listPredicateToSizeFunction(listPredicate: ListPredicate, matchPattern: string, where: string): string { - let clause: string; - - switch (listPredicate) { - case "all": - clause = `size([${matchPattern} WHERE NOT ${where} | 1]) = 0`; - break; - case "any": - clause = `size([${matchPattern} WHERE ${where} | 1]) > 0`; - break; - case "none": - clause = `size([${matchPattern} WHERE ${where} | 1]) = 0`; - break; - case "single": - clause = `size([${matchPattern} WHERE ${where} | 1]) = 1`; - break; - default: - throw new Error(`Unknown predicate ${listPredicate}`); - } - - return clause; -} diff --git a/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts b/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts index 152d707b12..83bf99f027 100644 --- a/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts +++ b/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts @@ -17,16 +17,16 @@ * limitations under the License. */ -import type { ConnectionField, ConnectionWhereArg, Context } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; +import type { ConnectionField, ConnectionWhereArg, Context, PredicateReturn } from "../../../types"; import type { Node, Relationship } from "../../../classes"; -import { getListPredicate } from "../utils"; -import { listPredicateToSizeFunction } from "../list-predicate-to-size-function"; +import { getListPredicate, ListPredicate } from "../utils"; import type { WhereOperator } from "../types"; // Recursive function import { createWherePredicate } from "../create-where-predicate"; import { filterTruthy } from "../../../utils/utils"; +import { createRelationshipPredicate } from "./create-relationship-operation"; export function createConnectionOperation({ connectionField, @@ -34,16 +34,15 @@ export function createConnectionOperation({ context, parentNode, operator, + requiredVariables, }: { connectionField: ConnectionField; value: any; context: Context; parentNode: Cypher.Node; operator: string | undefined; -}): { - predicate: Cypher.BooleanOp | Cypher.RawCypher | undefined; - preComputedSubqueries: Cypher.CompositeClause | undefined; -} { + requiredVariables: Cypher.Variable[]; +}): PredicateReturn { let nodeEntries: Record; if (!connectionField?.relationship.union) { @@ -53,7 +52,9 @@ export function createConnectionOperation({ } let subqueries: Cypher.CompositeClause | undefined; - const operations: (Cypher.BooleanOp | Cypher.RawCypher | undefined)[] = []; + const operations: (Cypher.Predicate | undefined)[] = []; + const aggregatingVariables: Cypher.Variable[] = []; + const matchPatterns: Cypher.Pattern[] = []; Object.entries(nodeEntries).forEach((entry) => { let nodeOnValue: string | undefined = undefined; @@ -110,37 +111,64 @@ export function createConnectionOperation({ const contextRelationship = context.relationships.find( (x) => x.name === connectionField.relationshipTypeName ) as Relationship; - const { predicate: whereOperator, preComputedSubqueries } = createConnectionWherePropertyOperation({ + const innerOperation = createConnectionWherePropertyOperation({ context, whereInput: entry[1], edgeRef: relationship, targetNode: childNode, edge: contextRelationship, node: refNode, + listPredicateStr, }); + if (orOperatorMultipleNodeLabels) { + innerOperation.predicate = Cypher.and(innerOperation.predicate, orOperatorMultipleNodeLabels); + } + + subqueries = Cypher.concat(subqueries, innerOperation.preComputedSubqueries); + requiredVariables.push(...innerOperation.requiredVariables); + aggregatingVariables.push(...innerOperation.aggregatingVariables); + matchPatterns.push(matchPattern); + if (listPredicateStr === "any" && !connectionField.relationship.typeMeta.array) { listPredicateStr = "single"; } - const subquery = new Cypher.RawCypher((env: Cypher.Environment) => { - const patternStr = matchPattern.getCypher(env); - - let whereStr = ""; - if (whereOperator && orOperatorMultipleNodeLabels) { - whereStr = Cypher.and(whereOperator, orOperatorMultipleNodeLabels).getCypher(env); - } else if (whereOperator) { - whereStr = whereOperator.getCypher(env); - } - const clause = listPredicateToSizeFunction(listPredicateStr, patternStr, whereStr); - return [clause, {}]; + const predicate = createRelationshipPredicate({ + matchPattern, + listPredicateStr, + childNode, + innerOperation: innerOperation.predicate, + edgePredicate: true, }); - subqueries = Cypher.concat(subqueries, preComputedSubqueries); - operations.push(subquery); + operations.push(predicate); }); - return { predicate: Cypher.and(...operations) as Cypher.BooleanOp | undefined, preComputedSubqueries: subqueries }; + if (aggregatingVariables && aggregatingVariables.length) { + const aggregatingWithClause = new Cypher.With( + parentNode, + ...requiredVariables, + ...(aggregatingVariables.map((returnVar) => [Cypher.collect(returnVar), returnVar]) as any) + ); + + return { + predicate: Cypher.and(...operations), + preComputedSubqueries: Cypher.concat( + ...matchPatterns.map((matchPattern) => new Cypher.OptionalMatch(matchPattern)), + subqueries, + aggregatingWithClause + ), + requiredVariables: [...requiredVariables, ...aggregatingVariables], + aggregatingVariables: [], + }; + } + return { + predicate: Cypher.and(...operations), + preComputedSubqueries: subqueries, + requiredVariables: requiredVariables, + aggregatingVariables: [], + }; } export function createConnectionWherePropertyOperation({ @@ -150,6 +178,7 @@ export function createConnectionWherePropertyOperation({ targetNode, node, edge, + listPredicateStr, }: { whereInput: ConnectionWhereArg; context: Context; @@ -157,24 +186,35 @@ export function createConnectionWherePropertyOperation({ edge: Relationship; edgeRef: Cypher.Variable; targetNode: Cypher.Node; -}): { predicate: Cypher.Predicate | undefined; preComputedSubqueries: Cypher.CompositeClause | undefined } { + listPredicateStr?: ListPredicate; +}): PredicateReturn { + const requiredVariables: Cypher.Variable[] = []; + const aggregatingVariables: Cypher.Variable[] = []; const preComputedSubqueriesResult: (Cypher.CompositeClause | undefined)[] = []; const params: (Cypher.Predicate | undefined)[] = []; Object.entries(whereInput).forEach(([key, value]) => { if (key === "AND" || key === "OR") { const subOperations: (Cypher.Predicate | undefined)[] = []; (value as Array).forEach((input) => { - const { predicate, preComputedSubqueries } = createConnectionWherePropertyOperation({ + const { + predicate, + preComputedSubqueries, + requiredVariables: innerRequiredVariables, + aggregatingVariables: innerAggregatingVariables, + } = createConnectionWherePropertyOperation({ context, whereInput: input, edgeRef, targetNode, node, edge, + listPredicateStr, }); subOperations.push(predicate); if (preComputedSubqueries && !preComputedSubqueries.empty) preComputedSubqueriesResult.push(preComputedSubqueries); + requiredVariables.push(...innerRequiredVariables); + aggregatingVariables.push(...innerAggregatingVariables); }); if (key === "AND") { params.push(Cypher.and(...filterTruthy(subOperations))); @@ -188,16 +228,24 @@ export function createConnectionWherePropertyOperation({ if (key.startsWith("edge")) { const nestedProperties: Record = value; - const { predicate: result, preComputedSubqueries } = createWherePredicate({ + const { + predicate: result, + preComputedSubqueries, + requiredVariables: innerRequiredVariables, + aggregatingVariables: innerAggregatingVariables, + } = createWherePredicate({ targetElement: edgeRef, whereInput: nestedProperties, context, element: edge, + listPredicateStr, }); params.push(result); if (preComputedSubqueries && !preComputedSubqueries.empty) preComputedSubqueriesResult.push(preComputedSubqueries); + requiredVariables.push(...innerRequiredVariables); + aggregatingVariables.push(...innerAggregatingVariables); return; } @@ -215,23 +263,35 @@ export function createConnectionWherePropertyOperation({ throw new Error("_on is used as the only argument and node is not present within"); } - const { predicate: result, preComputedSubqueries } = createWherePredicate({ + const { + predicate: result, + preComputedSubqueries, + requiredVariables: innerRequiredVariables, + aggregatingVariables: innerAggregatingVariables, + } = createWherePredicate({ targetElement: targetNode, whereInput: nestedProperties, context, element: node, + listPredicateStr, }); // NOTE: _NOT is handled by the size()=0 params.push(result); if (preComputedSubqueries && !preComputedSubqueries.empty) preComputedSubqueriesResult.push(preComputedSubqueries); + requiredVariables.push(...innerRequiredVariables); + aggregatingVariables.push(...innerAggregatingVariables); return; } }); return { predicate: Cypher.and(...filterTruthy(params)), - preComputedSubqueries: Cypher.concat(...preComputedSubqueriesResult), + preComputedSubqueries: preComputedSubqueriesResult.length + ? Cypher.concat(...preComputedSubqueriesResult) + : undefined, + requiredVariables, + aggregatingVariables, }; } diff --git a/packages/graphql/src/translate/where/property-operations/create-property-where.ts b/packages/graphql/src/translate/where/property-operations/create-property-where.ts index b823c6e19b..5bcab28a29 100644 --- a/packages/graphql/src/translate/where/property-operations/create-property-where.ts +++ b/packages/graphql/src/translate/where/property-operations/create-property-where.ts @@ -17,10 +17,10 @@ * limitations under the License. */ -import type { Context } from "../../../types"; +import type { Context, PredicateReturn } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; import { GraphElement, Node } from "../../../classes"; -import { whereRegEx, WhereRegexGroups } from "../utils"; +import { ListPredicate, whereRegEx, WhereRegexGroups } from "../utils"; import mapToDbProperty from "../../../utils/map-to-db-property"; import { createGlobalNodeOperation } from "./create-global-node-operation"; // Recursive function @@ -39,16 +39,17 @@ export function createPropertyWhere({ element, targetElement, context, + listPredicateStr, + requiredVariables, }: { key: string; value: any; element: GraphElement; targetElement: Cypher.Variable; context: Context; -}): { - predicate: Cypher.Predicate | undefined; - preComputedSubquery?: Cypher.Call | undefined; -} { + listPredicateStr?: ListPredicate; + requiredVariables: Cypher.Variable[]; +}): PredicateReturn { const match = whereRegEx.exec(key); if (!match) { throw new Error(`Failed to match key in filter: ${key}`); @@ -83,6 +84,8 @@ export function createPropertyWhere({ targetElement, coalesceValue, }), + requiredVariables: [], + aggregatingVariables: [], }; } @@ -94,12 +97,21 @@ export function createPropertyWhere({ } const relationField = node.relationFields.find((x) => x.fieldName === fieldName); - const relationTypeName = node.connectionFields.find((x) => x.relationship.fieldName === fieldName)?.relationshipTypeName; - const relationship = context.relationships.find(x => x.name === relationTypeName); + const relationTypeName = node.connectionFields.find( + (x) => x.relationship.fieldName === fieldName + )?.relationshipTypeName; + const relationship = context.relationships.find((x) => x.name === relationTypeName); if (isAggregate) { if (!relationField) throw new Error("Aggregate filters must be on relationship fields"); - return aggregatePreComputedWhereFields(value, relationField, relationship, context, targetElement); + return aggregatePreComputedWhereFields( + value, + relationField, + relationship, + context, + targetElement, + listPredicateStr + ); } if (relationField) { @@ -110,6 +122,7 @@ export function createPropertyWhere({ operator, value, isNot, + requiredVariables, }); } @@ -121,6 +134,7 @@ export function createPropertyWhere({ context, parentNode: targetElement as Cypher.Node, operator, + requiredVariables, }); } @@ -128,10 +142,14 @@ export function createPropertyWhere({ if (isNot) { return { predicate: Cypher.isNotNull(propertyRef), + requiredVariables: [], + aggregatingVariables: [], }; } return { predicate: Cypher.isNull(propertyRef), + requiredVariables: [], + aggregatingVariables: [], }; } } @@ -151,7 +169,9 @@ export function createPropertyWhere({ if (isNot) { return { predicate: Cypher.not(comparisonOp), + requiredVariables: [], + aggregatingVariables: [], }; } - return { predicate: comparisonOp }; + return { predicate: comparisonOp, requiredVariables: [], aggregatingVariables: [] }; } diff --git a/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts b/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts index 2a6d2af262..4010fdcae3 100644 --- a/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts +++ b/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts @@ -17,11 +17,12 @@ * limitations under the License. */ -import type { Context, GraphQLWhereArg, RelationField } from "../../../types"; +import type { Context, GraphQLWhereArg, RelationField, PredicateReturn } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; -// Recursive function import { createWherePredicate } from "../create-where-predicate"; +import { getListPredicate } from "../utils"; +import type { WhereOperator } from "../types"; export function createRelationshipOperation({ relationField, @@ -30,6 +31,7 @@ export function createRelationshipOperation({ operator, value, isNot, + requiredVariables, }: { relationField: RelationField; context: Context; @@ -37,7 +39,8 @@ export function createRelationshipOperation({ operator: string | undefined; value: GraphQLWhereArg; isNot: boolean; -}): { predicate: Cypher.Predicate | undefined; preComputedSubqueries?: Cypher.CompositeClause | undefined } { + requiredVariables: Cypher.Variable[]; +}): PredicateReturn { const refNode = context.nodes.find((n) => n.name === relationField.typeMeta.name); if (!refNode) throw new Error("Relationship filters must reference nodes"); @@ -61,52 +64,110 @@ export function createRelationshipOperation({ const exists = new Cypher.Exists(existsSubquery); if (!isNot) { // Bit confusing, but basically checking for not null is the same as checking for relationship exists - return { predicate: Cypher.not(exists) }; + return { predicate: Cypher.not(exists), requiredVariables: [], aggregatingVariables: [] }; } - return { predicate: exists }; + return { predicate: exists, requiredVariables: [], aggregatingVariables: [] }; } - const { predicate: relationOperator, preComputedSubqueries } = createWherePredicate({ + let listPredicateStr = getListPredicate(operator as WhereOperator); + + if (listPredicateStr === "any" && !relationField.typeMeta.array) { + listPredicateStr = "single"; + } + const { + predicate: innerOperation, + preComputedSubqueries, + requiredVariables: innerRequiredVariables, + aggregatingVariables, + } = createWherePredicate({ // Nested properties here whereInput: value, targetElement: childNode, element: refNode, context, + listPredicateStr, + }); + + requiredVariables = [...requiredVariables, ...innerRequiredVariables]; + + const predicate = createRelationshipPredicate({ + childNode, + matchPattern, + listPredicateStr, + innerOperation, }); - if (!relationOperator) { - return { predicate: undefined }; + if (aggregatingVariables && aggregatingVariables.length) { + const aggregatingWithClause = new Cypher.With( + parentNode, + ...requiredVariables, + ...(aggregatingVariables.map((returnVar) => [Cypher.collect(returnVar), returnVar]) as any) + ); + + return { + predicate, + preComputedSubqueries: Cypher.concat( + new Cypher.OptionalMatch(matchPattern), + preComputedSubqueries, + aggregatingWithClause + ), + requiredVariables: [...requiredVariables, ...aggregatingVariables], + aggregatingVariables: [], + }; } - // TODO: use EXISTS in top-level where - switch (operator) { - case "ALL": { + return { + predicate, + preComputedSubqueries: preComputedSubqueries, + requiredVariables, + aggregatingVariables: [], + }; +} + +export function createRelationshipPredicate({ + matchPattern, + listPredicateStr, + childNode, + innerOperation, + edgePredicate, +}: { + matchPattern: Cypher.Pattern; + listPredicateStr: string; + childNode: Cypher.Node; + innerOperation: Cypher.Predicate | undefined; + edgePredicate?: boolean; +}): Cypher.Predicate | undefined { + if (!innerOperation) return undefined; + const matchClause = new Cypher.Match(matchPattern).where(innerOperation); + + switch (listPredicateStr) { + case "all": { // Testing "ALL" requires testing that at least one element exists and that no elements not matching the filter exists - const existsMatch = new Cypher.Match(matchPattern).where(relationOperator); - const existsMatchNot = new Cypher.Match(matchPattern).where(Cypher.not(relationOperator)); - return { - predicate: Cypher.and(new Cypher.Exists(existsMatch), Cypher.not(new Cypher.Exists(existsMatchNot))), - preComputedSubqueries, - }; + const notExistsMatchClause = new Cypher.Match(matchPattern).where(Cypher.not(innerOperation)); + return Cypher.and(new Cypher.Exists(matchClause), Cypher.not(new Cypher.Exists(notExistsMatchClause))); } - case "NOT": - case "NONE": { - const relationshipMatch = new Cypher.Match(matchPattern).where(relationOperator); - const existsPredicate = new Cypher.Exists(relationshipMatch); - return { predicate: Cypher.not(existsPredicate), preComputedSubqueries }; - } - case "SINGLE": { + case "single": { + // If there are edge properties used in the innerOperation predicate, it is not possible to use the + // more performant single() function. Therefore, we fall back to size() + if (edgePredicate) { + const sizeFunction = Cypher.size( + new Cypher.PatternComprehension(matchPattern, new Cypher.Literal(1)).where(innerOperation) + ); + return Cypher.eq(sizeFunction, new Cypher.Literal(1)); + } + const patternComprehension = new Cypher.PatternComprehension(matchPattern, childNode); - return { - predicate: Cypher.single(childNode, patternComprehension, relationOperator), - preComputedSubqueries, - }; + return Cypher.single(childNode, patternComprehension, innerOperation); } - case "SOME": + case "not": + case "none": + case "some": default: { - const relationshipMatch = new Cypher.Match(matchPattern).where(relationOperator); - const existsPredicate = new Cypher.Exists(relationshipMatch); - return { predicate: existsPredicate, preComputedSubqueries }; + const existsPredicate = new Cypher.Exists(matchClause); + if (["not", "none"].includes(listPredicateStr)) { + return Cypher.not(existsPredicate); + } + return existsPredicate; } } } diff --git a/packages/graphql/src/translate/where/utils.ts b/packages/graphql/src/translate/where/utils.ts index 437f7d8aed..3dd2b4fde7 100644 --- a/packages/graphql/src/translate/where/utils.ts +++ b/packages/graphql/src/translate/where/utils.ts @@ -62,13 +62,14 @@ export type AggregationFieldRegexGroups = { logicalOperator?: string; } -export type ListPredicate = "all" | "none" | "single" | "any"; +export type ListPredicate = "all" | "none" | "single" | "any" | "not"; export const getListPredicate = (operator?: WhereOperator): ListPredicate => { switch (operator) { case "ALL": return "all"; case "NOT": + return "not"; case "NONE": return "none"; case "SINGLE": diff --git a/packages/graphql/src/types.ts b/packages/graphql/src/types.ts index bb8c7dab88..042353b88e 100644 --- a/packages/graphql/src/types.ts +++ b/packages/graphql/src/types.ts @@ -21,6 +21,7 @@ import type { EventEmitter } from "events"; import type { InputValueDefinitionNode, DirectiveNode, TypeNode, GraphQLSchema } from "graphql"; import type { ResolveTree } from "graphql-parse-resolve-info"; import type { Driver, Integer, Session, Transaction } from "neo4j-driver"; +import type Cypher from "@neo4j/cypher-builder"; import type { Node, Relationship } from "./classes"; import type { Neo4jDatabaseInfo } from "./classes/Neo4jDatabaseInfo"; import type { RelationshipQueryDirectionOption } from "./constants"; @@ -368,7 +369,7 @@ export interface Neo4jGraphQLAuthPlugin { /** * This function tries to resolve public or secret keys. * The implementation on how to resolve the keys by the `JWKSEndpoint` or by the `Secret` is set on when the plugin is being initiated. - * @param req + * @param req */ tryToResolveKeys(req: unknown): void; } @@ -524,3 +525,10 @@ export interface Neo4jFiltersSettings { export interface Neo4jFeaturesSettings { filters?: Neo4jFiltersSettings; } + +export type PredicateReturn = { + predicate: Cypher.Predicate | undefined; + preComputedSubqueries?: Cypher.CompositeClause | undefined; + requiredVariables: Cypher.Variable[]; + aggregatingVariables: Cypher.Variable[]; +}; diff --git a/packages/graphql/tests/integration/issues/2670.int.test.ts b/packages/graphql/tests/integration/issues/2670.int.test.ts new file mode 100644 index 0000000000..f9dd5259b2 --- /dev/null +++ b/packages/graphql/tests/integration/issues/2670.int.test.ts @@ -0,0 +1,577 @@ +/* + * 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 type { Driver, Session } from "neo4j-driver"; +import { graphql } from "graphql"; +import Neo4j from "../neo4j"; +import { Neo4jGraphQL } from "../../../src/classes"; +import { generateUniqueType, UniqueType } from "../../utils/graphql-types"; +import { cleanNodes } from "../../utils/clean-nodes"; + +describe("https://github.com/neo4j/graphql/issues/2670", () => { + let driver: Driver; + let neo4j: Neo4j; + let neoSchema: Neo4jGraphQL; + let session: Session; + + let movieType: UniqueType; + let genreType: UniqueType; + let seriesType: UniqueType; + let inGenreInterface: UniqueType; + + const movieTitle1 = "A title"; + const movieTitle2 = "Exciting new film!"; + const movieTitle3 = "short"; + const movieTitle4 = "a fourth title"; + const movieTitle5 = "an unconnected movie"; + const seriesName1 = "series 1"; + const seriesName2 = "second series"; + const genreName1 = "Action"; + const genreName2 = "Horror"; + const intValue1 = 1; + const intValue2 = 101; + const intValue3 = 983; + const intValue4 = 0; + const intValue5 = 42; + const genre2AverageTitleLength = (movieTitle4.length + movieTitle2.length) / 2; + + beforeAll(async () => { + neo4j = new Neo4j(); + driver = await neo4j.getDriver(); + }); + + beforeEach(async () => { + session = await neo4j.getSession(); + + movieType = generateUniqueType("Movie"); + genreType = generateUniqueType("Genre"); + seriesType = generateUniqueType("Series"); + inGenreInterface = generateUniqueType("InGenre"); + + const typeDefs = ` + type ${movieType.name} { + title: String + genres: [${genreType.name}!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "${inGenreInterface.name}") + } + + type ${genreType.name} { + name: String + movies: [${movieType.name}!]! @relationship(type: "IN_GENRE", direction: IN, properties: "${inGenreInterface.name}") + series: [${seriesType.name}!]! @relationship(type: "IN_GENRE", direction: IN, properties: "${inGenreInterface.name}") + } + + type ${seriesType} { + name: String! + genres: [${genreType.name}!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "${inGenreInterface.name}") + } + + interface ${inGenreInterface.name} { + intValue: Int! + } + `; + + neoSchema = new Neo4jGraphQL({ + typeDefs, + driver, + }); + + await session.run(` + CREATE (m1:${movieType.name} { title: "${movieTitle1}" })-[:IN_GENRE { intValue: ${intValue1} }]->(g1:${genreType.name} { name: "${genreName1}" }) + CREATE (m2:${movieType.name} { title: "${movieTitle2}" })-[:IN_GENRE { intValue: ${intValue2} }]->(g1) + CREATE (m3:${movieType.name} { title: "${movieTitle3}" })-[:IN_GENRE { intValue: ${intValue3} }]->(g1) + CREATE (m2)-[:IN_GENRE { intValue: ${intValue4} }]->(g2:${genreType.name} { name: "${genreName2}" }) + CREATE (m4:${movieType.name} { title: "${movieTitle4}" })-[:IN_GENRE { intValue: ${intValue5} }]->(g2) + CREATE (m5:${movieType.name} { title: "${movieTitle5}" }) + CREATE (s1:${seriesType.name} { name: "${seriesName1}" })-[:IN_GENRE { intValue: ${intValue1} }]->(g2) + CREATE (s2:${seriesType.name} { name: "${seriesName2}" })-[:IN_GENRE { intValue: ${intValue2} }]->(g2) + `); + }); + + afterEach(async () => { + await cleanNodes(session, [movieType, genreType, seriesType]); + await session.close(); + }); + + afterAll(async () => { + await driver.close(); + }); + + test("should find where moviesAggregate count equal", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate count_LT", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { count_LT: 3 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate count_GT", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { count_GT: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + ]), + }); + }); + + test("should find where moviesAggregate node property SHORTEST", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { node: { title_SHORTEST_EQUAL: ${movieTitle3.length} } } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + ]), + }); + }); + + test("should find where moviesAggregate node property AVERAGE", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { node: { title_AVERAGE_EQUAL: ${genre2AverageTitleLength} } } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate edge property MAX_LT", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { edge: { intValue_MAX_LT: ${intValue3} } } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate edge property MIN_EQUAL", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { edge: { intValue_MIN_EQUAL: ${intValue1} } } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + ]), + }); + }); + + test("should find where genresConnection_SOME and nested count", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection_SOME: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where genresConnection_NONE", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection_NONE: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle3, + }, + { + title: movieTitle5, + }, + ]), + }); + }); + + test("should find where genresConnection_ALL", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection_ALL: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find where genresConnection_SINGLE", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection_SINGLE: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find where genresConnection_NOT", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection_NOT: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle3, + }, + { + title: movieTitle5, + }, + ]), + }); + }); + + test("should find genresConnection with multiple AND aggregates", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { AND: [{ node: { moviesAggregate: { count: 2 } } }, { node: { seriesAggregate: { node: { name_SHORTEST_EQUAL: ${seriesName1.length} } } } }] } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle2, + }, + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find genresConnection with multiple OR aggregates", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { OR: [{ node: { moviesAggregate: { count: 3 } } }, { node: { seriesAggregate: { node: { name_SHORTEST_EQUAL: ${seriesName1.length} } } } }] } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find genresConnection with multiple implicit AND aggregates", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { count: 2 }, seriesAggregate: { node: { name_SHORTEST_EQUAL: ${seriesName1.length} } } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle2, + }, + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find genresConnection with aggregation at the same level", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection: { node: { moviesAggregate: { count: 3 } } }, genresAggregate: { count: 1 } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle3, + }, + ]), + }); + }); +}); diff --git a/packages/graphql/tests/integration/issues/2708.int.test.ts b/packages/graphql/tests/integration/issues/2708.int.test.ts new file mode 100644 index 0000000000..e20533c377 --- /dev/null +++ b/packages/graphql/tests/integration/issues/2708.int.test.ts @@ -0,0 +1,598 @@ +/* + * 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 type { Driver, Session } from "neo4j-driver"; +import { graphql } from "graphql"; +import Neo4j from "../neo4j"; +import { Neo4jGraphQL } from "../../../src/classes"; +import { generateUniqueType, UniqueType } from "../../utils/graphql-types"; +import { cleanNodes } from "../../utils/clean-nodes"; + +describe("https://github.com/neo4j/graphql/issues/2708", () => { + let driver: Driver; + let neo4j: Neo4j; + let neoSchema: Neo4jGraphQL; + let session: Session; + + let movieType: UniqueType; + let genreType: UniqueType; + let seriesType: UniqueType; + let inGenreInterface: UniqueType; + + const movieTitle1 = "A title"; + const movieTitle2 = "Exciting new film!"; + const movieTitle3 = "short"; + const movieTitle4 = "a fourth title"; + const movieTitle5 = "an unconnected movie"; + const seriesName1 = "series 1"; + const seriesName2 = "second series"; + const genreName1 = "Action"; + const genreName2 = "Horror"; + const intValue1 = 1; + const intValue2 = 101; + const intValue3 = 983; + const intValue4 = 0; + const intValue5 = 42; + const genre2AverageTitleLength = (movieTitle4.length + movieTitle2.length) / 2; + + beforeAll(async () => { + neo4j = new Neo4j(); + driver = await neo4j.getDriver(); + }); + + beforeEach(async () => { + session = await neo4j.getSession(); + + movieType = generateUniqueType("Movie"); + genreType = generateUniqueType("Genre"); + seriesType = generateUniqueType("Series"); + inGenreInterface = generateUniqueType("InGenre"); + + const typeDefs = ` + type ${movieType.name} { + title: String + genres: [${genreType.name}!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "${inGenreInterface.name}") + } + + type ${genreType.name} { + name: String + movies: [${movieType.name}!]! @relationship(type: "IN_GENRE", direction: IN, properties: "${inGenreInterface.name}") + series: [${seriesType.name}!]! @relationship(type: "IN_GENRE", direction: IN, properties: "${inGenreInterface.name}") + } + + type ${seriesType} { + name: String! + genres: [${genreType.name}!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "${inGenreInterface.name}") + } + + interface ${inGenreInterface.name} { + intValue: Int! + } + `; + + neoSchema = new Neo4jGraphQL({ + typeDefs, + driver, + }); + + await session.run(` + CREATE (m1:${movieType.name} { title: "${movieTitle1}" })-[:IN_GENRE { intValue: ${intValue1} }]->(g1:${genreType.name} { name: "${genreName1}" }) + CREATE (m2:${movieType.name} { title: "${movieTitle2}" })-[:IN_GENRE { intValue: ${intValue2} }]->(g1) + CREATE (m3:${movieType.name} { title: "${movieTitle3}" })-[:IN_GENRE { intValue: ${intValue3} }]->(g1) + CREATE (m2)-[:IN_GENRE { intValue: ${intValue4} }]->(g2:${genreType.name} { name: "${genreName2}" }) + CREATE (m4:${movieType.name} { title: "${movieTitle4}" })-[:IN_GENRE { intValue: ${intValue5} }]->(g2) + CREATE (m5:${movieType.name} { title: "${movieTitle5}" }) + CREATE (s1:${seriesType.name} { name: "${seriesName1}" })-[:IN_GENRE { intValue: ${intValue1} }]->(g2) + CREATE (s2:${seriesType.name} { name: "${seriesName2}" })-[:IN_GENRE { intValue: ${intValue2} }]->(g2) + `); + }); + + afterEach(async () => { + await cleanNodes(session, [movieType, genreType, seriesType]); + await session.close(); + }); + + afterAll(async () => { + await driver.close(); + }); + + test("should find where moviesAggregate count equal", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate count_LT", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { count_LT: 3 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate count_GT", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { count_GT: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + ]), + }); + }); + + test("should find where moviesAggregate node property SHORTEST", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { node: { title_SHORTEST_EQUAL: ${movieTitle3.length} } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + ]), + }); + }); + + test("should find where moviesAggregate node property AVERAGE", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { node: { title_AVERAGE_EQUAL: ${genre2AverageTitleLength} } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate edge property MAX_LT", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { edge: { intValue_MAX_LT: ${intValue3} } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where moviesAggregate edge property MIN_EQUAL", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { edge: { intValue_MIN_EQUAL: ${intValue1} } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + ]), + }); + }); + + test("should find where genres_SOME", async () => { + const query = ` + { + ${movieType.plural}(where: { genres_SOME: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + { + title: movieTitle2, + }, + ]), + }); + }); + + test("should find where genres_NONE", async () => { + const query = ` + { + ${movieType.plural}(where: { genres_NONE: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle3, + }, + { + title: movieTitle5, + }, + ]), + }); + }); + + test("should find where genres_ALL", async () => { + const query = ` + { + ${movieType.plural}(where: { genres_ALL: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find where genres_SINGLE", async () => { + const query = ` + { + ${movieType.plural}(where: { genres_SINGLE: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find where genres_NOT", async () => { + const query = ` + { + ${movieType.plural}(where: { genres_NOT: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle3, + }, + { + title: movieTitle5, + }, + ]), + }); + }); + + test("should not find genres_ALL where NONE true", async () => { + const query = ` + { + ${movieType.plural}(where: { genres_ALL: { moviesAggregate: { count: 0 } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: [], + }); + }); + + test("should find genres with multiple AND aggregates", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { AND: [{ moviesAggregate: { count: 2 } }, { seriesAggregate: { node: { name_SHORTEST_EQUAL: ${seriesName1.length} } } }] } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle2, + }, + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find genres with multiple OR aggregates", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { OR: [{ moviesAggregate: { count: 3 } }, { seriesAggregate: { node: { name_SHORTEST_EQUAL: ${seriesName1.length} } } }] } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle2, + }, + { + title: movieTitle3, + }, + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find genres with multiple implicit AND aggregates", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { count: 2 }, seriesAggregate: { node: { name_SHORTEST_EQUAL: ${seriesName1.length} } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle2, + }, + { + title: movieTitle4, + }, + ]), + }); + }); + + test("should find genres with aggregation at the same level", async () => { + const query = ` + { + ${movieType.plural}(where: { genres: { moviesAggregate: { count: 3 } }, genresAggregate: { count: 1 } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: expect.toIncludeSameMembers([ + { + title: movieTitle1, + }, + { + title: movieTitle3, + }, + ]), + }); + }); +}); diff --git a/packages/graphql/tests/integration/issues/2713.int.test.ts b/packages/graphql/tests/integration/issues/2713.int.test.ts new file mode 100644 index 0000000000..814d5c68a3 --- /dev/null +++ b/packages/graphql/tests/integration/issues/2713.int.test.ts @@ -0,0 +1,119 @@ +/* + * 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 type { Driver, Session } from "neo4j-driver"; +import { graphql } from "graphql"; +import Neo4j from "../neo4j"; +import { Neo4jGraphQL } from "../../../src/classes"; +import { generateUniqueType, UniqueType } from "../../utils/graphql-types"; +import { cleanNodes } from "../../utils/clean-nodes"; + +describe("https://github.com/neo4j/graphql/issues/2713", () => { + let driver: Driver; + let neo4j: Neo4j; + let neoSchema: Neo4jGraphQL; + let session: Session; + + let movieType: UniqueType; + let genreType: UniqueType; + let inGenreInterface: UniqueType; + + const movieTitle1 = "A title"; + const movieTitle2 = "Exciting new film!"; + const movieTitle3 = "short"; + const movieTitle4 = "a fourth title"; + const genreName1 = "Action"; + const genreName2 = "Horror"; + const intValue1 = 1; + const intValue2 = 101; + const intValue3 = 983; + const intValue4 = 0; + const intValue5 = 42; + + beforeAll(async () => { + neo4j = new Neo4j(); + driver = await neo4j.getDriver(); + }); + + beforeEach(async () => { + session = await neo4j.getSession(); + + movieType = generateUniqueType("Movie"); + genreType = generateUniqueType("Genre"); + inGenreInterface = generateUniqueType("InGenre"); + + const typeDefs = ` + type ${movieType.name} { + title: String + genres: [${genreType.name}!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "${inGenreInterface.name}") + } + type ${genreType.name} { + name: String + movies: [${movieType.name}!]! @relationship(type: "IN_GENRE", direction: IN, properties: "${inGenreInterface.name}") + } + + interface ${inGenreInterface.name} { + intValue: Int! + } + `; + + neoSchema = new Neo4jGraphQL({ + typeDefs, + driver, + }); + + await session.run(` + CREATE (m1:${movieType.name} { title: "${movieTitle1}" })-[:IN_GENRE { intValue: ${intValue1} }]->(g1:${genreType.name} { name: "${genreName1}" }) + CREATE (m2:${movieType.name} { title: "${movieTitle2}" })-[:IN_GENRE { intValue: ${intValue2} }]->(g1) + CREATE (m3:${movieType.name} { title: "${movieTitle3}" })-[:IN_GENRE { intValue: ${intValue3} }]->(g1) + CREATE (m2)-[:IN_GENRE { intValue: ${intValue4} }]->(g2:${genreType.name} { name: "${genreName2}" }) + CREATE (m4 :${movieType.name} { title: "${movieTitle4}" })-[:IN_GENRE { intValue: ${intValue5} }]->(g2) + `); + }); + + afterEach(async () => { + await cleanNodes(session, [movieType, genreType]); + await session.close(); + }); + + afterAll(async () => { + await driver.close(); + }); + + test("should not find genresConnection_ALL where NONE true", async () => { + const query = ` + { + ${movieType.plural}(where: { genresConnection_ALL: { node: { moviesAggregate: { count: 0 } } } }) { + title + } + } + `; + + const result = await graphql({ + schema: await neoSchema.getSchema(), + source: query, + contextValue: neo4j.getContextValues(), + }); + + expect(result.errors).toBeFalsy(); + expect(result.data).toEqual({ + [movieType.plural]: [], + }); + }); +}); diff --git a/packages/graphql/tests/tck/advanced-filtering.test.ts b/packages/graphql/tests/tck/advanced-filtering.test.ts index 5f6e017938..1f5b57aa1a 100644 --- a/packages/graphql/tests/tck/advanced-filtering.test.ts +++ b/packages/graphql/tests/tck/advanced-filtering.test.ts @@ -863,7 +863,10 @@ describe("Cypher Advanced Filtering", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Movie\`) - WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE this1.name = $param0 | 1]) > 0 + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE this1.name = $param0 + } RETURN this { .actorCount } AS this" `); @@ -890,7 +893,10 @@ describe("Cypher Advanced Filtering", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Movie\`) - WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE this1.name = $param0 | 1]) = 0 + WHERE NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE this1.name = $param0 + }) RETURN this { .actorCount } AS this" `); @@ -920,7 +926,13 @@ describe("Cypher Advanced Filtering", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Movie\`) - WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE NOT this1.name = $param0 | 1]) = 0 + WHERE (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE this1.name = $param0 + } AND NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE NOT (this1.name = $param0) + })) RETURN this { .actorCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` @@ -937,7 +949,10 @@ describe("Cypher Advanced Filtering", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Movie\`) - WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE this1.name = $param0 | 1]) = 0 + WHERE NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE this1.name = $param0 + }) RETURN this { .actorCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` @@ -954,7 +969,7 @@ describe("Cypher Advanced Filtering", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Movie\`) - WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE this1.name = $param0 | 1]) = 1 + WHERE size([(this)-[this1:IN_GENRE]->(this0:\`Genre\`) WHERE this0.name = $param0 | 1]) = 1 RETURN this { .actorCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` @@ -971,7 +986,10 @@ describe("Cypher Advanced Filtering", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Movie\`) - WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE this1.name = $param0 | 1]) > 0 + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE this1.name = $param0 + } RETURN this { .actorCount } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` diff --git a/packages/graphql/tests/tck/aggregations/where/count.test.ts b/packages/graphql/tests/tck/aggregations/where/count.test.ts index d6e067f806..256f67f905 100644 --- a/packages/graphql/tests/tck/aggregations/where/count.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/count.test.ts @@ -63,7 +63,7 @@ describe("Cypher Aggregations where with count", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) = $param0 AS var2 } WITH * @@ -99,7 +99,7 @@ describe("Cypher Aggregations where with count", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) < $param0 AS var2 } WITH * @@ -135,7 +135,7 @@ describe("Cypher Aggregations where with count", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) <= $param0 AS var2 } WITH * @@ -171,7 +171,7 @@ describe("Cypher Aggregations where with count", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) > $param0 AS var2 } WITH * @@ -207,7 +207,7 @@ describe("Cypher Aggregations where with count", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) >= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/bigint.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/bigint.test.ts index fac39c5c1d..4742852ac5 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/bigint.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/bigint.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someBigInt) WHERE var2 = $param0) AS var3 } WITH * @@ -104,7 +104,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someBigIntAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -140,7 +140,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someBigInt) WHERE var2 > $param0) AS var3 } WITH * @@ -176,7 +176,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someBigInt) WHERE var2 >= $param0) AS var3 } WITH * @@ -212,7 +212,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someBigInt) WHERE var2 < $param0) AS var3 } WITH * @@ -248,7 +248,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someBigInt) WHERE var2 <= $param0) AS var3 } WITH * @@ -284,7 +284,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someBigInt) = $param0 AS var2 } WITH * @@ -320,7 +320,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someBigInt) > $param0 AS var2 } WITH * @@ -356,7 +356,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someBigInt) >= $param0 AS var2 } WITH * @@ -392,7 +392,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someBigInt) < $param0 AS var2 } WITH * @@ -428,7 +428,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someBigInt) <= $param0 AS var2 } WITH * @@ -464,7 +464,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someBigInt) = $param0 AS var2 } WITH * @@ -500,7 +500,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someBigInt) > $param0 AS var2 } WITH * @@ -536,7 +536,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someBigInt) >= $param0 AS var2 } WITH * @@ -572,7 +572,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someBigInt) < $param0 AS var2 } WITH * @@ -608,7 +608,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someBigInt) <= $param0 AS var2 } WITH * @@ -644,7 +644,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someBigInt) = $param0 AS var2 } WITH * @@ -680,7 +680,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someBigInt) > $param0 AS var2 } WITH * @@ -716,7 +716,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someBigInt) >= $param0 AS var2 } WITH * @@ -752,7 +752,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someBigInt) < $param0 AS var2 } WITH * @@ -788,7 +788,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someBigInt) <= $param0 AS var2 } WITH * @@ -824,7 +824,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someBigInt) = $param0 AS var2 } WITH * @@ -860,7 +860,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someBigInt) > $param0 AS var2 } WITH * @@ -896,7 +896,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someBigInt) >= $param0 AS var2 } WITH * @@ -932,7 +932,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someBigInt) < $param0 AS var2 } WITH * @@ -968,7 +968,7 @@ describe("Cypher Aggregations where edge with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someBigInt) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/datetime.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/datetime.test.ts index 7654317fd1..53d80900d5 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/datetime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/datetime.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDateTime) WHERE var2 = $param0) AS var3 } WITH * @@ -110,7 +110,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someDateTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -152,7 +152,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDateTime) WHERE var2 > $param0) AS var3 } WITH * @@ -194,7 +194,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDateTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -236,7 +236,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDateTime) WHERE var2 < $param0) AS var3 } WITH * @@ -278,7 +278,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDateTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -320,7 +320,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDateTime) = $param0 AS var2 } WITH * @@ -362,7 +362,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDateTime) > $param0 AS var2 } WITH * @@ -404,7 +404,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDateTime) >= $param0 AS var2 } WITH * @@ -446,7 +446,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDateTime) < $param0 AS var2 } WITH * @@ -488,7 +488,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDateTime) <= $param0 AS var2 } WITH * @@ -530,7 +530,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDateTime) = $param0 AS var2 } WITH * @@ -572,7 +572,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDateTime) > $param0 AS var2 } WITH * @@ -614,7 +614,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDateTime) >= $param0 AS var2 } WITH * @@ -656,7 +656,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDateTime) < $param0 AS var2 } WITH * @@ -698,7 +698,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDateTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/duration.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/duration.test.ts index 17277801d5..cb6e1d1786 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/duration.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/duration.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDuration) WHERE var2 = $param0) AS var3 } WITH * @@ -112,7 +112,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someDurationAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -156,7 +156,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDuration) WHERE var2 > $param0) AS var3 } WITH * @@ -200,7 +200,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDuration) WHERE var2 >= $param0) AS var3 } WITH * @@ -244,7 +244,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDuration) WHERE var2 < $param0) AS var3 } WITH * @@ -288,7 +288,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someDuration) WHERE var2 <= $param0) AS var3 } WITH * @@ -332,7 +332,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someDuration) = $param0 AS var2 } WITH * @@ -376,7 +376,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someDuration) > $param0 AS var2 } WITH * @@ -420,7 +420,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someDuration) >= $param0 AS var2 } WITH * @@ -464,7 +464,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someDuration) < $param0 AS var2 } WITH * @@ -508,7 +508,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someDuration) <= $param0 AS var2 } WITH * @@ -552,7 +552,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDuration) = $param0 AS var2 } WITH * @@ -596,7 +596,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDuration) > $param0 AS var2 } WITH * @@ -640,7 +640,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDuration) >= $param0 AS var2 } WITH * @@ -684,7 +684,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDuration) < $param0 AS var2 } WITH * @@ -728,7 +728,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someDuration) <= $param0 AS var2 } WITH * @@ -772,7 +772,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDuration) = $param0 AS var2 } WITH * @@ -816,7 +816,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDuration) > $param0 AS var2 } WITH * @@ -860,7 +860,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDuration) >= $param0 AS var2 } WITH * @@ -904,7 +904,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDuration) < $param0 AS var2 } WITH * @@ -948,7 +948,7 @@ describe("Cypher Aggregations where edge with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someDuration) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/float.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/float.test.ts index 9b6d3f1f84..59184d0c23 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/float.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/float.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 = $param0) AS var3 } WITH * @@ -101,7 +101,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someFloatAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -134,7 +134,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 > $param0) AS var3 } WITH * @@ -167,7 +167,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 >= $param0) AS var3 } WITH * @@ -200,7 +200,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 < $param0) AS var3 } WITH * @@ -233,7 +233,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 <= $param0) AS var3 } WITH * @@ -266,7 +266,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someFloat) = $param0 AS var2 } WITH * @@ -299,7 +299,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someFloat) > $param0 AS var2 } WITH * @@ -332,7 +332,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someFloat) >= $param0 AS var2 } WITH * @@ -365,7 +365,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someFloat) < $param0 AS var2 } WITH * @@ -398,7 +398,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someFloat) <= $param0 AS var2 } WITH * @@ -431,7 +431,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someFloat) = $param0 AS var2 } WITH * @@ -464,7 +464,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someFloat) > $param0 AS var2 } WITH * @@ -497,7 +497,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someFloat) >= $param0 AS var2 } WITH * @@ -530,7 +530,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someFloat) < $param0 AS var2 } WITH * @@ -563,7 +563,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someFloat) <= $param0 AS var2 } WITH * @@ -596,7 +596,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someFloat) = $param0 AS var2 } WITH * @@ -629,7 +629,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someFloat) > $param0 AS var2 } WITH * @@ -662,7 +662,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someFloat) >= $param0 AS var2 } WITH * @@ -695,7 +695,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someFloat) < $param0 AS var2 } WITH * @@ -728,7 +728,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someFloat) <= $param0 AS var2 } WITH * @@ -761,7 +761,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someFloat) = $param0 AS var2 } WITH * @@ -794,7 +794,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someFloat) > $param0 AS var2 } WITH * @@ -827,7 +827,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someFloat) >= $param0 AS var2 } WITH * @@ -860,7 +860,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someFloat) < $param0 AS var2 } WITH * @@ -893,7 +893,7 @@ describe("Cypher Aggregations where edge with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someFloat) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/id.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/id.test.ts index b0d15321f1..08f8e9fa07 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/id.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/id.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with ID", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.id) WHERE var2 = $param0) AS var3 } WITH * @@ -101,7 +101,7 @@ describe("Cypher Aggregations where edge with ID", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someIdAlias) WHERE var2 = $param0) AS var3 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/int.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/int.test.ts index 7695939331..98dc10bab7 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/int.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/int.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someInt) WHERE var2 = $param0) AS var3 } WITH * @@ -104,7 +104,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someIntAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -140,7 +140,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someInt) WHERE var2 > $param0) AS var3 } WITH * @@ -176,7 +176,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someInt) WHERE var2 >= $param0) AS var3 } WITH * @@ -212,7 +212,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someInt) WHERE var2 < $param0) AS var3 } WITH * @@ -248,7 +248,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someInt) WHERE var2 <= $param0) AS var3 } WITH * @@ -284,7 +284,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someInt) = $param0 AS var2 } WITH * @@ -317,7 +317,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someInt) > $param0 AS var2 } WITH * @@ -350,7 +350,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someInt) >= $param0 AS var2 } WITH * @@ -383,7 +383,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someInt) < $param0 AS var2 } WITH * @@ -416,7 +416,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this0.someInt) <= $param0 AS var2 } WITH * @@ -449,7 +449,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someInt) = $param0 AS var2 } WITH * @@ -485,7 +485,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someInt) > $param0 AS var2 } WITH * @@ -521,7 +521,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someInt) >= $param0 AS var2 } WITH * @@ -557,7 +557,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someInt) < $param0 AS var2 } WITH * @@ -593,7 +593,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this0.someInt) <= $param0 AS var2 } WITH * @@ -629,7 +629,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someInt) = $param0 AS var2 } WITH * @@ -665,7 +665,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someInt) > $param0 AS var2 } WITH * @@ -701,7 +701,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someInt) >= $param0 AS var2 } WITH * @@ -737,7 +737,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someInt) < $param0 AS var2 } WITH * @@ -773,7 +773,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someInt) <= $param0 AS var2 } WITH * @@ -809,7 +809,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someInt) = $param0 AS var2 } WITH * @@ -845,7 +845,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someInt) > $param0 AS var2 } WITH * @@ -881,7 +881,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someInt) >= $param0 AS var2 } WITH * @@ -917,7 +917,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someInt) < $param0 AS var2 } WITH * @@ -953,7 +953,7 @@ describe("Cypher Aggregations where edge with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someInt) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/localdatetime.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/localdatetime.test.ts index 422f8a7907..a65980e5ce 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/localdatetime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/localdatetime.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalDateTime) WHERE var2 = $param0) AS var3 } WITH * @@ -109,7 +109,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someLocalDateTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -150,7 +150,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalDateTime) WHERE var2 > $param0) AS var3 } WITH * @@ -191,7 +191,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalDateTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -232,7 +232,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalDateTime) WHERE var2 < $param0) AS var3 } WITH * @@ -273,7 +273,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalDateTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -314,7 +314,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalDateTime) = $param0 AS var2 } WITH * @@ -355,7 +355,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalDateTime) > $param0 AS var2 } WITH * @@ -396,7 +396,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalDateTime) >= $param0 AS var2 } WITH * @@ -437,7 +437,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalDateTime) < $param0 AS var2 } WITH * @@ -478,7 +478,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalDateTime) <= $param0 AS var2 } WITH * @@ -519,7 +519,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalDateTime) = $param0 AS var2 } WITH * @@ -560,7 +560,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalDateTime) > $param0 AS var2 } WITH * @@ -601,7 +601,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalDateTime) >= $param0 AS var2 } WITH * @@ -642,7 +642,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalDateTime) < $param0 AS var2 } WITH * @@ -683,7 +683,7 @@ describe("Cypher Aggregations where edge with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalDateTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/localtime.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/localtime.test.ts index d8123390c0..9ca4c8c729 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/localtime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/localtime.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalTime) WHERE var2 = $param0) AS var3 } WITH * @@ -106,7 +106,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someLocalTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -144,7 +144,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalTime) WHERE var2 > $param0) AS var3 } WITH * @@ -182,7 +182,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -220,7 +220,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalTime) WHERE var2 < $param0) AS var3 } WITH * @@ -258,7 +258,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someLocalTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -296,7 +296,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalTime) = $param0 AS var2 } WITH * @@ -334,7 +334,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalTime) > $param0 AS var2 } WITH * @@ -372,7 +372,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalTime) >= $param0 AS var2 } WITH * @@ -410,7 +410,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalTime) < $param0 AS var2 } WITH * @@ -448,7 +448,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someLocalTime) <= $param0 AS var2 } WITH * @@ -486,7 +486,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalTime) = $param0 AS var2 } WITH * @@ -524,7 +524,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalTime) > $param0 AS var2 } WITH * @@ -562,7 +562,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalTime) >= $param0 AS var2 } WITH * @@ -600,7 +600,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalTime) < $param0 AS var2 } WITH * @@ -638,7 +638,7 @@ describe("Cypher Aggregations where edge with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someLocalTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/logical.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/logical.test.ts index 7871022d11..da02351107 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/logical.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/logical.test.ts @@ -69,7 +69,7 @@ describe("Cypher Aggregations where edge with Logical AND + OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 = $param0) AS var3, any(var4 IN collect(this0.someFloat) WHERE var4 = $param1) AS var5 } WITH * @@ -103,7 +103,7 @@ describe("Cypher Aggregations where edge with Logical AND + OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someFloat) WHERE var2 = $param0) AS var3, any(var4 IN collect(this0.someFloat) WHERE var4 = $param1) AS var5 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/string.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/string.test.ts index a437534625..e6afa92aa3 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/string.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/string.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someString) WHERE var2 = $param0) AS var3 } WITH * @@ -101,7 +101,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someStringAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -134,7 +134,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this0.someString)) WHERE var2 > $param0) AS var3 } WITH * @@ -170,7 +170,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this0.someString)) WHERE var2 >= $param0) AS var3 } WITH * @@ -206,7 +206,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this0.someString)) WHERE var2 < $param0) AS var3 } WITH * @@ -242,7 +242,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this0.someString)) WHERE var2 <= $param0) AS var3 } WITH * @@ -278,7 +278,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this0.someString)) = $param0 AS var2 } WITH * @@ -314,7 +314,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this0.someString)) > $param0 AS var2 } WITH * @@ -350,7 +350,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this0.someString)) >= $param0 AS var2 } WITH * @@ -386,7 +386,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this0.someString)) < $param0 AS var2 } WITH * @@ -422,7 +422,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this0.someString)) <= $param0 AS var2 } WITH * @@ -458,7 +458,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this0.someString)) = $param0 AS var2 } WITH * @@ -494,7 +494,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this0.someString)) > $param0 AS var2 } WITH * @@ -530,7 +530,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this0.someString)) >= $param0 AS var2 } WITH * @@ -566,7 +566,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this0.someString)) < $param0 AS var2 } WITH * @@ -602,7 +602,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this0.someString)) <= $param0 AS var2 } WITH * @@ -638,7 +638,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this0.someString)) = $param0 AS var2 } WITH * @@ -671,7 +671,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this0.someString)) > $param0 AS var2 } WITH * @@ -704,7 +704,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this0.someString)) >= $param0 AS var2 } WITH * @@ -737,7 +737,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this0.someString)) < $param0 AS var2 } WITH * @@ -770,7 +770,7 @@ describe("Cypher Aggregations where edge with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this0.someString)) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/edge/time.test.ts b/packages/graphql/tests/tck/aggregations/where/edge/time.test.ts index b3f2f6c3e4..c11e768d08 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/time.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/time.test.ts @@ -68,7 +68,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someTime) WHERE var2 = $param0) AS var3 } WITH * @@ -107,7 +107,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0._someTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -146,7 +146,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someTime) WHERE var2 > $param0) AS var3 } WITH * @@ -185,7 +185,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -224,7 +224,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someTime) WHERE var2 < $param0) AS var3 } WITH * @@ -263,7 +263,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this0.someTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -302,7 +302,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someTime) = $param0 AS var2 } WITH * @@ -341,7 +341,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someTime) > $param0 AS var2 } WITH * @@ -380,7 +380,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someTime) >= $param0 AS var2 } WITH * @@ -419,7 +419,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someTime) < $param0 AS var2 } WITH * @@ -458,7 +458,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this0.someTime) <= $param0 AS var2 } WITH * @@ -497,7 +497,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someTime) = $param0 AS var2 } WITH * @@ -536,7 +536,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someTime) > $param0 AS var2 } WITH * @@ -575,7 +575,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someTime) >= $param0 AS var2 } WITH * @@ -614,7 +614,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someTime) < $param0 AS var2 } WITH * @@ -653,7 +653,7 @@ describe("Cypher Aggregations where edge with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this0.someTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/logical.test.ts b/packages/graphql/tests/tck/aggregations/where/logical.test.ts index be3f69fc02..9026de23ef 100644 --- a/packages/graphql/tests/tck/aggregations/where/logical.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/logical.test.ts @@ -63,7 +63,7 @@ describe("Cypher Aggregations where with logical AND plus OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) > $param0 AS var2, count(this1) < $param1 AS var3 } WITH * @@ -103,7 +103,7 @@ describe("Cypher Aggregations where with logical AND plus OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) > $param0 AS var2, count(this1) < $param1 AS var3 } WITH * @@ -150,7 +150,7 @@ describe("Cypher Aggregations where with logical AND plus OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN count(this1) > $param0 AS var2, count(this1) < $param1 AS var3, count(this1) > $param2 AS var4, count(this1) < $param3 AS var5 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node.test.ts b/packages/graphql/tests/tck/aggregations/where/node.test.ts index ca6849bbb4..fce3285c6f 100644 --- a/packages/graphql/tests/tck/aggregations/where/node.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node.test.ts @@ -63,7 +63,7 @@ describe("Cypher Where Aggregations with @node directive", () => { "MATCH (this:\`_Post\`:\`additionalPost\`) CALL { WITH this - MATCH (this1:\`_User\`:\`additionalUser\`)-[this0:LIKES]->(this:\`_Post\`:\`additionalPost\`) + MATCH (this1:\`_User\`:\`additionalUser\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this1.someName)) WHERE var2 > $param0) AS var3 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/bigint.test.ts b/packages/graphql/tests/tck/aggregations/where/node/bigint.test.ts index a877a98534..937480663c 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/bigint.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/bigint.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someBigInt) WHERE var2 = $param0) AS var3 } WITH * @@ -100,7 +100,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someBigIntAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -136,7 +136,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someBigInt) WHERE var2 > $param0) AS var3 } WITH * @@ -172,7 +172,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someBigInt) WHERE var2 >= $param0) AS var3 } WITH * @@ -208,7 +208,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someBigInt) WHERE var2 < $param0) AS var3 } WITH * @@ -244,7 +244,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someBigInt) WHERE var2 <= $param0) AS var3 } WITH * @@ -280,7 +280,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someBigInt) = $param0 AS var2 } WITH * @@ -316,7 +316,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someBigInt) > $param0 AS var2 } WITH * @@ -352,7 +352,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someBigInt) >= $param0 AS var2 } WITH * @@ -388,7 +388,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someBigInt) < $param0 AS var2 } WITH * @@ -424,7 +424,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someBigInt) <= $param0 AS var2 } WITH * @@ -460,7 +460,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someBigInt) = $param0 AS var2 } WITH * @@ -496,7 +496,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someBigInt) > $param0 AS var2 } WITH * @@ -532,7 +532,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someBigInt) >= $param0 AS var2 } WITH * @@ -568,7 +568,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someBigInt) < $param0 AS var2 } WITH * @@ -604,7 +604,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someBigInt) <= $param0 AS var2 } WITH * @@ -640,7 +640,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someBigInt) = $param0 AS var2 } WITH * @@ -676,7 +676,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someBigInt) > $param0 AS var2 } WITH * @@ -712,7 +712,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someBigInt) >= $param0 AS var2 } WITH * @@ -748,7 +748,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someBigInt) < $param0 AS var2 } WITH * @@ -784,7 +784,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someBigInt) <= $param0 AS var2 } WITH * @@ -820,7 +820,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someBigInt) = $param0 AS var2 } WITH * @@ -856,7 +856,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someBigInt) > $param0 AS var2 } WITH * @@ -892,7 +892,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someBigInt) >= $param0 AS var2 } WITH * @@ -928,7 +928,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someBigInt) < $param0 AS var2 } WITH * @@ -964,7 +964,7 @@ describe("Cypher Aggregations where node with BigInt", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someBigInt) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/datetime.test.ts b/packages/graphql/tests/tck/aggregations/where/node/datetime.test.ts index 16b2ba6f23..fa29fe46d5 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/datetime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/datetime.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDateTime) WHERE var2 = $param0) AS var3 } WITH * @@ -106,7 +106,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someDateTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -148,7 +148,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDateTime) WHERE var2 > $param0) AS var3 } WITH * @@ -190,7 +190,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDateTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -232,7 +232,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDateTime) WHERE var2 < $param0) AS var3 } WITH * @@ -274,7 +274,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDateTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -316,7 +316,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDateTime) = $param0 AS var2 } WITH * @@ -358,7 +358,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDateTime) > $param0 AS var2 } WITH * @@ -400,7 +400,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDateTime) >= $param0 AS var2 } WITH * @@ -442,7 +442,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDateTime) < $param0 AS var2 } WITH * @@ -484,7 +484,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDateTime) <= $param0 AS var2 } WITH * @@ -526,7 +526,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDateTime) = $param0 AS var2 } WITH * @@ -568,7 +568,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDateTime) > $param0 AS var2 } WITH * @@ -610,7 +610,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDateTime) >= $param0 AS var2 } WITH * @@ -652,7 +652,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDateTime) < $param0 AS var2 } WITH * @@ -694,7 +694,7 @@ describe("Cypher Aggregations where node with DateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDateTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/duration.test.ts b/packages/graphql/tests/tck/aggregations/where/node/duration.test.ts index 4a725a4d37..daa8553f46 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/duration.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/duration.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDuration) WHERE var2 = $param0) AS var3 } WITH * @@ -108,7 +108,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someDurationAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -152,7 +152,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDuration) WHERE var2 > $param0) AS var3 } WITH * @@ -196,7 +196,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDuration) WHERE var2 >= $param0) AS var3 } WITH * @@ -240,7 +240,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDuration) WHERE var2 < $param0) AS var3 } WITH * @@ -284,7 +284,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someDuration) WHERE var2 <= $param0) AS var3 } WITH * @@ -328,7 +328,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someDuration) = $param0 AS var2 } WITH * @@ -372,7 +372,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someDuration) > $param0 AS var2 } WITH * @@ -416,7 +416,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someDuration) >= $param0 AS var2 } WITH * @@ -460,7 +460,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someDuration) < $param0 AS var2 } WITH * @@ -504,7 +504,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someDuration) <= $param0 AS var2 } WITH * @@ -548,7 +548,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDuration) = $param0 AS var2 } WITH * @@ -592,7 +592,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDuration) > $param0 AS var2 } WITH * @@ -636,7 +636,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDuration) >= $param0 AS var2 } WITH * @@ -680,7 +680,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDuration) < $param0 AS var2 } WITH * @@ -724,7 +724,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someDuration) <= $param0 AS var2 } WITH * @@ -768,7 +768,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDuration) = $param0 AS var2 } WITH * @@ -812,7 +812,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDuration) > $param0 AS var2 } WITH * @@ -856,7 +856,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDuration) >= $param0 AS var2 } WITH * @@ -900,7 +900,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDuration) < $param0 AS var2 } WITH * @@ -944,7 +944,7 @@ describe("Cypher Aggregations where node with Duration", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someDuration) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/float.test.ts b/packages/graphql/tests/tck/aggregations/where/node/float.test.ts index 339aafa503..431eb1a6a1 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/float.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/float.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 = $param0) AS var3 } WITH * @@ -97,7 +97,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someFloatAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -130,7 +130,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 > $param0) AS var3 } WITH * @@ -163,7 +163,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 >= $param0) AS var3 } WITH * @@ -196,7 +196,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 < $param0) AS var3 } WITH * @@ -229,7 +229,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 <= $param0) AS var3 } WITH * @@ -262,7 +262,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someFloat) = $param0 AS var2 } WITH * @@ -295,7 +295,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someFloat) > $param0 AS var2 } WITH * @@ -328,7 +328,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someFloat) >= $param0 AS var2 } WITH * @@ -361,7 +361,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someFloat) < $param0 AS var2 } WITH * @@ -394,7 +394,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someFloat) <= $param0 AS var2 } WITH * @@ -427,7 +427,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someFloat) = $param0 AS var2 } WITH * @@ -460,7 +460,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someFloat) > $param0 AS var2 } WITH * @@ -493,7 +493,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someFloat) >= $param0 AS var2 } WITH * @@ -526,7 +526,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someFloat) < $param0 AS var2 } WITH * @@ -559,7 +559,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someFloat) <= $param0 AS var2 } WITH * @@ -592,7 +592,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someFloat) = $param0 AS var2 } WITH * @@ -625,7 +625,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someFloat) > $param0 AS var2 } WITH * @@ -658,7 +658,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someFloat) >= $param0 AS var2 } WITH * @@ -691,7 +691,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someFloat) < $param0 AS var2 } WITH * @@ -724,7 +724,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someFloat) <= $param0 AS var2 } WITH * @@ -757,7 +757,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someFloat) = $param0 AS var2 } WITH * @@ -790,7 +790,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someFloat) > $param0 AS var2 } WITH * @@ -823,7 +823,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someFloat) >= $param0 AS var2 } WITH * @@ -856,7 +856,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someFloat) < $param0 AS var2 } WITH * @@ -889,7 +889,7 @@ describe("Cypher Aggregations where node with Float", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someFloat) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/id.test.ts b/packages/graphql/tests/tck/aggregations/where/node/id.test.ts index e7138043ac..a45b714cd3 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/id.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/id.test.ts @@ -65,7 +65,7 @@ describe("Cypher Aggregations where node with ID", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.id) WHERE var2 = $param0) AS var3 } WITH * @@ -98,7 +98,7 @@ describe("Cypher Aggregations where node with ID", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someIdAlias) WHERE var2 = $param0) AS var3 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/int.test.ts b/packages/graphql/tests/tck/aggregations/where/node/int.test.ts index 1d55c9743e..d513f6e663 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/int.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/int.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someInt) WHERE var2 = $param0) AS var3 } WITH * @@ -100,7 +100,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someIntAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -136,7 +136,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someInt) WHERE var2 > $param0) AS var3 } WITH * @@ -172,7 +172,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someInt) WHERE var2 >= $param0) AS var3 } WITH * @@ -208,7 +208,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someInt) WHERE var2 < $param0) AS var3 } WITH * @@ -244,7 +244,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someInt) WHERE var2 <= $param0) AS var3 } WITH * @@ -280,7 +280,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someInt) = $param0 AS var2 } WITH * @@ -313,7 +313,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someInt) > $param0 AS var2 } WITH * @@ -346,7 +346,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someInt) >= $param0 AS var2 } WITH * @@ -379,7 +379,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someInt) < $param0 AS var2 } WITH * @@ -412,7 +412,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(this1.someInt) <= $param0 AS var2 } WITH * @@ -445,7 +445,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someInt) = $param0 AS var2 } WITH * @@ -481,7 +481,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someInt) > $param0 AS var2 } WITH * @@ -517,7 +517,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someInt) >= $param0 AS var2 } WITH * @@ -553,7 +553,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someInt) < $param0 AS var2 } WITH * @@ -589,7 +589,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN sum(this1.someInt) <= $param0 AS var2 } WITH * @@ -625,7 +625,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someInt) = $param0 AS var2 } WITH * @@ -661,7 +661,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someInt) > $param0 AS var2 } WITH * @@ -697,7 +697,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someInt) >= $param0 AS var2 } WITH * @@ -733,7 +733,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someInt) < $param0 AS var2 } WITH * @@ -769,7 +769,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someInt) <= $param0 AS var2 } WITH * @@ -805,7 +805,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someInt) = $param0 AS var2 } WITH * @@ -841,7 +841,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someInt) > $param0 AS var2 } WITH * @@ -877,7 +877,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someInt) >= $param0 AS var2 } WITH * @@ -913,7 +913,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someInt) < $param0 AS var2 } WITH * @@ -949,7 +949,7 @@ describe("Cypher Aggregations where node with Int", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someInt) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/localdatetime.test.ts b/packages/graphql/tests/tck/aggregations/where/node/localdatetime.test.ts index 3d66592742..55b541ef2b 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/localdatetime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/localdatetime.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalDateTime) WHERE var2 = $param0) AS var3 } WITH * @@ -105,7 +105,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someLocalDateTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -146,7 +146,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalDateTime) WHERE var2 > $param0) AS var3 } WITH * @@ -187,7 +187,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalDateTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -228,7 +228,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalDateTime) WHERE var2 < $param0) AS var3 } WITH * @@ -269,7 +269,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalDateTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -310,7 +310,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalDateTime) = $param0 AS var2 } WITH * @@ -351,7 +351,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalDateTime) > $param0 AS var2 } WITH * @@ -392,7 +392,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalDateTime) >= $param0 AS var2 } WITH * @@ -433,7 +433,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalDateTime) < $param0 AS var2 } WITH * @@ -474,7 +474,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalDateTime) <= $param0 AS var2 } WITH * @@ -515,7 +515,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalDateTime) = $param0 AS var2 } WITH * @@ -556,7 +556,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalDateTime) > $param0 AS var2 } WITH * @@ -597,7 +597,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalDateTime) >= $param0 AS var2 } WITH * @@ -638,7 +638,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalDateTime) < $param0 AS var2 } WITH * @@ -679,7 +679,7 @@ describe("Cypher Aggregations where node with LocalDateTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalDateTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/localtime.test.ts b/packages/graphql/tests/tck/aggregations/where/node/localtime.test.ts index 3a48a9b1c5..9dcf49acf4 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/localtime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/localtime.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalTime) WHERE var2 = $param0) AS var3 } WITH * @@ -102,7 +102,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someLocalTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -140,7 +140,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalTime) WHERE var2 > $param0) AS var3 } WITH * @@ -178,7 +178,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -216,7 +216,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalTime) WHERE var2 < $param0) AS var3 } WITH * @@ -254,7 +254,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someLocalTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -292,7 +292,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalTime) = $param0 AS var2 } WITH * @@ -330,7 +330,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalTime) > $param0 AS var2 } WITH * @@ -368,7 +368,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalTime) >= $param0 AS var2 } WITH * @@ -406,7 +406,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalTime) < $param0 AS var2 } WITH * @@ -444,7 +444,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someLocalTime) <= $param0 AS var2 } WITH * @@ -482,7 +482,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalTime) = $param0 AS var2 } WITH * @@ -520,7 +520,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalTime) > $param0 AS var2 } WITH * @@ -558,7 +558,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalTime) >= $param0 AS var2 } WITH * @@ -596,7 +596,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalTime) < $param0 AS var2 } WITH * @@ -634,7 +634,7 @@ describe("Cypher Aggregations where node with LocalTime", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someLocalTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/logical.test.ts b/packages/graphql/tests/tck/aggregations/where/node/logical.test.ts index 721bd0e3b5..8bac955076 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/logical.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/logical.test.ts @@ -65,7 +65,7 @@ describe("Cypher Aggregations where node with Logical AND + OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 = $param0) AS var3, any(var4 IN collect(this1.someFloat) WHERE var4 = $param1) AS var5 } WITH * @@ -99,7 +99,7 @@ describe("Cypher Aggregations where node with Logical AND + OR", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someFloat) WHERE var2 = $param0) AS var3, any(var4 IN collect(this1.someFloat) WHERE var4 = $param1) AS var5 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/string.test.ts b/packages/graphql/tests/tck/aggregations/where/node/string.test.ts index e769e85737..d03e6ae7ea 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/string.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/string.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.name) WHERE var2 = $param0) AS var3 } WITH * @@ -97,7 +97,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someStringAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -130,7 +130,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this1.name)) WHERE var2 > $param0) AS var3 } WITH * @@ -166,7 +166,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this1.name)) WHERE var2 >= $param0) AS var3 } WITH * @@ -202,7 +202,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this1.name)) WHERE var2 < $param0) AS var3 } WITH * @@ -238,7 +238,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(size(this1.name)) WHERE var2 <= $param0) AS var3 } WITH * @@ -274,7 +274,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this1.name)) = $param0 AS var2 } WITH * @@ -310,7 +310,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this1.name)) > $param0 AS var2 } WITH * @@ -346,7 +346,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this1.name)) >= $param0 AS var2 } WITH * @@ -382,7 +382,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this1.name)) < $param0 AS var2 } WITH * @@ -418,7 +418,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(size(this1.name)) <= $param0 AS var2 } WITH * @@ -454,7 +454,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this1.name)) = $param0 AS var2 } WITH * @@ -490,7 +490,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this1.name)) > $param0 AS var2 } WITH * @@ -526,7 +526,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this1.name)) >= $param0 AS var2 } WITH * @@ -562,7 +562,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this1.name)) < $param0 AS var2 } WITH * @@ -598,7 +598,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(size(this1.name)) <= $param0 AS var2 } WITH * @@ -634,7 +634,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this1.name)) = $param0 AS var2 } WITH * @@ -667,7 +667,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this1.name)) > $param0 AS var2 } WITH * @@ -700,7 +700,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this1.name)) >= $param0 AS var2 } WITH * @@ -733,7 +733,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this1.name)) < $param0 AS var2 } WITH * @@ -766,7 +766,7 @@ describe("Cypher Aggregations where node with String", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN avg(size(this1.name)) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/aggregations/where/node/time.test.ts b/packages/graphql/tests/tck/aggregations/where/node/time.test.ts index 01923428cf..17454bae61 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/time.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/time.test.ts @@ -64,7 +64,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someTime) WHERE var2 = $param0) AS var3 } WITH * @@ -103,7 +103,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1._someTimeAlias) WHERE var2 = $param0) AS var3 } WITH * @@ -142,7 +142,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someTime) WHERE var2 > $param0) AS var3 } WITH * @@ -181,7 +181,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someTime) WHERE var2 >= $param0) AS var3 } WITH * @@ -220,7 +220,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someTime) WHERE var2 < $param0) AS var3 } WITH * @@ -259,7 +259,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN any(var2 IN collect(this1.someTime) WHERE var2 <= $param0) AS var3 } WITH * @@ -298,7 +298,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someTime) = $param0 AS var2 } WITH * @@ -337,7 +337,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someTime) > $param0 AS var2 } WITH * @@ -376,7 +376,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someTime) >= $param0 AS var2 } WITH * @@ -415,7 +415,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someTime) < $param0 AS var2 } WITH * @@ -454,7 +454,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN min(this1.someTime) <= $param0 AS var2 } WITH * @@ -493,7 +493,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someTime) = $param0 AS var2 } WITH * @@ -532,7 +532,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someTime) > $param0 AS var2 } WITH * @@ -571,7 +571,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someTime) >= $param0 AS var2 } WITH * @@ -610,7 +610,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someTime) < $param0 AS var2 } WITH * @@ -649,7 +649,7 @@ describe("Cypher Aggregations where node with Time", () => { "MATCH (this:\`Post\`) CALL { WITH this - MATCH (this1:\`User\`)-[this0:LIKES]->(this:\`Post\`) + MATCH (this1:\`User\`)-[this0:LIKES]->(this) RETURN max(this1.someTime) <= $param0 AS var2 } WITH * diff --git a/packages/graphql/tests/tck/directives/interface-relationships/update/connect.test.ts b/packages/graphql/tests/tck/directives/interface-relationships/update/connect.test.ts index b069e4cc87..a6a1c133a6 100644 --- a/packages/graphql/tests/tck/directives/interface-relationships/update/connect.test.ts +++ b/packages/graphql/tests/tck/directives/interface-relationships/update/connect.test.ts @@ -206,14 +206,6 @@ describe("Interface Relationships - Update connect", () => { } RETURN count(*) AS _ } - WITH this, this_connect_actedIn0_node, this_connect_actedIn0_node_actors0_node - CALL { - WITH this_connect_actedIn0_node - MATCH (this_connect_actedIn0_node)<-[this_connect_actedIn0_node_actors_Actor_unique:ACTED_IN]-(other:Actor) - WITH count(this_connect_actedIn0_node_actors_Actor_unique) as c, other - CALL apoc.util.validate(NOT (c = 1), '@neo4j/graphql/RELATIONSHIP-REQUIREDMovie.actors required exactly once for a specific Actor', [0]) - RETURN collect(c) AS this_connect_actedIn0_node_actors_Actor_unique_ignored - } WITH this, this_connect_actedIn0_node, this_connect_actedIn0_node_actors0_node RETURN count(*) AS connect_this_connect_actedIn0_node_actors_Actor } @@ -254,14 +246,6 @@ describe("Interface Relationships - Update connect", () => { } RETURN count(*) AS _ } - WITH this, this_connect_actedIn1_node, this_connect_actedIn1_node_actors0_node - CALL { - WITH this_connect_actedIn1_node - MATCH (this_connect_actedIn1_node)<-[this_connect_actedIn1_node_actors_Actor_unique:ACTED_IN]-(other:Actor) - WITH count(this_connect_actedIn1_node_actors_Actor_unique) as c, other - CALL apoc.util.validate(NOT (c = 1), '@neo4j/graphql/RELATIONSHIP-REQUIREDSeries.actors required exactly once for a specific Actor', [0]) - RETURN collect(c) AS this_connect_actedIn1_node_actors_Actor_unique_ignored - } WITH this, this_connect_actedIn1_node, this_connect_actedIn1_node_actors0_node RETURN count(*) AS connect_this_connect_actedIn1_node_actors_Actor } @@ -527,14 +511,6 @@ describe("Interface Relationships - Update connect", () => { } RETURN count(*) AS _ } - WITH this, this_connect_actedIn1_node, this_connect_actedIn1_node_actors0_node - CALL { - WITH this_connect_actedIn1_node - MATCH (this_connect_actedIn1_node)<-[this_connect_actedIn1_node_actors_Actor_unique:ACTED_IN]-(other:Actor) - WITH count(this_connect_actedIn1_node_actors_Actor_unique) as c, other - CALL apoc.util.validate(NOT (c = 1), '@neo4j/graphql/RELATIONSHIP-REQUIREDSeries.actors required exactly once for a specific Actor', [0]) - RETURN collect(c) AS this_connect_actedIn1_node_actors_Actor_unique_ignored - } WITH this, this_connect_actedIn1_node, this_connect_actedIn1_node_actors0_node RETURN count(*) AS connect_this_connect_actedIn1_node_actors_Actor } diff --git a/packages/graphql/tests/tck/directives/node/node-with-auth.test.ts b/packages/graphql/tests/tck/directives/node/node-with-auth.test.ts index 6f3e4c7984..45f300f486 100644 --- a/packages/graphql/tests/tck/directives/node/node-with-auth.test.ts +++ b/packages/graphql/tests/tck/directives/node/node-with-auth.test.ts @@ -103,10 +103,7 @@ describe("Node Directive", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Comment\`) - WHERE EXISTS { - MATCH (this0:\`Person\`)-[:HAS_POST]->(this) - WHERE this0.id = $param0 - } + WHERE single(this0 IN [(this0:\`Person\`)-[:HAS_POST]->(this) | this0] WHERE this0.id = $param0) WITH this CALL apoc.util.validate(NOT (any(auth_var1 IN [\\"admin\\"] WHERE any(auth_var0 IN $auth.roles WHERE auth_var0 = auth_var1))), \\"@neo4j/graphql/FORBIDDEN\\", [0]) DETACH DELETE this" diff --git a/packages/graphql/tests/tck/issues/1221.test.ts b/packages/graphql/tests/tck/issues/1221.test.ts index cdabbde49f..5d106b1970 100644 --- a/packages/graphql/tests/tck/issues/1221.test.ts +++ b/packages/graphql/tests/tck/issues/1221.test.ts @@ -86,7 +86,7 @@ describe("https://github.com/neo4j/graphql/issues/1221", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Series\`) - WHERE (this.current = $param0 AND size([(this)-[this0:ARCHITECTURE]->(this1:\`MasterData\`) WHERE size([(this1)-[this2:HAS_NAME]->(this3:\`NameDetails\`) WHERE this3.fullName = $param1 | 1]) = 1 | 1]) = 1) + WHERE (this.current = $param0 AND size([(this)-[this3:ARCHITECTURE]->(this2:\`MasterData\`) WHERE size([(this2)-[this1:HAS_NAME]->(this0:\`NameDetails\`) WHERE this0.fullName = $param1 | 1]) = 1 | 1]) = 1) CALL { WITH this MATCH (this)-[this_connection_architectureConnectionthis0:ARCHITECTURE]->(this_MasterData:\`MasterData\`) @@ -194,7 +194,10 @@ describe("https://github.com/neo4j/graphql/issues/1221", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Main\`) - WHERE (this.current = $param0 AND size([(this)-[this0:MAIN]->(this1:\`Series\`) WHERE size([(this1)-[this2:ARCHITECTURE]->(this3:\`MasterData\`) WHERE size([(this3)-[this4:HAS_NAME]->(this5:\`NameDetails\`) WHERE this5.fullName = $param1 | 1]) = 1 | 1]) > 0 | 1]) = 1) + WHERE (this.current = $param0 AND size([(this)-[this5:MAIN]->(this1:\`Series\`) WHERE EXISTS { + MATCH (this1)-[this0:ARCHITECTURE]->(this2:\`MasterData\`) + WHERE size([(this2)-[this4:HAS_NAME]->(this3:\`NameDetails\`) WHERE this3.fullName = $param1 | 1]) = 1 + } | 1]) = 1) CALL { WITH this MATCH (this)-[this_connection_mainConnectionthis0:MAIN]->(this_Series:\`Series\`) diff --git a/packages/graphql/tests/tck/issues/1685.test.ts b/packages/graphql/tests/tck/issues/1685.test.ts index fce0459f2c..71b0be9c48 100644 --- a/packages/graphql/tests/tck/issues/1685.test.ts +++ b/packages/graphql/tests/tck/issues/1685.test.ts @@ -74,7 +74,10 @@ describe("https://github.com/neo4j/graphql/issues/1685", () => { CALL { WITH this MATCH (this)<-[this_connection_moviesConnectionthis0:HAS_GENRE]-(this_Movie:\`Movie\`) - WHERE size([(this_Movie)-[this_connection_moviesConnectionthis1:HAS_GENRE]->(this_connection_moviesConnectionthis2:\`Genre\`) WHERE this_connection_moviesConnectionthis2.name = $this_connection_moviesConnectionparam0 | 1]) > 0 + WHERE EXISTS { + MATCH (this_Movie)-[this_connection_moviesConnectionthis1:HAS_GENRE]->(this_connection_moviesConnectionthis2:\`Genre\`) + WHERE this_connection_moviesConnectionthis2.name = $this_connection_moviesConnectionparam0 + } WITH { node: { __resolveType: \\"Movie\\" } } AS edge RETURN edge } diff --git a/packages/graphql/tests/tck/issues/1687.test.ts b/packages/graphql/tests/tck/issues/1687.test.ts index a66a179611..62b5ca30b2 100644 --- a/packages/graphql/tests/tck/issues/1687.test.ts +++ b/packages/graphql/tests/tck/issues/1687.test.ts @@ -64,7 +64,13 @@ describe("https://github.com/neo4j/graphql/issues/1687", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Genre\`) - WHERE size([(this1:\`Movie\`)-[this0:HAS_GENRE]->(this) WHERE NOT this1.title = $param0 | 1]) = 0 + WHERE (EXISTS { + MATCH (this1:\`Movie\`)-[this0:HAS_GENRE]->(this) + WHERE this1.title = $param0 + } AND NOT (EXISTS { + MATCH (this1:\`Movie\`)-[this0:HAS_GENRE]->(this) + WHERE NOT (this1.title = $param0) + })) RETURN this { .name } AS this" `); diff --git a/packages/graphql/tests/tck/issues/1783.test.ts b/packages/graphql/tests/tck/issues/1783.test.ts index 93e9039e35..4a4a8026be 100644 --- a/packages/graphql/tests/tck/issues/1783.test.ts +++ b/packages/graphql/tests/tck/issues/1783.test.ts @@ -121,7 +121,7 @@ describe("https://github.com/neo4j/graphql/issues/1783", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Series\`) - WHERE (this.current = $param0 AND size([(this)-[this0:ARCHITECTURE]->(this1:\`MasterData\`) WHERE (this0.current = $param1 AND size([(this1)-[this2:HAS_NAME]->(this3:\`NameDetails\`) WHERE (this2.current = $param2 AND this3.fullName = $param3) | 1]) = 1) | 1]) = 1 AND size([(this)-[this4:HAS_NAME]->(this5:\`NameDetails\`) WHERE (this4.current = $param4 AND this5.fullName CONTAINS $param5) | 1]) = 1) + WHERE (this.current = $param0 AND size([(this)-[this0:ARCHITECTURE]->(this3:\`MasterData\`) WHERE (this0.current = $param1 AND size([(this3)-[this1:HAS_NAME]->(this2:\`NameDetails\`) WHERE (this1.current = $param2 AND this2.fullName = $param3) | 1]) = 1) | 1]) = 1 AND size([(this)-[this4:HAS_NAME]->(this5:\`NameDetails\`) WHERE (this4.current = $param4 AND this5.fullName CONTAINS $param5) | 1]) = 1) CALL { WITH this MATCH (this)-[this_connection_nameDetailsConnectionthis0:HAS_NAME]->(this_NameDetails:\`NameDetails\`) diff --git a/packages/graphql/tests/tck/issues/1933.test.ts b/packages/graphql/tests/tck/issues/1933.test.ts index 9bfcc8fcca..f1425ab938 100644 --- a/packages/graphql/tests/tck/issues/1933.test.ts +++ b/packages/graphql/tests/tck/issues/1933.test.ts @@ -82,7 +82,7 @@ describe("https://github.com/neo4j/graphql/issues/1933", () => { "MATCH (this:\`Employee\`) CALL { WITH this - MATCH (this:\`Employee\`)-[this0:PARTICIPATES]->(this1:\`Project\`) + MATCH (this)-[this0:PARTICIPATES]->(this1:\`Project\`) RETURN sum(this0.allocation) <= $param0 AS var2 } WITH * @@ -135,7 +135,7 @@ describe("https://github.com/neo4j/graphql/issues/1933", () => { "MATCH (this:\`Employee\`) CALL { WITH this - MATCH (this:\`Employee\`)-[this0:PARTICIPATES]->(this1:\`Project\`) + MATCH (this)-[this0:PARTICIPATES]->(this1:\`Project\`) RETURN any(var2 IN collect(this0.allocation) WHERE var2 <= $param0) AS var3 } WITH * diff --git a/packages/graphql/tests/tck/issues/2396.test.ts b/packages/graphql/tests/tck/issues/2396.test.ts index a6cbb74de8..a716ab0014 100644 --- a/packages/graphql/tests/tck/issues/2396.test.ts +++ b/packages/graphql/tests/tck/issues/2396.test.ts @@ -156,19 +156,7 @@ describe("https://github.com/neo4j/graphql/issues/2396", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Mandate\`) - WHERE ((this.price >= $param0 AND EXISTS { - MATCH (this)-[:HAS_VALUATION]->(this0:\`Valuation\`) - WHERE EXISTS { - MATCH (this0)-[:VALUATION_FOR]->(this1:\`Estate\`) - WHERE (this1.area >= $param1 AND this1.floor >= $param2 AND this1.estateType IN $param3 AND EXISTS { - MATCH (this1)-[:HAS_ADDRESS]->(this2:\`Address\`) - WHERE EXISTS { - MATCH (this2)-[:HAS_POSTAL_CODE]->(this3:\`PostalCode\`) - WHERE this3.number IN $param4 - } - }) - } - }) AND this.archivedAt IS NULL) + WHERE ((this.price >= $param0 AND single(this3 IN [(this)-[:HAS_VALUATION]->(this3:\`Valuation\`) | this3] WHERE single(this0 IN [(this3)-[:VALUATION_FOR]->(this0:\`Estate\`) | this0] WHERE (this0.area >= $param1 AND this0.floor >= $param2 AND this0.estateType IN $param3 AND single(this2 IN [(this0)-[:HAS_ADDRESS]->(this2:\`Address\`) | this2] WHERE single(this1 IN [(this2)-[:HAS_POSTAL_CODE]->(this1:\`PostalCode\`) | this1] WHERE this1.number IN $param4)))))) AND this.archivedAt IS NULL) CALL { WITH this MATCH (this)-[this4:HAS_VALUATION]->(this_valuation:\`Valuation\`) @@ -243,19 +231,7 @@ describe("https://github.com/neo4j/graphql/issues/2396", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Mandate\`) - WHERE ((this.price >= $param0 AND EXISTS { - MATCH (this)-[:HAS_VALUATION]->(this0:\`Valuation\`) - WHERE EXISTS { - MATCH (this0)-[:VALUATION_FOR]->(this1:\`Estate\`) - WHERE (this1.area >= $param1 AND this1.floor >= $param2 AND this1.estateType IN $param3 AND EXISTS { - MATCH (this1)-[:HAS_ADDRESS]->(this2:\`Address\`) - WHERE EXISTS { - MATCH (this2)-[:HAS_POSTAL_CODE]->(this3:\`PostalCode\`) - WHERE this3.number IN $param4 - } - }) - } - }) AND this.archivedAt IS NULL) + WHERE ((this.price >= $param0 AND single(this3 IN [(this)-[:HAS_VALUATION]->(this3:\`Valuation\`) | this3] WHERE single(this0 IN [(this3)-[:VALUATION_FOR]->(this0:\`Estate\`) | this0] WHERE (this0.area >= $param1 AND this0.floor >= $param2 AND this0.estateType IN $param3 AND single(this2 IN [(this0)-[:HAS_ADDRESS]->(this2:\`Address\`) | this2] WHERE single(this1 IN [(this2)-[:HAS_POSTAL_CODE]->(this1:\`PostalCode\`) | this1] WHERE this1.number IN $param4)))))) AND this.archivedAt IS NULL) WITH * SKIP $param5 LIMIT $param6 @@ -341,19 +317,7 @@ describe("https://github.com/neo4j/graphql/issues/2396", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Mandate\`) - WHERE ((this.price >= $param0 AND EXISTS { - MATCH (this)-[:HAS_VALUATION]->(this0:\`Valuation\`) - WHERE EXISTS { - MATCH (this0)-[:VALUATION_FOR]->(this1:\`Estate\`) - WHERE (this1.area >= $param1 AND this1.floor >= $param2 AND this1.estateType IN $param3 AND EXISTS { - MATCH (this1)-[:HAS_ADDRESS]->(this2:\`Address\`) - WHERE EXISTS { - MATCH (this2)-[:HAS_POSTAL_CODE]->(this3:\`PostalCode\`) - WHERE this3.number IN $param4 - } - }) - } - }) AND this.archivedAt IS NULL) + WHERE ((this.price >= $param0 AND single(this3 IN [(this)-[:HAS_VALUATION]->(this3:\`Valuation\`) | this3] WHERE single(this0 IN [(this3)-[:VALUATION_FOR]->(this0:\`Estate\`) | this0] WHERE (this0.area >= $param1 AND this0.floor >= $param2 AND this0.estateType IN $param3 AND single(this2 IN [(this0)-[:HAS_ADDRESS]->(this2:\`Address\`) | this2] WHERE single(this1 IN [(this2)-[:HAS_POSTAL_CODE]->(this1:\`PostalCode\`) | this1] WHERE this1.number IN $param4)))))) AND this.archivedAt IS NULL) WITH * SKIP $param5 LIMIT $param6 diff --git a/packages/graphql/tests/tck/issues/2670.test.ts b/packages/graphql/tests/tck/issues/2670.test.ts new file mode 100644 index 0000000000..77f292e411 --- /dev/null +++ b/packages/graphql/tests/tck/issues/2670.test.ts @@ -0,0 +1,733 @@ +/* + * 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 { Neo4jGraphQL } from "../../../src"; +import { formatCypher, translateQuery, formatParams } from "../utils/tck-test-utils"; + +describe("https://github.com/neo4j/graphql/issues/2670", () => { + let neoSchema: Neo4jGraphQL; + + const typeDefs = gql` + type Movie { + title: String + genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "InGenre") + } + + type Genre { + name: String + movies: [Movie!]! @relationship(type: "IN_GENRE", direction: IN, properties: "InGenre") + series: [Series!]! @relationship(type: "IN_GENRE", direction: IN, properties: "InGenre") + } + + type Series { + name: String! + genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "InGenre") + } + + interface InGenre { + intValue: Int! + } + `; + + beforeAll(() => { + neoSchema = new Neo4jGraphQL({ + typeDefs, + }); + }); + + test("should find where moviesAggregate count equal", async () => { + const query = gql` + { + movies(where: { genresConnection: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate count_LT", async () => { + const query = gql` + { + movies(where: { genresConnection: { node: { moviesAggregate: { count_LT: 3 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) < $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 3, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate count_GT", async () => { + const query = gql` + { + movies(where: { genresConnection: { node: { moviesAggregate: { count_GT: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) > $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate node property SHORTEST", async () => { + const query = gql` + { + movies( + where: { genresConnection: { node: { moviesAggregate: { node: { title_SHORTEST_EQUAL: 5 } } } } } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN min(size(this3.title)) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 5, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate node property AVERAGE", async () => { + const query = gql` + { + movies( + where: { genresConnection: { node: { moviesAggregate: { node: { title_AVERAGE_EQUAL: 1 } } } } } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN avg(size(this3.title)) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": 1 + }" + `); + }); + + test("should find where moviesAggregate edge property MAX_LT", async () => { + const query = gql` + { + movies(where: { genresConnection: { node: { moviesAggregate: { edge: { intValue_MAX_LT: 983 } } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN max(this2.intValue) < $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 983, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate edge property MIN_EQUAL", async () => { + const query = gql` + { + movies( + where: { genresConnection: { node: { moviesAggregate: { edge: { intValue_MIN_EQUAL: 1 } } } } } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN min(this2.intValue) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genresConnection_SOME", async () => { + const query = gql` + { + movies(where: { genresConnection_SOME: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genresConnection_NONE", async () => { + const query = gql` + { + movies(where: { genresConnection_NONE: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + }) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genresConnection_ALL", async () => { + const query = gql` + { + movies(where: { genresConnection_ALL: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE all(var5 IN var4 WHERE var5 = true) + } AND NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE NOT (all(var5 IN var4 WHERE var5 = true)) + })) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genresConnection_SINGLE", async () => { + const query = gql` + { + movies(where: { genresConnection_SINGLE: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE size([(this)-[this0:IN_GENRE]->(this1:\`Genre\`) WHERE single(var5 IN var4 WHERE var5 = true) | 1]) = 1 + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genresConnection_NOT", async () => { + const query = gql` + { + movies(where: { genresConnection_NOT: { node: { moviesAggregate: { count: 2 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE true IN var4 + }) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genresConnection with multiple AND aggregates", async () => { + const query = gql` + { + movies( + where: { + genresConnection: { + AND: [ + { node: { moviesAggregate: { count: 2 } } } + { node: { seriesAggregate: { node: { name_SHORTEST_EQUAL: 1 } } } } + ] + } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + CALL { + WITH this1 + MATCH (this6:\`Series\`)-[this5:IN_GENRE]->(this1) + RETURN min(size(this6.name)) = $param1 AS var7 + } + WITH this, collect(var4) AS var4, collect(var7) AS var7 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE (true IN var4 AND true IN var7) + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genresConnection with multiple OR aggregates", async () => { + const query = gql` + { + movies( + where: { + genresConnection: { + OR: [ + { node: { moviesAggregate: { count: 3 } } } + { node: { seriesAggregate: { node: { name_SHORTEST_EQUAL: 983 } } } } + ] + } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + CALL { + WITH this1 + MATCH (this6:\`Series\`)-[this5:IN_GENRE]->(this1) + RETURN min(size(this6.name)) = $param1 AS var7 + } + WITH this, collect(var4) AS var4, collect(var7) AS var7 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE (true IN var4 OR true IN var7) + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 3, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 983, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genresConnection with multiple implicit AND aggregates", async () => { + const query = gql` + { + movies( + where: { + genresConnection: { + node: { + moviesAggregate: { count: 2 } + seriesAggregate: { node: { name_SHORTEST_EQUAL: 983 } } + } + } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + CALL { + WITH this1 + MATCH (this6:\`Series\`)-[this5:IN_GENRE]->(this1) + RETURN min(size(this6.name)) = $param1 AS var7 + } + WITH this, collect(var4) AS var4, collect(var7) AS var7 + WITH * + WHERE EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE (true IN var4 AND true IN var7) + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 983, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genresConnection with aggregation at the same level", async () => { + const query = gql` + { + movies( + where: { + genresConnection: { node: { moviesAggregate: { count: 3 } } } + genresAggregate: { count: 1 } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + CALL { + WITH this + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + RETURN count(this1) = $param0 AS var2 + } + OPTIONAL MATCH (this)-[this3:IN_GENRE]->(this4:\`Genre\`) + CALL { + WITH this4 + MATCH (this6:\`Movie\`)-[this5:IN_GENRE]->(this4) + RETURN count(this6) = $param1 AS var7 + } + WITH this, var2, collect(var7) AS var7 + WITH * + WHERE (var2 = true AND EXISTS { + MATCH (this)-[this3:IN_GENRE]->(this4:\`Genre\`) + WHERE true IN var7 + }) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 1, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 3, + \\"high\\": 0 + } + }" + `); + }); +}); diff --git a/packages/graphql/tests/tck/issues/2708.test.ts b/packages/graphql/tests/tck/issues/2708.test.ts new file mode 100644 index 0000000000..54c75e148d --- /dev/null +++ b/packages/graphql/tests/tck/issues/2708.test.ts @@ -0,0 +1,758 @@ +/* + * 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 { Neo4jGraphQL } from "../../../src"; +import { formatCypher, translateQuery, formatParams } from "../utils/tck-test-utils"; + +describe("https://github.com/neo4j/graphql/issues/2708", () => { + let neoSchema: Neo4jGraphQL; + + const typeDefs = gql` + type Movie { + title: String + genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "InGenre") + } + + type Genre { + name: String + movies: [Movie!]! @relationship(type: "IN_GENRE", direction: IN, properties: "InGenre") + series: [Series!]! @relationship(type: "IN_GENRE", direction: IN, properties: "InGenre") + } + + type Series { + name: String! + genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "InGenre") + } + + interface InGenre { + intValue: Int! + } + `; + + beforeAll(() => { + neoSchema = new Neo4jGraphQL({ + typeDefs, + }); + }); + + test("should find where moviesAggregate count equal", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate count_LT", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { count_LT: 3 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) < $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 3, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate count_GT", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { count_GT: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) > $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate node property SHORTEST", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { node: { title_SHORTEST_EQUAL: 1 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN min(size(this2.title)) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate node property AVERAGE", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { node: { title_AVERAGE_EQUAL: 1 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN avg(size(this2.title)) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": 1 + }" + `); + }); + + test("should find where moviesAggregate edge property MAX_LT", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { edge: { intValue_MAX_LT: 1 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN max(this1.intValue) < $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where moviesAggregate edge property MIN_EQUAL", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { edge: { intValue_MIN_EQUAL: 1 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN min(this1.intValue) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genres_SOME", async () => { + const query = gql` + { + movies(where: { genres_SOME: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genres_NONE", async () => { + const query = gql` + { + movies(where: { genres_NONE: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE NOT (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + }) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genres_ALL", async () => { + const query = gql` + { + movies(where: { genres_ALL: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE all(var4 IN var3 WHERE var4 = true) + } AND NOT (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE NOT (all(var4 IN var3 WHERE var4 = true)) + })) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genres_SINGLE", async () => { + const query = gql` + { + movies(where: { genres_SINGLE: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE single(this0 IN [(this)-[:IN_GENRE]->(this0:\`Genre\`) | this0] WHERE single(var4 IN var3 WHERE var4 = true)) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should find where genres_NOT", async () => { + const query = gql` + { + movies(where: { genres_NOT: { moviesAggregate: { count: 2 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE NOT (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + }) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + } + }" + `); + }); + + test("should not find genres_ALL where NONE true", async () => { + const query = gql` + { + movies(where: { genres_ALL: { moviesAggregate: { count: 0 } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + WITH * + WHERE (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE all(var4 IN var3 WHERE var4 = true) + } AND NOT (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE NOT (all(var4 IN var3 WHERE var4 = true)) + })) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 0, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genres with multiple AND aggregates", async () => { + const query = gql` + { + movies( + where: { + genres: { + AND: [ + { moviesAggregate: { count: 2 } } + { seriesAggregate: { node: { name_SHORTEST_EQUAL: 1 } } } + ] + } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + CALL { + WITH this0 + MATCH (this5:\`Series\`)-[this4:IN_GENRE]->(this0) + RETURN min(size(this5.name)) = $param1 AS var6 + } + WITH this, collect(var3) AS var3, collect(var6) AS var6 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE (true IN var3 AND true IN var6) + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genres with multiple OR aggregates", async () => { + const query = gql` + { + movies( + where: { + genres: { + OR: [ + { moviesAggregate: { count: 3 } } + { seriesAggregate: { node: { name_SHORTEST_EQUAL: 1 } } } + ] + } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + CALL { + WITH this0 + MATCH (this5:\`Series\`)-[this4:IN_GENRE]->(this0) + RETURN min(size(this5.name)) = $param1 AS var6 + } + WITH this, collect(var3) AS var3, collect(var6) AS var6 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE (true IN var3 OR true IN var6) + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 3, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genres with multiple implicit AND aggregates", async () => { + const query = gql` + { + movies( + where: { + genres: { moviesAggregate: { count: 2 }, seriesAggregate: { node: { name_SHORTEST_EQUAL: 1 } } } + } + ) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + CALL { + WITH this0 + MATCH (this5:\`Series\`)-[this4:IN_GENRE]->(this0) + RETURN min(size(this5.name)) = $param1 AS var6 + } + WITH this, collect(var3) AS var3, collect(var6) AS var6 + WITH * + WHERE EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE (true IN var3 AND true IN var6) + } + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 2, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); + + test("should find genres with aggregation at the same level", async () => { + const query = gql` + { + movies(where: { genres: { moviesAggregate: { count: 3 } }, genresAggregate: { count: 1 } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + CALL { + WITH this0 + MATCH (this2:\`Movie\`)-[this1:IN_GENRE]->(this0) + RETURN count(this2) = $param0 AS var3 + } + WITH this, collect(var3) AS var3 + CALL { + WITH this + MATCH (this)-[this4:IN_GENRE]->(this5:\`Genre\`) + RETURN count(this5) = $param1 AS var6 + } + WITH * + WHERE (EXISTS { + MATCH (this)-[:IN_GENRE]->(this0:\`Genre\`) + WHERE true IN var3 + } AND var6 = true) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 3, + \\"high\\": 0 + }, + \\"param1\\": { + \\"low\\": 1, + \\"high\\": 0 + } + }" + `); + }); +}); diff --git a/packages/graphql/tests/tck/issues/2709.test.ts b/packages/graphql/tests/tck/issues/2709.test.ts index 9e2222cf57..a308bd3ef2 100644 --- a/packages/graphql/tests/tck/issues/2709.test.ts +++ b/packages/graphql/tests/tck/issues/2709.test.ts @@ -106,7 +106,10 @@ describe("https://github.com/neo4j/graphql/issues/2709", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Film\`) - WHERE size([(this1:\`Netflix\`)-[this0:DISTRIBUTED_BY]->(this) WHERE this1.name = $param0 | 1]) > 0 + WHERE EXISTS { + MATCH (this1:\`Netflix\`)-[this0:DISTRIBUTED_BY]->(this) + WHERE this1.name = $param0 + } RETURN this { .title } AS this" `); @@ -131,7 +134,10 @@ describe("https://github.com/neo4j/graphql/issues/2709", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Film\`) - WHERE size([(this1:\`Dishney\`)-[this0:DISTRIBUTED_BY]->(this) WHERE this1.name = $param0 | 1]) > 0 + WHERE EXISTS { + MATCH (this1:\`Dishney\`)-[this0:DISTRIBUTED_BY]->(this) + WHERE this1.name = $param0 + } RETURN this { .title } AS this" `); @@ -154,7 +160,10 @@ describe("https://github.com/neo4j/graphql/issues/2709", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Film\`) - WHERE size([(this1:\`Dishney\`)-[this0:DISTRIBUTED_BY]->(this) WHERE this1.name = $param0 | 1]) > 0 + WHERE EXISTS { + MATCH (this1:\`Dishney\`)-[this0:DISTRIBUTED_BY]->(this) + WHERE this1.name = $param0 + } RETURN this { .title } AS this" `); @@ -177,7 +186,10 @@ describe("https://github.com/neo4j/graphql/issues/2709", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Film\`) - WHERE size([(this1)-[this0:DISTRIBUTED_BY]->(this) WHERE (this1.name = $param0 AND (this1:\`Dishney\` OR this1:\`Prime\` OR this1:\`Netflix\`)) | 1]) > 0 + WHERE EXISTS { + MATCH (this1)-[this0:DISTRIBUTED_BY]->(this) + WHERE (this1.name = $param0 AND (this1:\`Dishney\` OR this1:\`Prime\` OR this1:\`Netflix\`)) + } RETURN this { .title } AS this" `); diff --git a/packages/graphql/tests/tck/issues/2713.test.ts b/packages/graphql/tests/tck/issues/2713.test.ts new file mode 100644 index 0000000000..48b8567a4a --- /dev/null +++ b/packages/graphql/tests/tck/issues/2713.test.ts @@ -0,0 +1,95 @@ +/* + * 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 { Neo4jGraphQL } from "../../../src"; +import { formatCypher, translateQuery, formatParams } from "../utils/tck-test-utils"; + +describe("https://github.com/neo4j/graphql/issues/2713", () => { + let neoSchema: Neo4jGraphQL; + + const typeDefs = gql` + type Movie { + title: String + genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "InGenre") + } + + type Genre { + name: String + movies: [Movie!]! @relationship(type: "IN_GENRE", direction: IN, properties: "InGenre") + series: [Series!]! @relationship(type: "IN_GENRE", direction: IN, properties: "InGenre") + } + + type Series { + name: String! + genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT, properties: "InGenre") + } + + interface InGenre { + intValue: Int! + } + `; + + beforeAll(() => { + neoSchema = new Neo4jGraphQL({ + typeDefs, + }); + }); + + test("should not find genresConnection_ALL where NONE true", async () => { + const query = gql` + { + movies(where: { genresConnection_ALL: { node: { moviesAggregate: { count: 0 } } } }) { + title + } + } + `; + + const result = await translateQuery(neoSchema, query); + + expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` + "MATCH (this:\`Movie\`) + OPTIONAL MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + CALL { + WITH this1 + MATCH (this3:\`Movie\`)-[this2:IN_GENRE]->(this1) + RETURN count(this3) = $param0 AS var4 + } + WITH this, collect(var4) AS var4 + WITH * + WHERE (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE all(var5 IN var4 WHERE var5 = true) + } AND NOT (EXISTS { + MATCH (this)-[this0:IN_GENRE]->(this1:\`Genre\`) + WHERE NOT (all(var5 IN var4 WHERE var5 = true)) + })) + RETURN this { .title } AS this" + `); + + expect(formatParams(result.params)).toMatchInlineSnapshot(` + "{ + \\"param0\\": { + \\"low\\": 0, + \\"high\\": 0 + } + }" + `); + }); +}); diff --git a/packages/graphql/tests/tck/issues/488.test.ts b/packages/graphql/tests/tck/issues/488.test.ts index ac5c7c2355..b93ab4d17e 100644 --- a/packages/graphql/tests/tck/issues/488.test.ts +++ b/packages/graphql/tests/tck/issues/488.test.ts @@ -80,7 +80,10 @@ describe("#488", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Journalist\`) - WHERE size([(this)-[this0:HAS_KEYWORD]->(this1:\`Emoji\`) WHERE this1.type = $param0 | 1]) > 0 + WHERE EXISTS { + MATCH (this)-[this0:HAS_KEYWORD]->(this1:\`Emoji\`) + WHERE this1.type = $param0 + } CALL { WITH this CALL { @@ -134,7 +137,10 @@ describe("#488", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Journalist\`) - WHERE size([(this)-[this0:HAS_KEYWORD]->(this1:\`Emoji\`) WHERE this1.type = $param0 | 1]) = 0 + WHERE NOT (EXISTS { + MATCH (this)-[this0:HAS_KEYWORD]->(this1:\`Emoji\`) + WHERE this1.type = $param0 + }) CALL { WITH this CALL { diff --git a/packages/graphql/tests/tck/issues/582.test.ts b/packages/graphql/tests/tck/issues/582.test.ts index 7d52307128..8edd4d736d 100644 --- a/packages/graphql/tests/tck/issues/582.test.ts +++ b/packages/graphql/tests/tck/issues/582.test.ts @@ -73,7 +73,13 @@ describe("#582", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Entity\`) - WHERE (this.type = $param0 AND size([(this)-[this0:EDGE]->(this1:\`Entity\`) WHERE (this1.type = $param1 AND size([(this3:\`Entity\`)-[this2:EDGE]->(this1) WHERE this3.type = $param2 | 1]) > 0) | 1]) > 0) + WHERE (this.type = $param0 AND EXISTS { + MATCH (this)-[this0:EDGE]->(this1:\`Entity\`) + WHERE (this1.type = $param1 AND EXISTS { + MATCH (this3:\`Entity\`)-[this2:EDGE]->(this1) + WHERE this3.type = $param2 + }) + }) RETURN this { .type } AS this" `); @@ -120,7 +126,16 @@ describe("#582", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Entity\`) - WHERE (this.type = $param0 AND size([(this)-[this0:EDGE]->(this1:\`Entity\`) WHERE (this1.type = $param1 AND size([(this3:\`Entity\`)-[this2:EDGE]->(this1) WHERE (this3.type = $param2 AND size([(this3)-[this4:EDGE]->(this5:\`Entity\`) WHERE this5.type = $param3 | 1]) > 0) | 1]) > 0) | 1]) > 0) + WHERE (this.type = $param0 AND EXISTS { + MATCH (this)-[this0:EDGE]->(this1:\`Entity\`) + WHERE (this1.type = $param1 AND EXISTS { + MATCH (this3:\`Entity\`)-[this2:EDGE]->(this1) + WHERE (this3.type = $param2 AND EXISTS { + MATCH (this3)-[this4:EDGE]->(this5:\`Entity\`) + WHERE this5.type = $param3 + }) + }) + }) RETURN this { .type } AS this" `); diff --git a/packages/graphql/tests/tck/issues/988.test.ts b/packages/graphql/tests/tck/issues/988.test.ts index e0a78b306b..959a34976a 100644 --- a/packages/graphql/tests/tck/issues/988.test.ts +++ b/packages/graphql/tests/tck/issues/988.test.ts @@ -136,7 +136,16 @@ describe("https://github.com/neo4j/graphql/issues/988", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:\`Series\`) - WHERE (((size([(this)-[this0:MANUFACTURER]->(this1:\`Manufacturer\`) WHERE (this0.current = $param0 AND this1.name = $param1) | 1]) > 0 OR size([(this)-[this2:MANUFACTURER]->(this3:\`Manufacturer\`) WHERE (this2.current = $param2 AND this3.name = $param3) | 1]) > 0) AND size([(this)-[this4:BRAND]->(this5:\`Brand\`) WHERE (this4.current = $param4 AND this5.name = $param5) | 1]) > 0) AND this.current = $param6) + WHERE (((EXISTS { + MATCH (this)-[this0:MANUFACTURER]->(this1:\`Manufacturer\`) + WHERE (this0.current = $param0 AND this1.name = $param1) + } OR EXISTS { + MATCH (this)-[this2:MANUFACTURER]->(this3:\`Manufacturer\`) + WHERE (this2.current = $param2 AND this3.name = $param3) + }) AND EXISTS { + MATCH (this)-[this4:BRAND]->(this5:\`Brand\`) + WHERE (this4.current = $param4 AND this5.name = $param5) + }) AND this.current = $param6) CALL { WITH this MATCH (this)-[this_connection_manufacturerConnectionthis0:MANUFACTURER]->(this_Manufacturer:\`Manufacturer\`) diff --git a/packages/graphql/tests/tck/operations/connect.test.ts b/packages/graphql/tests/tck/operations/connect.test.ts index fea6c0c6bd..b5c489ec54 100644 --- a/packages/graphql/tests/tck/operations/connect.test.ts +++ b/packages/graphql/tests/tck/operations/connect.test.ts @@ -152,13 +152,6 @@ describe("Cypher Connect", () => { RETURN count(*) AS _ } WITH this0, this0_colors_connect0_node, this0_colors_connect0_node_photos0_node - CALL { - WITH this0_colors_connect0_node - MATCH (this0_colors_connect0_node)<-[this0_colors_connect0_node_photos_Photo_unique:OF_COLOR]-(other:Photo) - WITH count(this0_colors_connect0_node_photos_Photo_unique) as c, other - CALL apoc.util.validate(NOT (c = 1), '@neo4j/graphql/RELATIONSHIP-REQUIREDColor.photos required exactly once for a specific Photo', [0]) - RETURN collect(c) AS this0_colors_connect0_node_photos_Photo_unique_ignored - } CALL { WITH this0_colors_connect0_node_photos0_node MATCH (this0_colors_connect0_node_photos0_node)-[this0_colors_connect0_node_photos0_node_color_Color_unique:OF_COLOR]->(:Color)