From 14c6397a04a3d23fc504d7b6aa92b21f29233b0c Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Mon, 6 Jan 2025 14:52:45 +0000 Subject: [PATCH 1/4] Consistent creation of zoned temporal values --- .changeset/good-sheep-refuse.md | 5 + .../graphql/src/graphql/scalars/DateTime.ts | 14 +- packages/graphql/src/graphql/scalars/Time.ts | 22 +-- .../src/translate/create-create-and-params.ts | 17 +++ .../AggregationDateTimePropertyFilter.ts | 50 +++++++ .../AggregationDurationPropertyFilter.ts | 2 +- .../AggregationTimePropertyFilter.ts | 50 +++++++ .../filters/property-filters/CypherFilter.ts | 20 +++ .../property-filters/DateTimeFilter.ts | 33 +++++ .../filters/property-filters/TimeFilter.ts | 33 +++++ .../utils/create-date-time-operation.ts | 71 ++++++++++ .../filters/utils/create-time-operation.ts | 71 ++++++++++ .../ast/input-fields/PropertyInputField.ts | 19 +++ .../queryAST/factory/FilterFactory.ts | 42 ++++++ .../utils/get-mutation-field-statements.ts | 20 +++ .../populatedBy-node-properties.int.test.ts | 4 +- ...atedBy-relationship-properties.int.test.ts | 2 +- .../aggregations/where/edge/datetime.test.ts | 130 +++--------------- .../tck/aggregations/where/edge/time.test.ts | 100 +++----------- .../aggregations/where/node/datetime.test.ts | 130 +++--------------- .../tck/aggregations/where/node/time.test.ts | 100 +++----------- .../filtering/relationship/temporal.test.ts | 13 +- .../cypher-filtering-temporal.test.ts | 13 +- packages/graphql/tests/tck/issues/360.test.ts | 52 ++----- .../graphql/tests/tck/types/datetime.test.ts | 39 +----- packages/graphql/tests/tck/types/time.test.ts | 50 ++----- 26 files changed, 564 insertions(+), 538 deletions(-) create mode 100644 .changeset/good-sheep-refuse.md create mode 100644 packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDateTimePropertyFilter.ts create mode 100644 packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationTimePropertyFilter.ts create mode 100644 packages/graphql/src/translate/queryAST/ast/filters/property-filters/DateTimeFilter.ts create mode 100644 packages/graphql/src/translate/queryAST/ast/filters/property-filters/TimeFilter.ts create mode 100644 packages/graphql/src/translate/queryAST/ast/filters/utils/create-date-time-operation.ts create mode 100644 packages/graphql/src/translate/queryAST/ast/filters/utils/create-time-operation.ts diff --git a/.changeset/good-sheep-refuse.md b/.changeset/good-sheep-refuse.md new file mode 100644 index 0000000000..a2359ba828 --- /dev/null +++ b/.changeset/good-sheep-refuse.md @@ -0,0 +1,5 @@ +--- +"@neo4j/graphql": major +--- + +`DateTime` and `Time` values are now converted from strings into temporal types in the generated Cypher instead of in server code using the driver. This could result in different values when the database is in a different timezone to the GraphQL server. diff --git a/packages/graphql/src/graphql/scalars/DateTime.ts b/packages/graphql/src/graphql/scalars/DateTime.ts index 30b3311235..357ff7db14 100644 --- a/packages/graphql/src/graphql/scalars/DateTime.ts +++ b/packages/graphql/src/graphql/scalars/DateTime.ts @@ -19,7 +19,8 @@ import type { ValueNode } from "graphql"; import { GraphQLError, GraphQLScalarType, Kind } from "graphql"; -import neo4j, { isDateTime } from "neo4j-driver"; +import type neo4j from "neo4j-driver"; +import { isDateTime } from "neo4j-driver"; export const GraphQLDateTime = new GraphQLScalarType({ name: "DateTime", @@ -43,13 +44,14 @@ export const GraphQLDateTime = new GraphQLScalarType({ throw new GraphQLError(`DateTime cannot represent non temporal value: ${inputValue}`); } - return neo4j.types.DateTime.fromStandardDate(date); - } - - if (isDateTime(inputValue)) { return inputValue; + // return neo4j.types.DateTime.fromStandardDate(date); } + // if (isDateTime(inputValue)) { + // return inputValue; + // } + throw new GraphQLError(`DateTime cannot represent non string value: ${inputValue}`); }, parseLiteral(ast: ValueNode) { @@ -57,6 +59,6 @@ export const GraphQLDateTime = new GraphQLScalarType({ throw new GraphQLError("DateTime cannot represent non string value."); } - return neo4j.types.DateTime.fromStandardDate(new Date(ast.value)); + return ast.value; }, }); diff --git a/packages/graphql/src/graphql/scalars/Time.ts b/packages/graphql/src/graphql/scalars/Time.ts index 6f68e6bc49..a5ef1dfcba 100644 --- a/packages/graphql/src/graphql/scalars/Time.ts +++ b/packages/graphql/src/graphql/scalars/Time.ts @@ -19,7 +19,7 @@ import type { ValueNode } from "graphql"; import { GraphQLError, GraphQLScalarType, Kind } from "graphql"; -import neo4j, { isTime } from "neo4j-driver"; +import neo4j from "neo4j-driver"; export const TIME_REGEX = /^(?[01]\d|2[0-3]):(?[0-5]\d)(:(?[0-5]\d)(\.(?\d{1}(?:\d{0,8})))?((?:[Zz])|((?[-|+])(?[01]\d|2[0-3]):(?[0-5]\d)))?)?$/; @@ -78,15 +78,15 @@ export const parseTime = (value: unknown): ParsedTime => { }; }; -const parse = (value: unknown) => { - if (isTime(value)) { - return value; - } +// const parse = (value: unknown) => { +// if (isTime(value)) { +// return value; +// } - const { hour, minute, second, nanosecond, timeZoneOffsetSeconds } = parseTime(value); +// const { hour, minute, second, nanosecond, timeZoneOffsetSeconds } = parseTime(value); - return new neo4j.types.Time(hour, minute, second, nanosecond, timeZoneOffsetSeconds); -}; +// return new neo4j.types.Time(hour, minute, second, nanosecond, timeZoneOffsetSeconds); +// }; export const GraphQLTime = new GraphQLScalarType({ name: "Time", @@ -105,12 +105,14 @@ export const GraphQLTime = new GraphQLScalarType({ return stringifiedValue; }, parseValue: (value: unknown) => { - return parse(value); + return value as string; + // return parse(value); }, parseLiteral: (ast: ValueNode) => { if (ast.kind !== Kind.STRING) { throw new GraphQLError(`Only strings can be validated as Time, but received: ${ast.kind}`); } - return parse(ast.value); + return ast.value; + // return parse(ast.value); }, }); diff --git a/packages/graphql/src/translate/create-create-and-params.ts b/packages/graphql/src/translate/create-create-and-params.ts index 96cdca27bb..1f02e84f61 100644 --- a/packages/graphql/src/translate/create-create-and-params.ts +++ b/packages/graphql/src/translate/create-create-and-params.ts @@ -80,6 +80,7 @@ function createCreateAndParams({ const relationField = node.relationFields.find((x) => key === x.fieldName); const primitiveField = node.primitiveFields.find((x) => key === x.fieldName); const pointField = node.pointFields.find((x) => key === x.fieldName); + const temporalField = node.temporalFields.find((x) => key === x.fieldName); const dbFieldName = mapToDbProperty(node, key); if (primitiveField) { @@ -273,6 +274,22 @@ function createCreateAndParams({ return res; } + if (temporalField && ["DateTime", "Time"].includes(temporalField.typeMeta.name)) { + if (temporalField.typeMeta.array) { + res.creates.push( + `SET ${varName}.${dbFieldName} = [t in $${varNameKey} | ${temporalField.typeMeta.name.toLowerCase()}(t)]` + ); + } else { + res.creates.push( + `SET ${varName}.${dbFieldName} = ${temporalField.typeMeta.name.toLowerCase()}($${varNameKey})` + ); + } + + res.params[varNameKey] = value; + + return res; + } + res.creates.push(`SET ${varName}.${dbFieldName} = $${varNameKey}`); res.params[varNameKey] = value; diff --git a/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDateTimePropertyFilter.ts b/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDateTimePropertyFilter.ts new file mode 100644 index 0000000000..bd97e336c0 --- /dev/null +++ b/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDateTimePropertyFilter.ts @@ -0,0 +1,50 @@ +/* + * 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 Cypher from "@neo4j/cypher-builder"; +import type { AggregationLogicalOperator } from "../../../factory/parsers/parse-where-field"; +import { AggregationPropertyFilter } from "./AggregationPropertyFilter"; + +export class AggregationDateTimeFilter extends AggregationPropertyFilter { + protected getOperation(expr: Cypher.Expr): Cypher.ComparisonOp { + return this.createDateTimeOperation({ + operator: this.logicalOperator, + property: expr, + param: new Cypher.Param(this.comparisonValue), + }); + } + + private createDateTimeOperation({ + operator, + property, + param, + }: { + operator: AggregationLogicalOperator; + property: Cypher.Expr; + param: Cypher.Expr; + }) { + const variable = Cypher.datetime(param); + + return this.createBaseOperation({ + operator, + property, + param: variable, + }); + } +} diff --git a/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDurationPropertyFilter.ts b/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDurationPropertyFilter.ts index 8036adc709..a6d1059ad5 100644 --- a/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDurationPropertyFilter.ts +++ b/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationDurationPropertyFilter.ts @@ -18,8 +18,8 @@ */ import Cypher from "@neo4j/cypher-builder"; -import { AggregationPropertyFilter } from "./AggregationPropertyFilter"; import type { AggregationLogicalOperator } from "../../../factory/parsers/parse-where-field"; +import { AggregationPropertyFilter } from "./AggregationPropertyFilter"; export class AggregationDurationFilter extends AggregationPropertyFilter { protected getOperation(expr: Cypher.Expr): Cypher.ComparisonOp { diff --git a/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationTimePropertyFilter.ts b/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationTimePropertyFilter.ts new file mode 100644 index 0000000000..a37464df0f --- /dev/null +++ b/packages/graphql/src/translate/queryAST/ast/filters/aggregation/AggregationTimePropertyFilter.ts @@ -0,0 +1,50 @@ +/* + * 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 Cypher from "@neo4j/cypher-builder"; +import type { AggregationLogicalOperator } from "../../../factory/parsers/parse-where-field"; +import { AggregationPropertyFilter } from "./AggregationPropertyFilter"; + +export class AggregationTimeFilter extends AggregationPropertyFilter { + protected getOperation(expr: Cypher.Expr): Cypher.ComparisonOp { + return this.createTimeOperation({ + operator: this.logicalOperator, + property: expr, + param: new Cypher.Param(this.comparisonValue), + }); + } + + private createTimeOperation({ + operator, + property, + param, + }: { + operator: AggregationLogicalOperator; + property: Cypher.Expr; + param: Cypher.Expr; + }) { + const variable = Cypher.time(param); + + return this.createBaseOperation({ + operator, + property, + param: variable, + }); + } +} diff --git a/packages/graphql/src/translate/queryAST/ast/filters/property-filters/CypherFilter.ts b/packages/graphql/src/translate/queryAST/ast/filters/property-filters/CypherFilter.ts index 48f976b538..55d740d198 100644 --- a/packages/graphql/src/translate/queryAST/ast/filters/property-filters/CypherFilter.ts +++ b/packages/graphql/src/translate/queryAST/ast/filters/property-filters/CypherFilter.ts @@ -26,8 +26,10 @@ import type { CustomCypherSelection } from "../../selection/CustomCypherSelectio import type { FilterOperator } from "../Filter"; import { Filter } from "../Filter"; import { coalesceValueIfNeeded } from "../utils/coalesce-if-needed"; +import { createDateTimeOperation } from "../utils/create-date-time-operation"; import { createDurationOperation } from "../utils/create-duration-operation"; import { createPointOperation } from "../utils/create-point-operation"; +import { createTimeOperation } from "../utils/create-time-operation"; /** A property which comparison has already been parsed into a Param */ export class CypherFilter extends Filter { @@ -127,6 +129,24 @@ export class CypherFilter extends Filter { }); } + if (this.attribute.typeHelper.isDateTime()) { + return createDateTimeOperation({ + operator, + property: coalesceProperty, + param: this.comparisonValue, + attribute: this.attribute, + }); + } + + if (this.attribute.typeHelper.isTime()) { + return createTimeOperation({ + operator, + property: coalesceProperty, + param: this.comparisonValue, + attribute: this.attribute, + }); + } + return createComparisonOperation({ operator, property: coalesceProperty, param }); } } diff --git a/packages/graphql/src/translate/queryAST/ast/filters/property-filters/DateTimeFilter.ts b/packages/graphql/src/translate/queryAST/ast/filters/property-filters/DateTimeFilter.ts new file mode 100644 index 0000000000..0eb4c1d65c --- /dev/null +++ b/packages/graphql/src/translate/queryAST/ast/filters/property-filters/DateTimeFilter.ts @@ -0,0 +1,33 @@ +/* + * 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 Cypher from "@neo4j/cypher-builder"; +import { createDateTimeOperation } from "../utils/create-date-time-operation"; +import { PropertyFilter } from "./PropertyFilter"; + +export class DateTimeFilter extends PropertyFilter { + protected getOperation(prop: Cypher.Property): Cypher.ComparisonOp { + return createDateTimeOperation({ + operator: this.operator || "EQ", + property: prop, + param: new Cypher.Param(this.comparisonValue), + attribute: this.attribute, + }); + } +} diff --git a/packages/graphql/src/translate/queryAST/ast/filters/property-filters/TimeFilter.ts b/packages/graphql/src/translate/queryAST/ast/filters/property-filters/TimeFilter.ts new file mode 100644 index 0000000000..dbd48d96f7 --- /dev/null +++ b/packages/graphql/src/translate/queryAST/ast/filters/property-filters/TimeFilter.ts @@ -0,0 +1,33 @@ +/* + * 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 Cypher from "@neo4j/cypher-builder"; +import { createTimeOperation } from "../utils/create-time-operation"; +import { PropertyFilter } from "./PropertyFilter"; + +export class TimeFilter extends PropertyFilter { + protected getOperation(prop: Cypher.Property): Cypher.ComparisonOp { + return createTimeOperation({ + operator: this.operator || "EQ", + property: prop, + param: new Cypher.Param(this.comparisonValue), + attribute: this.attribute, + }); + } +} diff --git a/packages/graphql/src/translate/queryAST/ast/filters/utils/create-date-time-operation.ts b/packages/graphql/src/translate/queryAST/ast/filters/utils/create-date-time-operation.ts new file mode 100644 index 0000000000..338684781f --- /dev/null +++ b/packages/graphql/src/translate/queryAST/ast/filters/utils/create-date-time-operation.ts @@ -0,0 +1,71 @@ +/* + * 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 Cypher from "@neo4j/cypher-builder"; +import type { AttributeAdapter } from "../../../../../schema-model/attribute/model-adapters/AttributeAdapter"; +import type { FilterOperator } from "../Filter"; + +export function createDateTimeOperation({ + operator, + property, + param, + attribute, +}: { + operator: FilterOperator; + property: Cypher.Expr; + param: Cypher.Param | Cypher.Variable | Cypher.Property; + attribute: AttributeAdapter; +}): Cypher.ComparisonOp { + const datetime = Cypher.datetime(param); + + switch (operator) { + case "LT": + return Cypher.lt(property, datetime); + case "LTE": + return Cypher.lte(property, datetime); + case "GT": + return Cypher.gt(property, datetime); + case "GTE": + return Cypher.gte(property, datetime); + case "EQ": { + if (attribute.typeHelper.isList()) { + const dateTimeList = createDateTimeListComprehension(param); + return Cypher.eq(property, dateTimeList); + } + + return Cypher.eq(property, datetime); + } + case "IN": { + const dateTimeList = createDateTimeListComprehension(param); + return Cypher.in(property, dateTimeList); + } + case "INCLUDES": + return Cypher.in(datetime, property); + default: + throw new Error(`Invalid operator ${operator}`); + } +} + +function createDateTimeListComprehension( + param: Cypher.Param | Cypher.Variable | Cypher.Property +): Cypher.ListComprehension { + const comprehensionVar = new Cypher.Variable(); + const mapDateTime = Cypher.datetime(comprehensionVar); + return new Cypher.ListComprehension(comprehensionVar, param).map(mapDateTime); +} diff --git a/packages/graphql/src/translate/queryAST/ast/filters/utils/create-time-operation.ts b/packages/graphql/src/translate/queryAST/ast/filters/utils/create-time-operation.ts new file mode 100644 index 0000000000..ba811a4b85 --- /dev/null +++ b/packages/graphql/src/translate/queryAST/ast/filters/utils/create-time-operation.ts @@ -0,0 +1,71 @@ +/* + * 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 Cypher from "@neo4j/cypher-builder"; +import type { AttributeAdapter } from "../../../../../schema-model/attribute/model-adapters/AttributeAdapter"; +import type { FilterOperator } from "../Filter"; + +export function createTimeOperation({ + operator, + property, + param, + attribute, +}: { + operator: FilterOperator; + property: Cypher.Expr; + param: Cypher.Param | Cypher.Variable | Cypher.Property; + attribute: AttributeAdapter; +}): Cypher.ComparisonOp { + const time = Cypher.time(param); + + switch (operator) { + case "LT": + return Cypher.lt(property, time); + case "LTE": + return Cypher.lte(property, time); + case "GT": + return Cypher.gt(property, time); + case "GTE": + return Cypher.gte(property, time); + case "EQ": { + if (attribute.typeHelper.isList()) { + const timeList = createTimeListComprehension(param); + return Cypher.eq(property, timeList); + } + + return Cypher.eq(property, time); + } + case "IN": { + const timeList = createTimeListComprehension(param); + return Cypher.in(property, timeList); + } + case "INCLUDES": + return Cypher.in(time, property); + default: + throw new Error(`Invalid operator ${operator}`); + } +} + +function createTimeListComprehension( + param: Cypher.Param | Cypher.Variable | Cypher.Property +): Cypher.ListComprehension { + const comprehensionVar = new Cypher.Variable(); + const mapTime = Cypher.time(comprehensionVar); + return new Cypher.ListComprehension(comprehensionVar, param).map(mapTime); +} diff --git a/packages/graphql/src/translate/queryAST/ast/input-fields/PropertyInputField.ts b/packages/graphql/src/translate/queryAST/ast/input-fields/PropertyInputField.ts index a70c9d4a2e..2a40ca2518 100644 --- a/packages/graphql/src/translate/queryAST/ast/input-fields/PropertyInputField.ts +++ b/packages/graphql/src/translate/queryAST/ast/input-fields/PropertyInputField.ts @@ -78,6 +78,25 @@ export class PropertyInputField extends InputField { const mapPoint = Cypher.point(comprehensionVar); return new Cypher.ListComprehension(comprehensionVar, variable).map(mapPoint); } + + if (this.attribute.typeHelper.isDateTime()) { + if (!this.attribute.typeHelper.isList()) { + return Cypher.datetime(variable); + } + const comprehensionVar = new Cypher.Variable(); + const mapDateTime = Cypher.datetime(comprehensionVar); + return new Cypher.ListComprehension(comprehensionVar, variable).map(mapDateTime); + } + + if (this.attribute.typeHelper.isTime()) { + if (!this.attribute.typeHelper.isList()) { + return Cypher.time(variable); + } + const comprehensionVar = new Cypher.Variable(); + const mapTime = Cypher.time(comprehensionVar); + return new Cypher.ListComprehension(comprehensionVar, variable).map(mapTime); + } + return variable; } diff --git a/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts b/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts index 43e6cfa214..96e3d2842c 100644 --- a/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts +++ b/packages/graphql/src/translate/queryAST/factory/FilterFactory.ts @@ -35,14 +35,18 @@ import type { Filter, FilterOperator, RelationshipWhereOperator } from "../ast/f import { isRelationshipOperator } from "../ast/filters/Filter"; import { LogicalFilter } from "../ast/filters/LogicalFilter"; import { RelationshipFilter } from "../ast/filters/RelationshipFilter"; +import { AggregationDateTimeFilter } from "../ast/filters/aggregation/AggregationDateTimePropertyFilter"; import { AggregationDurationFilter } from "../ast/filters/aggregation/AggregationDurationPropertyFilter"; import { AggregationFilter } from "../ast/filters/aggregation/AggregationFilter"; import { AggregationPropertyFilter } from "../ast/filters/aggregation/AggregationPropertyFilter"; +import { AggregationTimeFilter } from "../ast/filters/aggregation/AggregationTimePropertyFilter"; import { CountFilter } from "../ast/filters/aggregation/CountFilter"; import { CypherFilter } from "../ast/filters/property-filters/CypherFilter"; +import { DateTimeFilter } from "../ast/filters/property-filters/DateTimeFilter"; import { DurationFilter } from "../ast/filters/property-filters/DurationFilter"; import { PointFilter } from "../ast/filters/property-filters/PointFilter"; import { PropertyFilter } from "../ast/filters/property-filters/PropertyFilter"; +import { TimeFilter } from "../ast/filters/property-filters/TimeFilter"; import { TypenameFilter } from "../ast/filters/property-filters/TypenameFilter"; import { CustomCypherSelection } from "../ast/selection/CustomCypherSelection"; import { getConcreteEntities } from "../utils/get-concrete-entities"; @@ -260,6 +264,24 @@ export class FilterFactory { attachedTo, }); } + if (attribute.typeHelper.isDateTime()) { + return new DateTimeFilter({ + attribute, + comparisonValue, + isNot, + operator: filterOperator, + attachedTo, + }); + } + if (attribute.typeHelper.isTime()) { + return new TimeFilter({ + attribute, + comparisonValue, + isNot, + operator: filterOperator, + attachedTo, + }); + } return new PropertyFilter({ attribute, @@ -729,6 +751,26 @@ export class FilterFactory { }); } + if (attr.typeHelper.isDateTime()) { + return new AggregationDateTimeFilter({ + attribute: attr, + comparisonValue: value, + logicalOperator: logicalOperator || "EQUAL", + aggregationOperator: aggregationOperator, + attachedTo, + }); + } + + if (attr.typeHelper.isTime()) { + return new AggregationTimeFilter({ + attribute: attr, + comparisonValue: value, + logicalOperator: logicalOperator || "EQUAL", + aggregationOperator: aggregationOperator, + attachedTo, + }); + } + return new AggregationPropertyFilter({ attribute: attr, relationship, diff --git a/packages/graphql/src/translate/utils/get-mutation-field-statements.ts b/packages/graphql/src/translate/utils/get-mutation-field-statements.ts index e2f2355a76..612aaa5330 100644 --- a/packages/graphql/src/translate/utils/get-mutation-field-statements.ts +++ b/packages/graphql/src/translate/utils/get-mutation-field-statements.ts @@ -55,12 +55,23 @@ export function getMutationFieldStatements({ switch (operator) { case "SET": { const isSpatial = SPATIAL_TYPES.includes(settableField.typeMeta.name); + const isZonedTemporal = ["DateTime", "Time"].includes(settableField.typeMeta.name); if (isSpatial) { if (settableField.typeMeta.array) { strs.push(`SET ${varName}.${dbFieldName} = [p in $${param} | point(p)]`); } else { strs.push(`SET ${varName}.${dbFieldName} = point($${param})`); } + } else if (isZonedTemporal) { + if (settableField.typeMeta.array) { + strs.push( + `SET ${varName}.${dbFieldName} = [t in $${param} | ${settableField.typeMeta.name.toLowerCase()}(t)]` + ); + } else { + strs.push( + `SET ${varName}.${dbFieldName} = ${settableField.typeMeta.name.toLowerCase()}($${param})` + ); + } } else { strs.push(`SET ${varName}.${dbFieldName} = $${param}`); } @@ -81,11 +92,20 @@ export function getMutationFieldStatements({ } case "PUSH": { const pointArrayField = nodeOrRel.pointFields.find((x) => x.fieldName === settableField.fieldName); + const zonedTemporalArrayField = nodeOrRel.temporalFields.find( + (x) => + x.fieldName === settableField.fieldName && + ["DateTime", "Time"].includes(settableField.typeMeta.name) + ); if (pointArrayField) { strs.push( `SET ${varName}.${dbFieldName} = ${varName}.${dbFieldName} + [p in $${param} | point(p)]` ); + } else if (zonedTemporalArrayField) { + strs.push( + `SET ${varName}.${dbFieldName} = ${varName}.${dbFieldName} + [t in $${param} | ${settableField.typeMeta.name.toLowerCase()}(t)]` + ); } else { strs.push(`SET ${varName}.${dbFieldName} = ${varName}.${dbFieldName} + $${param}`); } diff --git a/packages/graphql/tests/integration/directives/populatedBy/populatedBy-node-properties.int.test.ts b/packages/graphql/tests/integration/directives/populatedBy/populatedBy-node-properties.int.test.ts index 8458e7b536..1df2cd5d7a 100644 --- a/packages/graphql/tests/integration/directives/populatedBy/populatedBy-node-properties.int.test.ts +++ b/packages/graphql/tests/integration/directives/populatedBy/populatedBy-node-properties.int.test.ts @@ -1747,7 +1747,7 @@ describe("@populatedBy directive - Node properties", () => { [testMovie.plural]: [ { id: movieId, - callback: `${date.toISOString().split("T")[1]?.split("Z")[0]}000000Z`, + callback: `${date.toISOString().split("T")[1]?.split("Z")[0]}Z`, }, ], }, @@ -1804,7 +1804,7 @@ describe("@populatedBy directive - Node properties", () => { [testMovie.plural]: [ { id: movieId, - callback: `${date.toISOString().split("T")[1]?.split("Z")[0]}000000Z`, + callback: `${date.toISOString().split("T")[1]?.split("Z")[0]}Z`, }, ], }, diff --git a/packages/graphql/tests/integration/directives/populatedBy/populatedBy-relationship-properties.int.test.ts b/packages/graphql/tests/integration/directives/populatedBy/populatedBy-relationship-properties.int.test.ts index 2080643540..6d0dfc8ae7 100644 --- a/packages/graphql/tests/integration/directives/populatedBy/populatedBy-relationship-properties.int.test.ts +++ b/packages/graphql/tests/integration/directives/populatedBy/populatedBy-relationship-properties.int.test.ts @@ -2439,7 +2439,7 @@ describe("@populatedBy directive - Relationship properties", () => { description: "@populatedBy - Time", type: "Time", callback: () => Promise.resolve(`${date.toISOString().split("T")[1]}`), - expectedValue: `${date.toISOString().split("T")[1]?.split("Z")[0]}000000Z`, + expectedValue: `${date.toISOString().split("T")[1]?.split("Z")[0]}Z`, }, { description: "@populatedBy - LocalDateTime", 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 cd9028effa..a6a34995c4 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/datetime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/datetime.test.ts @@ -62,7 +62,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someDateTime) = $param0 AS var2 + RETURN min(this0.someDateTime) = datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -71,16 +71,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -101,7 +92,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someDateTime) > $param0 AS var2 + RETURN min(this0.someDateTime) > datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -110,16 +101,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -140,7 +122,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someDateTime) >= $param0 AS var2 + RETURN min(this0.someDateTime) >= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -149,16 +131,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -179,7 +152,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someDateTime) < $param0 AS var2 + RETURN min(this0.someDateTime) < datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -188,16 +161,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -218,7 +182,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someDateTime) <= $param0 AS var2 + RETURN min(this0.someDateTime) <= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -227,16 +191,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -257,7 +212,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someDateTime) = $param0 AS var2 + RETURN max(this0.someDateTime) = datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -266,16 +221,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -296,7 +242,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someDateTime) > $param0 AS var2 + RETURN max(this0.someDateTime) > datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -305,16 +251,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -335,7 +272,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someDateTime) >= $param0 AS var2 + RETURN max(this0.someDateTime) >= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -344,16 +281,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -374,7 +302,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someDateTime) < $param0 AS var2 + RETURN max(this0.someDateTime) < datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -383,16 +311,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -413,7 +332,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someDateTime) <= $param0 AS var2 + RETURN max(this0.someDateTime) <= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -422,16 +341,7 @@ describe("Cypher Aggregations where edge with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); 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 c70659f3ea..7e947524aa 100644 --- a/packages/graphql/tests/tck/aggregations/where/edge/time.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/edge/time.test.ts @@ -62,7 +62,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someTime) = $param0 AS var2 + RETURN min(this0.someTime) = time($param0) AS var2 } WITH * WHERE var2 = true @@ -71,13 +71,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -98,7 +92,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someTime) > $param0 AS var2 + RETURN min(this0.someTime) > time($param0) AS var2 } WITH * WHERE var2 = true @@ -107,13 +101,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -134,7 +122,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someTime) >= $param0 AS var2 + RETURN min(this0.someTime) >= time($param0) AS var2 } WITH * WHERE var2 = true @@ -143,13 +131,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -170,7 +152,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someTime) < $param0 AS var2 + RETURN min(this0.someTime) < time($param0) AS var2 } WITH * WHERE var2 = true @@ -179,13 +161,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -206,7 +182,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this0.someTime) <= $param0 AS var2 + RETURN min(this0.someTime) <= time($param0) AS var2 } WITH * WHERE var2 = true @@ -215,13 +191,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -242,7 +212,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someTime) = $param0 AS var2 + RETURN max(this0.someTime) = time($param0) AS var2 } WITH * WHERE var2 = true @@ -251,13 +221,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -278,7 +242,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someTime) > $param0 AS var2 + RETURN max(this0.someTime) > time($param0) AS var2 } WITH * WHERE var2 = true @@ -287,13 +251,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -314,7 +272,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someTime) >= $param0 AS var2 + RETURN max(this0.someTime) >= time($param0) AS var2 } WITH * WHERE var2 = true @@ -323,13 +281,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -350,7 +302,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someTime) < $param0 AS var2 + RETURN max(this0.someTime) < time($param0) AS var2 } WITH * WHERE var2 = true @@ -359,13 +311,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -386,7 +332,7 @@ describe("Cypher Aggregations where edge with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this0.someTime) <= $param0 AS var2 + RETURN max(this0.someTime) <= time($param0) AS var2 } WITH * WHERE var2 = true @@ -395,13 +341,7 @@ describe("Cypher Aggregations where edge with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); 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 68c3553c38..5daa101b1b 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/datetime.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/datetime.test.ts @@ -58,7 +58,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someDateTime) = $param0 AS var2 + RETURN min(this1.someDateTime) = datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -67,16 +67,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -97,7 +88,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someDateTime) > $param0 AS var2 + RETURN min(this1.someDateTime) > datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -106,16 +97,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -136,7 +118,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someDateTime) >= $param0 AS var2 + RETURN min(this1.someDateTime) >= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -145,16 +127,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -175,7 +148,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someDateTime) < $param0 AS var2 + RETURN min(this1.someDateTime) < datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -184,16 +157,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -214,7 +178,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someDateTime) <= $param0 AS var2 + RETURN min(this1.someDateTime) <= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -223,16 +187,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -253,7 +208,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someDateTime) = $param0 AS var2 + RETURN max(this1.someDateTime) = datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -262,16 +217,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -292,7 +238,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someDateTime) > $param0 AS var2 + RETURN max(this1.someDateTime) > datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -301,16 +247,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -331,7 +268,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someDateTime) >= $param0 AS var2 + RETURN max(this1.someDateTime) >= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -340,16 +277,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -370,7 +298,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someDateTime) < $param0 AS var2 + RETURN max(this1.someDateTime) < datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -379,16 +307,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); @@ -409,7 +328,7 @@ describe("Cypher Aggregations where node with DateTime", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someDateTime) <= $param0 AS var2 + RETURN max(this1.someDateTime) <= datetime($param0) AS var2 } WITH * WHERE var2 = true @@ -418,16 +337,7 @@ describe("Cypher Aggregations where node with DateTime", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 9, - \\"day\\": 25, - \\"hour\\": 12, - \\"minute\\": 51, - \\"second\\": 24, - \\"nanosecond\\": 37000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-09-25T12:51:24.037Z\\" }" `); }); 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 8108c6d8da..4e25a48e78 100644 --- a/packages/graphql/tests/tck/aggregations/where/node/time.test.ts +++ b/packages/graphql/tests/tck/aggregations/where/node/time.test.ts @@ -58,7 +58,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someTime) = $param0 AS var2 + RETURN min(this1.someTime) = time($param0) AS var2 } WITH * WHERE var2 = true @@ -67,13 +67,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -94,7 +88,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someTime) > $param0 AS var2 + RETURN min(this1.someTime) > time($param0) AS var2 } WITH * WHERE var2 = true @@ -103,13 +97,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -130,7 +118,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someTime) >= $param0 AS var2 + RETURN min(this1.someTime) >= time($param0) AS var2 } WITH * WHERE var2 = true @@ -139,13 +127,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -166,7 +148,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someTime) < $param0 AS var2 + RETURN min(this1.someTime) < time($param0) AS var2 } WITH * WHERE var2 = true @@ -175,13 +157,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -202,7 +178,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN min(this1.someTime) <= $param0 AS var2 + RETURN min(this1.someTime) <= time($param0) AS var2 } WITH * WHERE var2 = true @@ -211,13 +187,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -238,7 +208,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someTime) = $param0 AS var2 + RETURN max(this1.someTime) = time($param0) AS var2 } WITH * WHERE var2 = true @@ -247,13 +217,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -274,7 +238,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someTime) > $param0 AS var2 + RETURN max(this1.someTime) > time($param0) AS var2 } WITH * WHERE var2 = true @@ -283,13 +247,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -310,7 +268,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someTime) >= $param0 AS var2 + RETURN max(this1.someTime) >= time($param0) AS var2 } WITH * WHERE var2 = true @@ -319,13 +277,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -346,7 +298,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someTime) < $param0 AS var2 + RETURN max(this1.someTime) < time($param0) AS var2 } WITH * WHERE var2 = true @@ -355,13 +307,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -382,7 +328,7 @@ describe("Cypher Aggregations where node with Time", () => { CALL { WITH this MATCH (this)<-[this0:LIKES]-(this1:User) - RETURN max(this1.someTime) <= $param0 AS var2 + RETURN max(this1.someTime) <= time($param0) AS var2 } WITH * WHERE var2 = true @@ -391,13 +337,7 @@ describe("Cypher Aggregations where node with Time", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); diff --git a/packages/graphql/tests/tck/connections/filtering/relationship/temporal.test.ts b/packages/graphql/tests/tck/connections/filtering/relationship/temporal.test.ts index 4cb178d361..f2791bf16f 100644 --- a/packages/graphql/tests/tck/connections/filtering/relationship/temporal.test.ts +++ b/packages/graphql/tests/tck/connections/filtering/relationship/temporal.test.ts @@ -76,7 +76,7 @@ describe("Cypher -> Connections -> Filtering -> Relationship -> Temporal", () => CALL { WITH this MATCH (this)<-[this0:ACTED_IN]-(this1:Actor) - WHERE (this0.startDate > $param0 AND this0.endDateTime < $param1) + WHERE (this0.startDate > $param0 AND this0.endDateTime < datetime($param1)) WITH collect({ node: this1, relationship: this0 }) AS edges WITH edges, size(edges) AS totalCount CALL { @@ -97,16 +97,7 @@ describe("Cypher -> Connections -> Filtering -> Relationship -> Temporal", () => \\"month\\": 1, \\"day\\": 1 }, - \\"param1\\": { - \\"year\\": 2010, - \\"month\\": 1, - \\"day\\": 1, - \\"hour\\": 0, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param1\\": \\"2010-01-01T00:00:00.000Z\\" }" `); }); diff --git a/packages/graphql/tests/tck/directives/cypher/filtering/cypher-filtering-temporal.test.ts b/packages/graphql/tests/tck/directives/cypher/filtering/cypher-filtering-temporal.test.ts index bdcccba31f..1d0d6732ed 100644 --- a/packages/graphql/tests/tck/directives/cypher/filtering/cypher-filtering-temporal.test.ts +++ b/packages/graphql/tests/tck/directives/cypher/filtering/cypher-filtering-temporal.test.ts @@ -63,7 +63,7 @@ describe("cypher directive filtering - Auth", () => { RETURN this0 AS var1 } WITH * - WHERE var1 > $param0 + WHERE var1 > datetime($param0) CALL { WITH this CALL { @@ -79,16 +79,7 @@ describe("cypher directive filtering - Auth", () => { expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2024, - \\"month\\": 9, - \\"day\\": 2, - \\"hour\\": 0, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2024-09-02T00:00:00Z\\" }" `); }); diff --git a/packages/graphql/tests/tck/issues/360.test.ts b/packages/graphql/tests/tck/issues/360.test.ts index 223db53082..5a8785eee3 100644 --- a/packages/graphql/tests/tck/issues/360.test.ts +++ b/packages/graphql/tests/tck/issues/360.test.ts @@ -58,32 +58,14 @@ describe("#360", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Event) - WHERE (this.start >= $param0 AND this.start <= $param1) + WHERE (this.start >= datetime($param0) AND this.start <= datetime($param1)) RETURN this { .activity, start: apoc.date.convertFormat(toString(this.start), \\"iso_zoned_date_time\\", \\"iso_offset_date_time\\") } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 7, - \\"day\\": 17, - \\"hour\\": 23, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - }, - \\"param1\\": { - \\"year\\": 2021, - \\"month\\": 7, - \\"day\\": 18, - \\"hour\\": 22, - \\"minute\\": 59, - \\"second\\": 59, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-07-18T00:00:00+0100\\", + \\"param1\\": \\"2021-07-18T23:59:59+0100\\" }" `); }); @@ -91,7 +73,9 @@ describe("#360", () => { test("Should exclude undefined members in OR", async () => { const query = /* GraphQL */ ` query ($rangeStart: DateTime, $rangeEnd: DateTime, $activity: String) { - events(where: { OR: [{ start_GTE: $rangeStart }, { start_LTE: $rangeEnd }, { activity_EQ: $activity }] }) { + events( + where: { OR: [{ start_GTE: $rangeStart }, { start_LTE: $rangeEnd }, { activity_EQ: $activity }] } + ) { start activity } @@ -104,32 +88,14 @@ describe("#360", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Event) - WHERE (this.start >= $param0 OR this.start <= $param1) + WHERE (this.start >= datetime($param0) OR this.start <= datetime($param1)) RETURN this { .activity, start: apoc.date.convertFormat(toString(this.start), \\"iso_zoned_date_time\\", \\"iso_offset_date_time\\") } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 2021, - \\"month\\": 7, - \\"day\\": 17, - \\"hour\\": 23, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - }, - \\"param1\\": { - \\"year\\": 2021, - \\"month\\": 7, - \\"day\\": 18, - \\"hour\\": 22, - \\"minute\\": 59, - \\"second\\": 59, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"2021-07-18T00:00:00+0100\\", + \\"param1\\": \\"2021-07-18T23:59:59+0100\\" }" `); }); diff --git a/packages/graphql/tests/tck/types/datetime.test.ts b/packages/graphql/tests/tck/types/datetime.test.ts index 8a31284608..9c0d02398a 100644 --- a/packages/graphql/tests/tck/types/datetime.test.ts +++ b/packages/graphql/tests/tck/types/datetime.test.ts @@ -50,22 +50,13 @@ describe("Cypher DateTime", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Movie) - WHERE this.datetime = $param0 + WHERE this.datetime = datetime($param0) RETURN this { datetime: apoc.date.convertFormat(toString(this.datetime), \\"iso_zoned_date_time\\", \\"iso_offset_date_time\\") } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"year\\": 1970, - \\"month\\": 1, - \\"day\\": 1, - \\"hour\\": 0, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"1970-01-01T00:00:00.000Z\\" }" `); }); @@ -89,7 +80,7 @@ describe("Cypher DateTime", () => { WITH create_var0 CREATE (create_this1:Movie) SET - create_this1.datetime = create_var0.datetime + create_this1.datetime = datetime(create_var0.datetime) RETURN create_this1 } RETURN collect(create_this1 { datetime: apoc.date.convertFormat(toString(create_this1.datetime), \\"iso_zoned_date_time\\", \\"iso_offset_date_time\\") }) AS data" @@ -99,16 +90,7 @@ describe("Cypher DateTime", () => { "{ \\"create_param0\\": [ { - \\"datetime\\": { - \\"year\\": 1970, - \\"month\\": 1, - \\"day\\": 1, - \\"hour\\": 0, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"datetime\\": \\"1970-01-01T00:00:00.000Z\\" } ] }" @@ -131,22 +113,13 @@ describe("Cypher DateTime", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Movie) - SET this.datetime = $this_update_datetime_SET + SET this.datetime = datetime($this_update_datetime_SET) RETURN collect(DISTINCT this { .id, datetime: apoc.date.convertFormat(toString(this.datetime), \\"iso_zoned_date_time\\", \\"iso_offset_date_time\\") }) AS data" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"this_update_datetime_SET\\": { - \\"year\\": 1970, - \\"month\\": 1, - \\"day\\": 1, - \\"hour\\": 0, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - }, + \\"this_update_datetime_SET\\": \\"1970-01-01T00:00:00.000Z\\", \\"resolvedCallbacks\\": {} }" `); diff --git a/packages/graphql/tests/tck/types/time.test.ts b/packages/graphql/tests/tck/types/time.test.ts index 1a9608a017..73b4d32ea8 100644 --- a/packages/graphql/tests/tck/types/time.test.ts +++ b/packages/graphql/tests/tck/types/time.test.ts @@ -50,19 +50,13 @@ describe("Cypher Time", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Movie) - WHERE this.time = $param0 + WHERE this.time = time($param0) RETURN this { .time } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 12, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"12:00:00\\" }" `); }); @@ -80,19 +74,13 @@ describe("Cypher Time", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Movie) - WHERE this.time >= $param0 + WHERE this.time >= time($param0) RETURN this { .time } AS this" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"param0\\": { - \\"hour\\": 13, - \\"minute\\": 45, - \\"second\\": 33, - \\"nanosecond\\": 250000000, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"param0\\": \\"13:45:33.250\\" }" `); }); @@ -116,7 +104,7 @@ describe("Cypher Time", () => { WITH create_var0 CREATE (create_this1:Movie) SET - create_this1.time = create_var0.time + create_this1.time = time(create_var0.time) RETURN create_this1 } RETURN collect(create_this1 { .time }) AS data" @@ -126,13 +114,7 @@ describe("Cypher Time", () => { "{ \\"create_param0\\": [ { - \\"time\\": { - \\"hour\\": 22, - \\"minute\\": 0, - \\"second\\": 15, - \\"nanosecond\\": 555000000, - \\"timeZoneOffsetSeconds\\": -3600 - } + \\"time\\": \\"22:00:15.555-01:00\\" } ] }" @@ -155,19 +137,13 @@ describe("Cypher Time", () => { expect(formatCypher(result.cypher)).toMatchInlineSnapshot(` "MATCH (this:Movie) - SET this.time = $this_update_time_SET + SET this.time = time($this_update_time_SET) RETURN collect(DISTINCT this { .id, .time }) AS data" `); expect(formatParams(result.params)).toMatchInlineSnapshot(` "{ - \\"this_update_time_SET\\": { - \\"hour\\": 9, - \\"minute\\": 24, - \\"second\\": 40, - \\"nanosecond\\": 845512000, - \\"timeZoneOffsetSeconds\\": 23400 - }, + \\"this_update_time_SET\\": \\"09:24:40.845512+06:30\\", \\"resolvedCallbacks\\": {} }" `); @@ -192,7 +168,7 @@ describe("Cypher Time", () => { WITH create_var0 CREATE (create_this1:Movie) SET - create_this1.time = create_var0.time + create_this1.time = time(create_var0.time) RETURN create_this1 } RETURN collect(create_this1 { .time }) AS data" @@ -202,13 +178,7 @@ describe("Cypher Time", () => { "{ \\"create_param0\\": [ { - \\"time\\": { - \\"hour\\": 22, - \\"minute\\": 0, - \\"second\\": 0, - \\"nanosecond\\": 0, - \\"timeZoneOffsetSeconds\\": 0 - } + \\"time\\": \\"22:00\\" } ] }" From 4264ac52b063e72103ac353d1d326d7d08a27f48 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Thu, 9 Jan 2025 13:42:35 +0000 Subject: [PATCH 2/4] Remove comments in scalars --- .../graphql/src/graphql/scalars/DateTime.ts | 5 -- packages/graphql/src/graphql/scalars/Time.ts | 60 ++----------------- 2 files changed, 4 insertions(+), 61 deletions(-) diff --git a/packages/graphql/src/graphql/scalars/DateTime.ts b/packages/graphql/src/graphql/scalars/DateTime.ts index 357ff7db14..e726d4c71c 100644 --- a/packages/graphql/src/graphql/scalars/DateTime.ts +++ b/packages/graphql/src/graphql/scalars/DateTime.ts @@ -45,13 +45,8 @@ export const GraphQLDateTime = new GraphQLScalarType({ } return inputValue; - // return neo4j.types.DateTime.fromStandardDate(date); } - // if (isDateTime(inputValue)) { - // return inputValue; - // } - throw new GraphQLError(`DateTime cannot represent non string value: ${inputValue}`); }, parseLiteral(ast: ValueNode) { diff --git a/packages/graphql/src/graphql/scalars/Time.ts b/packages/graphql/src/graphql/scalars/Time.ts index a5ef1dfcba..9d2eeeeb49 100644 --- a/packages/graphql/src/graphql/scalars/Time.ts +++ b/packages/graphql/src/graphql/scalars/Time.ts @@ -24,25 +24,7 @@ import neo4j from "neo4j-driver"; export const TIME_REGEX = /^(?[01]\d|2[0-3]):(?[0-5]\d)(:(?[0-5]\d)(\.(?\d{1}(?:\d{0,8})))?((?:[Zz])|((?[-|+])(?[01]\d|2[0-3]):(?[0-5]\d)))?)?$/; -type TimeRegexMatchGroups = { - hour: string; - minute: string; - second: string; - fraction: string; - offsetDirection: string; - offsetHour: string; - offsetMinute: string; -}; - -type ParsedTime = { - hour: number; - minute: number; - second: number; - nanosecond: number; - timeZoneOffsetSeconds: number; -}; - -export const parseTime = (value: unknown): ParsedTime => { +export const validateTime = (value: unknown): string => { if (typeof value !== "string") { throw new TypeError(`Value must be of type string: ${value}`); } @@ -53,41 +35,9 @@ export const parseTime = (value: unknown): ParsedTime => { throw new TypeError(`Value must be formatted as Time: ${value}`); } - const { hour, minute, second, fraction, offsetDirection, offsetHour, offsetMinute } = - match.groups as TimeRegexMatchGroups; - // Calculate the number of nanoseconds by padding the fraction of seconds with zeroes to nine digits - let nanosecond = 0; - if (fraction) { - nanosecond = +`${fraction}000000000`.substring(0, 9); - } - - // Calculate the timeZoneOffsetSeconds by calculating the offset in seconds with the appropriate sign - let timeZoneOffsetSeconds = 0; - if (offsetDirection && offsetHour && offsetMinute) { - const offsetInMinutes = +offsetMinute + +offsetHour * 60; - const offsetInSeconds = offsetInMinutes * 60; - timeZoneOffsetSeconds = +`${offsetDirection}${offsetInSeconds}`; - } - - return { - hour: +hour, - minute: +minute, - second: +(second || 0), - nanosecond, - timeZoneOffsetSeconds, - }; + return value; }; -// const parse = (value: unknown) => { -// if (isTime(value)) { -// return value; -// } - -// const { hour, minute, second, nanosecond, timeZoneOffsetSeconds } = parseTime(value); - -// return new neo4j.types.Time(hour, minute, second, nanosecond, timeZoneOffsetSeconds); -// }; - export const GraphQLTime = new GraphQLScalarType({ name: "Time", description: "A time, represented as an RFC3339 time string", @@ -105,14 +55,12 @@ export const GraphQLTime = new GraphQLScalarType({ return stringifiedValue; }, parseValue: (value: unknown) => { - return value as string; - // return parse(value); + return validateTime(value); }, parseLiteral: (ast: ValueNode) => { if (ast.kind !== Kind.STRING) { throw new GraphQLError(`Only strings can be validated as Time, but received: ${ast.kind}`); } - return ast.value; - // return parse(ast.value); + return validateTime(ast.value); }, }); From 0641b6274be0ff09027435c5ed913ef296c812ae Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Thu, 9 Jan 2025 14:08:05 +0000 Subject: [PATCH 3/4] Fix tests --- .../graphql/src/graphql/scalars/Time.test.ts | 51 ------ .../custom-rules/directives/default.ts | 4 +- .../types-time-filter-deprecated.int.test.ts | 72 +++----- .../tests/integration/types/time.int.test.ts | 172 +++++++----------- 4 files changed, 91 insertions(+), 208 deletions(-) delete mode 100644 packages/graphql/src/graphql/scalars/Time.test.ts diff --git a/packages/graphql/src/graphql/scalars/Time.test.ts b/packages/graphql/src/graphql/scalars/Time.test.ts deleted file mode 100644 index ea94f95e40..0000000000 --- a/packages/graphql/src/graphql/scalars/Time.test.ts +++ /dev/null @@ -1,51 +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 { parseTime } from "./Time"; - -describe("Time Scalar", () => { - describe("parseTime", () => { - test.each(["22:20:00", "22:20"])("should properly parse %s", (input: string) => { - const parsedTime = parseTime(input); - expect(parsedTime).toEqual({ - hour: 22, - minute: 20, - second: 0, - nanosecond: 0, - timeZoneOffsetSeconds: 0, - }); - }); - - test("should properly parse time in RFC3339 format", () => { - const parsedTime = parseTime("22:10:15.555-01:02"); - - expect(parsedTime).toEqual({ - hour: 22, - minute: 10, - second: 15, - nanosecond: 555000000, - timeZoneOffsetSeconds: -3720, - }); - }); - - test.each(["22", "22:00.555"])("should not parse %s", (input: string) => { - expect(() => parseTime(input)).toThrow(); - }); - }); -}); diff --git a/packages/graphql/src/schema/validation/custom-rules/directives/default.ts b/packages/graphql/src/schema/validation/custom-rules/directives/default.ts index 68781386c9..3b4022dc70 100644 --- a/packages/graphql/src/schema/validation/custom-rules/directives/default.ts +++ b/packages/graphql/src/schema/validation/custom-rules/directives/default.ts @@ -21,7 +21,7 @@ import { Kind } from "graphql"; import { GRAPHQL_BUILTIN_SCALAR_TYPES } from "../../../../constants"; import { GraphQLDate, GraphQLDateTime, GraphQLLocalDateTime } from "../../../../graphql/scalars"; import { GraphQLLocalTime, parseLocalTime } from "../../../../graphql/scalars/LocalTime"; -import { GraphQLTime, parseTime } from "../../../../graphql/scalars/Time"; +import { GraphQLTime, validateTime } from "../../../../graphql/scalars/Time"; import { DocumentValidationError } from "../utils/document-validation-error"; import type { ObjectOrInterfaceWithExtensions } from "../utils/path-parser"; import { assertArgumentHasSameTypeAsField } from "../utils/same-type-argument-as-field"; @@ -60,7 +60,7 @@ export function verifyDefault(enums: EnumTypeDefinitionNode[]) { } } else if (expectedType === GraphQLTime.name) { try { - parseTime((defaultArg?.value as StringValueNode).value); + validateTime((defaultArg?.value as StringValueNode).value); } catch { throw new DocumentValidationError( `@default.${defaultArg.name.value} is not a valid ${expectedType}`, diff --git a/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts b/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts index 14680d3b34..c7aee97c95 100644 --- a/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts +++ b/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts @@ -19,7 +19,6 @@ 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"; @@ -50,7 +49,6 @@ describe("Time - deprecated filters", () => { 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( ` @@ -76,7 +74,7 @@ describe("Time - deprecated filters", () => { 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); + expect(graphqlMovie.time).toStrictEqual(time); }); test.each(["LT", "LTE", "GT", "GTE"])("should filter based on time comparison for filter: %s", async (filter) => { @@ -90,51 +88,33 @@ describe("Time - deprecated filters", () => { 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 future = "13:00:00Z"; 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 present = "12:00:00Z"; 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 - ); + const past = "11:00:00Z"; await testHelper.executeCypher( ` - CREATE (future:${Movie}) - SET future = $future - CREATE (present:${Movie}) - SET present = $present - CREATE (past:${Movie}) - SET past = $past - `, + CREATE (future:${Movie}) + SET future.id = $futureId + SET future.time = time($future) + CREATE (present:${Movie}) + SET present.id = $presentId + SET present.time = time($present) + CREATE (past:${Movie}) + SET past.id = $pastId + SET past.time = time($past) + `, { - future: { id: futureId, time: neo4jFuture }, - present: { id: presentId, time: neo4jPresent }, - past: { id: pastId, time: neo4jPast }, + futureId, + future, + presentId, + present, + pastId, + past, } ); @@ -165,31 +145,31 @@ describe("Time - deprecated filters", () => { if (filter === "LT") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(pastId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + expect(graphqlMovies[0]?.time).toStrictEqual(past); } if (filter === "LTE") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(pastId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + expect(graphqlMovies[0]?.time).toStrictEqual(past); expect(graphqlMovies[1]?.id).toBe(presentId); - expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); + expect(graphqlMovies[1]?.time).toStrictEqual(present); } if (filter === "GT") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(futureId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedFuture); + expect(graphqlMovies[0]?.time).toStrictEqual(future); } if (filter === "GTE") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(presentId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPresent); + expect(graphqlMovies[0]?.time).toStrictEqual(present); expect(graphqlMovies[1]?.id).toBe(futureId); - expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedFuture); + expect(graphqlMovies[1]?.time).toStrictEqual(future); } /* eslint-enable jest/no-conditional-expect */ }); diff --git a/packages/graphql/tests/integration/types/time.int.test.ts b/packages/graphql/tests/integration/types/time.int.test.ts index 998c29f7ee..5c48d99dfb 100644 --- a/packages/graphql/tests/integration/types/time.int.test.ts +++ b/packages/graphql/tests/integration/types/time.int.test.ts @@ -17,9 +17,8 @@ * limitations under the License. */ -import { Time, isTime } from "neo4j-driver"; +import { isTime } 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"; @@ -48,8 +47,7 @@ describe("Time", () => { await testHelper.initNeo4jGraphQL({ typeDefs }); const id = generate({ readable: false }); - const time = "2024-01-29T03:57:32.358Z".split("T")[1]; - const parsedTime = parseTime(time); + const time = "2024-01-29T03:57:32.358000000Z".split("T")[1]; const mutation = ` mutation ($id: ID!, $time: Time!) { @@ -71,7 +69,7 @@ describe("Time", () => { ][0]; expect(graphqlMovie).toBeDefined(); expect(graphqlMovie.id).toBe(id); - expect(parseTime(graphqlMovie.time)).toStrictEqual(parsedTime); + expect(graphqlMovie.time).toStrictEqual(time); const neo4jResult = await testHelper.executeCypher( ` @@ -85,7 +83,7 @@ describe("Time", () => { expect(neo4jMovie).toBeDefined(); expect(neo4jMovie.id).toEqual(id); expect(isTime(neo4jMovie.time)).toBe(true); - expect(parseTime(neo4jMovie.time.toString())).toStrictEqual(parsedTime); + expect(neo4jMovie.time.toString()).toStrictEqual(time); }); test("should create a movie (with many Times)", async () => { @@ -99,8 +97,7 @@ describe("Time", () => { await testHelper.initNeo4jGraphQL({ typeDefs }); const id = generate({ readable: false }); - const times = [...new Array(4)].map(() => "2023-06-09T11:17:47.789Z".split("T")[1]); - const parsedTimes = times.map((time) => parseTime(time)); + const times = [...new Array(4)].map(() => "2023-06-09T11:17:47.789000000Z".split("T")[1]); const mutation = ` mutation ($id: ID!, $times: [Time!]!) { @@ -123,10 +120,8 @@ describe("Time", () => { expect(graphqlMovie.id).toBe(id); expect(graphqlMovie.times).toHaveLength(times.length); - const parsedGraphQLTimes = graphqlMovie.times.map((time) => parseTime(time)); - - parsedTimes.forEach((parsedTime) => { - expect(parsedGraphQLTimes).toContainEqual(parsedTime); + times.forEach((time) => { + expect(graphqlMovie.times).toContainEqual(time); }); const neo4jResult = await testHelper.executeCypher( @@ -146,10 +141,8 @@ describe("Time", () => { expect(isTime(time)).toBe(true); } - const parsedNeo4jTimes = neo4jMovie.times.map((time) => parseTime(time.toString())); - - parsedTimes.forEach((parsedTime) => { - expect(parsedNeo4jTimes).toContainEqual(parsedTime); + neo4jMovie.times.forEach((time) => { + expect(times).toContainEqual(time.toString()); }); }); }); @@ -166,8 +159,7 @@ describe("Time", () => { await testHelper.initNeo4jGraphQL({ typeDefs }); const id = generate({ readable: false }); - const time = "2023-07-12T05:44:06.918Z".split("T")[1]; - const parsedTime = parseTime(time); + const time = "2023-07-12T05:44:06.918000000Z".split("T")[1]; await testHelper.executeCypher( ` @@ -197,7 +189,7 @@ describe("Time", () => { ][0]; expect(graphqlMovie).toBeDefined(); expect(graphqlMovie.id).toEqual(id); - expect(parseTime(graphqlMovie.time)).toStrictEqual(parsedTime); + expect(graphqlMovie.time).toStrictEqual(time); const neo4jResult = await testHelper.executeCypher( ` @@ -211,7 +203,7 @@ describe("Time", () => { expect(neo4jMovie).toBeDefined(); expect(neo4jMovie.id).toEqual(id); expect(isTime(neo4jMovie.time)).toBe(true); - expect(parseTime(neo4jMovie.time.toString())).toStrictEqual(parsedTime); + expect(neo4jMovie.time.toString()).toStrictEqual(time); }); }); @@ -227,17 +219,15 @@ describe("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); + const time = "11:49:48.322000000Z"; await testHelper.executeCypher( ` CREATE (movie:${Movie}) - SET movie = $movie + SET movie.id = $id + SET movie.time = time($time) `, - { movie: { id, time: neo4jTime } } + { id, time } ); const query = /* GraphQL */ ` @@ -256,7 +246,7 @@ describe("Time", () => { 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); + expect(graphqlMovie.time).toStrictEqual(time); }); test.each(["lt", "lte", "gt", "gte"])( @@ -272,51 +262,33 @@ describe("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 future = "13:00:00Z"; 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 present = "12:00:00Z"; 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 - ); + const past = "11:00:00Z"; await testHelper.executeCypher( ` - CREATE (future:${Movie}) - SET future = $future - CREATE (present:${Movie}) - SET present = $present - CREATE (past:${Movie}) - SET past = $past - `, + CREATE (future:${Movie}) + SET future.id = $futureId + SET future.time = time($future) + CREATE (present:${Movie}) + SET present.id = $presentId + SET present.time = time($present) + CREATE (past:${Movie}) + SET past.id = $pastId + SET past.time = time($past) + `, { - future: { id: futureId, time: neo4jFuture }, - present: { id: presentId, time: neo4jPresent }, - past: { id: pastId, time: neo4jPast }, + futureId, + future, + presentId, + present, + pastId, + past, } ); @@ -347,31 +319,31 @@ describe("Time", () => { if (filter === "lt") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(pastId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + expect(graphqlMovies[0]?.time).toStrictEqual(past); } if (filter === "lte") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(pastId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + expect(graphqlMovies[0]?.time).toStrictEqual(past); expect(graphqlMovies[1]?.id).toBe(presentId); - expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); + expect(graphqlMovies[1]?.time).toStrictEqual(present); } if (filter === "gt") { expect(graphqlMovies).toHaveLength(1); expect(graphqlMovies[0]?.id).toBe(futureId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedFuture); + expect(graphqlMovies[0]?.time).toStrictEqual(future); } if (filter === "gte") { expect(graphqlMovies).toHaveLength(2); expect(graphqlMovies[0]?.id).toBe(presentId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPresent); + expect(graphqlMovies[0]?.time).toStrictEqual(present); expect(graphqlMovies[1]?.id).toBe(futureId); - expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedFuture); + expect(graphqlMovies[1]?.time).toStrictEqual(future); } /* eslint-enable jest/no-conditional-expect */ } @@ -389,51 +361,33 @@ describe("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 future = "13:00:00Z"; 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 present = "12:00:00Z"; 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 - ); + const past = "11:00:00Z"; await testHelper.executeCypher( ` CREATE (future:${Movie}) - SET future = $future + SET future.id = $futureId + SET future.time = time($future) CREATE (present:${Movie}) - SET present = $present + SET present.id = $presentId + SET present.time = time($present) CREATE (past:${Movie}) - SET past = $past + SET past.id = $pastId + SET past.time = time($past) `, { - future: { id: futureId, time: neo4jFuture }, - present: { id: presentId, time: neo4jPresent }, - past: { id: pastId, time: neo4jPast }, + futureId, + future, + presentId, + present, + pastId, + past, } ); @@ -464,24 +418,24 @@ describe("Time", () => { /* eslint-disable jest/no-conditional-expect */ if (sort === "ASC") { expect(graphqlMovies[0]?.id).toBe(pastId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedPast); + expect(graphqlMovies[0]?.time).toStrictEqual(past); expect(graphqlMovies[1]?.id).toBe(presentId); - expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); + expect(graphqlMovies[1]?.time).toStrictEqual(present); expect(graphqlMovies[2]?.id).toBe(futureId); - expect(parseTime(graphqlMovies[2]?.time)).toStrictEqual(parsedFuture); + expect(graphqlMovies[2]?.time).toStrictEqual(future); } if (sort === "DESC") { expect(graphqlMovies[0]?.id).toBe(futureId); - expect(parseTime(graphqlMovies[0]?.time)).toStrictEqual(parsedFuture); + expect(graphqlMovies[0]?.time).toStrictEqual(future); expect(graphqlMovies[1]?.id).toBe(presentId); - expect(parseTime(graphqlMovies[1]?.time)).toStrictEqual(parsedPresent); + expect(graphqlMovies[1]?.time).toStrictEqual(present); expect(graphqlMovies[2]?.id).toBe(pastId); - expect(parseTime(graphqlMovies[2]?.time)).toStrictEqual(parsedPast); + expect(graphqlMovies[2]?.time).toStrictEqual(past); } /* eslint-enable jest/no-conditional-expect */ }); From 05fa0c2aad4f9c1a0ea95eec961ecd1f9395fe3d Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Fri, 10 Jan 2025 11:14:43 +0000 Subject: [PATCH 4/4] Fix test --- .../types/types-time-filter-deprecated.int.test.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts b/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts index c7aee97c95..6275f1ebf8 100644 --- a/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts +++ b/packages/graphql/tests/integration/deprecations/generic-filtering/types/types-time-filter-deprecated.int.test.ts @@ -17,7 +17,6 @@ * limitations under the License. */ -import { Time } from "neo4j-driver"; import { generate } from "randomstring"; import type { UniqueType } from "../../../../utils/graphql-types"; import { TestHelper } from "../../../../utils/tests-helper"; @@ -46,16 +45,15 @@ describe("Time - deprecated filters", () => { 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 time = "11:49:48.322000000Z"; await testHelper.executeCypher( ` CREATE (movie:${Movie}) - SET movie = $movie + SET movie.id = $id + SET movie.time = time($time) `, - { movie: { id, time: neo4jTime } } + { id, time } ); const query = /* GraphQL */ `