diff --git a/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts b/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts index 7624f227d7..23f022a790 100644 --- a/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts +++ b/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts @@ -541,6 +541,14 @@ export class FilterFactory { }); } + if (rawOperator === "distance") { + const distanceFilters = Object.entries(value).flatMap((distanceWhere) => { + return this.parseGenericFilter(entity, fieldName, distanceWhere); + }); + + return this.wrapMultipleFiltersInLogical(distanceFilters); + } + const operator = this.parseGenericOperator(rawOperator); const attribute = entity.findAttribute(fieldName); diff --git a/packages/graphql/tests/integration/deprecations/point-cartesian-array-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/point-cartesian-array-filter.int.test.ts new file mode 100644 index 0000000000..6f9a0a3c1a --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/point-cartesian-array-filter.int.test.ts @@ -0,0 +1,130 @@ +/* + * 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 { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("[CartesianPoint] - deprecated filters", () => { + const testHelper = new TestHelper(); + let Part: UniqueType; + + beforeEach(async () => { + Part = testHelper.createUniqueType("Part"); + const typeDefs = /* GraphQL */ ` + type ${Part} @node { + id: String! + locations: [CartesianPoint!]! + } + `; + await testHelper.initNeo4jGraphQL({ typeDefs }); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("enables query of a node with multiple cartesian points", async () => { + const id = "5ba92bc4-95e7-4361-857c-60edcd771391"; + const locations = [...new Array(8)].map(() => ({ + x: 0.02772025833837688, + y: 0.07264417805708945, + })); + + await testHelper.executeCypher( + ` + CALL { + CREATE (r:${Part}) + SET r.id = $id + SET r.locations = [p in $locations | point(p)] + RETURN r + } + + RETURN r { .id, .locations } AS r + `, + { id, locations } + ); + + const partsQuery = /* GraphQL */ ` + query Parts($id: String!) { + ${Part.plural}(where: { id_EQ: $id }) { + id + locations { + y + x + z + crs + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(partsQuery, { variableValues: { id } }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Part.plural][0]).toEqual({ + id, + locations: locations.map((location) => ({ ...location, z: null, crs: "cartesian" })), + }); + }); + + test("enables query of a node with multiple cartesian-3d points", async () => { + const id = "052322ec-95e5-4b88-8a90-9f0c1df17ee3"; + const locations = [...new Array(8)].map(() => ({ + x: 0.8367510938551277, + y: 0.7110547178890556, + z: 0.9648887133225799, + })); + + await testHelper.executeCypher( + ` + CALL { + CREATE (r:${Part}) + SET r.id = $id + SET r.locations = [p in $locations | point(p)] + RETURN r + } + + RETURN r { .id, .locations } AS r + `, + { id, locations } + ); + + const partsQuery = /* GraphQL */ ` + query Parts($id: String!) { + ${Part.plural}(where: { id_EQ: $id }) { + id + locations { + y + x + z + crs + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(partsQuery, { variableValues: { id } }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Part.plural][0]).toEqual({ + id, + locations: locations.map((location) => ({ ...location, crs: "cartesian-3d" })), + }); + }); +}); diff --git a/packages/graphql/tests/integration/deprecations/points-array-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/points-array-filter.int.test.ts new file mode 100644 index 0000000000..3c72c4107c --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/points-array-filter.int.test.ts @@ -0,0 +1,159 @@ +/* + * 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 { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("[Point] - deprecated filter", () => { + const testHelper = new TestHelper(); + let Route: UniqueType; + + beforeEach(async () => { + Route = testHelper.createUniqueType("Route"); + const typeDefs = /* GraphQL */ ` + type ${Route} @node { + id: String! + waypoints: [Point!]! + } + `; + await testHelper.initNeo4jGraphQL({ typeDefs }); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("enables query of a node with multiple wgs-84 points", async () => { + // Create test data and prepare for testing + const id = "25c4676e-1e38-4b1b-b156-6a7e28c8013e"; + const waypoints = [...new Array(9)].map(() => ({ + longitude: parseFloat("34.1879"), + latitude: parseFloat("30.5402"), + })); + + await testHelper.executeCypher( + ` + CALL { + CREATE (r:${Route}) + SET r.id = $id + SET r.waypoints = [p in $waypoints | point(p)] + RETURN r + } + + RETURN r { .id, .waypoints } AS r + `, + { id, waypoints } + ); + + // Test for equality + const routesQuery = /* GraphQL */ ` + query Routes($waypoints: [PointInput!]) { + ${Route.plural}(where: { waypoints_EQ: $waypoints }) { + id + waypoints { + latitude + longitude + height + crs + } + } + } + `; + + const routesResult = await testHelper.executeGraphQL(routesQuery, { variableValues: { waypoints } }); + + expect(routesResult.errors).toBeFalsy(); + expect((routesResult.data as any)[Route.plural][0]).toEqual({ + id, + waypoints: waypoints.map((waypoint) => ({ ...waypoint, height: null, crs: "wgs-84" })), + }); + + // Test INCLUDES functionality + const routesIncludesQuery = /* GraphQL */ ` + query RoutesIncludes($waypoint: PointInput) { + ${Route.plural}(where: { waypoints_INCLUDES: $waypoint }) { + id + waypoints { + latitude + longitude + height + crs + } + } + } + `; + + const routesIncludesResult = await testHelper.executeGraphQL(routesIncludesQuery, { + variableValues: { waypoint: waypoints[0] }, + }); + + expect(routesIncludesResult.errors).toBeFalsy(); + expect((routesIncludesResult.data as any)[Route.plural][0]).toEqual({ + id, + waypoints: waypoints.map((waypoint) => ({ ...waypoint, height: null, crs: "wgs-84" })), + }); + }); + + test("enables query of a node with multiple wgs-84-3d points", async () => { + const id = "dd320626-cc23-4938-9f33-ba624a3a3e8d"; + const waypoints = [...new Array(7)].map(() => ({ + longitude: parseFloat("146.1568"), + latitude: parseFloat("-54.6132"), + height: 0.03157347836531699, + })); + + await testHelper.executeCypher( + ` + CALL { + CREATE (r:${Route}) + SET r.id = $id + SET r.waypoints = [p in $waypoints | point(p)] + RETURN r + } + + RETURN r { .id, .waypoints } AS r + `, + { id, waypoints } + ); + + const routesQuery = /* GraphQL */ ` + query Routes($id: String!) { + ${Route.plural}(where: { id_EQ: $id }) { + id + waypoints { + latitude + longitude + height + crs + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(routesQuery, { + variableValues: { id }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Route.plural][0]).toEqual({ + id, + waypoints: waypoints.map((waypoint) => ({ ...waypoint, crs: "wgs-84-3d" })), + }); + }); +}); diff --git a/packages/graphql/tests/integration/deprecations/types-filters.int.test.ts b/packages/graphql/tests/integration/deprecations/types-filters.int.test.ts new file mode 100644 index 0000000000..25a9f47ad2 --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/types-filters.int.test.ts @@ -0,0 +1,362 @@ +import neo4jDriver from "neo4j-driver"; +import { generate } from "randomstring"; +import { parseDuration } from "../../../src/graphql/scalars/Duration"; +import type { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("deprecated types filtering", () => { + const testHelper = new TestHelper(); + let Movie: UniqueType; + let File: UniqueType; + + beforeEach(() => { + Movie = testHelper.createUniqueType("Movie"); + File = testHelper.createUniqueType("File"); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("should find a movie (with a Date) - deprecated", async () => { + const typeDefs = /* GraphQL */ ` + type ${Movie.name} @node { + date: Date + } + `; + + const date = new Date(); + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const query = /* GraphQL */ ` + query { + ${Movie.plural}(where: { date_EQ: "${date.toISOString()}" }) { + date + } + } + `; + + const nDate = neo4jDriver.types.Date.fromStandardDate(date); + + await testHelper.executeCypher( + ` + CREATE (m:${Movie.name}) + SET m.date = $nDate + `, + { nDate } + ); + + const gqlResult = await testHelper.executeGraphQL(query); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Movie.plural][0]).toEqual({ + date: date.toISOString().split("T")[0], + }); + }); + + test("should find a movie (with a DateTime) - deprecated", async () => { + const typeDefs = /* GraphQL */ ` + type ${Movie.name} @node { + datetime: DateTime + } + `; + + const date = new Date(); + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const query = ` + query { + ${Movie.plural}(where: { datetime_EQ: "${date.toISOString()}" }) { + datetime + } + } + `; + + const nDateTime = neo4jDriver.types.DateTime.fromStandardDate(date); + + await testHelper.executeCypher( + ` + CREATE (m:${Movie.name}) + SET m.datetime = $nDateTime + `, + { nDateTime } + ); + + const gqlResult = await testHelper.executeGraphQL(query); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Movie.plural][0]).toEqual({ datetime: date.toISOString() }); + }); + + test("should find a movie (with a DateTime created with a timezone) - deprecated", async () => { + const typeDefs = /* GraphQL */ ` + type ${Movie.name} @node { + name: String + datetime: DateTime + } + `; + + const date = new Date(); + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const query = /* GraphQL */ ` + query { + ${Movie.plural}(where: { name_EQ: "${Movie.name}" }) { + datetime + } + } + `; + + await testHelper.executeCypher(` + CREATE (m:${Movie.name}) + SET m.name = "${Movie.name}" + SET m.datetime = datetime("${date.toISOString().replace("Z", "[Etc/UTC]")}") + `); + + const gqlResult = await testHelper.executeGraphQL(query); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Movie.plural][0]).toEqual({ datetime: date.toISOString() }); + }); + + test("should filter based on duration equality - deprecated", async () => { + const typeDefs = /* GraphQL */ ` + type ${Movie} @node { + id: ID! + duration: Duration! + } + `; + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const id = generate({ readable: false }); + const days = 4; + const duration = `P${days}D`; + const parsedDuration = parseDuration(duration); + const neo4jDuration = new neo4jDriver.types.Duration(0, days, 0, 0); + + await testHelper.executeCypher( + ` + CREATE (movie:${Movie}) + SET movie = $movie + `, + { movie: { id, duration: neo4jDuration } } + ); + + const query = /* GraphQL */ ` + query ($id: ID!, $duration: Duration!) { + ${Movie.plural}(where: { id_EQ: $id, duration_EQ: $duration }) { + id + duration + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { id, duration }, + }); + + expect(graphqlResult.errors).toBeFalsy(); + + const graphqlMovie: { id: string; duration: string } = (graphqlResult.data as any)[Movie.plural][0]; + expect(graphqlMovie).toBeDefined(); + expect(graphqlMovie.id).toEqual(id); + expect(parseDuration(graphqlMovie.duration)).toStrictEqual(parsedDuration); + }); + + test.each(["LT", "LTE", "GT", "GTE"])( + "should filter based on duration comparison, for filter: %s - deprecated", + async (filter) => { + const typeDefs = ` + type ${Movie} @node { + id: ID! + duration: Duration! + } + `; + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const longId = generate({ readable: false }); + const long = "P2Y"; + const parsedLong = parseDuration(long); + const neo4jLong = new neo4jDriver.types.Duration( + parsedLong.months, + parsedLong.days, + parsedLong.seconds, + parsedLong.nanoseconds + ); + + const mediumId = generate({ readable: false }); + const medium = "P2M"; + const parsedMedium = parseDuration(medium); + const neo4jMedium = new neo4jDriver.types.Duration( + parsedMedium.months, + parsedMedium.days, + parsedMedium.seconds, + parsedMedium.nanoseconds + ); + + const shortId = generate({ readable: false }); + const short = "P2D"; + const parsedShort = parseDuration(short); + const neo4jShort = new neo4jDriver.types.Duration( + parsedShort.months, + parsedShort.days, + parsedShort.seconds, + parsedShort.nanoseconds + ); + + await testHelper.executeCypher( + ` + CREATE (long:${Movie}) + SET long = $long + CREATE (medium:${Movie}) + SET medium = $medium + CREATE (short:${Movie}) + SET short = $short + `, + { + long: { id: longId, duration: neo4jLong }, + medium: { id: mediumId, duration: neo4jMedium }, + short: { id: shortId, duration: neo4jShort }, + } + ); + + const query = /* GraphQL */ ` + query ($where: ${Movie.name}Where!) { + ${Movie.plural}(where: $where, sort: [{ duration: ASC }]) { + id + duration + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { + where: { id_IN: [longId, mediumId, shortId], [`duration_${filter}`]: medium }, + }, + }); + + expect(graphqlResult.errors).toBeUndefined(); + + const graphqlMovies: { id: string; duration: string }[] = (graphqlResult.data as any)[Movie.plural]; + expect(graphqlMovies).toBeDefined(); + + /* eslint-disable jest/no-conditional-expect */ + if (filter === "LT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(shortId); + expect(parseDuration(graphqlMovies[0]?.duration as string)).toStrictEqual(parsedShort); + } + + if (filter === "LTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(shortId); + expect(parseDuration(graphqlMovies[0]?.duration as string)).toStrictEqual(parsedShort); + + expect(graphqlMovies[1]?.id).toBe(mediumId); + expect(parseDuration(graphqlMovies[1]?.duration as string)).toStrictEqual(parsedMedium); + } + + if (filter === "GT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(longId); + expect(parseDuration(graphqlMovies[0]?.duration as string)).toStrictEqual(parsedLong); + } + + if (filter === "GTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(mediumId); + expect(parseDuration(graphqlMovies[0]?.duration as string)).toStrictEqual(parsedMedium); + + expect(graphqlMovies[1]?.id).toBe(longId); + expect(parseDuration(graphqlMovies[1]?.duration as string)).toStrictEqual(parsedLong); + } + /* eslint-enable jest/no-conditional-expect */ + } + ); + + test("BigInt should work returning a BigInt property - deprecated", async () => { + const name = generate({ + charset: "alphabetic", + }); + + const typeDefs = ` + type ${File} @node { + name: String! + size: BigInt! @cypher(statement: """ + RETURN 9223372036854775807 as result + """, columnName:"result") + } + `; + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const query = ` + query { + ${File.plural}(where: { name_EQ: "${name}" }) { + name + size + } + } + `; + + await testHelper.executeCypher(` + CREATE (f:${File}) + SET f.name = "${name}" + `); + + const gqlResult = await testHelper.executeGraphQL(query); + + expect(gqlResult.errors).toBeFalsy(); + + expect(gqlResult?.data).toEqual({ + [File.plural]: [ + { + name, + size: "9223372036854775807", + }, + ], + }); + }); + + test("float should return normal JS number if the value isInt - deprecated filter", async () => { + const typeDefs = /* GraphQL */ ` + type ${Movie} @node { + id: String + fakeFloat: Float! @cypher(statement: """ + RETURN 12345 as result + """, columnName: "result") + } + + + `; + + const id = generate({ + charset: "alphabetic", + }); + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const query = /* GraphQL */ ` + query { + ${Movie.plural}(where: { id_EQ: "${id}" }){ + fakeFloat + } + } + `; + + await testHelper.executeCypher( + ` + CREATE (m:${Movie} { id: "${id}" }) + `, + {} + ); + const gqlResult = await testHelper.executeGraphQL(query, {}); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Movie.plural][0].fakeFloat).toBe(12345); + }); +}); diff --git a/packages/graphql/tests/integration/deprecations/types-localdatetime-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/types-localdatetime-filter.int.test.ts new file mode 100644 index 0000000000..8648fb0bfe --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/types-localdatetime-filter.int.test.ts @@ -0,0 +1,194 @@ +/* + * 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 neo4jDriver from "neo4j-driver"; +import { generate } from "randomstring"; +import { parseLocalDateTime } from "../../../src/graphql/scalars/LocalDateTime"; +import type { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("LocalDateTime - deprecated filters", () => { + const testHelper = new TestHelper(); + let Movie: UniqueType; + + beforeEach(async () => { + Movie = testHelper.createUniqueType("Movie"); + + const typeDefs = /* GraphQL */ ` + type ${Movie} @node { + id: ID! + localDT: LocalDateTime + localDTs: [LocalDateTime!] + } + `; + + await testHelper.initNeo4jGraphQL({ typeDefs }); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("should filter based on localDT equality", async () => { + const id = generate({ readable: false }); + const date = new Date("2024-09-17T11:49:48.322Z"); + const localDT = date.toISOString().split("Z")[0]; + const neo4jLocalDateTime = neo4jDriver.types.LocalDateTime.fromStandardDate(date); + const parsedLocalDateTime = parseLocalDateTime(localDT); + + await testHelper.executeCypher( + ` + CREATE (movie:${Movie}) + SET movie = $movie + `, + { movie: { id, localDT: neo4jLocalDateTime } } + ); + + const query = /* GraphQL */ ` + query ($localDT: LocalDateTime!) { + ${Movie.plural}(where: { localDT_EQ: $localDT }) { + id + localDT + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { localDT }, + }); + + expect(graphqlResult.errors).toBeFalsy(); + + const graphqlMovie: { id: string; localDT: string } = (graphqlResult.data as any)[Movie.plural][0]; + expect(graphqlMovie).toBeDefined(); + expect(graphqlMovie.id).toEqual(id); + expect(parseLocalDateTime(graphqlMovie.localDT)).toStrictEqual(parsedLocalDateTime); + }); + test.each(["LT", "LTE", "GT", "GTE"])( + "should filter based on localDT comparison, for filter %s", + async (filter) => { + const futureId = generate({ readable: false }); + const future = "2025-02-18T18:10:55.462Z".split("Z")[0]; + const parsedFuture = parseLocalDateTime(future); + const neo4jFuture = new neo4jDriver.types.LocalDateTime( + parsedFuture.year, + parsedFuture.month, + parsedFuture.day, + parsedFuture.hour, + parsedFuture.minute, + parsedFuture.second, + parsedFuture.nanosecond + ); + + const presentId = generate({ readable: false }); + const present = new Date().toISOString().split("Z")[0]; + const parsedPresent = parseLocalDateTime(present); + const neo4jPresent = new neo4jDriver.types.LocalDateTime( + parsedPresent.year, + parsedPresent.month, + parsedPresent.day, + parsedPresent.hour, + parsedPresent.minute, + parsedPresent.second, + parsedPresent.nanosecond + ); + + const pastId = generate({ readable: false }); + const past = "2022-08-29T10:21:43.108Z".split("Z")[0]; + const parsedPast = parseLocalDateTime(past); + const neo4jPast = new neo4jDriver.types.LocalDateTime( + parsedPast.year, + parsedPast.month, + parsedPast.day, + parsedPast.hour, + parsedPast.minute, + parsedPast.second, + parsedPast.nanosecond + ); + + await testHelper.executeCypher( + ` + CREATE (future:${Movie}) + SET future = $future + CREATE (present:${Movie}) + SET present = $present + CREATE (past:${Movie}) + SET past = $past + `, + { + future: { id: futureId, localDT: neo4jFuture }, + present: { id: presentId, localDT: neo4jPresent }, + past: { id: pastId, localDT: neo4jPast }, + } + ); + + const query = /* GraphQL */ ` + query ($where: ${Movie.name}Where!) { + ${Movie.plural}(where: $where, sort: [{ localDT: ASC }]) { + id + localDT + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { + where: { id_IN: [futureId, presentId, pastId], [`localDT_${filter}`]: present }, + }, + }); + + expect(graphqlResult.errors).toBeUndefined(); + + const graphqlMovies: { id: string; localDT: string }[] = (graphqlResult.data as any)[Movie.plural]; + expect(graphqlMovies).toBeDefined(); + + /* eslint-disable jest/no-conditional-expect */ + if (filter === "LT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(pastId); + expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedPast); + } + + if (filter === "LTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(pastId); + expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedPast); + + expect(graphqlMovies[1]?.id).toBe(presentId); + expect(parseLocalDateTime(graphqlMovies[1]?.localDT)).toStrictEqual(parsedPresent); + } + + if (filter === "GT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(futureId); + expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedFuture); + } + + if (filter === "GTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(presentId); + expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedPresent); + + expect(graphqlMovies[1]?.id).toBe(futureId); + expect(parseLocalDateTime(graphqlMovies[1]?.localDT)).toStrictEqual(parsedFuture); + } + /* eslint-enable jest/no-conditional-expect */ + } + ); +}); diff --git a/packages/graphql/tests/integration/deprecations/types-localtime-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/types-localtime-filter.int.test.ts new file mode 100644 index 0000000000..232b949908 --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/types-localtime-filter.int.test.ts @@ -0,0 +1,182 @@ +/* + * 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 neo4jDriver from "neo4j-driver"; +import { generate } from "randomstring"; +import { parseLocalTime } from "../../../src/graphql/scalars/LocalTime"; +import type { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("LocalTime - deprecated filters", () => { + const testHelper = new TestHelper(); + let Movie: UniqueType; + + beforeEach(async () => { + Movie = testHelper.createUniqueType("Movie"); + + const typeDefs = /* GraphQL */ ` + type ${Movie} @node { + id: ID! + time: LocalTime + times: [LocalTime!] + } + `; + + await testHelper.initNeo4jGraphQL({ typeDefs }); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("should filter based on time equality", async () => { + const id = generate({ readable: false }); + const date = new Date("2024-09-17T11:49:48.322Z"); + const time = date.toISOString().split("T")[1]?.split("Z")[0]; + const neo4jTime = neo4jDriver.types.LocalTime.fromStandardDate(date); + const parsedTime = parseLocalTime(time); + + await testHelper.executeCypher( + ` + CREATE (movie:${Movie}) + SET movie = $movie + `, + { movie: { id, time: neo4jTime } } + ); + + const query = /* GraphQL */ ` + query ($time: LocalTime!) { + ${Movie.plural}(where: { time_EQ: $time }) { + id + time + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { id, time }, + }); + + expect(graphqlResult.errors).toBeFalsy(); + + const graphqlMovie: { id: string; time: string } = (graphqlResult.data as any)[Movie.plural][0]; + expect(graphqlMovie).toBeDefined(); + expect(graphqlMovie.id).toEqual(id); + expect(parseLocalTime(graphqlMovie.time)).toStrictEqual(parsedTime); + }); + test.each(["LT", "LTE", "GT", "GTE"])("should filter based on time comparison, for filter %s", async (filter) => { + const futureId = generate({ readable: false }); + const future = "13:00:00"; + const parsedFuture = parseLocalTime(future); + const neo4jFuture = new neo4jDriver.types.LocalTime( + parsedFuture.hour, + parsedFuture.minute, + parsedFuture.second, + parsedFuture.nanosecond + ); + + const presentId = generate({ readable: false }); + const present = "12:00:00"; + const parsedPresent = parseLocalTime(present); + const neo4jPresent = new neo4jDriver.types.LocalTime( + parsedPresent.hour, + parsedPresent.minute, + parsedPresent.second, + parsedPresent.nanosecond + ); + + const pastId = generate({ readable: false }); + const past = "11:00:00"; + const parsedPast = parseLocalTime(past); + const neo4jPast = new neo4jDriver.types.LocalTime( + parsedPast.hour, + parsedPast.minute, + parsedPast.second, + parsedPast.nanosecond + ); + + await testHelper.executeCypher( + ` + CREATE (future:${Movie}) + SET future = $future + CREATE (present:${Movie}) + SET present = $present + CREATE (past:${Movie}) + SET past = $past + `, + { + future: { id: futureId, time: neo4jFuture }, + present: { id: presentId, time: neo4jPresent }, + past: { id: pastId, time: neo4jPast }, + } + ); + + const query = /* GraphQL */ ` + query ($where: ${Movie.name}Where!) { + ${Movie.plural}(where: $where, sort: [{ time: ASC }]) { + id + time + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { + where: { id_IN: [futureId, presentId, pastId], [`time_${filter}`]: present }, + }, + }); + + expect(graphqlResult.errors).toBeUndefined(); + + const graphqlMovies: { id: string; time: string }[] = (graphqlResult.data as any)[Movie.plural]; + expect(graphqlMovies).toBeDefined(); + + /* eslint-disable jest/no-conditional-expect */ + if (filter === "LT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(pastId); + expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + } + + if (filter === "LTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(pastId); + expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + + expect(graphqlMovies[1]?.id).toBe(presentId); + expect(parseLocalTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); + } + + if (filter === "GT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(futureId); + expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedFuture); + } + + if (filter === "GTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(presentId); + expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPresent); + + expect(graphqlMovies[1]?.id).toBe(futureId); + expect(parseLocalTime(graphqlMovies[1]?.time)).toStrictEqual(parsedFuture); + } + /* eslint-enable jest/no-conditional-expect */ + }); +}); diff --git a/packages/graphql/tests/integration/deprecations/types-point-cartesian-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/types-point-cartesian-filter.int.test.ts new file mode 100644 index 0000000000..307da4e04c --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/types-point-cartesian-filter.int.test.ts @@ -0,0 +1,268 @@ +/* + * 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 { int } from "neo4j-driver"; +import type { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("CartesianPoint", () => { + const testHelper = new TestHelper(); + + let Part: UniqueType; + + beforeEach(async () => { + Part = testHelper.createUniqueType("Part"); + const typeDefs = /* GraphQL */ ` + type ${Part} @node { + serial: String! + location: CartesianPoint! + } + `; + await testHelper.initNeo4jGraphQL({ typeDefs }); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("enables update of a node with a cartesian point", async () => { + const serial = "f5e40cae-f839-4ec3-a12b-45da40e8de7f"; + const x = 0.9797746981494129; + const y = 0.6287962510250509; + const newY = 0.8291290057823062; + + const beforeResult = await testHelper.executeCypher(` + CALL { + CREATE (p:${Part}) + SET p.serial = "${serial}" + SET p.location = point({x: ${x}, y: ${y}}) + RETURN p + } + + RETURN p { .serial, .location } AS p + `); + + expect((beforeResult.records[0] as any).toObject().p.location.x).toEqual(x); + expect((beforeResult.records[0] as any).toObject().p.location.y).toEqual(y); + + const update = /* GraphQL */ ` + mutation UpdateParts($serial: String!, $x: Float!, $y: Float!) { + ${Part.operations.update}(where: { serial_EQ: $serial }, update: { location_SET: { x: $x, y: $y } }) { + ${Part.plural} { + serial + location { + x + y + z + crs + } + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(update, { + variableValues: { serial, x, y: newY }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Part.operations.update][Part.plural][0]).toEqual({ + serial, + location: { + x, + y: newY, + z: null, + crs: "cartesian", + }, + }); + + const result = await testHelper.executeCypher(` + MATCH (p:${Part} {serial: "${serial}"}) + RETURN p { .serial, .location} as p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(x); + expect((result.records[0] as any).toObject().p.location.y).toEqual(newY); + expect((result.records[0] as any).toObject().p.location.srid).toEqual(int(7203)); + }); + + test("enables update of a node with a cartesian-3d point", async () => { + const serial = "ff4af64d-90f6-4f74-ad65-13dce16502bc"; + const x = 0.954262402607128; + const y = 0.9950293721631169; + const z = 0.30888770753517747; + const newY = 0.8628286835737526; + + const beforeResult = await testHelper.executeCypher(` + CALL { + CREATE (p:${Part}) + SET p.serial = "${serial}" + SET p.location = point({x: ${x}, y: ${y}, z: ${z}}) + RETURN p + } + + RETURN p { .serial, .location } AS p + `); + + expect((beforeResult.records[0] as any).toObject().p.location.x).toEqual(x); + expect((beforeResult.records[0] as any).toObject().p.location.y).toEqual(y); + expect((beforeResult.records[0] as any).toObject().p.location.z).toEqual(z); + + const update = /* GraphQL */ ` + mutation UpdateParts($serial: String!, $x: Float!, $y: Float!, $z: Float!) { + ${Part.operations.update}(where: { serial_EQ: $serial }, update: { location_SET: { x: $x, y: $y, z: $z } }) { + ${Part.plural} { + serial + location { + x + y + z + crs + } + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(update, { + variableValues: { serial, x, y: newY, z }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Part.operations.update][Part.plural][0]).toEqual({ + serial, + location: { + x, + y: newY, + z, + crs: "cartesian-3d", + }, + }); + + const result = await testHelper.executeCypher(` + MATCH (p:${Part} {serial: "${serial}"}) + RETURN p { .serial, .location} as p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(x); + expect((result.records[0] as any).toObject().p.location.y).toEqual(newY); + expect((result.records[0] as any).toObject().p.location.z).toEqual(z); + expect((result.records[0] as any).toObject().p.location.srid).toEqual(int(9157)); + }); + + test("enables query of a node with a cartesian point", async () => { + const serial = "bf92efbc-6c15-40ac-9cd5-8ab95fa4da90"; + const x = 0.2800768264569342; + const y = 0.6105434170458466; + + const result = await testHelper.executeCypher(` + CALL { + CREATE (p:${Part}) + SET p.serial = "${serial}" + SET p.location = point({x: ${x}, y: ${y}}) + RETURN p + } + + RETURN p { .id, .location } AS p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(x); + expect((result.records[0] as any).toObject().p.location.y).toEqual(y); + + const partsQuery = /* GraphQL */ ` + query Parts($serial: String!) { + ${Part.plural}(where: { serial_EQ: $serial }) { + serial + location { + x + y + z + crs + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(partsQuery, { + variableValues: { serial }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Part.plural][0]).toEqual({ + serial, + location: { + x, + y, + z: null, + crs: "cartesian", + }, + }); + }); + + test("enables query of a node with a cartesian-3d point", async () => { + const serial = "c7715adc-9c9c-45ff-b4ed-6cb20bb044ad"; + const x = 0.9446345162577927; + const y = 0.7858678111806512; + const z = 0.4248296618461609; + + const result = await testHelper.executeCypher(` + CALL { + CREATE (p:${Part}) + SET p.serial = "${serial}" + SET p.location = point({x: ${x}, y: ${y}, z: ${z}}) + RETURN p + } + + RETURN p { .id, .location } AS p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(x); + expect((result.records[0] as any).toObject().p.location.y).toEqual(y); + expect((result.records[0] as any).toObject().p.location.z).toEqual(z); + + const partsQuery = /* GraphQL */ ` + query Parts($serial: String!) { + ${Part.plural}(where: { serial_EQ: $serial }) { + serial + location { + x + y + z + crs + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(partsQuery, { + variableValues: { serial }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Part.plural][0]).toEqual({ + serial, + location: { + x, + y, + z, + crs: "cartesian-3d", + }, + }); + }); +}); diff --git a/packages/graphql/tests/integration/deprecations/types-point-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/types-point-filter.int.test.ts new file mode 100644 index 0000000000..6485d78c00 --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/types-point-filter.int.test.ts @@ -0,0 +1,411 @@ +/* + * 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 { int } from "neo4j-driver"; +import type { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("Point - deprecated", () => { + const testHelper = new TestHelper(); + + let Photograph: UniqueType; + + beforeEach(async () => { + Photograph = testHelper.createUniqueType("Photograph"); + + const typeDefs = /* GraphQL */ ` + type ${Photograph} @node { + id: String! + size: Int! + location: Point! + } + + type Query { + custom: String! + } + `; + // Dummy custom resolvers to validate fix for https://github.com/neo4j/graphql/issues/278 + const resolvers = { + Query: { + custom: () => "hello", + }, + }; + await testHelper.initNeo4jGraphQL({ typeDefs, resolvers }); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("enables update of a node with a wgs-84 point", async () => { + const id = "09132bb0-504a-407c-9096-6d945695dc89"; + const size = 95026; + const longitude = parseFloat("117.5113"); + const latitude = parseFloat("9.5509"); + const newLatitude = parseFloat("10.6116"); + + const beforeResult = await testHelper.executeCypher(` + CALL { + CREATE (p:${Photograph}) + SET p.id = "${id}" + SET p.size = ${size} + SET p.location = point({longitude: ${longitude}, latitude: ${latitude}}) + RETURN p + } + + RETURN p { .id, .size, .location } AS p + `); + + expect((beforeResult.records[0] as any).toObject().p.location.x).toEqual(longitude); + expect((beforeResult.records[0] as any).toObject().p.location.y).toEqual(latitude); + + const update = /* GraphQL */ ` + mutation UpdatePhotographs($id: String!, $longitude: Float!, $latitude: Float!) { + ${Photograph.operations.update}( + where: { id_EQ: $id } + update: { location_SET: { longitude: $longitude, latitude: $latitude } } + ) { + ${Photograph.plural} { + id + size + location { + latitude + longitude + height + crs + } + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(update, { + variableValues: { id, longitude, latitude: newLatitude }, + }); + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Photograph.operations.update][Photograph.plural][0]).toEqual({ + id, + size, + location: { + latitude: newLatitude, + longitude, + height: null, + crs: "wgs-84", + }, + }); + + const result = await testHelper.executeCypher(` + MATCH (p:${Photograph} {id: "${id}"}) + RETURN p { .id, .size, .location} as p + `); + + expect((result.records[0] as any)?.toObject().p.location.x).toEqual(longitude); + expect((result.records[0] as any)?.toObject().p.location.y).toEqual(newLatitude); + expect((result.records[0] as any)?.toObject().p.location.srid).toEqual(int(4326)); + }); + + test("enables update of a node with a wgs-84-3d point", async () => { + const id = "3b3170d8-03ed-43be-ae02-876a4233e2c7"; + const size = 55312; + const longitude = parseFloat("102.1785"); + const latitude = parseFloat("78.8688"); + const height = 0.9209601751063019; + const newLatitude = parseFloat("71.2271"); + + const beforeResult = await testHelper.executeCypher(` + CALL { + CREATE (p:${Photograph}) + SET p.id = "${id}" + SET p.size = ${size} + SET p.location = point({longitude: ${longitude}, latitude: ${latitude}, height: ${height}}) + RETURN p + } + + RETURN p { .id, .size, .location } AS p + `); + + expect((beforeResult.records[0] as any).toObject().p.location.x).toEqual(longitude); + expect((beforeResult.records[0] as any).toObject().p.location.y).toEqual(latitude); + expect((beforeResult.records[0] as any).toObject().p.location.z).toEqual(height); + + const update = /* GraphQL */ ` + mutation UpdatePhotographs($id: String!, $longitude: Float!, $latitude: Float!, $height: Float!) { + ${Photograph.operations.update}( + where: { id_EQ: $id } + update: { location_SET: { longitude: $longitude, latitude: $latitude, height: $height } } + ) { + ${Photograph.plural} { + id + size + location { + latitude + longitude + height + crs + } + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(update, { + variableValues: { id, longitude, latitude: newLatitude, height }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Photograph.operations.update][Photograph.plural][0]).toEqual({ + id, + size, + location: { + latitude: newLatitude, + longitude, + height, + crs: "wgs-84-3d", + }, + }); + + const result = await testHelper.executeCypher(` + MATCH (p:${Photograph} {id: "${id}"}) + RETURN p { .id, .size, .location} as p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(longitude); + expect((result.records[0] as any).toObject().p.location.y).toEqual(newLatitude); + expect((result.records[0] as any).toObject().p.location.z).toEqual(height); + expect((result.records[0] as any).toObject().p.location.srid).toEqual(int(4979)); + }); + + test("enables query of a node with a wgs-84 point", async () => { + // Create node + const id = "f8a5a58a-7380-4a39-9103-07a2c0528d8e"; + const size = 31364; + const longitude = parseFloat("62.5196"); + const latitude = parseFloat("-41.1021"); + + const result = await testHelper.executeCypher(` + CALL { + CREATE (p:${Photograph}) + SET p.id = "${id}" + SET p.size = ${size} + SET p.location = point({longitude: ${longitude}, latitude: ${latitude}}) + RETURN p + } + + RETURN p { .id, .size, .location } AS p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(longitude); + expect((result.records[0] as any).toObject().p.location.y).toEqual(latitude); + + // Test equality + const photographsEqualsQuery = /* GraphQL */ ` + query Photographs($longitude: Float!, $latitude: Float!) { + ${Photograph.plural}(where: { location_EQ: { longitude: $longitude, latitude: $latitude } }) { + id + size + location { + latitude + longitude + height + crs + } + } + } + `; + + const equalsResult = await testHelper.executeGraphQL(photographsEqualsQuery, { + variableValues: { longitude, latitude }, + }); + + expect(equalsResult.errors).toBeFalsy(); + expect((equalsResult.data as any)[Photograph.plural][0]).toEqual({ + id, + size, + location: { + latitude, + longitude, + height: null, + crs: "wgs-84", + }, + }); + + // Test IN functionality + const photographsInQuery = /* GraphQL */ ` + query Photographs($locations: [PointInput!]) { + ${Photograph.plural}(where: { location_IN: $locations }) { + id + size + location { + latitude + longitude + height + crs + } + } + } + `; + + const inResult = await testHelper.executeGraphQL(photographsInQuery, { + variableValues: { + locations: [ + { longitude, latitude }, + { + longitude: parseFloat("-156.8208"), + latitude: parseFloat("64.9108"), + }, + ], + }, + }); + + expect(inResult.errors).toBeFalsy(); + expect((inResult.data as any)[Photograph.plural]).toContainEqual({ + id, + size, + location: { + latitude, + longitude, + height: null, + crs: "wgs-84", + }, + }); + + // Test less than + const photographsLessThanQuery = /* GraphQL */ ` + query Photographs($longitude: Float!, $latitude: Float!) { + ${Photograph.plural}( + where: { location_LT: { point: { longitude: $longitude, latitude: $latitude }, distance: 1000000 } } + ) { + id + size + location { + latitude + longitude + height + crs + } + } + } + `; + + const lessThanResult = await testHelper.executeGraphQL(photographsLessThanQuery, { + variableValues: { longitude, latitude: latitude + 1 }, + }); + + expect(lessThanResult.errors).toBeFalsy(); + expect((lessThanResult.data as any)[Photograph.plural]).toContainEqual({ + id, + size, + location: { + latitude, + longitude, + height: null, + crs: "wgs-84", + }, + }); + + // Test greater than + const photographsGreaterThanQuery = /* GraphQL */ ` + query Photographs($longitude: Float!, $latitude: Float!) { + ${Photograph.plural}( + where: { location_GT: { point: { longitude: $longitude, latitude: $latitude }, distance: 1 } } + ) { + id + size + location { + latitude + longitude + height + crs + } + } + } + `; + + const greaterThanResult = await testHelper.executeGraphQL(photographsGreaterThanQuery, { + variableValues: { longitude, latitude: latitude + 1 }, + }); + + expect(greaterThanResult.errors).toBeFalsy(); + expect((greaterThanResult.data as any)[Photograph.plural]).toContainEqual({ + id, + size, + location: { + latitude, + longitude, + height: null, + crs: "wgs-84", + }, + }); + }); + + test("enables query for equality of a node with a wgs-84-3d point", async () => { + const id = "3019fe82-5231-4103-8662-39c1fcc7d50c"; + const size = 99119; + const longitude = parseFloat("125.6358"); + const latitude = parseFloat("-7.2045"); + const height = 0.6950517320074141; + + const result = await testHelper.executeCypher(` + CALL { + CREATE (p:${Photograph}) + SET p.id = "${id}" + SET p.size = ${size} + SET p.location = point({longitude: ${longitude}, latitude: ${latitude}, height: ${height}}) + RETURN p + } + + RETURN p { .id, .size, .location } AS p + `); + + expect((result.records[0] as any).toObject().p.location.x).toEqual(longitude); + expect((result.records[0] as any).toObject().p.location.y).toEqual(latitude); + expect((result.records[0] as any).toObject().p.location.z).toEqual(height); + + const photographsQuery = /* GraphQL */ ` + query Photographs($longitude: Float!, $latitude: Float!, $height: Float) { + ${Photograph.plural}(where: { location_EQ: { longitude: $longitude, latitude: $latitude, height: $height } }) { + id + size + location { + latitude + longitude + height + crs + } + } + } + `; + + const gqlResult = await testHelper.executeGraphQL(photographsQuery, { + variableValues: { longitude, latitude, height }, + }); + + expect(gqlResult.errors).toBeFalsy(); + expect((gqlResult.data as any)[Photograph.plural][0]).toEqual({ + id, + size, + location: { + latitude, + longitude, + height, + crs: "wgs-84-3d", + }, + }); + }); +}); diff --git a/packages/graphql/tests/integration/deprecations/types-time-filter.int.test.ts b/packages/graphql/tests/integration/deprecations/types-time-filter.int.test.ts new file mode 100644 index 0000000000..3158cbc59a --- /dev/null +++ b/packages/graphql/tests/integration/deprecations/types-time-filter.int.test.ts @@ -0,0 +1,196 @@ +/* + * 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 { Time } from "neo4j-driver"; +import { generate } from "randomstring"; +import { parseTime } from "../../../src/graphql/scalars/Time"; +import type { UniqueType } from "../../utils/graphql-types"; +import { TestHelper } from "../../utils/tests-helper"; + +describe("Time - deprecated filters", () => { + const testHelper = new TestHelper(); + + let Movie: UniqueType; + + beforeEach(() => { + Movie = testHelper.createUniqueType("Movie"); + }); + + afterEach(async () => { + await testHelper.close(); + }); + + test("should filter based on time equality", async () => { + const typeDefs = /* GraphQL */ ` + type ${Movie} @node { + id: ID! + time: Time! + } + `; + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const id = generate({ readable: false }); + const date = new Date("2024-02-17T11:49:48.322Z"); + const time = date.toISOString().split("T")[1]; + const neo4jTime = Time.fromStandardDate(date); + const parsedTime = parseTime(time); + + await testHelper.executeCypher( + ` + CREATE (movie:${Movie}) + SET movie = $movie + `, + { movie: { id, time: neo4jTime } } + ); + + const query = /* GraphQL */ ` + query ($time: Time!) { + ${Movie.plural}(where: { time_EQ: $time }) { + id + time + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { variableValues: { time } }); + + expect(graphqlResult.errors).toBeFalsy(); + + const graphqlMovie: { id: string; time: string } = (graphqlResult.data as any)[Movie.plural][0]; + expect(graphqlMovie).toBeDefined(); + expect(graphqlMovie.id).toEqual(id); + expect(parseTime(graphqlMovie.time)).toStrictEqual(parsedTime); + }); + + test.each(["LT", "LTE", "GT", "GTE"])("should filter based on time comparison for filter: %s", async (filter) => { + const typeDefs = /* GraphQL */ ` + type ${Movie} @node { + id: ID! + time: Time! + } + `; + + await testHelper.initNeo4jGraphQL({ typeDefs }); + + const futureId = generate({ readable: false }); + const future = "13:00:00"; + const parsedFuture = parseTime(future); + const neo4jFuture = new Time( + parsedFuture.hour, + parsedFuture.minute, + parsedFuture.second, + parsedFuture.nanosecond, + parsedFuture.timeZoneOffsetSeconds + ); + + const presentId = generate({ readable: false }); + const present = "12:00:00"; + const parsedPresent = parseTime(present); + const neo4jPresent = new Time( + parsedPresent.hour, + parsedPresent.minute, + parsedPresent.second, + parsedPresent.nanosecond, + parsedPresent.timeZoneOffsetSeconds + ); + + const pastId = generate({ readable: false }); + const past = "11:00:00"; + const parsedPast = parseTime(past); + const neo4jPast = new Time( + parsedPast.hour, + parsedPast.minute, + parsedPast.second, + parsedPast.nanosecond, + parsedPast.timeZoneOffsetSeconds + ); + + await testHelper.executeCypher( + ` + CREATE (future:${Movie}) + SET future = $future + CREATE (present:${Movie}) + SET present = $present + CREATE (past:${Movie}) + SET past = $past + `, + { + future: { id: futureId, time: neo4jFuture }, + present: { id: presentId, time: neo4jPresent }, + past: { id: pastId, time: neo4jPast }, + } + ); + + const query = /* GraphQL */ ` + query ($where: ${Movie.name}Where!) { + ${Movie.plural}( + where: $where + sort: [{ time: ASC }] + ) { + id + time + } + } + `; + + const graphqlResult = await testHelper.executeGraphQL(query, { + variableValues: { + where: { id_IN: [futureId, presentId, pastId], [`time_${filter}`]: present }, + }, + }); + + expect(graphqlResult.errors).toBeUndefined(); + + const graphqlMovies: { id: string; time: string }[] = (graphqlResult.data as any)[Movie.plural]; + expect(graphqlMovies).toBeDefined(); + + /* eslint-disable jest/no-conditional-expect */ + if (filter === "LT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(pastId); + expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + } + + if (filter === "LTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(pastId); + expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + + expect(graphqlMovies[1]?.id).toBe(presentId); + expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); + } + + if (filter === "GT") { + expect(graphqlMovies).toHaveLength(1); + expect(graphqlMovies[0]?.id).toBe(futureId); + expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedFuture); + } + + if (filter === "GTE") { + expect(graphqlMovies).toHaveLength(2); + expect(graphqlMovies[0]?.id).toBe(presentId); + expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPresent); + + expect(graphqlMovies[1]?.id).toBe(futureId); + expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedFuture); + } + /* eslint-enable jest/no-conditional-expect */ + }); +}); diff --git a/packages/graphql/tests/integration/types/bigint.int.test.ts b/packages/graphql/tests/integration/types/bigint.int.test.ts index 159c5a9ab4..539319eb66 100644 --- a/packages/graphql/tests/integration/types/bigint.int.test.ts +++ b/packages/graphql/tests/integration/types/bigint.int.test.ts @@ -185,7 +185,7 @@ describe("BigInt", () => { const query = ` query { - ${File.plural}(where: { name_EQ: "${name}" }) { + ${File.plural}(where: { name: {equals: "${name}" } }) { name size } diff --git a/packages/graphql/tests/integration/types/date.int.test.ts b/packages/graphql/tests/integration/types/date.int.test.ts index 48f357ae64..30adc714ee 100644 --- a/packages/graphql/tests/integration/types/date.int.test.ts +++ b/packages/graphql/tests/integration/types/date.int.test.ts @@ -143,7 +143,7 @@ describe("Date", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}(where: { date_EQ: "${date.toISOString()}" }) { + ${Movie.plural}(where: { date: { equals: "${date.toISOString()}" }}) { date } } diff --git a/packages/graphql/tests/integration/types/datetime.int.test.ts b/packages/graphql/tests/integration/types/datetime.int.test.ts index fb9ef99f0d..fdb65b9549 100644 --- a/packages/graphql/tests/integration/types/datetime.int.test.ts +++ b/packages/graphql/tests/integration/types/datetime.int.test.ts @@ -143,7 +143,7 @@ describe("DateTime", () => { const query = ` query { - ${Movie.plural}(where: { datetime_EQ: "${date.toISOString()}" }) { + ${Movie.plural}(where: { datetime: {equals: "${date.toISOString()}" } }) { datetime } } @@ -179,7 +179,7 @@ describe("DateTime", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}(where: { name_EQ: "${Movie.name}" }) { + ${Movie.plural}(where: { name: {equals: "${Movie.name}" }}) { datetime } } diff --git a/packages/graphql/tests/integration/types/duration.int.test.ts b/packages/graphql/tests/integration/types/duration.int.test.ts index c386887771..216fce3278 100644 --- a/packages/graphql/tests/integration/types/duration.int.test.ts +++ b/packages/graphql/tests/integration/types/duration.int.test.ts @@ -255,7 +255,7 @@ describe("Duration", () => { const query = /* GraphQL */ ` query ($id: ID!, $duration: Duration!) { - ${Movie.plural}(where: { id_EQ: $id, duration_EQ: $duration }) { + ${Movie.plural}(where: { id: {equals: $id }, duration: { equals: $duration } }) { id duration } @@ -274,7 +274,7 @@ describe("Duration", () => { expect(parseDuration(graphqlMovie.duration)).toStrictEqual(parsedDuration); }); - test.each(["LT", "LTE", "GT", "GTE"])( + test.each(["lessThan", "lessThanEquals", "greaterThan", "greaterThanEquals"])( "should filter based on duration comparison, for filter: %s", async (filter) => { const typeDefs = ` @@ -342,7 +342,7 @@ describe("Duration", () => { const graphqlResult = await testHelper.executeGraphQL(query, { variableValues: { - where: { id_IN: [longId, mediumId, shortId], [`duration_${filter}`]: medium }, + where: { id: { in: [longId, mediumId, shortId] }, duration: { [filter]: medium } }, }, }); diff --git a/packages/graphql/tests/integration/types/float.int.test.ts b/packages/graphql/tests/integration/types/float.int.test.ts index 51781d7b80..219436e06f 100644 --- a/packages/graphql/tests/integration/types/float.int.test.ts +++ b/packages/graphql/tests/integration/types/float.int.test.ts @@ -225,7 +225,7 @@ describe("Float", () => { const query = /* GraphQL */ ` query { - ${Movie.plural}(where: { id_EQ: "${id}" }){ + ${Movie.plural}(where: { id: { equals: "${id}" } }){ fakeFloat } } diff --git a/packages/graphql/tests/integration/types/localdatetime.int.test.ts b/packages/graphql/tests/integration/types/localdatetime.int.test.ts index ac408a71a3..7b14679cbf 100644 --- a/packages/graphql/tests/integration/types/localdatetime.int.test.ts +++ b/packages/graphql/tests/integration/types/localdatetime.int.test.ts @@ -224,7 +224,7 @@ describe("LocalDateTime", () => { const query = /* GraphQL */ ` query ($localDT: LocalDateTime!) { - ${Movie.plural}(where: { localDT_EQ: $localDT }) { + ${Movie.plural}(where: { localDT: { equals: $localDT } }) { id localDT } @@ -242,7 +242,7 @@ describe("LocalDateTime", () => { expect(graphqlMovie.id).toEqual(id); expect(parseLocalDateTime(graphqlMovie.localDT)).toStrictEqual(parsedLocalDateTime); }); - test.each(["LT", "LTE", "GT", "GTE"])( + test.each(["lessThan", "lessThanEquals", "greaterThan", "greaterThanEquals"])( "should filter based on localDT comparison, for filter %s", async (filter) => { const futureId = generate({ readable: false }); @@ -311,7 +311,7 @@ describe("LocalDateTime", () => { const graphqlResult = await testHelper.executeGraphQL(query, { variableValues: { - where: { id_IN: [futureId, presentId, pastId], [`localDT_${filter}`]: present }, + where: { id: { in: [futureId, presentId, pastId] }, localDT: { [filter]: present } }, }, }); @@ -321,13 +321,13 @@ describe("LocalDateTime", () => { expect(graphqlMovies).toBeDefined(); /* eslint-disable jest/no-conditional-expect */ - if (filter === "LT") { + if (filter === "lessThan") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(pastId); expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedPast); } - if (filter === "LTE") { + if (filter === "lessThanEquals") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(pastId); expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedPast); @@ -336,13 +336,13 @@ describe("LocalDateTime", () => { expect(parseLocalDateTime(graphqlMovies[1]?.localDT)).toStrictEqual(parsedPresent); } - if (filter === "GT") { + if (filter === "greaterThan") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(futureId); expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedFuture); } - if (filter === "GTE") { + if (filter === "greaterThanEquals") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(presentId); expect(parseLocalDateTime(graphqlMovies[0]?.localDT)).toStrictEqual(parsedPresent); diff --git a/packages/graphql/tests/integration/types/localtime.int.test.ts b/packages/graphql/tests/integration/types/localtime.int.test.ts index b89a58f17f..7ac58a3ac2 100644 --- a/packages/graphql/tests/integration/types/localtime.int.test.ts +++ b/packages/graphql/tests/integration/types/localtime.int.test.ts @@ -222,7 +222,7 @@ describe("LocalTime", () => { const query = /* GraphQL */ ` query ($time: LocalTime!) { - ${Movie.plural}(where: { time_EQ: $time }) { + ${Movie.plural}(where: { time: { equals: $time } }) { id time } @@ -240,7 +240,7 @@ describe("LocalTime", () => { expect(graphqlMovie.id).toEqual(id); expect(parseLocalTime(graphqlMovie.time)).toStrictEqual(parsedTime); }); - test.each(["LT", "LTE", "GT", "GTE"])( + test.each(["lessThan", "lessThanEquals", "greaterThan", "greaterThanEquals"])( "should filter based on time comparison, for filter %s", async (filter) => { const futureId = generate({ readable: false }); @@ -300,7 +300,7 @@ describe("LocalTime", () => { const graphqlResult = await testHelper.executeGraphQL(query, { variableValues: { - where: { id_IN: [futureId, presentId, pastId], [`time_${filter}`]: present }, + where: { id: { in: [futureId, presentId, pastId] }, time: { [filter]: present } }, }, }); @@ -310,13 +310,13 @@ describe("LocalTime", () => { expect(graphqlMovies).toBeDefined(); /* eslint-disable jest/no-conditional-expect */ - if (filter === "LT") { + if (filter === "lessThan") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(pastId); expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); } - if (filter === "LTE") { + if (filter === "lessThanEquals") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(pastId); expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); @@ -325,13 +325,13 @@ describe("LocalTime", () => { expect(parseLocalTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); } - if (filter === "GT") { + if (filter === "greaterThan") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(futureId); expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedFuture); } - if (filter === "GTE") { + if (filter === "greaterThanEquals") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(presentId); expect(parseLocalTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPresent); diff --git a/packages/graphql/tests/integration/types/point-cartesian.int.test.ts b/packages/graphql/tests/integration/types/point-cartesian.int.test.ts index 5814de30ba..050b048cc6 100644 --- a/packages/graphql/tests/integration/types/point-cartesian.int.test.ts +++ b/packages/graphql/tests/integration/types/point-cartesian.int.test.ts @@ -155,7 +155,7 @@ describe("CartesianPoint", () => { const update = /* GraphQL */ ` mutation UpdateParts($serial: String!, $x: Float!, $y: Float!) { - ${Part.operations.update}(where: { serial_EQ: $serial }, update: { location_SET: { x: $x, y: $y } }) { + ${Part.operations.update}(where: { serial: {equals: $serial } }, update: { location_SET: { x: $x, y: $y } }) { ${Part.plural} { serial location { @@ -218,7 +218,7 @@ describe("CartesianPoint", () => { const update = /* GraphQL */ ` mutation UpdateParts($serial: String!, $x: Float!, $y: Float!, $z: Float!) { - ${Part.operations.update}(where: { serial_EQ: $serial }, update: { location_SET: { x: $x, y: $y, z: $z } }) { + ${Part.operations.update}(where: { serial: { equals: $serial } }, update: { location_SET: { x: $x, y: $y, z: $z } }) { ${Part.plural} { serial location { @@ -279,7 +279,7 @@ describe("CartesianPoint", () => { const partsQuery = /* GraphQL */ ` query Parts($serial: String!) { - ${Part.plural}(where: { serial_EQ: $serial }) { + ${Part.plural}(where: { serial: {equals: $serial} }) { serial location { x @@ -330,7 +330,7 @@ describe("CartesianPoint", () => { const partsQuery = /* GraphQL */ ` query Parts($serial: String!) { - ${Part.plural}(where: { serial_EQ: $serial }) { + ${Part.plural}(where: { serial: {equals: $serial } }) { serial location { x diff --git a/packages/graphql/tests/integration/types/point.int.test.ts b/packages/graphql/tests/integration/types/point.int.test.ts index 16dec61048..eb1674c4db 100644 --- a/packages/graphql/tests/integration/types/point.int.test.ts +++ b/packages/graphql/tests/integration/types/point.int.test.ts @@ -331,7 +331,7 @@ describe("Point", () => { // Test equality const photographsEqualsQuery = /* GraphQL */ ` query Photographs($longitude: Float!, $latitude: Float!) { - ${Photograph.plural}(where: { location_EQ: { longitude: $longitude, latitude: $latitude } }) { + ${Photograph.plural}(where: { location: { equals: { longitude: $longitude, latitude: $latitude } } }) { id size location { @@ -363,7 +363,7 @@ describe("Point", () => { // Test IN functionality const photographsInQuery = /* GraphQL */ ` query Photographs($locations: [PointInput!]) { - ${Photograph.plural}(where: { location_IN: $locations }) { + ${Photograph.plural}(where: { location: {in: $locations } }) { id size location { @@ -404,7 +404,7 @@ describe("Point", () => { const photographsLessThanQuery = /* GraphQL */ ` query Photographs($longitude: Float!, $latitude: Float!) { ${Photograph.plural}( - where: { location_LT: { point: { longitude: $longitude, latitude: $latitude }, distance: 1000000 } } + where: { location: { distance: { lessThan: { point: { longitude: $longitude, latitude: $latitude }, distance: 1000000 } } } } ) { id size @@ -438,7 +438,7 @@ describe("Point", () => { const photographsGreaterThanQuery = /* GraphQL */ ` query Photographs($longitude: Float!, $latitude: Float!) { ${Photograph.plural}( - where: { location_GT: { point: { longitude: $longitude, latitude: $latitude }, distance: 1 } } + where: { location: { distance: { greaterThan: { point: { longitude: $longitude, latitude: $latitude }, distance: 1 } } } } ) { id size @@ -494,7 +494,7 @@ describe("Point", () => { const photographsQuery = /* GraphQL */ ` query Photographs($longitude: Float!, $latitude: Float!, $height: Float) { - ${Photograph.plural}(where: { location_EQ: { longitude: $longitude, latitude: $latitude, height: $height } }) { + ${Photograph.plural}(where: { location: { equals: { longitude: $longitude, latitude: $latitude, height: $height } } }) { id size location { diff --git a/packages/graphql/tests/integration/types/points-cartesian.int.test.ts b/packages/graphql/tests/integration/types/points-cartesian.int.test.ts index b33157d50c..630d9d6fc5 100644 --- a/packages/graphql/tests/integration/types/points-cartesian.int.test.ts +++ b/packages/graphql/tests/integration/types/points-cartesian.int.test.ts @@ -264,7 +264,7 @@ describe("[CartesianPoint]", () => { const update = /* GraphQL */ ` mutation UpdateParts($id: String!, $locations: [CartesianPointInput!]) { - ${Part.operations.update}(where: { id_EQ: $id }, update: { locations_SET: $locations }) { + ${Part.operations.update}(where: { id: { equals: $id } }, update: { locations_SET: $locations }) { ${Part.plural} { id locations { @@ -328,7 +328,7 @@ describe("[CartesianPoint]", () => { const partsQuery = /* GraphQL */ ` query Parts($id: String!) { - ${Part.plural}(where: { id_EQ: $id }) { + ${Part.plural}(where: { id: { equals: $id } }) { id locations { y @@ -373,7 +373,7 @@ describe("[CartesianPoint]", () => { const partsQuery = /* GraphQL */ ` query Parts($id: String!) { - ${Part.plural}(where: { id_EQ: $id }) { + ${Part.plural}(where: { id: { equals: $id } }) { id locations { y diff --git a/packages/graphql/tests/integration/types/points.int.test.ts b/packages/graphql/tests/integration/types/points.int.test.ts index b95d1502ae..b4fd1e852b 100644 --- a/packages/graphql/tests/integration/types/points.int.test.ts +++ b/packages/graphql/tests/integration/types/points.int.test.ts @@ -334,7 +334,7 @@ describe("[Point]", () => { // Test for equality const routesQuery = /* GraphQL */ ` query Routes($waypoints: [PointInput!]) { - ${Route.plural}(where: { waypoints_EQ: $waypoints }) { + ${Route.plural}(where: { waypoints: { equals: $waypoints } }) { id waypoints { latitude @@ -357,7 +357,7 @@ describe("[Point]", () => { // Test INCLUDES functionality const routesIncludesQuery = /* GraphQL */ ` query RoutesIncludes($waypoint: PointInput) { - ${Route.plural}(where: { waypoints_INCLUDES: $waypoint }) { + ${Route.plural}(where: { waypoints: {includes: $waypoint } }) { id waypoints { latitude @@ -404,7 +404,7 @@ describe("[Point]", () => { const routesQuery = /* GraphQL */ ` query Routes($id: String!) { - ${Route.plural}(where: { id_EQ: $id }) { + ${Route.plural}(where: { id: { equals: $id } }) { id waypoints { latitude diff --git a/packages/graphql/tests/integration/types/time.int.test.ts b/packages/graphql/tests/integration/types/time.int.test.ts index c7bf472332..aeb6cbd9ef 100644 --- a/packages/graphql/tests/integration/types/time.int.test.ts +++ b/packages/graphql/tests/integration/types/time.int.test.ts @@ -242,7 +242,7 @@ describe("Time", () => { const query = /* GraphQL */ ` query ($time: Time!) { - ${Movie.plural}(where: { time_EQ: $time }) { + ${Movie.plural}(where: { time: { equals: $time } }) { id time } @@ -259,7 +259,7 @@ describe("Time", () => { expect(parseTime(graphqlMovie.time)).toStrictEqual(parsedTime); }); - test.each(["LT", "LTE", "GT", "GTE"])( + test.each(["lessThan", "lessThanEquals", "greaterThan", "greaterThanEquals"])( "should filter based on time comparison for filter: %s", async (filter) => { const typeDefs = /* GraphQL */ ` @@ -334,7 +334,7 @@ describe("Time", () => { const graphqlResult = await testHelper.executeGraphQL(query, { variableValues: { - where: { id_IN: [futureId, presentId, pastId], [`time_${filter}`]: present }, + where: { id: { in: [futureId, presentId, pastId] }, time: { [filter]: present } }, }, });