From 34845684effbcabe664e4faea55258dbafd546ca Mon Sep 17 00:00:00 2001 From: Onji Kim Date: Thu, 16 Nov 2023 23:42:17 +0900 Subject: [PATCH 01/29] Add HexColorCode Scalar --- README.md | 23 ++++ .../java/graphql/scalars/ExtendedScalars.java | 7 + .../scalars/color/hex/HexColorCodeScalar.java | 120 ++++++++++++++++++ .../color/hex/HexColorCodeScalarTest.groovy | 92 ++++++++++++++ .../graphql/scalars/util/TestKit.groovy | 10 +- 5 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java create mode 100644 src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy diff --git a/README.md b/README.md index 082ff1b..16d6060 100644 --- a/README.md +++ b/README.md @@ -541,3 +541,26 @@ For example, imagine a `phoneNumber` scalar like this : .build() ``` + +## HexColorCode Scalar + + + + + + + + + +
Scalar DefinitionDescription
+scalar HexColorCode
+  @specifiedBy(url: 
+    "https://tools.ietf.org/html/bcp47"
+  )
+
The HexColorCode scalar handles hex color code. You can handle it via java.awt.Color (which was built into JDK)
+It Support Following Formats: + +- #RRGGBB +- #RGB +- #RRGGBBAA +- #RGBA diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index ce36232..0970206 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -2,6 +2,7 @@ import graphql.PublicApi; import graphql.scalars.alias.AliasedScalar; +import graphql.scalars.color.hex.HexColorCodeScalar; import graphql.scalars.country.code.CountryCodeScalar; import graphql.scalars.currency.CurrencyScalar; import graphql.scalars.datetime.DateScalar; @@ -150,6 +151,12 @@ public class ExtendedScalars { */ public static final GraphQLScalarType CountryCode = CountryCodeScalar.INSTANCE; + /** + * A field whose value is a hex color code + * See the Web colors for more details. + */ + public static final GraphQLScalarType HexColorCode = HexColorCodeScalar.INSTANCE; + /** * A UUID scalar that accepts a universally unique identifier and produces {@link * java.util.UUID} objects at runtime. diff --git a/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java b/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java new file mode 100644 index 0000000..0cdc721 --- /dev/null +++ b/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java @@ -0,0 +1,120 @@ +package graphql.scalars.color.hex; + +import graphql.language.StringValue; +import graphql.language.Value; +import graphql.schema.*; + +import java.awt.*; +import java.util.function.Function; +import java.util.regex.Pattern; + +import static graphql.scalars.util.Kit.typeName; +/** + * Access this via {@link graphql.scalars.ExtendedScalars#HexColorCode} + * See the Web colors for more details. + * @implNote Supports the following formats: #RGB, #RGBA, #RRGGBB, #RRGGBBAA. Need to be prefixed with '#' + */ +public class HexColorCodeScalar { + + public static final GraphQLScalarType INSTANCE; + + + static { + Coercing coercing = new Coercing() { + + private final Pattern HEX_PATTERN = Pattern.compile("^(#([A-Fa-f0-9]{3,4}){1,2})$"); + + @Override + public String serialize(Object input) throws CoercingSerializeException { + Color color = parseColor(input, CoercingSerializeException::new); + boolean hasAlpha = color.getAlpha() != 255; + if (hasAlpha){ + return String.format("#%02x%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } else { + return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); + } + } + + @Override + public Color parseValue(Object input) throws CoercingParseValueException { + return parseColor(input, CoercingParseValueException::new); + } + + @Override + public Color parseLiteral(Object input) throws CoercingParseLiteralException { + if (!(input instanceof StringValue)) { + throw new CoercingParseLiteralException("Expected type 'StringValue' but was '" + typeName(input) + "'."); + } + String stringValue = ((StringValue) input).getValue(); + return parseColor(stringValue, CoercingParseLiteralException::new); + } + + @Override + public Value valueToLiteral(Object input) { + String s = serialize(input); + return StringValue.newStringValue(s).build(); + } + + + private Color parseColor(Object input, Function exceptionMaker) { + final Color result; + if (input instanceof Color) { + result = (Color) input; + } else if (input instanceof String) { + try { + String hex = ((String) input); + + //validation + //regex + if (!HEX_PATTERN.matcher(hex).matches()) { + throw new IllegalArgumentException("Invalid hex color code value : '" + input + "'."); + } + + int i = Integer.decode(hex); + int inputLength = hex.length(); + + if (inputLength == 4) { + // #RGB + result = new Color( + (i >> 8 & 0xF) * 0x11, + (i >> 4 & 0xF) * 0x11, + (i & 0xF) * 0x11 + ); + } else if (inputLength == 5) { + // #RGBA + result = new Color( + (i >> 12 & 0xF) * 0x11, + (i >> 8 & 0xF) * 0x11, + (i >> 4 & 0xF) * 0x11, + (i & 0xF) * 0x11 + ); + } else if (inputLength == 7) { + // #RRGGBB + result = new Color(i); + } else { + // #RRGGBBAA + result = new Color( + (i >> 24 & 0xFF), + (i >> 16 & 0xFF), + (i >> 8 & 0xFF), + (i & 0xFF) + ); + } + } catch (NullPointerException | IllegalArgumentException ex) { + throw exceptionMaker.apply("Invalid hex color code value : '" + input + "'. because of : '" + ex.getMessage() + "'"); + } + } else { + throw exceptionMaker.apply("Expected a 'String' or 'Color' but was '" + typeName(input) + "'."); + } + return result; + } + + }; + + INSTANCE = GraphQLScalarType.newScalar() + .name("HexColorCode") + .description("A field whose value is a hexadecimal color code: https://en.wikipedia.org/wiki/Web_colors.") + .coercing(coercing).build(); + } + +} diff --git a/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy b/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy new file mode 100644 index 0000000..97c6e18 --- /dev/null +++ b/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy @@ -0,0 +1,92 @@ +package graphql.scalars.color.hex + +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.schema.CoercingParseValueException +import spock.lang.Specification +import spock.lang.Unroll + +import static graphql.scalars.util.TestKit.mkColor + +class HexColorCodeScalarTest extends Specification { + + def coercing = ExtendedScalars.HexColorCode.getCoercing() + + @Unroll + def "invoke parseValue for hexCode"() { + when: + def result = coercing.parseValue(input) + then: + result.equals(expectedValue) + where: + input | expectedValue + "#ff0000" | mkColor(0xff, 0, 0) + "#123" | mkColor(0x11, 0x22, 0x33) + "#11223344" | mkColor(0x11, 0x22, 0x33, 0x44) + "#1234" | mkColor(0x11, 0x22, 0x33, 0x44) + } + + @Unroll + def "invoke parseLiteral for hexCode"() { + when: + def result = coercing.parseLiteral(input) + then: + result == expectedValue + where: + input | expectedValue + new StringValue("#ff0000") | mkColor(0xff, 0, 0) + new StringValue("#123") | mkColor(0x11, 0x22, 0x33) + new StringValue("#11223344") | mkColor(0x11, 0x22, 0x33, 0x44) + new StringValue("#1234") | mkColor(0x11, 0x22, 0x33, 0x44) + } + + @Unroll + def "invoke serialize with hexCode"() { + when: + def result = coercing.serialize(input) + then: + result == expectedValue + where: + input | expectedValue + "#ff0000" | "#ff0000" + "#123" | "#112233" + "#11223344" | "#11223344" + "#1234" | "#11223344" + mkColor(0x21, 0x23, 0x33) | "#212333" + mkColor(0x21, 0x23, 0x33, 0x44) | "#21233344" + } + + @Unroll + def "invoke valueToLiteral with hexCode"() { + when: + def result = coercing.valueToLiteral(input) + then: + result.isEqualTo(expectedValue) + where: + input | expectedValue + "#ff0000" | new StringValue("#ff0000") + "#123" | new StringValue("#112233") + "#11223344" | new StringValue("#11223344") + "#1234" | new StringValue("#11223344") + mkColor(0x21, 0x23, 0x33) | new StringValue("#212333") + mkColor(0x21, 0x23, 0x33, 0x44) | new StringValue("#21233344") + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + def result = coercing.parseValue(input) + then: + thrown(CoercingParseValueException) + where: + input | _ + "ff000" | _ + "" | _ + "not a hex code" | _ + "42.3" | _ + new Double(42.3) | _ + new Float(42.3) | _ + new Object() | _ + } + +} \ No newline at end of file diff --git a/src/test/groovy/graphql/scalars/util/TestKit.groovy b/src/test/groovy/graphql/scalars/util/TestKit.groovy index 2a96dee..e5acaac 100644 --- a/src/test/groovy/graphql/scalars/util/TestKit.groovy +++ b/src/test/groovy/graphql/scalars/util/TestKit.groovy @@ -5,6 +5,7 @@ import graphql.language.IntValue import graphql.language.StringValue import graphql.scalars.country.code.CountryCode +import java.awt.Color import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime @@ -97,4 +98,11 @@ class TestKit { static CountryCode mkCountryCode(String countryCode) { return CountryCode.valueOf(countryCode) } -} + + static Color mkColor(int r, int g, int b, int a) { + return new Color(r, g, b, a) + } + static Color mkColor(int r, int g, int b) { + return new Color(r, g, b) + } +} \ No newline at end of file From f4b4a3b8495a7e9a726802de77d14c0a624b6896 Mon Sep 17 00:00:00 2001 From: sachin-bansal <34054433+sachin-bansal@users.noreply.github.com> Date: Fri, 1 Mar 2024 00:39:22 +0530 Subject: [PATCH 02/29] fix issue 126 - use MILLI_OF_SECOND https://github.com/graphql-java/graphql-java-extended-scalars/issues/126 --- src/main/java/graphql/scalars/datetime/DateTimeScalar.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java index 12b01de..7777bcd 100644 --- a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java +++ b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java @@ -125,7 +125,7 @@ private static DateTimeFormatter getCustomDateTimeFormatter() { .appendValue(MINUTE_OF_HOUR, 2) .appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) - .appendFraction(NANO_OF_SECOND, 3, 3, true) + .appendFraction(MILLI_OF_SECOND, 3, 3, true) .appendOffset("+HH:MM", "Z") .toFormatter(); } From 7382cbc79238f7f22b24a65a81dd9479e5b49e97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 16:35:45 +0000 Subject: [PATCH 03/29] Bump org.codehaus.groovy:groovy from 3.0.20 to 3.0.21 Bumps [org.codehaus.groovy:groovy](https://github.com/apache/groovy) from 3.0.20 to 3.0.21. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.codehaus.groovy:groovy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ea31b80..96901d1 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation "com.graphql-java:graphql-java:21.3" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" - testImplementation "org.codehaus.groovy:groovy:3.0.20" + testImplementation "org.codehaus.groovy:groovy:3.0.21" } task sourcesJar(type: Jar, dependsOn: classes) { From 1a1a895d6bb4381028a45115d17adf010e61b79d Mon Sep 17 00:00:00 2001 From: Alexandre Carlton Date: Sun, 17 Mar 2024 00:46:45 +1100 Subject: [PATCH 04/29] Add AccurateDuration and NominalDuration Scalars This adds support for two scalars: - `AccurateDuration` (which maps to a `java.time.Duration`). - `NominalDuration` (which maps to a `java.time.Period`). Both of these heavily relate to durations as defined in ISO 8601 but with the following caveats: - `AccurateDuration` only relates to the portion of a duration that is context-free (i.e. does not need to know the calendar position to determine its value). It maps to a `java.time.Duration`. - `NominalDuration` relates to the portion of a duration that is dependent on knowing the calendar position to determine its value. It maps to a `java.time.Period`. The naming of these are strongly influenced by the wording in ISO 8601: > Duration can be expressed by a combination of components with accurate duration (hour, minute and second) and components with nominal duration (year, month, week and day). The code here follows the same pattern as that used for the `DateTime` Scalar. --- .../java/graphql/scalars/ExtendedScalars.java | 31 ++++ .../datetime/AccurateDurationScalar.java | 93 ++++++++++++ .../datetime/NominalDurationScalar.java | 92 ++++++++++++ .../AccurateDurationScalarTest.groovy | 139 ++++++++++++++++++ .../datetime/NominalDurationScalarTest.groovy | 134 +++++++++++++++++ .../graphql/scalars/util/TestKit.groovy | 17 +++ 6 files changed, 506 insertions(+) create mode 100644 src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java create mode 100644 src/main/java/graphql/scalars/datetime/NominalDurationScalar.java create mode 100644 src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy create mode 100644 src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index ce36232..214ff90 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -6,7 +6,9 @@ import graphql.scalars.currency.CurrencyScalar; import graphql.scalars.datetime.DateScalar; import graphql.scalars.datetime.DateTimeScalar; +import graphql.scalars.datetime.AccurateDurationScalar; import graphql.scalars.datetime.LocalTimeCoercing; +import graphql.scalars.datetime.NominalDurationScalar; import graphql.scalars.datetime.TimeScalar; import graphql.scalars.java.JavaPrimitives; import graphql.scalars.locale.LocaleScalar; @@ -85,6 +87,35 @@ public class ExtendedScalars { .coercing(new LocalTimeCoercing()) .build(); + /** + * A duration scalar that accepts string values like `P1DT2H3M4.5s` and produces * `java.time.Duration` objects at runtime. + *

+ * Components like years and months are not supported as these may have different meanings depending on the placement in the calendar year. + *

+ * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods + * accept Duration and formatted Strings as valid objects. + *

+ * See the ISO 8601 for more details on the format. + * + * @see java.time.Duration + */ + public static final GraphQLScalarType AccurateDuration = AccurateDurationScalar.INSTANCE; + + /** + * An RFC-3339 compliant duration scalar that accepts string values like `P1Y2M3D` and produces + * `java.time.Period` objects at runtime. + *

+ * Components like hours and seconds are not supported as these are handled by {@link #AccurateDuration}. + *

+ * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods + * accept Period and formatted Strings as valid objects. + *

+ * See the ISO 8601 for more details on the format. + * + * @see java.time.Period + */ + public static final GraphQLScalarType NominalDuration = NominalDurationScalar.INSTANCE; + /** * An object scalar allows you to have a multi level data value without defining it in the graphql schema. *

diff --git a/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java b/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java new file mode 100644 index 0000000..e23446b --- /dev/null +++ b/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java @@ -0,0 +1,93 @@ +package graphql.scalars.datetime; + +import graphql.Internal; +import graphql.language.StringValue; +import graphql.language.Value; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.Duration; +import java.time.format.DateTimeParseException; +import java.util.function.Function; + +import static graphql.scalars.util.Kit.typeName; + +/** + * Access this via {@link graphql.scalars.ExtendedScalars#AccurateDuration} + */ +@Internal +public class AccurateDurationScalar { + + public static final GraphQLScalarType INSTANCE; + + private AccurateDurationScalar() {} + + static { + Coercing coercing = new Coercing() { + @Override + public String serialize(Object input) throws CoercingSerializeException { + Duration duration; + if (input instanceof Duration) { + duration = (Duration) input; + } else if (input instanceof String) { + duration = parseDuration(input.toString(), CoercingSerializeException::new); + } else { + throw new CoercingSerializeException( + "Expected something we can convert to 'java.time.Duration' but was '" + typeName(input) + "'." + ); + } + return duration.toString(); + } + + @Override + public Duration parseValue(Object input) throws CoercingParseValueException { + Duration duration; + if (input instanceof Duration) { + duration = (Duration) input; + } else if (input instanceof String) { + duration = parseDuration(input.toString(), CoercingParseValueException::new); + } else { + throw new CoercingParseValueException( + "Expected a 'String' but was '" + typeName(input) + "'." + ); + } + return duration; + } + + @Override + public Duration parseLiteral(Object input) throws CoercingParseLiteralException { + if (!(input instanceof StringValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + ); + } + return parseDuration(((StringValue) input).getValue(), CoercingParseLiteralException::new); + } + + @Override + public Value valueToLiteral(Object input) { + String s = serialize(input); + return StringValue.newStringValue(s).build(); + } + + private Duration parseDuration(String s, Function exceptionMaker) { + try { + return Duration.parse(s); + } catch (DateTimeParseException e) { + throw exceptionMaker.apply("Invalid ISO 8601 value : '" + s + "'. because of : '" + e.getMessage() + "'"); + } + } + }; + + INSTANCE = GraphQLScalarType.newScalar() + .name("AccurateDuration") + .description("A ISO 8601 duration scalar with only day, hour, minute, second components.") + .specifiedByUrl("https://scalars.graphql.org/AlexandreCarlton/accurate-duration") // TODO: Change to .specifiedByURL when builder added to graphql-java + .coercing(coercing) + .build(); + } + +} diff --git a/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java b/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java new file mode 100644 index 0000000..320393a --- /dev/null +++ b/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java @@ -0,0 +1,92 @@ +package graphql.scalars.datetime; + +import graphql.Internal; +import graphql.language.StringValue; +import graphql.language.Value; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.Period; +import java.time.format.DateTimeParseException; +import java.util.function.Function; + +import static graphql.scalars.util.Kit.typeName; + +/** + * Access this via {@link graphql.scalars.ExtendedScalars#NominalDuration} + */ +@Internal +public class NominalDurationScalar { + + public static final GraphQLScalarType INSTANCE; + + private NominalDurationScalar() {} + + static { + Coercing coercing = new Coercing() { + @Override + public String serialize(Object input) throws CoercingSerializeException { + Period period; + if (input instanceof Period) { + period = (Period) input; + } else if (input instanceof String) { + period = parsePeriod(input.toString(), CoercingSerializeException::new); + } else { + throw new CoercingSerializeException( + "Expected something we can convert to 'java.time.OffsetDateTime' but was '" + typeName(input) + "'." + ); + } + return period.toString(); + } + + @Override + public Period parseValue(Object input) throws CoercingParseValueException { + Period period; + if (input instanceof Period) { + period = (Period) input; + } else if (input instanceof String) { + period = parsePeriod(input.toString(), CoercingParseValueException::new); + } else { + throw new CoercingParseValueException( + "Expected a 'String' but was '" + typeName(input) + "'." + ); + } + return period; + } + + @Override + public Period parseLiteral(Object input) throws CoercingParseLiteralException { + if (!(input instanceof StringValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + ); + } + return parsePeriod(((StringValue) input).getValue(), CoercingParseLiteralException::new); + } + + @Override + public Value valueToLiteral(Object input) { + String s = serialize(input); + return StringValue.newStringValue(s).build(); + } + + private Period parsePeriod(String s, Function exceptionMaker) { + try { + return Period.parse(s); + } catch (DateTimeParseException e) { + throw exceptionMaker.apply("Invalid ISO 8601 value : '" + s + "'. because of : '" + e.getMessage() + "'"); + } + } + }; + + INSTANCE = GraphQLScalarType.newScalar() + .name("NominalDuration") + .description("A ISO 8601 duration with only year, month, week and day components.") + .specifiedByUrl("https://scalars.graphql.org/AlexandreCarlton/nominal-duration") // TODO: Change to .specifiedByURL when builder added to graphql-java + .coercing(coercing) + .build(); + } +} diff --git a/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy new file mode 100644 index 0000000..9fb8009 --- /dev/null +++ b/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy @@ -0,0 +1,139 @@ +package graphql.scalars.datetime + + +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.Period +import java.time.temporal.ChronoUnit + +import static graphql.scalars.util.TestKit.mkDuration +import static graphql.scalars.util.TestKit.mkStringValue + +class AccurateDurationScalarTest extends Specification { + + def coercing = ExtendedScalars.AccurateDuration.getCoercing() + + @Unroll + def "accurateduration parseValue"() { + + when: + def result = coercing.parseValue(input) + then: + result == expectedValue + where: + input | expectedValue + "PT1S" | mkDuration("PT1S") + "PT1.5S" | mkDuration("PT1.5S") + "P1DT2H3M4S" | mkDuration("P1DT2H3M4S") + "-P1DT2H3M4S" | mkDuration("-P1DT2H3M4S") + "P1DT-2H3M4S" | mkDuration("P1DT-2H3M4S") + mkDuration(amount: 123456, unit: ChronoUnit.HOURS) | mkDuration("PT123456H") + } + + @Unroll + def "accurateduration valueToLiteral"() { + + when: + def result = coercing.valueToLiteral(input) + then: + result.isEqualTo(expectedValue) + where: + input | expectedValue + "PT1S" | mkStringValue("PT1S") + "PT1.5S" | mkStringValue("PT1.5S") + "P1D" | mkStringValue("PT24H") + "P1DT2H3M4S" | mkStringValue("PT26H3M4S") + mkDuration("P1DT2H3M4S") | mkStringValue("PT26H3M4S") + mkDuration("-P1DT2H3M4S") | mkStringValue("PT-26H-3M-4S") + mkDuration(amount: 123456, unit: ChronoUnit.HOURS) | mkStringValue("PT123456H") + } + + @Unroll + def "accurateduration parseValue bad inputs"() { + + when: + coercing.parseValue(input) + then: + thrown(expectedValue) + where: + input | expectedValue + "P1M" | CoercingParseValueException + "P1MT2H" | CoercingParseValueException + "P2W" | CoercingParseValueException + "P3Y" | CoercingParseValueException + 123 | CoercingParseValueException + "" | CoercingParseValueException + Period.of(1, 2, 3) | CoercingParseValueException + } + + def "accurateduration AST literal"() { + + when: + def result = coercing.parseLiteral(input) + then: + result == expectedValue + where: + input | expectedValue + new StringValue("P1DT2H3M4S") | mkDuration("P1DT2H3M4S") + } + + def "accurateduration serialisation"() { + + when: + def result = coercing.serialize(input) + then: + result == expectedValue + where: + input | expectedValue + "PT1S" | "PT1S" + "PT1.5S" | "PT1.5S" + "P1DT2H3M4S" | "PT26H3M4S" + "-P1DT2H3M4S" | "PT-26H-3M-4S" + "P1DT-2H3M4S" | "PT22H3M4S" + mkDuration("P1DT-2H3M4S") | "PT22H3M4S" + mkDuration(amount: 123456, unit: ChronoUnit.HOURS) | "PT123456H" + } + + def "accurateduration serialisation bad inputs"() { + + when: + coercing.serialize(input) + then: + thrown(expectedValue) + where: + input | expectedValue + "P1M" | CoercingSerializeException + "PT1.5M" | CoercingSerializeException + "P1MT2H" | CoercingSerializeException + "P2W" | CoercingSerializeException + "P3Y" | CoercingSerializeException + 123 | CoercingSerializeException + "" | CoercingSerializeException + Period.of(1, 2, 3) | CoercingSerializeException + } + + @Unroll + def "accurateduration parseLiteral bad inputs"() { + + when: + coercing.parseLiteral(input) + then: + thrown(expectedValue) + where: + input | expectedValue + "P1M" | CoercingParseLiteralException + "PT1.5M" | CoercingParseLiteralException + "P1MT2H" | CoercingParseLiteralException + "P2W" | CoercingParseLiteralException + "P3Y" | CoercingParseLiteralException + 123 | CoercingParseLiteralException + "" | CoercingParseLiteralException + Period.of(1, 2, 3) | CoercingParseLiteralException + } +} diff --git a/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy new file mode 100644 index 0000000..2790286 --- /dev/null +++ b/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy @@ -0,0 +1,134 @@ +package graphql.scalars.datetime + +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.Duration +import java.time.temporal.ChronoUnit + +import static graphql.scalars.util.TestKit.mkPeriod +import static graphql.scalars.util.TestKit.mkStringValue + +class NominalDurationScalarTest extends Specification { + + def coercing = ExtendedScalars.NominalDuration.getCoercing() + + @Unroll + def "nominalduration parseValue"() { + + when: + def result = coercing.parseValue(input) + then: + result == expectedValue + where: + input | expectedValue + "P1D" | mkPeriod("P1D") + "P1W" | mkPeriod("P7D") + "P1Y2M3D" | mkPeriod("P1Y2M3D") + "-P1Y2M3D" | mkPeriod("-P1Y2M3D") + "P1Y-2M3D" | mkPeriod("P1Y-2M3D") + mkPeriod(years: 1, months: 2, days: 3) | mkPeriod("P1Y2M3D") + } + + @Unroll + def "nominalduration valueToLiteral"() { + + when: + def result = coercing.valueToLiteral(input) + then: + result.isEqualTo(expectedValue) + where: + input | expectedValue + "P1D" | mkStringValue("P1D") + "P1W" | mkStringValue("P7D") + "P1Y2M3D" | mkStringValue("P1Y2M3D") + "-P1Y2M3D" | mkStringValue("P-1Y-2M-3D") + "P1Y-2M3D" | mkStringValue("P1Y-2M3D") + mkPeriod("P1Y2M3D") | mkStringValue("P1Y2M3D") + mkPeriod(years: 1, months: 2, days: 3) | mkStringValue("P1Y2M3D") + } + + @Unroll + def "nominalduration parseValue bad inputs"() { + + when: + coercing.parseValue(input) + then: + thrown(expectedValue) + where: + input | expectedValue + "P1.5M" | CoercingParseValueException + "P1MT2H" | CoercingParseValueException + "PT1S" | CoercingParseValueException + 123 | CoercingParseValueException + "" | CoercingParseValueException + Duration.of(30, ChronoUnit.MINUTES) | CoercingParseValueException + } + + def "nominalduration AST literal"() { + + when: + def result = coercing.parseLiteral(input) + then: + result == expectedValue + where: + input | expectedValue + new StringValue("P1Y2M3D") | mkPeriod("P1Y2M3D") + } + + def "nominalduration serialisation"() { + + when: + def result = coercing.serialize(input) + then: + result == expectedValue + where: + input | expectedValue + "P1D" | "P1D" + "P1W" | "P7D" + "P1Y2M3D" | "P1Y2M3D" + "-P1Y2M3D" | "P-1Y-2M-3D" + "P1Y-2M3D" | "P1Y-2M3D" + mkPeriod(years: 1, months: 2, days: 3) | "P1Y2M3D" + } + + def "nominalduration serialisation bad inputs"() { + + when: + coercing.serialize(input) + then: + thrown(expectedValue) + where: + input | expectedValue + "PT1M" | CoercingSerializeException + "P1.5M" | CoercingSerializeException + "P1MT2H" | CoercingSerializeException + "PY" | CoercingSerializeException + 123 | CoercingSerializeException + "" | CoercingSerializeException + Duration.of(1, ChronoUnit.MINUTES) | CoercingSerializeException + } + + @Unroll + def "nominalduration parseLiteral bad inputs"() { + + when: + coercing.parseLiteral(input) + then: + thrown(expectedValue) + where: + input | expectedValue + "PT1M" | CoercingParseLiteralException + "P1.5M" | CoercingParseLiteralException + "P1MT2H" | CoercingParseLiteralException + "PY" | CoercingParseLiteralException + 123 | CoercingParseLiteralException + "" | CoercingParseLiteralException + Duration.of(1, ChronoUnit.MINUTES) | CoercingParseLiteralException + } +} diff --git a/src/test/groovy/graphql/scalars/util/TestKit.groovy b/src/test/groovy/graphql/scalars/util/TestKit.groovy index 2a96dee..6ff0577 100644 --- a/src/test/groovy/graphql/scalars/util/TestKit.groovy +++ b/src/test/groovy/graphql/scalars/util/TestKit.groovy @@ -5,11 +5,13 @@ import graphql.language.IntValue import graphql.language.StringValue import graphql.scalars.country.code.CountryCode +import java.time.Duration import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime import java.time.OffsetDateTime import java.time.OffsetTime +import java.time.Period import java.time.ZoneId import java.time.ZoneOffset import java.time.ZonedDateTime @@ -51,6 +53,21 @@ class TestKit { args.min ?: 10, args.secs ?: 9, args.nanos ?: 0, ZoneId.ofOffset("", ZoneOffset.ofHours(10))) } + static Duration mkDuration(String s) { + Duration.parse(s) + } + + static Duration mkDuration(args) { + Duration.of(args.amount, args.unit) + } + + static Period mkPeriod(String s) { + Period.parse(s) + } + + static Period mkPeriod(args) { + Period.of(args.years, args.months, args.days) + } static assertValueOrException(result, expectedResult) { if (result instanceof Exception) { From 2f976670128b3b8854a43c7e4fccd0f9a819d05c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:59:50 +0000 Subject: [PATCH 05/29] Bump io.github.gradle-nexus.publish-plugin from 1.3.0 to 2.0.0 Bumps io.github.gradle-nexus.publish-plugin from 1.3.0 to 2.0.0. --- updated-dependencies: - dependency-name: io.github.gradle-nexus.publish-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ea31b80..8311311 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { id 'java-library' id 'maven-publish' id 'signing' - id "io.github.gradle-nexus.publish-plugin" version "1.3.0" + id "io.github.gradle-nexus.publish-plugin" version "2.0.0" id "biz.aQute.bnd.builder" version "6.4.0" } From 4965ab3c39eceb7d8579e2007fd907f567551c2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:21:15 +0000 Subject: [PATCH 06/29] Bump gradle/wrapper-validation-action from 2 to 3 Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 2 to 3. - [Release notes](https://github.com/gradle/wrapper-validation-action/releases) - [Commits](https://github.com/gradle/wrapper-validation-action/compare/v2...v3) --- updated-dependencies: - dependency-name: gradle/wrapper-validation-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/master.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 42f43cf..7c96d55 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 + - uses: gradle/wrapper-validation-action@v3 - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 80cb5ac..7206a48 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 + - uses: gradle/wrapper-validation-action@v3 - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9d2a133..21b31d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 + - uses: gradle/wrapper-validation-action@v3 - name: Set up JDK 11 uses: actions/setup-java@v4 with: From 439b29653524a4868eb40834382110f1dde1e6e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 16:45:17 +0000 Subject: [PATCH 07/29] Bump com.graphql-java:graphql-java from 22.0 to 22.1 Bumps [com.graphql-java:graphql-java](https://github.com/graphql-java/graphql-java) from 22.0 to 22.1. - [Release notes](https://github.com/graphql-java/graphql-java/releases) - [Commits](https://github.com/graphql-java/graphql-java/compare/v22.0...v22.1) --- updated-dependencies: - dependency-name: com.graphql-java:graphql-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1610808..2d54637 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ repositories { } dependencies { - implementation "com.graphql-java:graphql-java:22.0" + implementation "com.graphql-java:graphql-java:22.1" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" testImplementation "org.codehaus.groovy:groovy:3.0.21" From bdaec03fc686c170c7beb98d36d51636d11c4afc Mon Sep 17 00:00:00 2001 From: Yunus Date: Wed, 12 Jun 2024 17:19:01 +0200 Subject: [PATCH 08/29] Fix BigDecimal and BigInteger package name in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd199f7..a0ae01b 100644 --- a/README.md +++ b/README.md @@ -308,11 +308,11 @@ query {

scalar GraphQLBigDecimal
-A scalar which represents java.lang.BigDecimal +A scalar which represents java.math.BigDecimal
scalar GraphQLBigInteger
-A scalar which represents java.lang.BigInteger +A scalar which represents java.math.BigInteger
scalar GraphQLChar
From 25e43b08599a811d4ad97dc1954cdc9838875ccb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:01:39 +0000 Subject: [PATCH 09/29] Bump org.codehaus.groovy:groovy from 3.0.21 to 3.0.22 Bumps [org.codehaus.groovy:groovy](https://github.com/apache/groovy) from 3.0.21 to 3.0.22. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.codehaus.groovy:groovy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2d54637..be8992d 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation "com.graphql-java:graphql-java:22.1" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" - testImplementation "org.codehaus.groovy:groovy:3.0.21" + testImplementation "org.codehaus.groovy:groovy:3.0.22" } task sourcesJar(type: Jar, dependsOn: classes) { From f028938d6acd84bfdef34801a57d80bd594d6f23 Mon Sep 17 00:00:00 2001 From: tetsuyawakita Date: Thu, 22 Aug 2024 19:05:07 +0700 Subject: [PATCH 10/29] Support year/yearMonth --- .../java/graphql/scalars/ExtendedScalars.java | 21 ++++ .../scalars/datetime/YearMonthScalar.java | 109 ++++++++++++++++++ .../graphql/scalars/datetime/YearScalar.java | 109 ++++++++++++++++++ .../datetime/YearMonthScalarTest.groovy | 64 ++++++++++ .../scalars/datetime/YearScalarTest.groovy | 64 ++++++++++ 5 files changed, 367 insertions(+) create mode 100644 src/main/java/graphql/scalars/datetime/YearMonthScalar.java create mode 100644 src/main/java/graphql/scalars/datetime/YearScalar.java create mode 100644 src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy create mode 100644 src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index ce36232..fa7edf4 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -8,6 +8,8 @@ import graphql.scalars.datetime.DateTimeScalar; import graphql.scalars.datetime.LocalTimeCoercing; import graphql.scalars.datetime.TimeScalar; +import graphql.scalars.datetime.YearMonthScalar; +import graphql.scalars.datetime.YearScalar; import graphql.scalars.java.JavaPrimitives; import graphql.scalars.locale.LocaleScalar; import graphql.scalars.id.UUIDScalar; @@ -69,6 +71,25 @@ public class ExtendedScalars { * @see java.time.OffsetTime */ public static final GraphQLScalarType Time = TimeScalar.INSTANCE; + /** + * A scalar that represents a year and month (e.g., `1996-12`) and produces + * `java.time.YearMonth` objects at runtime. + *

+ * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods + * accept YearMonth instances and formatted Strings as valid objects. + * + * @see java.time.YearMonth + */ + public static final GraphQLScalarType YearMonth = YearMonthScalar.INSTANCE; + /** + * A scalar that represents a year (e.g., `1996`) and produces `java.time.Year` objects at runtime. + *

+ * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods + * accept Year instances and formatted Strings as valid objects. + * + * @see java.time.Year + */ + public static final GraphQLScalarType Year = YearScalar.INSTANCE; /** * A 24-hour local time scalar that accepts strings like `hh:mm:ss` and `hh:mm:ss.sss` and produces diff --git a/src/main/java/graphql/scalars/datetime/YearMonthScalar.java b/src/main/java/graphql/scalars/datetime/YearMonthScalar.java new file mode 100644 index 0000000..2d679f1 --- /dev/null +++ b/src/main/java/graphql/scalars/datetime/YearMonthScalar.java @@ -0,0 +1,109 @@ +package graphql.scalars.datetime; + +import graphql.Internal; +import graphql.language.StringValue; +import graphql.language.Value; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.DateTimeException; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + +import static graphql.scalars.util.Kit.typeName; + +/** + * Access this via {@link graphql.scalars.ExtendedScalars#YearMonth} + */ +@Internal +public final class YearMonthScalar { + + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM"); + + public static final GraphQLScalarType INSTANCE; + + private YearMonthScalar() {} + + static { + Coercing coercing = new Coercing() { + @Override + public String serialize(Object input) throws CoercingSerializeException { + TemporalAccessor temporalAccessor; + if (input instanceof TemporalAccessor) { + temporalAccessor = (TemporalAccessor) input; + } else if (input instanceof String) { + temporalAccessor = parseYearMonth(input.toString(), CoercingSerializeException::new); + } else { + throw new CoercingSerializeException( + "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." + ); + } + try { + return DATE_FORMATTER.format(temporalAccessor); + } catch (DateTimeException e) { + throw new CoercingSerializeException( + "Unable to turn TemporalAccessor into full yearMonth because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public YearMonth parseValue(Object input) throws CoercingParseValueException { + TemporalAccessor temporalAccessor; + if (input instanceof TemporalAccessor) { + temporalAccessor = (TemporalAccessor) input; + } else if (input instanceof String) { + temporalAccessor = parseYearMonth(input.toString(), CoercingParseValueException::new); + } else { + throw new CoercingParseValueException( + "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." + ); + } + try { + return YearMonth.from(temporalAccessor); + } catch (DateTimeException e) { + throw new CoercingParseValueException( + "Unable to turn TemporalAccessor into full yearMonth because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public YearMonth parseLiteral(Object input) throws CoercingParseLiteralException { + if (!(input instanceof StringValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + ); + } + return parseYearMonth(((StringValue) input).getValue(), CoercingParseLiteralException::new); + } + + @Override + public Value valueToLiteral(Object input) { + String s = serialize(input); + return StringValue.newStringValue(s).build(); + } + + private YearMonth parseYearMonth(String s, Function exceptionMaker) { + try { + TemporalAccessor temporalAccessor = DATE_FORMATTER.parse(s); + return YearMonth.from(temporalAccessor); + } catch (DateTimeParseException e) { + throw exceptionMaker.apply("Invalid RFC3339 full yearMonth value : '" + s + "'. because of : '" + e.getMessage() + "'"); + } + } + }; + + INSTANCE = GraphQLScalarType.newScalar() + .name("YearMonth") + .description("An RFC-3339 compliant Full YearMonth Scalar") + .coercing(coercing) + .build(); + } +} diff --git a/src/main/java/graphql/scalars/datetime/YearScalar.java b/src/main/java/graphql/scalars/datetime/YearScalar.java new file mode 100644 index 0000000..dd268a5 --- /dev/null +++ b/src/main/java/graphql/scalars/datetime/YearScalar.java @@ -0,0 +1,109 @@ +package graphql.scalars.datetime; + +import graphql.Internal; +import graphql.language.StringValue; +import graphql.language.Value; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.DateTimeException; +import java.time.Year; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + +import static graphql.scalars.util.Kit.typeName; + +/** + * Access this via {@link graphql.scalars.ExtendedScalars#Year} + */ +@Internal +public final class YearScalar { + + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); + + public static final GraphQLScalarType INSTANCE; + + private YearScalar() {} + + static { + Coercing coercing = new Coercing() { + @Override + public String serialize(Object input) throws CoercingSerializeException { + TemporalAccessor temporalAccessor; + if (input instanceof TemporalAccessor) { + temporalAccessor = (TemporalAccessor) input; + } else if (input instanceof String) { + temporalAccessor = parseYear(input.toString(), CoercingSerializeException::new); + } else { + throw new CoercingSerializeException( + "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." + ); + } + try { + return DATE_FORMATTER.format(temporalAccessor); + } catch (DateTimeException e) { + throw new CoercingSerializeException( + "Unable to turn TemporalAccessor into full year because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public Year parseValue(Object input) throws CoercingParseValueException { + TemporalAccessor temporalAccessor; + if (input instanceof TemporalAccessor) { + temporalAccessor = (TemporalAccessor) input; + } else if (input instanceof String) { + temporalAccessor = parseYear(input.toString(), CoercingParseValueException::new); + } else { + throw new CoercingParseValueException( + "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." + ); + } + try { + return Year.from(temporalAccessor); + } catch (DateTimeException e) { + throw new CoercingParseValueException( + "Unable to turn TemporalAccessor into full year because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public Year parseLiteral(Object input) throws CoercingParseLiteralException { + if (!(input instanceof StringValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + ); + } + return parseYear(((StringValue) input).getValue(), CoercingParseLiteralException::new); + } + + @Override + public Value valueToLiteral(Object input) { + String s = serialize(input); + return StringValue.newStringValue(s).build(); + } + + private Year parseYear(String s, Function exceptionMaker) { + try { + TemporalAccessor temporalAccessor = DATE_FORMATTER.parse(s); + return Year.from(temporalAccessor); + } catch (DateTimeParseException e) { + throw exceptionMaker.apply("Invalid RFC3339 full year value : '" + s + "'. because of : '" + e.getMessage() + "'"); + } + } + }; + + INSTANCE = GraphQLScalarType.newScalar() + .name("Year") + .description("An RFC-3339 compliant Full Year Scalar") + .coercing(coercing) + .build(); + } +} diff --git a/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy new file mode 100644 index 0000000..c6f0e9b --- /dev/null +++ b/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy @@ -0,0 +1,64 @@ +package graphql.scalars.datetime + +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.YearMonth + +import static graphql.scalars.util.TestKit.mkStringValue + +class YearMonthScalarTest extends Specification { + + def coercing = ExtendedScalars.YearMonth.getCoercing() + + @Unroll + def "yearMonth parseValue"() { + + when: + def result = coercing.parseValue(input) + then: + result == expectedValue + where: + input | expectedValue + "1937-01" | YearMonth.of(1937, 1) + } + + @Unroll + def "yearMonth parseLiteral"() { + + when: + def result = coercing.parseLiteral(input) + then: + result == expectedValue + where: + input | expectedValue + new StringValue("1937-01") | YearMonth.of(1937, 1) + } + + @Unroll + def "yearMonth serialize"() { + + when: + def result = coercing.serialize(input) + then: + result == expectedValue + where: + input | expectedValue + "1937-01" | "1937-01" + } + + @Unroll + def "yearMonth valueToLiteral"() { + + when: + def result = coercing.valueToLiteral(input) + then: + result.isEqualTo(expectedValue) + where: + input | expectedValue + "1937-01" | mkStringValue("1937-01") + } + +} diff --git a/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy new file mode 100644 index 0000000..0d622fa --- /dev/null +++ b/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy @@ -0,0 +1,64 @@ +package graphql.scalars.datetime + +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.Year + +import static graphql.scalars.util.TestKit.mkStringValue + +class YearScalarTest extends Specification { + + def coercing = ExtendedScalars.Year.getCoercing() + + @Unroll + def "year parseValue"() { + + when: + def result = coercing.parseValue(input) + then: + result == expectedValue + where: + input | expectedValue + "1937" | Year.of(1937) + } + + @Unroll + def "year parseLiteral"() { + + when: + def result = coercing.parseLiteral(input) + then: + result == expectedValue + where: + input | expectedValue + new StringValue("1937") | Year.of(1937) + } + + @Unroll + def "year serialize"() { + + when: + def result = coercing.serialize(input) + then: + result == expectedValue + where: + input | expectedValue + "1937" | "1937" + } + + @Unroll + def "year valueToLiteral"() { + + when: + def result = coercing.valueToLiteral(input) + then: + result.isEqualTo(expectedValue) + where: + input | expectedValue + "1937" | mkStringValue("1937") + } + +} From 7788c76e4cd4e7482a040d9ab805706a9514a7d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:37:07 +0000 Subject: [PATCH 11/29] Bump com.graphql-java:graphql-java from 22.1 to 22.3 Bumps [com.graphql-java:graphql-java](https://github.com/graphql-java/graphql-java) from 22.1 to 22.3. - [Release notes](https://github.com/graphql-java/graphql-java/releases) - [Commits](https://github.com/graphql-java/graphql-java/compare/v22.1...v22.3) --- updated-dependencies: - dependency-name: com.graphql-java:graphql-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index be8992d..d35f12c 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ repositories { } dependencies { - implementation "com.graphql-java:graphql-java:22.1" + implementation "com.graphql-java:graphql-java:22.3" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" testImplementation "org.codehaus.groovy:groovy:3.0.22" From d753669f37de14ab47616ee3ee788904a5f43056 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:11:57 +0000 Subject: [PATCH 12/29] Bump org.codehaus.groovy:groovy from 3.0.22 to 3.0.23 Bumps [org.codehaus.groovy:groovy](https://github.com/apache/groovy) from 3.0.22 to 3.0.23. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.codehaus.groovy:groovy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d35f12c..ca5e95d 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation "com.graphql-java:graphql-java:22.3" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" - testImplementation "org.codehaus.groovy:groovy:3.0.22" + testImplementation "org.codehaus.groovy:groovy:3.0.23" } task sourcesJar(type: Jar, dependsOn: classes) { From d5f88f41e5549f98ec1f16519b72f17386757e7d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sat, 25 Jan 2025 20:13:00 +1100 Subject: [PATCH 13/29] Add more test cases from specification examples --- .../datetime/DateTimeScalarTest.groovy | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy index 42c6c9c..cc9acad 100644 --- a/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy @@ -60,11 +60,15 @@ class DateTimeScalarTest extends Specification { then: thrown(expectedValue) where: - input | expectedValue - "1985-04-12" | CoercingParseValueException - "2022-11-24T01:00:01.02-00:00" | CoercingParseValueException - mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException - 666 || CoercingParseValueException + input | expectedValue + "1985-04-12" | CoercingParseValueException // No time provided + "2022-11-24T01:00:01.02-00:00" | CoercingParseValueException // -00:00 is not a valid offset in specification + mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException // LocalDateTime has no time zone + 666 | CoercingParseValueException // A random number + "2011-08-30T13:22:53.108" | CoercingParseValueException // No offset provided + "2011-08-30T24:22:53.108Z" | CoercingParseValueException // 24 is not allowed as hour of the time. | + "2010-02-30T21:22:53.108Z" | CoercingParseValueException // 30th of February is not a valid date | + "2010-02-11T21:22:53.108Z+25:11" | CoercingParseValueException // 25 is not a valid hour for offset } def "datetime AST literal"() { @@ -101,11 +105,15 @@ class DateTimeScalarTest extends Specification { then: thrown(expectedValue) where: - input | expectedValue - "1985-04-12" | CoercingSerializeException - "2022-11-24T01:00:01.02-00:00" | CoercingSerializeException - mkLocalDT(year: 1980, hour: 3) | CoercingSerializeException - 666 || CoercingSerializeException + input | expectedValue + "1985-04-12" | CoercingSerializeException // No time provided + "2022-11-24T01:00:01.02-00:00" | CoercingSerializeException // -00:00 is not a valid offset in specification + mkLocalDT(year: 1980, hour: 3) | CoercingSerializeException // LocalDateTime has no time zone + 666 | CoercingSerializeException // A random number + "2011-08-30T13:22:53.108" | CoercingSerializeException // No offset provided + "2011-08-30T24:22:53.108Z" | CoercingSerializeException // 24 is not allowed as hour of the time. | + "2010-02-30T21:22:53.108Z" | CoercingSerializeException // 30th of February is not a valid date | + "2010-02-11T21:22:53.108Z+25:11" | CoercingSerializeException // 25 is not a valid hour for offset } @Unroll @@ -116,8 +124,16 @@ class DateTimeScalarTest extends Specification { then: thrown(expectedValue) where: - input | expectedValue - "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException + input | expectedValue + "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException // -00:00 is not a valid offset in specification + "1985-04-12" | CoercingParseLiteralException // No time provided + "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException // -00:00 is not a valid offset in specification + mkLocalDT(year: 1980, hour: 3) | CoercingParseLiteralException // LocalDateTime has no time zone + 666 | CoercingParseLiteralException // A random number + "2011-08-30T13:22:53.108" | CoercingParseLiteralException // No offset provided + "2011-08-30T24:22:53.108Z" | CoercingParseLiteralException // 24 is not allowed as hour of the time. | + "2010-02-30T21:22:53.108Z" | CoercingParseLiteralException // 30th of February is not a valid date | + "2010-02-11T21:22:53.108Z+25:11" | CoercingParseLiteralException // 25 is not a valid hour for offset } } From 7c2c1d3f74abe039e874b9484631ec7214b32051 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sat, 25 Jan 2025 20:16:23 +1100 Subject: [PATCH 14/29] Tidy up --- .../scalars/datetime/DateTimeScalarTest.groovy | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy index cc9acad..74d8d1e 100644 --- a/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy @@ -66,8 +66,8 @@ class DateTimeScalarTest extends Specification { mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException // LocalDateTime has no time zone 666 | CoercingParseValueException // A random number "2011-08-30T13:22:53.108" | CoercingParseValueException // No offset provided - "2011-08-30T24:22:53.108Z" | CoercingParseValueException // 24 is not allowed as hour of the time. | - "2010-02-30T21:22:53.108Z" | CoercingParseValueException // 30th of February is not a valid date | + "2011-08-30T24:22:53.108Z" | CoercingParseValueException // 24 is not allowed as hour of the time + "2010-02-30T21:22:53.108Z" | CoercingParseValueException // 30th of February is not a valid date "2010-02-11T21:22:53.108Z+25:11" | CoercingParseValueException // 25 is not a valid hour for offset } @@ -111,8 +111,8 @@ class DateTimeScalarTest extends Specification { mkLocalDT(year: 1980, hour: 3) | CoercingSerializeException // LocalDateTime has no time zone 666 | CoercingSerializeException // A random number "2011-08-30T13:22:53.108" | CoercingSerializeException // No offset provided - "2011-08-30T24:22:53.108Z" | CoercingSerializeException // 24 is not allowed as hour of the time. | - "2010-02-30T21:22:53.108Z" | CoercingSerializeException // 30th of February is not a valid date | + "2011-08-30T24:22:53.108Z" | CoercingSerializeException // 24 is not allowed as hour of the time + "2010-02-30T21:22:53.108Z" | CoercingSerializeException // 30th of February is not a valid date "2010-02-11T21:22:53.108Z+25:11" | CoercingSerializeException // 25 is not a valid hour for offset } @@ -131,8 +131,8 @@ class DateTimeScalarTest extends Specification { mkLocalDT(year: 1980, hour: 3) | CoercingParseLiteralException // LocalDateTime has no time zone 666 | CoercingParseLiteralException // A random number "2011-08-30T13:22:53.108" | CoercingParseLiteralException // No offset provided - "2011-08-30T24:22:53.108Z" | CoercingParseLiteralException // 24 is not allowed as hour of the time. | - "2010-02-30T21:22:53.108Z" | CoercingParseLiteralException // 30th of February is not a valid date | + "2011-08-30T24:22:53.108Z" | CoercingParseLiteralException // 24 is not allowed as hour of the time + "2010-02-30T21:22:53.108Z" | CoercingParseLiteralException // 30th of February is not a valid date "2010-02-11T21:22:53.108Z+25:11" | CoercingParseLiteralException // 25 is not a valid hour for offset } From e44219a61c8d40f6026212ec2e76975c7eb9f6b1 Mon Sep 17 00:00:00 2001 From: TrianguloY Date: Thu, 6 Feb 2025 10:13:44 +0100 Subject: [PATCH 15/29] Missing final for ExtendedScalars#UUID field --- src/main/java/graphql/scalars/ExtendedScalars.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index ce36232..24c4d24 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -154,7 +154,7 @@ public class ExtendedScalars { * A UUID scalar that accepts a universally unique identifier and produces {@link * java.util.UUID} objects at runtime. */ - public static GraphQLScalarType UUID = UUIDScalar.INSTANCE; + public static final GraphQLScalarType UUID = UUIDScalar.INSTANCE; /** * An `Int` scalar that MUST be greater than zero From 89676c443b93a8e884a213162b22298f643a651a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:13:23 +0000 Subject: [PATCH 16/29] Bump org.codehaus.groovy:groovy from 3.0.23 to 3.0.24 Bumps [org.codehaus.groovy:groovy](https://github.com/apache/groovy) from 3.0.23 to 3.0.24. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.codehaus.groovy:groovy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ca5e95d..c50928a 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation "com.graphql-java:graphql-java:22.3" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" - testImplementation "org.codehaus.groovy:groovy:3.0.23" + testImplementation "org.codehaus.groovy:groovy:3.0.24" } task sourcesJar(type: Jar, dependsOn: classes) { From d6c13f5aa268365ffc8ed03407c32a1219595a41 Mon Sep 17 00:00:00 2001 From: bbaker Date: Sun, 15 Jun 2025 13:06:07 +1000 Subject: [PATCH 17/29] Fixed up failing compilation and tests --- README.md | 2 +- .../scalars/color/hex/HexColorCodeScalar.java | 3 +- .../color/hex/HexColorCodeScalarTest.groovy | 52 +++++++++---------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0b3c7fb..e3b0e30 100644 --- a/README.md +++ b/README.md @@ -451,7 +451,7 @@ query {

-scalar URL
+scalar Url
   @specifiedBy(url: 
     "https://www.w3.org/Addressing/URL/url-spec.txt"
   )
diff --git a/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java b/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java
index 0cdc721..8a44648 100644
--- a/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java
+++ b/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java
@@ -12,7 +12,8 @@
 /**
  * Access this via {@link graphql.scalars.ExtendedScalars#HexColorCode}
  * See the Web colors for more details.
- * @implNote Supports the following formats: #RGB, #RGBA, #RRGGBB, #RRGGBBAA. Need to be prefixed with '#'
+ * 

+ * Supports the following formats: #RGB, #RGBA, #RRGGBB, #RRGGBBAA. Need to be prefixed with '#' */ public class HexColorCodeScalar { diff --git a/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy b/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy index 97c6e18..6af9f60 100644 --- a/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy @@ -19,11 +19,11 @@ class HexColorCodeScalarTest extends Specification { then: result.equals(expectedValue) where: - input | expectedValue - "#ff0000" | mkColor(0xff, 0, 0) - "#123" | mkColor(0x11, 0x22, 0x33) - "#11223344" | mkColor(0x11, 0x22, 0x33, 0x44) - "#1234" | mkColor(0x11, 0x22, 0x33, 0x44) + input | expectedValue + "#ff0000" | mkColor(0xff, 0, 0) + "#123" | mkColor(0x11, 0x22, 0x33) + "#11223344" | mkColor(0x11, 0x22, 0x33, 0x44) + "#1234" | mkColor(0x11, 0x22, 0x33, 0x44) } @Unroll @@ -47,12 +47,12 @@ class HexColorCodeScalarTest extends Specification { then: result == expectedValue where: - input | expectedValue - "#ff0000" | "#ff0000" - "#123" | "#112233" - "#11223344" | "#11223344" - "#1234" | "#11223344" - mkColor(0x21, 0x23, 0x33) | "#212333" + input | expectedValue + "#ff0000" | "#ff0000" + "#123" | "#112233" + "#11223344" | "#11223344" + "#1234" | "#11223344" + mkColor(0x21, 0x23, 0x33) | "#212333" mkColor(0x21, 0x23, 0x33, 0x44) | "#21233344" } @@ -63,30 +63,30 @@ class HexColorCodeScalarTest extends Specification { then: result.isEqualTo(expectedValue) where: - input | expectedValue - "#ff0000" | new StringValue("#ff0000") - "#123" | new StringValue("#112233") - "#11223344" | new StringValue("#11223344") - "#1234" | new StringValue("#11223344") - mkColor(0x21, 0x23, 0x33) | new StringValue("#212333") + input | expectedValue + "#ff0000" | new StringValue("#ff0000") + "#123" | new StringValue("#112233") + "#11223344" | new StringValue("#11223344") + "#1234" | new StringValue("#11223344") + mkColor(0x21, 0x23, 0x33) | new StringValue("#212333") mkColor(0x21, 0x23, 0x33, 0x44) | new StringValue("#21233344") } @Unroll - def "parseValue throws exception for invalid input #value"() { + def "parseValue throws exception for invalid input #input"() { when: def result = coercing.parseValue(input) then: thrown(CoercingParseValueException) where: - input | _ - "ff000" | _ - "" | _ - "not a hex code" | _ - "42.3" | _ - new Double(42.3) | _ - new Float(42.3) | _ - new Object() | _ + input | _ + "ff000" | _ + "" | _ + "not a hex code" | _ + "42.3" | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ + new Object() | _ } } \ No newline at end of file From 2097a0ebeccf20418d5b38eac275555c23afc752 Mon Sep 17 00:00:00 2001 From: bbaker Date: Sun, 15 Jun 2025 22:26:32 +1000 Subject: [PATCH 18/29] This removes all the deprecated Coercing methods and replaces them with the proper ones It also addresses https://github.com/graphql-java/graphql-java-extended-scalars/issues/156 --- .../graphql/scalars/alias/AliasedScalar.java | 31 +++---- .../scalars/color/hex/HexColorCodeScalar.java | 24 +++-- .../country/code/CountryCodeScalar.java | 21 +++-- .../scalars/currency/CurrencyScalar.java | 21 +++-- .../datetime/AccurateDurationScalar.java | 34 ++++--- .../graphql/scalars/datetime/DateScalar.java | 20 ++-- .../scalars/datetime/DateTimeScalar.java | 19 ++-- .../scalars/datetime/LocalTimeCoercing.java | 16 +++- .../datetime/NominalDurationScalar.java | 34 ++++--- .../graphql/scalars/datetime/TimeScalar.java | 18 ++-- .../scalars/datetime/YearMonthScalar.java | 20 ++-- .../graphql/scalars/datetime/YearScalar.java | 20 ++-- .../java/graphql/scalars/id/UUIDScalar.java | 15 +-- .../graphql/scalars/java/JavaPrimitives.java | 66 +++++++------- .../graphql/scalars/locale/LocaleScalar.java | 18 ++-- .../scalars/numeric/FloatCoercing.java | 20 ++-- .../graphql/scalars/numeric/IntCoercing.java | 20 ++-- .../graphql/scalars/object/ObjectScalar.java | 40 ++++---- .../graphql/scalars/regex/RegexScalar.java | 20 ++-- .../java/graphql/scalars/url/UrlScalar.java | 20 ++-- .../scalars/alias/AliasedScalarTest.groovy | 15 +-- .../color/hex/HexColorCodeScalarTest.groovy | 14 +-- .../country/code/CountryCodeScalarTest.groovy | 21 +++-- .../currency/CurrencyScalarTest.groovy | 32 +++---- .../AccurateDurationScalarTest.groovy | 37 ++++---- .../scalars/datetime/DateScalarTest.groovy | 12 +-- .../datetime/DateTimeScalarTest.groovy | 56 ++++++------ .../datetime/LocalTimeScalarTest.groovy | 29 ++++-- .../datetime/NominalDurationScalarTest.groovy | 34 +++---- .../scalars/datetime/TimeScalarTest.groovy | 16 ++-- .../datetime/YearMonthScalarTest.groovy | 28 +++--- .../scalars/datetime/YearScalarTest.groovy | 28 +++--- .../graphql/scalars/id/UUIDScalarTest.groovy | 18 ++-- .../scalars/java/ScalarsBigDecimalTest.groovy | 45 ++++----- .../scalars/java/ScalarsBigIntegerTest.groovy | 23 +++-- .../scalars/java/ScalarsByteTest.groovy | 90 +++++++++--------- .../scalars/java/ScalarsCharTest.groovy | 18 ++-- .../scalars/java/ScalarsLongTest.groovy | 91 +++++++++---------- .../scalars/java/ScalarsShortTest.groovy | 49 +++++----- .../scalars/locale/LocaleScalarTest.groovy | 12 +-- .../numeric/NegativeFloatScalarTest.groovy | 11 +-- .../numeric/NegativeIntScalarTest.groovy | 10 +- .../numeric/NonNegativeFloatScalarTest.groovy | 10 +- .../numeric/NonNegativeIntScalarTest.groovy | 10 +- .../numeric/NonPositiveFloatScalarTest.groovy | 10 +- .../numeric/NonPositiveIntScalarTest.groovy | 10 +- .../numeric/PositiveFloatScalarTest.groovy | 10 +- .../numeric/PositiveIntScalarTest.groovy | 10 +- .../scalars/object/ObjectScalarTest.groovy | 47 +++++----- .../scalars/regex/RegexScalarTest.groovy | 26 +++--- .../graphql/scalars/url/UrlScalarTest.groovy | 19 ++-- .../scalars/util/AbstractScalarTest.groovy | 22 +++++ .../graphql/scalars/util/TestKit.groovy | 3 +- 53 files changed, 740 insertions(+), 623 deletions(-) create mode 100644 src/test/groovy/graphql/scalars/util/AbstractScalarTest.groovy diff --git a/src/main/java/graphql/scalars/alias/AliasedScalar.java b/src/main/java/graphql/scalars/alias/AliasedScalar.java index 9f7ba58..3f3777c 100644 --- a/src/main/java/graphql/scalars/alias/AliasedScalar.java +++ b/src/main/java/graphql/scalars/alias/AliasedScalar.java @@ -1,7 +1,9 @@ package graphql.scalars.alias; import graphql.Assert; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.Value; import graphql.schema.Coercing; import graphql.schema.CoercingParseLiteralException; @@ -9,7 +11,7 @@ import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; -import java.util.Map; +import java.util.Locale; /** * Access this via {@link graphql.scalars.ExtendedScalars#newAliasedScalar(String)} @@ -17,7 +19,8 @@ @Internal public final class AliasedScalar { - private AliasedScalar() {} + private AliasedScalar() { + } /** * A builder for {@link graphql.scalars.alias.AliasedScalar} @@ -75,31 +78,25 @@ public GraphQLScalarType build() { private static GraphQLScalarType aliasedScalarImpl(String name, String description, GraphQLScalarType aliasedScalar) { Assert.assertNotNull(aliasedScalar); - Coercing coercing = new Coercing() { - @Override - public Object serialize(Object input) throws CoercingSerializeException { - return aliasedScalar.getCoercing().serialize(input); - } - + Coercing coercing = new Coercing<>() { @Override - public Object parseValue(Object input) throws CoercingParseValueException { - return aliasedScalar.getCoercing().parseValue(input); + public Object serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { + return aliasedScalar.getCoercing().serialize(input, graphQLContext, locale); } @Override - public Object parseLiteral(Object input) throws CoercingParseLiteralException { - return aliasedScalar.getCoercing().parseLiteral(input); + public Object parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { + return aliasedScalar.getCoercing().parseValue(input, graphQLContext, locale); } @Override - public Object parseLiteral(Object input, Map variables) throws CoercingParseLiteralException { - Coercing c = aliasedScalar.getCoercing(); - return c.parseLiteral(input, variables); + public Object parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { + return aliasedScalar.getCoercing().parseLiteral(input, variables, graphQLContext, locale); } @Override - public Value valueToLiteral(Object input) { - return aliasedScalar.getCoercing().valueToLiteral(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + return aliasedScalar.getCoercing().valueToLiteral(input, graphQLContext, locale); } }; return GraphQLScalarType.newScalar() diff --git a/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java b/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java index 8a44648..45d914d 100644 --- a/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java +++ b/src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java @@ -1,14 +1,22 @@ package graphql.scalars.color.hex; +import graphql.GraphQLContext; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; -import graphql.schema.*; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; import java.awt.*; +import java.util.Locale; import java.util.function.Function; import java.util.regex.Pattern; import static graphql.scalars.util.Kit.typeName; + /** * Access this via {@link graphql.scalars.ExtendedScalars#HexColorCode} * See the Web colors for more details. @@ -21,15 +29,15 @@ public class HexColorCodeScalar { static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { private final Pattern HEX_PATTERN = Pattern.compile("^(#([A-Fa-f0-9]{3,4}){1,2})$"); @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Color color = parseColor(input, CoercingSerializeException::new); boolean hasAlpha = color.getAlpha() != 255; - if (hasAlpha){ + if (hasAlpha) { return String.format("#%02x%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); } else { return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); @@ -37,12 +45,12 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public Color parseValue(Object input) throws CoercingParseValueException { + public Color parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { return parseColor(input, CoercingParseValueException::new); } @Override - public Color parseLiteral(Object input) throws CoercingParseLiteralException { + public Color parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException("Expected type 'StringValue' but was '" + typeName(input) + "'."); } @@ -51,8 +59,8 @@ public Color parseLiteral(Object input) throws CoercingParseLiteralException { } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/country/code/CountryCodeScalar.java b/src/main/java/graphql/scalars/country/code/CountryCodeScalar.java index b88c139..5cee4f0 100644 --- a/src/main/java/graphql/scalars/country/code/CountryCodeScalar.java +++ b/src/main/java/graphql/scalars/country/code/CountryCodeScalar.java @@ -1,10 +1,17 @@ package graphql.scalars.country.code; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; -import graphql.schema.*; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -18,21 +25,21 @@ public class CountryCodeScalar { public static final GraphQLScalarType INSTANCE; static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { CountryCode countryCode = parseCountryCode(input, CoercingParseValueException::new); return countryCode.name(); } @Override - public CountryCode parseValue(Object input) throws CoercingParseValueException { + public CountryCode parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { return parseCountryCode(input, CoercingParseValueException::new); } @Override - public CountryCode parseLiteral(Object input) throws CoercingParseLiteralException { + public CountryCode parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException("Expected AST type 'StringValue' but was '" + typeName(input) + "'."); } @@ -42,8 +49,8 @@ public CountryCode parseLiteral(Object input) throws CoercingParseLiteralExcepti } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/currency/CurrencyScalar.java b/src/main/java/graphql/scalars/currency/CurrencyScalar.java index a2193a0..29c8967 100644 --- a/src/main/java/graphql/scalars/currency/CurrencyScalar.java +++ b/src/main/java/graphql/scalars/currency/CurrencyScalar.java @@ -1,11 +1,18 @@ package graphql.scalars.currency; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; -import graphql.schema.*; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; import java.util.Currency; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -19,21 +26,21 @@ public class CurrencyScalar { public static final GraphQLScalarType INSTANCE; static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Currency currency = parseCurrency(input, CoercingSerializeException::new); return currency.getCurrencyCode(); } @Override - public Currency parseValue(Object input) throws CoercingParseValueException { + public Currency parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { return parseCurrency(input, CoercingParseValueException::new); } @Override - public Currency parseLiteral(Object input) throws CoercingParseLiteralException { + public Currency parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException("Expected AST type 'StringValue' but was '" + typeName(input) + "'."); } @@ -42,8 +49,8 @@ public Currency parseLiteral(Object input) throws CoercingParseLiteralException } @Override - public Value valueToLiteral(Object input) { - String serializedInput = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String serializedInput = serialize(input, graphQLContext, locale); return StringValue.newStringValue(serializedInput).build(); } diff --git a/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java b/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java index e23446b..c9b45c6 100644 --- a/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java +++ b/src/main/java/graphql/scalars/datetime/AccurateDurationScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -11,6 +13,7 @@ import java.time.Duration; import java.time.format.DateTimeParseException; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -23,12 +26,13 @@ public class AccurateDurationScalar { public static final GraphQLScalarType INSTANCE; - private AccurateDurationScalar() {} + private AccurateDurationScalar() { + } static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Duration duration; if (input instanceof Duration) { duration = (Duration) input; @@ -36,14 +40,14 @@ public String serialize(Object input) throws CoercingSerializeException { duration = parseDuration(input.toString(), CoercingSerializeException::new); } else { throw new CoercingSerializeException( - "Expected something we can convert to 'java.time.Duration' but was '" + typeName(input) + "'." + "Expected something we can convert to 'java.time.Duration' but was '" + typeName(input) + "'." ); } return duration.toString(); } @Override - public Duration parseValue(Object input) throws CoercingParseValueException { + public Duration parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { Duration duration; if (input instanceof Duration) { duration = (Duration) input; @@ -51,25 +55,25 @@ public Duration parseValue(Object input) throws CoercingParseValueException { duration = parseDuration(input.toString(), CoercingParseValueException::new); } else { throw new CoercingParseValueException( - "Expected a 'String' but was '" + typeName(input) + "'." + "Expected a 'String' but was '" + typeName(input) + "'." ); } return duration; } @Override - public Duration parseLiteral(Object input) throws CoercingParseLiteralException { + public Duration parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( - "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." ); } return parseDuration(((StringValue) input).getValue(), CoercingParseLiteralException::new); } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } @@ -83,11 +87,11 @@ private Duration parseDuration(String s, Function exce }; INSTANCE = GraphQLScalarType.newScalar() - .name("AccurateDuration") - .description("A ISO 8601 duration scalar with only day, hour, minute, second components.") - .specifiedByUrl("https://scalars.graphql.org/AlexandreCarlton/accurate-duration") // TODO: Change to .specifiedByURL when builder added to graphql-java - .coercing(coercing) - .build(); + .name("AccurateDuration") + .description("A ISO 8601 duration scalar with only day, hour, minute, second components.") + .specifiedByUrl("https://scalars.graphql.org/AlexandreCarlton/accurate-duration") // TODO: Change to .specifiedByURL when builder added to graphql-java + .coercing(coercing) + .build(); } } diff --git a/src/main/java/graphql/scalars/datetime/DateScalar.java b/src/main/java/graphql/scalars/datetime/DateScalar.java index 592f04e..625df03 100644 --- a/src/main/java/graphql/scalars/datetime/DateScalar.java +++ b/src/main/java/graphql/scalars/datetime/DateScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -14,6 +16,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -22,18 +25,19 @@ * Access this via {@link graphql.scalars.ExtendedScalars#Date} */ @Internal -public final class DateScalar { +public final class DateScalar { private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); public static final GraphQLScalarType INSTANCE; - private DateScalar() {} + private DateScalar() { + } static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -54,7 +58,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public LocalDate parseValue(Object input) throws CoercingParseValueException { + public LocalDate parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -75,7 +79,7 @@ public LocalDate parseValue(Object input) throws CoercingParseValueException { } @Override - public LocalDate parseLiteral(Object input) throws CoercingParseLiteralException { + public LocalDate parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -85,8 +89,8 @@ public LocalDate parseLiteral(Object input) throws CoercingParseLiteralException } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java index 12b01de..86a5ea9 100644 --- a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java +++ b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -15,6 +17,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -33,13 +36,15 @@ public final class DateTimeScalar { public static final GraphQLScalarType INSTANCE; - private DateTimeScalar() {} + private DateTimeScalar() { + } + private static final DateTimeFormatter customOutputFormatter = getCustomDateTimeFormatter(); static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { OffsetDateTime offsetDateTime; if (input instanceof OffsetDateTime) { offsetDateTime = (OffsetDateTime) input; @@ -62,7 +67,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { + public OffsetDateTime parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { OffsetDateTime offsetDateTime; if (input instanceof OffsetDateTime) { offsetDateTime = (OffsetDateTime) input; @@ -79,7 +84,7 @@ public OffsetDateTime parseValue(Object input) throws CoercingParseValueExceptio } @Override - public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { + public OffsetDateTime parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -89,8 +94,8 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/datetime/LocalTimeCoercing.java b/src/main/java/graphql/scalars/datetime/LocalTimeCoercing.java index 4c5666d..924e92e 100644 --- a/src/main/java/graphql/scalars/datetime/LocalTimeCoercing.java +++ b/src/main/java/graphql/scalars/datetime/LocalTimeCoercing.java @@ -1,6 +1,9 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; +import graphql.language.Value; import graphql.schema.Coercing; import graphql.schema.CoercingParseLiteralException; import graphql.schema.CoercingParseValueException; @@ -11,6 +14,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -20,7 +24,7 @@ public class LocalTimeCoercing implements Coercing { private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_TIME; @Override - public String serialize(final Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -41,7 +45,7 @@ public String serialize(final Object input) throws CoercingSerializeException { } @Override - public LocalTime parseValue(final Object input) throws CoercingParseValueException { + public LocalTime parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -62,7 +66,7 @@ public LocalTime parseValue(final Object input) throws CoercingParseValueExcepti } @Override - public LocalTime parseLiteral(final Object input) throws CoercingParseLiteralException { + public LocalTime parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -71,6 +75,12 @@ public LocalTime parseLiteral(final Object input) throws CoercingParseLiteralExc return parseTime(((StringValue) input).getValue(), CoercingParseLiteralException::new); } + @Override + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); + return StringValue.newStringValue(s).build(); + } + private static LocalTime parseTime(String s, Function exceptionMaker) { try { TemporalAccessor temporalAccessor = DATE_FORMATTER.parse(s); diff --git a/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java b/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java index 320393a..410ba19 100644 --- a/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java +++ b/src/main/java/graphql/scalars/datetime/NominalDurationScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -11,6 +13,7 @@ import java.time.Period; import java.time.format.DateTimeParseException; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -23,12 +26,13 @@ public class NominalDurationScalar { public static final GraphQLScalarType INSTANCE; - private NominalDurationScalar() {} + private NominalDurationScalar() { + } static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Period period; if (input instanceof Period) { period = (Period) input; @@ -36,14 +40,14 @@ public String serialize(Object input) throws CoercingSerializeException { period = parsePeriod(input.toString(), CoercingSerializeException::new); } else { throw new CoercingSerializeException( - "Expected something we can convert to 'java.time.OffsetDateTime' but was '" + typeName(input) + "'." + "Expected something we can convert to 'java.time.OffsetDateTime' but was '" + typeName(input) + "'." ); } return period.toString(); } @Override - public Period parseValue(Object input) throws CoercingParseValueException { + public Period parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { Period period; if (input instanceof Period) { period = (Period) input; @@ -51,25 +55,25 @@ public Period parseValue(Object input) throws CoercingParseValueException { period = parsePeriod(input.toString(), CoercingParseValueException::new); } else { throw new CoercingParseValueException( - "Expected a 'String' but was '" + typeName(input) + "'." + "Expected a 'String' but was '" + typeName(input) + "'." ); } return period; } @Override - public Period parseLiteral(Object input) throws CoercingParseLiteralException { + public Period parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( - "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." ); } return parsePeriod(((StringValue) input).getValue(), CoercingParseLiteralException::new); } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } @@ -83,10 +87,10 @@ private Period parsePeriod(String s, Function exceptio }; INSTANCE = GraphQLScalarType.newScalar() - .name("NominalDuration") - .description("A ISO 8601 duration with only year, month, week and day components.") - .specifiedByUrl("https://scalars.graphql.org/AlexandreCarlton/nominal-duration") // TODO: Change to .specifiedByURL when builder added to graphql-java - .coercing(coercing) - .build(); + .name("NominalDuration") + .description("A ISO 8601 duration with only year, month, week and day components.") + .specifiedByUrl("https://scalars.graphql.org/AlexandreCarlton/nominal-duration") // TODO: Change to .specifiedByURL when builder added to graphql-java + .coercing(coercing) + .build(); } } diff --git a/src/main/java/graphql/scalars/datetime/TimeScalar.java b/src/main/java/graphql/scalars/datetime/TimeScalar.java index 1ce9ba9..34d3074 100644 --- a/src/main/java/graphql/scalars/datetime/TimeScalar.java +++ b/src/main/java/graphql/scalars/datetime/TimeScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -14,6 +16,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -28,12 +31,13 @@ public final class TimeScalar { public static final GraphQLScalarType INSTANCE; - private TimeScalar() {} + private TimeScalar() { + } static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -54,7 +58,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public OffsetTime parseValue(Object input) throws CoercingParseValueException { + public OffsetTime parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -75,7 +79,7 @@ public OffsetTime parseValue(Object input) throws CoercingParseValueException { } @Override - public OffsetTime parseLiteral(Object input) throws CoercingParseLiteralException { + public OffsetTime parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -85,8 +89,8 @@ public OffsetTime parseLiteral(Object input) throws CoercingParseLiteralExceptio } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/datetime/YearMonthScalar.java b/src/main/java/graphql/scalars/datetime/YearMonthScalar.java index 2d679f1..261ed8c 100644 --- a/src/main/java/graphql/scalars/datetime/YearMonthScalar.java +++ b/src/main/java/graphql/scalars/datetime/YearMonthScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -14,6 +16,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -22,18 +25,19 @@ * Access this via {@link graphql.scalars.ExtendedScalars#YearMonth} */ @Internal -public final class YearMonthScalar { +public final class YearMonthScalar { private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM"); public static final GraphQLScalarType INSTANCE; - private YearMonthScalar() {} + private YearMonthScalar() { + } static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -54,7 +58,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public YearMonth parseValue(Object input) throws CoercingParseValueException { + public YearMonth parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -75,7 +79,7 @@ public YearMonth parseValue(Object input) throws CoercingParseValueException { } @Override - public YearMonth parseLiteral(Object input) throws CoercingParseLiteralException { + public YearMonth parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -85,8 +89,8 @@ public YearMonth parseLiteral(Object input) throws CoercingParseLiteralException } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/datetime/YearScalar.java b/src/main/java/graphql/scalars/datetime/YearScalar.java index dd268a5..2df68bd 100644 --- a/src/main/java/graphql/scalars/datetime/YearScalar.java +++ b/src/main/java/graphql/scalars/datetime/YearScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.datetime; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -14,6 +16,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; +import java.util.Locale; import java.util.function.Function; import static graphql.scalars.util.Kit.typeName; @@ -22,18 +25,19 @@ * Access this via {@link graphql.scalars.ExtendedScalars#Year} */ @Internal -public final class YearScalar { +public final class YearScalar { private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); public static final GraphQLScalarType INSTANCE; - private YearScalar() {} + private YearScalar() { + } static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -54,7 +58,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public Year parseValue(Object input) throws CoercingParseValueException { + public Year parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { TemporalAccessor temporalAccessor; if (input instanceof TemporalAccessor) { temporalAccessor = (TemporalAccessor) input; @@ -75,7 +79,7 @@ public Year parseValue(Object input) throws CoercingParseValueException { } @Override - public Year parseLiteral(Object input) throws CoercingParseLiteralException { + public Year parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -85,8 +89,8 @@ public Year parseLiteral(Object input) throws CoercingParseLiteralException { } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/id/UUIDScalar.java b/src/main/java/graphql/scalars/id/UUIDScalar.java index 79868d9..1d0c149 100644 --- a/src/main/java/graphql/scalars/id/UUIDScalar.java +++ b/src/main/java/graphql/scalars/id/UUIDScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.id; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.scalars.util.Kit; @@ -10,6 +12,7 @@ import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; +import java.util.Locale; import java.util.UUID; import static graphql.scalars.util.Kit.typeName; @@ -23,7 +26,7 @@ public class UUIDScalar { public static GraphQLScalarType INSTANCE; static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { private UUID convertImpl(Object input) { if (input instanceof String) { try { @@ -38,7 +41,7 @@ private UUID convertImpl(Object input) { } @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { UUID result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -49,7 +52,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public UUID parseValue(Object input) throws CoercingParseValueException { + public UUID parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { UUID result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -60,7 +63,7 @@ public UUID parseValue(Object input) throws CoercingParseValueException { } @Override - public UUID parseLiteral(Object input) throws CoercingParseLiteralException { + public UUID parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected a 'java.util.UUID' AST type object but was '" + typeName(input) + "'." @@ -76,8 +79,8 @@ public UUID parseLiteral(Object input) throws CoercingParseLiteralException { } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } }; diff --git a/src/main/java/graphql/scalars/java/JavaPrimitives.java b/src/main/java/graphql/scalars/java/JavaPrimitives.java index ab401e5..e262549 100644 --- a/src/main/java/graphql/scalars/java/JavaPrimitives.java +++ b/src/main/java/graphql/scalars/java/JavaPrimitives.java @@ -1,6 +1,8 @@ package graphql.scalars.java; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.FloatValue; import graphql.language.IntValue; import graphql.language.StringValue; @@ -13,6 +15,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Locale; import java.util.Objects; /** @@ -21,7 +24,8 @@ @Internal public final class JavaPrimitives { - private JavaPrimitives() {} + private JavaPrimitives() { + } private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE); private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE); @@ -48,7 +52,7 @@ private static String typeName(Object input) { public static final GraphQLScalarType GraphQLLong; static { - Coercing longCoercing = new Coercing() { + Coercing longCoercing = new Coercing<>() { private Long convertImpl(Object input) { if (input instanceof Long) { @@ -72,7 +76,7 @@ private Long convertImpl(Object input) { } @Override - public Long serialize(Object input) { + public Long serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Long result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -83,7 +87,7 @@ public Long serialize(Object input) { } @Override - public Long parseValue(Object input) { + public Long parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { Long result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -94,7 +98,7 @@ public Long parseValue(Object input) { } @Override - public Long parseLiteral(Object input) { + public Long parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (input instanceof StringValue) { try { return Long.parseLong(((StringValue) input).getValue()); @@ -118,7 +122,7 @@ public Long parseLiteral(Object input) { } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { Long result = Objects.requireNonNull(convertImpl(input)); return IntValue.newIntValue(BigInteger.valueOf(result)).build(); } @@ -135,7 +139,7 @@ public Value valueToLiteral(Object input) { public static final GraphQLScalarType GraphQLShort; static { - Coercing shortCoercing = new Coercing() { + Coercing shortCoercing = new Coercing<>() { private Short convertImpl(Object input) { if (input instanceof Short) { @@ -159,7 +163,7 @@ private Short convertImpl(Object input) { } @Override - public Short serialize(Object input) { + public Short serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Short result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -170,7 +174,7 @@ public Short serialize(Object input) { } @Override - public Short parseValue(Object input) { + public Short parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { Short result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -181,7 +185,7 @@ public Short parseValue(Object input) { } @Override - public Short parseLiteral(Object input) { + public Short parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof IntValue)) { throw new CoercingParseLiteralException( "Expected AST type 'IntValue' but was '" + typeName(input) + "'." @@ -197,7 +201,7 @@ public Short parseLiteral(Object input) { } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { Short result = Objects.requireNonNull(convertImpl(input)); return IntValue.newIntValue(BigInteger.valueOf(result)).build(); } @@ -214,7 +218,7 @@ public Value valueToLiteral(Object input) { public static final GraphQLScalarType GraphQLByte; static { - Coercing byteCoercing = new Coercing() { + Coercing byteCoercing = new Coercing<>() { private Byte convertImpl(Object input) { if (input instanceof Byte) { @@ -238,7 +242,7 @@ private Byte convertImpl(Object input) { } @Override - public Byte serialize(Object input) { + public Byte serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Byte result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -249,7 +253,7 @@ public Byte serialize(Object input) { } @Override - public Byte parseValue(Object input) { + public Byte parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { Byte result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -260,7 +264,7 @@ public Byte parseValue(Object input) { } @Override - public Byte parseLiteral(Object input) { + public Byte parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof IntValue)) { throw new CoercingParseLiteralException( "Expected AST type 'IntValue' but was '" + typeName(input) + "'." @@ -276,7 +280,7 @@ public Byte parseLiteral(Object input) { } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { Byte result = Objects.requireNonNull(convertImpl(input)); return IntValue.newIntValue(BigInteger.valueOf(result)).build(); } @@ -294,7 +298,7 @@ public Value valueToLiteral(Object input) { public static final GraphQLScalarType GraphQLBigInteger; static { - Coercing bigIntCoercing = new Coercing() { + Coercing bigIntCoercing = new Coercing<>() { private BigInteger convertImpl(Object input) { if (isNumberIsh(input)) { @@ -315,7 +319,7 @@ private BigInteger convertImpl(Object input) { } @Override - public BigInteger serialize(Object input) { + public BigInteger serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { BigInteger result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -326,7 +330,7 @@ public BigInteger serialize(Object input) { } @Override - public BigInteger parseValue(Object input) { + public BigInteger parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { BigInteger result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -337,7 +341,7 @@ public BigInteger parseValue(Object input) { } @Override - public BigInteger parseLiteral(Object input) { + public BigInteger parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (input instanceof StringValue) { try { return new BigDecimal(((StringValue) input).getValue()).toBigIntegerExact(); @@ -363,7 +367,7 @@ public BigInteger parseLiteral(Object input) { } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { BigInteger result = Objects.requireNonNull(convertImpl(input)); return IntValue.newIntValue(result).build(); } @@ -380,7 +384,7 @@ public Value valueToLiteral(Object input) { public static final GraphQLScalarType GraphQLBigDecimal; static { - Coercing bigDecimalCoercing = new Coercing() { + Coercing bigDecimalCoercing = new Coercing<>() { private BigDecimal convertImpl(Object input) { if (isNumberIsh(input)) { @@ -395,7 +399,7 @@ private BigDecimal convertImpl(Object input) { } @Override - public BigDecimal serialize(Object input) { + public BigDecimal serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { BigDecimal result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -406,7 +410,7 @@ public BigDecimal serialize(Object input) { } @Override - public BigDecimal parseValue(Object input) { + public BigDecimal parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { BigDecimal result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -417,7 +421,7 @@ public BigDecimal parseValue(Object input) { } @Override - public BigDecimal parseLiteral(Object input) { + public BigDecimal parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (input instanceof StringValue) { try { return new BigDecimal(((StringValue) input).getValue()); @@ -437,7 +441,7 @@ public BigDecimal parseLiteral(Object input) { } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { BigDecimal result = Objects.requireNonNull(convertImpl(input)); return FloatValue.newFloatValue(result).build(); } @@ -456,7 +460,7 @@ public Value valueToLiteral(Object input) { public static final GraphQLScalarType GraphQLChar; static { - Coercing characterCoercing = new Coercing() { + Coercing characterCoercing = new Coercing<>() { private Character convertImpl(Object input) { if (input instanceof String && ((String) input).length() == 1) { @@ -470,7 +474,7 @@ private Character convertImpl(Object input) { } @Override - public Character serialize(Object input) { + public Character serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Character result = convertImpl(input); if (result == null) { throw new CoercingSerializeException( @@ -481,7 +485,7 @@ public Character serialize(Object input) { } @Override - public Character parseValue(Object input) { + public Character parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { Character result = convertImpl(input); if (result == null) { throw new CoercingParseValueException( @@ -492,7 +496,7 @@ public Character parseValue(Object input) { } @Override - public Character parseLiteral(Object input) { + public Character parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -508,7 +512,7 @@ public Character parseLiteral(Object input) { } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { Character result = Objects.requireNonNull(convertImpl(input)); return StringValue.newStringValue(result.toString()).build(); } diff --git a/src/main/java/graphql/scalars/locale/LocaleScalar.java b/src/main/java/graphql/scalars/locale/LocaleScalar.java index 78101b4..af84dd8 100644 --- a/src/main/java/graphql/scalars/locale/LocaleScalar.java +++ b/src/main/java/graphql/scalars/locale/LocaleScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.locale; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -19,15 +21,16 @@ @Internal public final class LocaleScalar { - private LocaleScalar() {} + private LocaleScalar() { + } public static final GraphQLScalarType INSTANCE; static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { if (input instanceof String) { try { return Locale.forLanguageTag((String) input).toLanguageTag(); @@ -45,7 +48,7 @@ public String serialize(Object input) throws CoercingSerializeException { } @Override - public Locale parseValue(Object input) throws CoercingParseValueException { + public Locale parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { if (input instanceof String) { try { return Locale.forLanguageTag(input.toString()); @@ -61,8 +64,9 @@ public Locale parseValue(Object input) throws CoercingParseValueException { } } + @Override - public Locale parseLiteral(Object input) throws CoercingParseLiteralException { + public Locale parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (input instanceof StringValue) { return Locale.forLanguageTag(((StringValue) input).getValue()); } else { @@ -72,8 +76,8 @@ public Locale parseLiteral(Object input) throws CoercingParseLiteralException { } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } }; diff --git a/src/main/java/graphql/scalars/numeric/FloatCoercing.java b/src/main/java/graphql/scalars/numeric/FloatCoercing.java index 3563b92..c2ab9b0 100644 --- a/src/main/java/graphql/scalars/numeric/FloatCoercing.java +++ b/src/main/java/graphql/scalars/numeric/FloatCoercing.java @@ -1,12 +1,15 @@ package graphql.scalars.numeric; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.Value; import graphql.schema.Coercing; import graphql.schema.CoercingParseLiteralException; import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; +import java.util.Locale; import java.util.function.Function; import static graphql.Scalars.GraphQLFloat; @@ -17,25 +20,26 @@ abstract class FloatCoercing implements Coercing { protected abstract Double check(Double d, Function exceptionMaker); @Override - public Double serialize(Object input) throws CoercingSerializeException { - Double d = (Double) GraphQLFloat.getCoercing().serialize(input); + public Double serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { + Double d = (Double) GraphQLFloat.getCoercing().serialize(input, graphQLContext, locale); return check(d, CoercingSerializeException::new); } @Override - public Double parseValue(Object input) throws CoercingParseValueException { - Double d = (Double) GraphQLFloat.getCoercing().parseValue(input); + public Double parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { + Double d = (Double) GraphQLFloat.getCoercing().parseValue(input, graphQLContext, locale); return check(d, CoercingParseValueException::new); } @Override - public Double parseLiteral(Object input) throws CoercingParseLiteralException { - Double d = (Double) GraphQLFloat.getCoercing().parseLiteral(input); + public Double parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { + Double d = (Double) GraphQLFloat.getCoercing().parseLiteral(input, variables, graphQLContext, locale); return check(d, CoercingParseLiteralException::new); } @Override - public Value valueToLiteral(Object input) { - return GraphQLFloat.getCoercing().valueToLiteral(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + return GraphQLFloat.getCoercing().valueToLiteral(input, graphQLContext, locale); } + } diff --git a/src/main/java/graphql/scalars/numeric/IntCoercing.java b/src/main/java/graphql/scalars/numeric/IntCoercing.java index d70cce7..55bf7b3 100644 --- a/src/main/java/graphql/scalars/numeric/IntCoercing.java +++ b/src/main/java/graphql/scalars/numeric/IntCoercing.java @@ -1,12 +1,15 @@ package graphql.scalars.numeric; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.Value; import graphql.schema.Coercing; import graphql.schema.CoercingParseLiteralException; import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; +import java.util.Locale; import java.util.function.Function; import static graphql.Scalars.GraphQLInt; @@ -17,26 +20,25 @@ abstract class IntCoercing implements Coercing { protected abstract Integer check(Integer i, Function exceptionMaker); @Override - public Integer serialize(Object input) throws CoercingSerializeException { - Integer i = (Integer) GraphQLInt.getCoercing().serialize(input); + public Integer serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { + Integer i = (Integer) GraphQLInt.getCoercing().serialize(input, graphQLContext, locale); return check(i, CoercingSerializeException::new); } @Override - public Integer parseValue(Object input) throws CoercingParseValueException { - Integer i = (Integer) GraphQLInt.getCoercing().parseValue(input); + public Integer parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { + Integer i = (Integer) GraphQLInt.getCoercing().parseValue(input, graphQLContext, locale); return check(i, CoercingParseValueException::new); } @Override - public Integer parseLiteral(Object input) throws CoercingParseLiteralException { - Integer i = (Integer) GraphQLInt.getCoercing().parseLiteral(input); + public Integer parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { + Integer i = (Integer) GraphQLInt.getCoercing().parseLiteral(input, variables, graphQLContext, locale); return check(i, CoercingParseLiteralException::new); } @Override - public Value valueToLiteral(Object input) { - return GraphQLInt.getCoercing().valueToLiteral(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + return GraphQLInt.getCoercing().valueToLiteral(input, graphQLContext, locale); } - } diff --git a/src/main/java/graphql/scalars/object/ObjectScalar.java b/src/main/java/graphql/scalars/object/ObjectScalar.java index ff92d31..89a0acd 100644 --- a/src/main/java/graphql/scalars/object/ObjectScalar.java +++ b/src/main/java/graphql/scalars/object/ObjectScalar.java @@ -1,7 +1,9 @@ package graphql.scalars.object; import graphql.Assert; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.ArrayValue; import graphql.language.BooleanValue; import graphql.language.EnumValue; @@ -23,9 +25,9 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; @@ -38,27 +40,22 @@ @Internal public final class ObjectScalar { - private ObjectScalar() {} + private ObjectScalar() { + } - static final Coercing OBJECT_COERCING = new Coercing() { + static final Coercing OBJECT_COERCING = new Coercing<>() { @Override - public Object serialize(Object input) throws CoercingSerializeException { + public Object serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { return input; } @Override - public Object parseValue(Object input) throws CoercingParseValueException { + public Object parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { return input; } @Override - public Object parseLiteral(Object input) throws CoercingParseLiteralException { - // on purpose - object scalars can be null - return parseLiteral(input, Collections.emptyMap()); - } - - @Override - public Object parseLiteral(Object input, Map variables) throws CoercingParseLiteralException { + public Object parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof Value)) { throw new CoercingParseLiteralException( "Expected AST type 'Value' but was '" + typeName(input) + "'." @@ -84,9 +81,10 @@ public Object parseLiteral(Object input, Map variables) throws C return variables.get(varName); } if (input instanceof ArrayValue) { + //noinspection rawtypes List values = ((ArrayValue) input).getValues(); return values.stream() - .map(v -> parseLiteral(v, variables)) + .map(v -> parseLiteral(v, variables, graphQLContext, locale)) .collect(Collectors.toList()); } if (input instanceof ObjectValue) { @@ -97,7 +95,7 @@ public Object parseLiteral(Object input, Map variables) throws C if (fld.getValue() instanceof NullValue) { // Nested NullValue inside ObjectValue parsedValue = null; } else { - parsedValue = parseLiteral(fld.getValue(), variables); + parsedValue = parseLiteral(fld.getValue(), variables, graphQLContext, locale); } parsedValues.put(fld.getName(), parsedValue); }); @@ -107,7 +105,7 @@ public Object parseLiteral(Object input, Map variables) throws C } @Override - public Value valueToLiteral(Object input) { + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { if (input == null) { return NullValue.newNullValue().build(); } @@ -134,19 +132,19 @@ public Value valueToLiteral(Object input) { return new BooleanValue((Boolean) input); } if (FpKit.isIterable(input)) { - return handleIterable(FpKit.toIterable(input)); + return handleIterable(FpKit.toIterable(input), graphQLContext, locale); } if (input instanceof Map) { - return handleMap((Map) input); + return handleMap((Map) input, graphQLContext, locale); } throw new UnsupportedOperationException("The ObjectScalar cant handle values of type : " + input.getClass()); } - private Value handleMap(Map map) { + private Value handleMap(Map map, GraphQLContext graphQLContext, Locale locale) { ObjectValue.Builder builder = ObjectValue.newObjectValue(); for (Map.Entry entry : map.entrySet()) { String name = String.valueOf(entry.getKey()); - Value value = valueToLiteral(entry.getValue()); + Value value = valueToLiteral(entry.getValue(), graphQLContext, locale); builder.objectField( newObjectField().name(name).value(value).build() @@ -156,10 +154,10 @@ private Value handleMap(Map map) { } @SuppressWarnings("rawtypes") - private Value handleIterable(Iterable input) { + private Value handleIterable(Iterable input, GraphQLContext graphQLContext, Locale locale) { List values = new ArrayList<>(); for (Object val : input) { - values.add(valueToLiteral(val)); + values.add(valueToLiteral(val, graphQLContext, locale)); } return ArrayValue.newArrayValue().values(values).build(); } diff --git a/src/main/java/graphql/scalars/regex/RegexScalar.java b/src/main/java/graphql/scalars/regex/RegexScalar.java index 79a8957..db3d4d5 100644 --- a/src/main/java/graphql/scalars/regex/RegexScalar.java +++ b/src/main/java/graphql/scalars/regex/RegexScalar.java @@ -1,7 +1,9 @@ package graphql.scalars.regex; import graphql.Assert; +import graphql.GraphQLContext; import graphql.PublicApi; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -13,6 +15,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -26,7 +29,8 @@ @PublicApi public final class RegexScalar { - private RegexScalar() {} + private RegexScalar() { + } /** * A builder for {@link graphql.scalars.regex.RegexScalar} @@ -34,7 +38,7 @@ private RegexScalar() {} public static class Builder { private String name; private String description; - private List patterns = new ArrayList<>(); + private final List patterns = new ArrayList<>(); /** * Sets the name of the regex scalar @@ -96,21 +100,21 @@ public GraphQLScalarType build() { private static GraphQLScalarType regexScalarImpl(String name, String description, List patterns) { Assert.assertNotNull(patterns); - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input) throws CoercingSerializeException { + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { String value = String.valueOf(input); return matches(value, CoercingSerializeException::new); } @Override - public String parseValue(Object input) throws CoercingParseValueException { + public String parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { String value = String.valueOf(input); return matches(value, CoercingParseValueException::new); } @Override - public String parseLiteral(Object input) throws CoercingParseLiteralException { + public String parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -121,8 +125,8 @@ public String parseLiteral(Object input) throws CoercingParseLiteralException { } @Override - public Value valueToLiteral(Object input) { - String s = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); return StringValue.newStringValue(s).build(); } diff --git a/src/main/java/graphql/scalars/url/UrlScalar.java b/src/main/java/graphql/scalars/url/UrlScalar.java index 75dceb9..2b024b2 100644 --- a/src/main/java/graphql/scalars/url/UrlScalar.java +++ b/src/main/java/graphql/scalars/url/UrlScalar.java @@ -1,6 +1,8 @@ package graphql.scalars.url; +import graphql.GraphQLContext; import graphql.Internal; +import graphql.execution.CoercedVariables; import graphql.language.StringValue; import graphql.language.Value; import graphql.schema.Coercing; @@ -13,6 +15,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import java.util.Locale; import java.util.Optional; import java.util.function.Function; @@ -21,14 +24,15 @@ @Internal public final class UrlScalar { - private UrlScalar() {} + private UrlScalar() { + } public static final GraphQLScalarType INSTANCE; static { - Coercing coercing = new Coercing() { + Coercing coercing = new Coercing<>() { @Override - public URL serialize(Object input) throws CoercingSerializeException { + public URL serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { Optional url; if (input instanceof String) { url = Optional.of(parseURL(input.toString(), CoercingSerializeException::new)); @@ -44,13 +48,13 @@ public URL serialize(Object input) throws CoercingSerializeException { } @Override - public URL parseValue(Object input) throws CoercingParseValueException { + public URL parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { String urlStr; if (input instanceof String) { urlStr = String.valueOf(input); } else { Optional url = toURL(input); - if (!url.isPresent()) { + if (url.isEmpty()) { throw new CoercingParseValueException( "Expected a 'URL' like object but was '" + typeName(input) + "'." ); @@ -61,7 +65,7 @@ public URL parseValue(Object input) throws CoercingParseValueException { } @Override - public URL parseLiteral(Object input) throws CoercingParseLiteralException { + public URL parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { if (!(input instanceof StringValue)) { throw new CoercingParseLiteralException( "Expected AST type 'StringValue' but was '" + typeName(input) + "'." @@ -71,8 +75,8 @@ public URL parseLiteral(Object input) throws CoercingParseLiteralException { } @Override - public Value valueToLiteral(Object input) { - URL url = serialize(input); + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + URL url = serialize(input, graphQLContext, locale); return StringValue.newStringValue(url.toExternalForm()).build(); } diff --git a/src/test/groovy/graphql/scalars/alias/AliasedScalarTest.groovy b/src/test/groovy/graphql/scalars/alias/AliasedScalarTest.groovy index 9a2e275..7ef8a43 100644 --- a/src/test/groovy/graphql/scalars/alias/AliasedScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/alias/AliasedScalarTest.groovy @@ -3,10 +3,10 @@ package graphql.scalars.alias import graphql.Scalars import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.GraphQLScalarType -import spock.lang.Specification -class AliasedScalarTest extends Specification { +class AliasedScalarTest extends AbstractScalarTest { GraphQLScalarType socialMediaLink = ExtendedScalars.newAliasedScalar("SocialMediaLink") .aliasedScalar(Scalars.GraphQLString) @@ -15,22 +15,17 @@ class AliasedScalarTest extends Specification { def "basic wrapping"() { when: - def result = socialMediaLink.coercing.serialize("ABC") + def result = socialMediaLink.coercing.serialize("ABC", graphQLContext, locale) then: result == "ABC" when: - result = socialMediaLink.coercing.parseValue("ABC") + result = socialMediaLink.coercing.parseValue("ABC", graphQLContext, locale) then: result == "ABC" when: - result = socialMediaLink.coercing.parseLiteral(new StringValue("ABC")) - then: - result == "ABC" - - when: - result = socialMediaLink.coercing.parseLiteral(new StringValue("ABC"), [:]) + result = socialMediaLink.coercing.parseLiteral(new StringValue("ABC"), variables, graphQLContext, locale) then: result == "ABC" diff --git a/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy b/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy index 6af9f60..3c47bf7 100644 --- a/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/color/hex/HexColorCodeScalarTest.groovy @@ -2,20 +2,20 @@ package graphql.scalars.color.hex import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseValueException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkColor -class HexColorCodeScalarTest extends Specification { +class HexColorCodeScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.HexColorCode.getCoercing() @Unroll def "invoke parseValue for hexCode"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result.equals(expectedValue) where: @@ -29,7 +29,7 @@ class HexColorCodeScalarTest extends Specification { @Unroll def "invoke parseLiteral for hexCode"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -43,7 +43,7 @@ class HexColorCodeScalarTest extends Specification { @Unroll def "invoke serialize with hexCode"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -59,7 +59,7 @@ class HexColorCodeScalarTest extends Specification { @Unroll def "invoke valueToLiteral with hexCode"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -75,7 +75,7 @@ class HexColorCodeScalarTest extends Specification { @Unroll def "parseValue throws exception for invalid input #input"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: thrown(CoercingParseValueException) where: diff --git a/src/test/groovy/graphql/scalars/country/code/CountryCodeScalarTest.groovy b/src/test/groovy/graphql/scalars/country/code/CountryCodeScalarTest.groovy index 6cebaf0..4e09923 100644 --- a/src/test/groovy/graphql/scalars/country/code/CountryCodeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/country/code/CountryCodeScalarTest.groovy @@ -2,21 +2,22 @@ package graphql.scalars.country.code import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseValueException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkCountryCode import static graphql.scalars.util.TestKit.mkStringValue -class CountryCodeScalarTest extends Specification { +class CountryCodeScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.CountryCode.getCoercing() + @Unroll def "invoke parseValue for countryCode"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -31,7 +32,7 @@ class CountryCodeScalarTest extends Specification { def "invoke parseLiteral for countryCode"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -44,7 +45,7 @@ class CountryCodeScalarTest extends Specification { @Unroll def "invoke serialize with countryCode"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -59,7 +60,7 @@ class CountryCodeScalarTest extends Specification { def "invoke valueToLiteral with countryCode"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -73,7 +74,7 @@ class CountryCodeScalarTest extends Specification { @Unroll def "parseValue throws exception for invalid input #value"() { when: - coercing.parseValue(value) + coercing.parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) @@ -83,8 +84,8 @@ class CountryCodeScalarTest extends Specification { "US(UNITED STATES)" | _ "not a countryCode " | _ "42.3" | _ - new Double(42.3) | _ - new Float(42.3) | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ new Object() | _ } @@ -92,7 +93,7 @@ class CountryCodeScalarTest extends Specification { @Unroll def "invoke parseValue with all countryCode list"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: diff --git a/src/test/groovy/graphql/scalars/currency/CurrencyScalarTest.groovy b/src/test/groovy/graphql/scalars/currency/CurrencyScalarTest.groovy index 616b8ba..6283091 100644 --- a/src/test/groovy/graphql/scalars/currency/CurrencyScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/currency/CurrencyScalarTest.groovy @@ -2,14 +2,14 @@ package graphql.scalars.currency import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseValueException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkCurrency import static graphql.scalars.util.TestKit.mkStringValue -class CurrencyScalarTest extends Specification { +class CurrencyScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.Currency.getCoercing() @@ -18,7 +18,7 @@ class CurrencyScalarTest extends Specification { def "currency parseValue cases"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -42,7 +42,7 @@ class CurrencyScalarTest extends Specification { def "currency parseLiteral"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -56,7 +56,7 @@ class CurrencyScalarTest extends Specification { def "currency serialize"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -69,7 +69,7 @@ class CurrencyScalarTest extends Specification { def "currency valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -81,19 +81,19 @@ class CurrencyScalarTest extends Specification { @Unroll def "parseValue throws exception for invalid input #value"() { when: - coercing.parseValue(value) + coercing.parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) where: - value | _ - "" | _ - "US_DOLLAR" | _ - "not a currency " | _ - "42.3" | _ - new Double(42.3) | _ - new Float(42.3) | _ - new Object() | _ + value | _ + "" | _ + "US_DOLLAR" | _ + "not a currency " | _ + "42.3" | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ + new Object() | _ } @@ -101,7 +101,7 @@ class CurrencyScalarTest extends Specification { def "all currency ISO list parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: diff --git a/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy index 9fb8009..7b656b5 100644 --- a/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/AccurateDurationScalarTest.groovy @@ -1,21 +1,21 @@ package graphql.scalars.datetime - import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import java.time.Period import java.time.temporal.ChronoUnit import static graphql.scalars.util.TestKit.mkDuration +import static graphql.scalars.util.TestKit.mkIntValue import static graphql.scalars.util.TestKit.mkStringValue -class AccurateDurationScalarTest extends Specification { +class AccurateDurationScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.AccurateDuration.getCoercing() @@ -23,7 +23,7 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -40,7 +40,7 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -58,7 +58,7 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -75,7 +75,7 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration AST literal"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -86,7 +86,7 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration serialisation"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -103,7 +103,7 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration serialisation bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -122,18 +122,17 @@ class AccurateDurationScalarTest extends Specification { def "accurateduration parseLiteral bad inputs"() { when: - coercing.parseLiteral(input) + coercing.parseLiteral(input, variables, graphQLContext, locale) then: thrown(expectedValue) where: - input | expectedValue - "P1M" | CoercingParseLiteralException - "PT1.5M" | CoercingParseLiteralException - "P1MT2H" | CoercingParseLiteralException - "P2W" | CoercingParseLiteralException - "P3Y" | CoercingParseLiteralException - 123 | CoercingParseLiteralException - "" | CoercingParseLiteralException - Period.of(1, 2, 3) | CoercingParseLiteralException + input | expectedValue + mkStringValue("P1M") | CoercingParseLiteralException + mkStringValue("PT1.5M") | CoercingParseLiteralException + mkStringValue("P1MT2H") | CoercingParseLiteralException + mkStringValue("P2W") | CoercingParseLiteralException + mkStringValue("P3Y") | CoercingParseLiteralException + mkIntValue(123) | CoercingParseLiteralException + mkStringValue("") | CoercingParseLiteralException } } diff --git a/src/test/groovy/graphql/scalars/datetime/DateScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/DateScalarTest.groovy index f86de8e..46bc707 100644 --- a/src/test/groovy/graphql/scalars/datetime/DateScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/DateScalarTest.groovy @@ -2,7 +2,7 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars -import spock.lang.Specification +import graphql.scalars.util.AbstractScalarTest import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkLocalDate @@ -10,7 +10,7 @@ import static graphql.scalars.util.TestKit.mkOffsetDT import static graphql.scalars.util.TestKit.mkStringValue import static graphql.scalars.util.TestKit.mkZonedDT -class DateScalarTest extends Specification { +class DateScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.Date.getCoercing() @@ -18,7 +18,7 @@ class DateScalarTest extends Specification { def "full date parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -32,7 +32,7 @@ class DateScalarTest extends Specification { def "full date parseLiteral"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -44,7 +44,7 @@ class DateScalarTest extends Specification { def "full date serialize"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -58,7 +58,7 @@ class DateScalarTest extends Specification { def "full date valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: diff --git a/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy index 74d8d1e..d68948b 100644 --- a/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy @@ -2,18 +2,19 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll +import static graphql.scalars.util.TestKit.mkIntValue import static graphql.scalars.util.TestKit.mkLocalDT import static graphql.scalars.util.TestKit.mkOffsetDT import static graphql.scalars.util.TestKit.mkStringValue import static graphql.scalars.util.TestKit.mkZonedDT -class DateTimeScalarTest extends Specification { +class DateTimeScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.DateTime.getCoercing() @@ -21,7 +22,7 @@ class DateTimeScalarTest extends Specification { def "datetime parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -38,7 +39,7 @@ class DateTimeScalarTest extends Specification { def "datetime valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -56,25 +57,25 @@ class DateTimeScalarTest extends Specification { def "datetime parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(expectedValue) where: - input | expectedValue - "1985-04-12" | CoercingParseValueException // No time provided - "2022-11-24T01:00:01.02-00:00" | CoercingParseValueException // -00:00 is not a valid offset in specification - mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException // LocalDateTime has no time zone - 666 | CoercingParseValueException // A random number - "2011-08-30T13:22:53.108" | CoercingParseValueException // No offset provided - "2011-08-30T24:22:53.108Z" | CoercingParseValueException // 24 is not allowed as hour of the time - "2010-02-30T21:22:53.108Z" | CoercingParseValueException // 30th of February is not a valid date - "2010-02-11T21:22:53.108Z+25:11" | CoercingParseValueException // 25 is not a valid hour for offset + input | expectedValue + "1985-04-12" | CoercingParseValueException // No time provided + "2022-11-24T01:00:01.02-00:00" | CoercingParseValueException // -00:00 is not a valid offset in specification + mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException // LocalDateTime has no time zone + 666 | CoercingParseValueException // A random number + "2011-08-30T13:22:53.108" | CoercingParseValueException // No offset provided + "2011-08-30T24:22:53.108Z" | CoercingParseValueException // 24 is not allowed as hour of the time + "2010-02-30T21:22:53.108Z" | CoercingParseValueException // 30th of February is not a valid date + "2010-02-11T21:22:53.108Z+25:11" | CoercingParseValueException // 25 is not a valid hour for offset } def "datetime AST literal"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -85,7 +86,7 @@ class DateTimeScalarTest extends Specification { def "datetime serialisation"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -101,7 +102,7 @@ class DateTimeScalarTest extends Specification { def "datetime serialisation bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -120,20 +121,19 @@ class DateTimeScalarTest extends Specification { def "datetime parseLiteral bad inputs"() { when: - coercing.parseLiteral(input) + coercing.parseLiteral(input, variables, graphQLContext, locale) then: thrown(expectedValue) where: - input | expectedValue - "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException // -00:00 is not a valid offset in specification - "1985-04-12" | CoercingParseLiteralException // No time provided - "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException // -00:00 is not a valid offset in specification - mkLocalDT(year: 1980, hour: 3) | CoercingParseLiteralException // LocalDateTime has no time zone - 666 | CoercingParseLiteralException // A random number - "2011-08-30T13:22:53.108" | CoercingParseLiteralException // No offset provided - "2011-08-30T24:22:53.108Z" | CoercingParseLiteralException // 24 is not allowed as hour of the time - "2010-02-30T21:22:53.108Z" | CoercingParseLiteralException // 30th of February is not a valid date - "2010-02-11T21:22:53.108Z+25:11" | CoercingParseLiteralException // 25 is not a valid hour for offset + input | expectedValue + mkStringValue("2022-11-24T01:00:01.02-00:00") | CoercingParseLiteralException // -00:00 is not a valid offset in specification + mkStringValue("1985-04-12") | CoercingParseLiteralException // No time provided + mkStringValue("2022-11-24T01:00:01.02-00:00") | CoercingParseLiteralException // -00:00 is not a valid offset in specification + mkIntValue(666) | CoercingParseLiteralException // A random number + mkStringValue("2011-08-30T13:22:53.108") | CoercingParseLiteralException // No offset provided + mkStringValue("2011-08-30T24:22:53.108Z") | CoercingParseLiteralException // 24 is not allowed as hour of the time + mkStringValue("2010-02-30T21:22:53.108Z") | CoercingParseLiteralException // 30th of February is not a valid date + mkStringValue("2010-02-11T21:22:53.108Z+25:11") | CoercingParseLiteralException // 25 is not a valid hour for offset } } diff --git a/src/test/groovy/graphql/scalars/datetime/LocalTimeScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/LocalTimeScalarTest.groovy index 1d03acb..ceac21c 100644 --- a/src/test/groovy/graphql/scalars/datetime/LocalTimeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/LocalTimeScalarTest.groovy @@ -2,14 +2,15 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkLocalT +import static graphql.scalars.util.TestKit.mkStringValue -class LocalTimeScalarTest extends Specification { +class LocalTimeScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.LocalTime.getCoercing() @@ -17,7 +18,7 @@ class LocalTimeScalarTest extends Specification { def "localtime parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -32,7 +33,7 @@ class LocalTimeScalarTest extends Specification { def "localtime parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -45,7 +46,7 @@ class LocalTimeScalarTest extends Specification { def "localtime AST literal"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -59,7 +60,7 @@ class LocalTimeScalarTest extends Specification { def "localtime serialisation"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -70,10 +71,24 @@ class LocalTimeScalarTest extends Specification { mkLocalT("16:39:57.1") | "16:39:57.1" } + def "localtime valueToLiteral"() { + + when: + def result = coercing.valueToLiteral(input, graphQLContext, locale) + then: + result.isEqualTo(expectedValue) + + where: + input | expectedValue + "23:20:50" | mkStringValue("23:20:50") + "16:39" | mkStringValue("16:39:00") + "12:00:27.999999999" | mkStringValue("12:00:27.999999999") + } + def "datetime serialisation bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(expectedValue) where: diff --git a/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy index 2790286..0d15ca0 100644 --- a/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/NominalDurationScalarTest.groovy @@ -2,19 +2,20 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import java.time.Duration import java.time.temporal.ChronoUnit +import static graphql.scalars.util.TestKit.mkIntValue import static graphql.scalars.util.TestKit.mkPeriod import static graphql.scalars.util.TestKit.mkStringValue -class NominalDurationScalarTest extends Specification { +class NominalDurationScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NominalDuration.getCoercing() @@ -22,7 +23,7 @@ class NominalDurationScalarTest extends Specification { def "nominalduration parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -39,7 +40,7 @@ class NominalDurationScalarTest extends Specification { def "nominalduration valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -57,7 +58,7 @@ class NominalDurationScalarTest extends Specification { def "nominalduration parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -73,7 +74,7 @@ class NominalDurationScalarTest extends Specification { def "nominalduration AST literal"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -84,7 +85,7 @@ class NominalDurationScalarTest extends Specification { def "nominalduration serialisation"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -100,7 +101,7 @@ class NominalDurationScalarTest extends Specification { def "nominalduration serialisation bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -118,17 +119,16 @@ class NominalDurationScalarTest extends Specification { def "nominalduration parseLiteral bad inputs"() { when: - coercing.parseLiteral(input) + coercing.parseLiteral(input, variables, graphQLContext, locale) then: thrown(expectedValue) where: - input | expectedValue - "PT1M" | CoercingParseLiteralException - "P1.5M" | CoercingParseLiteralException - "P1MT2H" | CoercingParseLiteralException - "PY" | CoercingParseLiteralException - 123 | CoercingParseLiteralException - "" | CoercingParseLiteralException - Duration.of(1, ChronoUnit.MINUTES) | CoercingParseLiteralException + input | expectedValue + mkStringValue("PT1M") | CoercingParseLiteralException + mkStringValue("P1.5M") | CoercingParseLiteralException + mkStringValue("P1MT2H") | CoercingParseLiteralException + mkStringValue("PY") | CoercingParseLiteralException + mkIntValue(123) | CoercingParseLiteralException + mkStringValue("") | CoercingParseLiteralException } } diff --git a/src/test/groovy/graphql/scalars/datetime/TimeScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/TimeScalarTest.groovy index 37fc002..d211d44 100644 --- a/src/test/groovy/graphql/scalars/datetime/TimeScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/TimeScalarTest.groovy @@ -2,9 +2,9 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkLocalDT @@ -13,7 +13,7 @@ import static graphql.scalars.util.TestKit.mkOffsetT import static graphql.scalars.util.TestKit.mkStringValue import static graphql.scalars.util.TestKit.mkZonedDT -class TimeScalarTest extends Specification { +class TimeScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.Time.getCoercing() @@ -21,7 +21,7 @@ class TimeScalarTest extends Specification { def "datetime parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -37,7 +37,7 @@ class TimeScalarTest extends Specification { def "datetime parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -50,7 +50,7 @@ class TimeScalarTest extends Specification { def "datetime AST literal"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -61,7 +61,7 @@ class TimeScalarTest extends Specification { def "datetime serialisation"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -76,7 +76,7 @@ class TimeScalarTest extends Specification { def "datetime valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: @@ -91,7 +91,7 @@ class TimeScalarTest extends Specification { def "datetime serialisation bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(expectedValue) where: diff --git a/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy index c6f0e9b..995de59 100644 --- a/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/YearMonthScalarTest.groovy @@ -2,14 +2,14 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars -import spock.lang.Specification +import graphql.scalars.util.AbstractScalarTest import spock.lang.Unroll import java.time.YearMonth import static graphql.scalars.util.TestKit.mkStringValue -class YearMonthScalarTest extends Specification { +class YearMonthScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.YearMonth.getCoercing() @@ -17,48 +17,48 @@ class YearMonthScalarTest extends Specification { def "yearMonth parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: - input | expectedValue - "1937-01" | YearMonth.of(1937, 1) + input | expectedValue + "1937-01" | YearMonth.of(1937, 1) } @Unroll def "yearMonth parseLiteral"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: - input | expectedValue - new StringValue("1937-01") | YearMonth.of(1937, 1) + input | expectedValue + new StringValue("1937-01") | YearMonth.of(1937, 1) } @Unroll def "yearMonth serialize"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: - input | expectedValue - "1937-01" | "1937-01" + input | expectedValue + "1937-01" | "1937-01" } @Unroll def "yearMonth valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: - input | expectedValue - "1937-01" | mkStringValue("1937-01") + input | expectedValue + "1937-01" | mkStringValue("1937-01") } } diff --git a/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy index 0d622fa..c03e49c 100644 --- a/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/YearScalarTest.groovy @@ -2,14 +2,14 @@ package graphql.scalars.datetime import graphql.language.StringValue import graphql.scalars.ExtendedScalars -import spock.lang.Specification +import graphql.scalars.util.AbstractScalarTest import spock.lang.Unroll import java.time.Year import static graphql.scalars.util.TestKit.mkStringValue -class YearScalarTest extends Specification { +class YearScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.Year.getCoercing() @@ -17,48 +17,48 @@ class YearScalarTest extends Specification { def "year parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: - input | expectedValue - "1937" | Year.of(1937) + input | expectedValue + "1937" | Year.of(1937) } @Unroll def "year parseLiteral"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: - input | expectedValue - new StringValue("1937") | Year.of(1937) + input | expectedValue + new StringValue("1937") | Year.of(1937) } @Unroll def "year serialize"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: - input | expectedValue - "1937" | "1937" + input | expectedValue + "1937" | "1937" } @Unroll def "year valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: - input | expectedValue - "1937" | mkStringValue("1937") + input | expectedValue + "1937" | mkStringValue("1937") } } diff --git a/src/test/groovy/graphql/scalars/id/UUIDScalarTest.groovy b/src/test/groovy/graphql/scalars/id/UUIDScalarTest.groovy index f9c1e91..87928fc 100644 --- a/src/test/groovy/graphql/scalars/id/UUIDScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/id/UUIDScalarTest.groovy @@ -2,16 +2,16 @@ package graphql.scalars.id import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkStringValue import static graphql.scalars.util.TestKit.mkUUIDValue -class UUIDScalarTest extends Specification { +class UUIDScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.UUID.getCoercing() @@ -19,7 +19,7 @@ class UUIDScalarTest extends Specification { def "UUID parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -32,7 +32,7 @@ class UUIDScalarTest extends Specification { def "UUID parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -45,7 +45,7 @@ class UUIDScalarTest extends Specification { def "UUID AST literal"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -56,7 +56,7 @@ class UUIDScalarTest extends Specification { def "UUID AST literal bad inputs"() { when: - coercing.parseLiteral(input) + coercing.parseLiteral(input, variables, graphQLContext, locale) then: thrown(expectedValue) where: @@ -67,7 +67,7 @@ class UUIDScalarTest extends Specification { def "UUID serialization"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -80,7 +80,7 @@ class UUIDScalarTest extends Specification { def "UUID serialization bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(expectedValue) where: @@ -93,7 +93,7 @@ class UUIDScalarTest extends Specification { def "UUID valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: diff --git a/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy index bbd6c57..ca8c789 100644 --- a/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy +++ b/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy @@ -1,24 +1,25 @@ package graphql.scalars.java + import graphql.language.BooleanValue import graphql.language.FloatValue import graphql.language.IntValue import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import java.util.concurrent.atomic.AtomicInteger -class ScalarsBigDecimalTest extends Specification { +class ScalarsBigDecimalTest extends AbstractScalarTest { @Unroll def "BigDecimal parse literal #literal.value as #result"() { expect: - ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal) == result + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) == result where: literal | result @@ -31,7 +32,7 @@ class ScalarsBigDecimalTest extends Specification { @Unroll def "BigDecimal returns null for invalid #literal"() { when: - ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal) + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) then: thrown(CoercingParseLiteralException) @@ -44,30 +45,30 @@ class ScalarsBigDecimalTest extends Specification { @Unroll def "BigDecimal serialize #value into #result (#result.class)"() { expect: - ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value) == result - ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value) == result + ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value, graphQLContext, locale) == result + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value, graphQLContext, locale) == result where: - value | result - "42" | new BigDecimal("42") - "42.123" | new BigDecimal("42.123") - 42.0000d | new BigDecimal("42.000") - new Integer(42) | new BigDecimal("42") - "-1" | new BigDecimal("-1") - new BigInteger(42) | new BigDecimal("42") - new BigDecimal("42") | new BigDecimal("42") - 42.3f | new BigDecimal("42.3") - 42.0d | new BigDecimal("42") - new Byte("42") | new BigDecimal("42") - new Short("42") | new BigDecimal("42") - 1234567l | new BigDecimal("1234567") - new AtomicInteger(42) | new BigDecimal("42") + value | result + "42" | new BigDecimal("42") + "42.123" | new BigDecimal("42.123") + 42.0000d | new BigDecimal("42.000") + Integer.valueOf(42) | new BigDecimal("42") + "-1" | new BigDecimal("-1") + BigInteger.valueOf(42) | new BigDecimal("42") + new BigDecimal("42") | new BigDecimal("42") + 42.3f | new BigDecimal("42.3") + 42.0d | new BigDecimal("42") + Byte.valueOf("42") | new BigDecimal("42") + Short.valueOf("42") | new BigDecimal("42") + 1234567l | new BigDecimal("1234567") + new AtomicInteger(42) | new BigDecimal("42") } @Unroll def "serialize throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value) + ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value, graphQLContext, locale) then: thrown(CoercingSerializeException) @@ -81,7 +82,7 @@ class ScalarsBigDecimalTest extends Specification { @Unroll def "parseValue throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value) + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) diff --git a/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy index 32f9719..132d86c 100644 --- a/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy +++ b/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy @@ -1,25 +1,24 @@ package graphql.scalars.java -import graphql.Scalars import graphql.language.BooleanValue import graphql.language.FloatValue import graphql.language.IntValue import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import java.util.concurrent.atomic.AtomicInteger -class ScalarsBigIntegerTest extends Specification { +class ScalarsBigIntegerTest extends AbstractScalarTest { @Unroll def "BigInteger parse literal #literal.value as #result"() { expect: - ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal) == result + ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) == result where: literal | result @@ -31,7 +30,7 @@ class ScalarsBigIntegerTest extends Specification { @Unroll def "BigInteger returns null for invalid #literal"() { when: - ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal) + ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) then: thrown(CoercingParseLiteralException) @@ -46,18 +45,18 @@ class ScalarsBigIntegerTest extends Specification { @Unroll def "BigInteger serialize #value into #result (#result.class)"() { expect: - ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value) == result - ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value) == result + ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value, graphQLContext, locale) == result + ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value, graphQLContext, locale) == result where: value | result "42" | new BigInteger("42") - new Integer(42) | new BigInteger("42") + Integer.valueOf(42) | new BigInteger("42") "-1" | new BigInteger("-1") new BigInteger("42") | new BigInteger("42") 42.0d | new BigInteger("42") - new Byte("42") | new BigInteger("42") - new Short("42") | new BigInteger("42") + Byte.valueOf("42") | new BigInteger("42") + Short.valueOf("42") | new BigInteger("42") 1234567l | new BigInteger("1234567") new AtomicInteger(42) | new BigInteger("42") } @@ -65,7 +64,7 @@ class ScalarsBigIntegerTest extends Specification { @Unroll def "serialize throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value) + ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value, graphQLContext, locale) then: thrown(CoercingSerializeException) @@ -81,7 +80,7 @@ class ScalarsBigIntegerTest extends Specification { @Unroll def "parseValue throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value) + ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) diff --git a/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy index 9d2dcea..2458e4e 100644 --- a/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy +++ b/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy @@ -1,23 +1,23 @@ package graphql.scalars.java -import graphql.scalars.ExtendedScalars import graphql.language.FloatValue import graphql.language.IntValue import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import java.util.concurrent.atomic.AtomicInteger -class ScalarsByteTest extends Specification { +class ScalarsByteTest extends AbstractScalarTest { @Unroll def "Byte parse literal #literal.value as #result"() { expect: - ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal) == result + ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) == result where: literal | result @@ -30,7 +30,7 @@ class ScalarsByteTest extends Specification { @Unroll def "Byte returns null for invalid #literal"() { when: - ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal) + ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) then: thrown(CoercingParseLiteralException) @@ -49,67 +49,67 @@ class ScalarsByteTest extends Specification { @Unroll def "Byte serialize #value into #result (#result.class)"() { expect: - ExtendedScalars.GraphQLByte.getCoercing().serialize(value) == result - ExtendedScalars.GraphQLByte.getCoercing().parseValue(value) == result + ExtendedScalars.GraphQLByte.getCoercing().serialize(value, graphQLContext, locale) == result + ExtendedScalars.GraphQLByte.getCoercing().parseValue(value, graphQLContext, locale) == result where: - value | result - "42" | 42 - "42.0000" | 42 - 42.0000d | 42 - new Integer(42) | 42 - "-1" | -1 - new BigInteger(42) | 42 - new BigDecimal("42") | 42 - 42.0f | 42 - 42.0d | 42 - new Byte("42") | 42 - new Short("42") | 42 - 123l | 123 - new AtomicInteger(42) | 42 - Byte.MAX_VALUE | Byte.MAX_VALUE - Byte.MIN_VALUE | Byte.MIN_VALUE + value | result + "42" | 42 + "42.0000" | 42 + 42.0000d | 42 + Integer.valueOf(42) | 42 + "-1" | -1 + BigInteger.valueOf(42) | 42 + new BigDecimal("42") | 42 + 42.0f | 42 + 42.0d | 42 + Byte.valueOf("42") | 42 + Short.valueOf("42") | 42 + 123l | 123 + new AtomicInteger(42) | 42 + Byte.MAX_VALUE | Byte.MAX_VALUE + Byte.MIN_VALUE | Byte.MIN_VALUE } @Unroll def "serialize throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLByte.getCoercing().serialize(value) + ExtendedScalars.GraphQLByte.getCoercing().serialize(value, graphQLContext, locale) then: thrown(CoercingSerializeException) where: - value | _ - "" | _ - "not a number " | _ - "42.3" | _ - new Long(42345784398534785l) | _ - new Double(42.3) | _ - new Float(42.3) | _ - Byte.MAX_VALUE + 1l | _ - Byte.MIN_VALUE - 1l | _ - new Object() | _ + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + Long.valueOf(42345784398534785l) | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ + Byte.MAX_VALUE + 1l | _ + Byte.MIN_VALUE - 1l | _ + new Object() | _ } @Unroll def "parseValue throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLByte.getCoercing().parseValue(value) + ExtendedScalars.GraphQLByte.getCoercing().parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) where: - value | _ - "" | _ - "not a number " | _ - "42.3" | _ - new Long(42345784398534785l) | _ - new Double(42.3) | _ - new Float(42.3) | _ - Byte.MAX_VALUE + 1l | _ - Byte.MIN_VALUE - 1l | _ - new Object() | _ + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + Long.valueOf(42345784398534785l) | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ + Byte.MAX_VALUE + 1l | _ + Byte.MIN_VALUE - 1l | _ + new Object() | _ } diff --git a/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy index 7808f28..68ad209 100644 --- a/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy +++ b/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy @@ -1,20 +1,20 @@ package graphql.scalars.java -import graphql.scalars.ExtendedScalars import graphql.language.IntValue import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll -class ScalarsCharTest extends Specification { +class ScalarsCharTest extends AbstractScalarTest { @Unroll def "Char parse literal #literal.value as #result"() { expect: - ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal) == result + ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) == result where: literal | result @@ -26,7 +26,7 @@ class ScalarsCharTest extends Specification { @Unroll def "Short returns null for invalid #literal"() { when: - ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal) + ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) then: thrown(CoercingParseLiteralException) @@ -39,8 +39,8 @@ class ScalarsCharTest extends Specification { @Unroll def "Short serialize #value into #result (#result.class)"() { expect: - ExtendedScalars.GraphQLChar.getCoercing().serialize(value) == result - ExtendedScalars.GraphQLChar.getCoercing().parseValue(value) == result + ExtendedScalars.GraphQLChar.getCoercing().serialize(value, graphQLContext, locale) == result + ExtendedScalars.GraphQLChar.getCoercing().parseValue(value, graphQLContext, locale) == result where: value | result @@ -51,7 +51,7 @@ class ScalarsCharTest extends Specification { @Unroll def "serialize throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLChar.getCoercing().serialize(value) + ExtendedScalars.GraphQLChar.getCoercing().serialize(value, graphQLContext, locale) then: thrown(CoercingSerializeException) @@ -66,7 +66,7 @@ class ScalarsCharTest extends Specification { @Unroll def "parseValue throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLChar.getCoercing().parseValue(value) + ExtendedScalars.GraphQLChar.getCoercing().parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) diff --git a/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy index 39793f4..6682bbe 100644 --- a/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy +++ b/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy @@ -1,19 +1,19 @@ package graphql.scalars.java -import graphql.scalars.ExtendedScalars import graphql.language.FloatValue import graphql.language.IntValue import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException import spock.lang.Shared -import spock.lang.Specification import spock.lang.Unroll import java.util.concurrent.atomic.AtomicInteger -class ScalarsLongTest extends Specification { +class ScalarsLongTest extends AbstractScalarTest { @Shared def tooBig = new BigInteger(Long.toString(Long.MAX_VALUE)).add(new BigInteger("1")) @@ -23,7 +23,7 @@ class ScalarsLongTest extends Specification { @Unroll def "Long parse literal #literal.value as #result"() { expect: - ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal) == result + ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) == result where: literal | result @@ -38,7 +38,7 @@ class ScalarsLongTest extends Specification { @Unroll def "Long returns null for invalid #literal"() { when: - ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal) + ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) then: thrown(CoercingParseLiteralException) @@ -46,73 +46,70 @@ class ScalarsLongTest extends Specification { literal | _ new StringValue("not a number") | _ new FloatValue(42.3) | _ - tooBig | null - tooSmall | null - new FloatValue(42.3) | null } @Unroll def "Long serialize #value into #result (#result.class)"() { expect: - ExtendedScalars.GraphQLLong.getCoercing().serialize(value) == result - ExtendedScalars.GraphQLLong.getCoercing().parseValue(value) == result + ExtendedScalars.GraphQLLong.getCoercing().serialize(value, graphQLContext, locale) == result + ExtendedScalars.GraphQLLong.getCoercing().parseValue(value, graphQLContext, locale) == result where: - value | result - "42" | 42 - "42.0000" | 42 - 42.0000d | 42 - new Integer(42) | 42 - "-1" | -1 - new BigInteger(42) | 42 - new BigDecimal("42") | 42 - 42.0f | 42 - 42.0d | 42 - new Byte("42") | 42 - new Short("42") | 42 - 12345678910l | 12345678910l - new AtomicInteger(42) | 42 - Long.MAX_VALUE | Long.MAX_VALUE - Long.MIN_VALUE | Long.MIN_VALUE - new Long(42345784398534785l) | 42345784398534785l + value | result + "42" | 42 + "42.0000" | 42 + 42.0000d | 42 + Integer.valueOf(42) | 42 + "-1" | -1 + BigInteger.valueOf(42) | 42 + new BigDecimal("42") | 42 + 42.0f | 42 + 42.0d | 42 + Byte.valueOf("42") | 42 + Short.valueOf("42") | 42 + 12345678910l | 12345678910l + new AtomicInteger(42) | 42 + Long.MAX_VALUE | Long.MAX_VALUE + Long.MIN_VALUE | Long.MIN_VALUE + Long.valueOf(42345784398534785l) | 42345784398534785l } @Unroll def "serialize throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLLong.getCoercing().serialize(value) + ExtendedScalars.GraphQLLong.getCoercing().serialize(value, graphQLContext, locale) then: thrown(CoercingSerializeException) where: - value | _ - "" | _ - "not a number " | _ - "42.3" | _ - new Double(42.3) | _ - new Float(42.3) | _ - tooBig | _ - tooSmall | _ - new Object() | _ + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ + tooBig | _ + tooSmall | _ + new Object() | _ } @Unroll def "parseValue throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLLong.getCoercing().parseValue(value) + ExtendedScalars.GraphQLLong.getCoercing().parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) where: - value | _ - "" | _ - "not a number " | _ - "42.3" | _ - new Double(42.3) | _ - new Float(42.3) | _ - tooBig | _ - tooSmall | _ - new Object() | _ + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + Double.valueOf(42.3) | _ + Float.valueOf(42.3) | _ + tooBig | _ + tooSmall | _ + new Object() | _ } } diff --git a/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy index e8ff506..06ed235 100644 --- a/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy +++ b/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy @@ -1,23 +1,24 @@ package graphql.scalars.java + import graphql.language.FloatValue import graphql.language.IntValue import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import java.util.concurrent.atomic.AtomicInteger -class ScalarsShortTest extends Specification { +class ScalarsShortTest extends AbstractScalarTest { @Unroll def "Short parse literal #literal.value as #result"() { expect: - ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal) == result + ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) == result where: literal | result @@ -30,7 +31,7 @@ class ScalarsShortTest extends Specification { @Unroll def "Short returns null for invalid #literal"() { when: - ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal) + ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal, variables, graphQLContext, locale) then: thrown(CoercingParseLiteralException) @@ -48,32 +49,32 @@ class ScalarsShortTest extends Specification { @Unroll def "Short serialize #value into #result (#result.class)"() { expect: - ExtendedScalars.GraphQLShort.getCoercing().serialize(value) == result - ExtendedScalars.GraphQLShort.getCoercing().parseValue(value) == result + ExtendedScalars.GraphQLShort.getCoercing().serialize(value, graphQLContext, locale) == result + ExtendedScalars.GraphQLShort.getCoercing().parseValue(value, graphQLContext, locale) == result where: - value | result - "42" | 42 - "42.0000" | 42 - 42.0000d | 42 - new Integer(42) | 42 - "-1" | -1 - new BigInteger(42) | 42 - new BigDecimal("42") | 42 - 42.0f | 42 - 42.0d | 42 - new Byte("42") | 42 - new Short("42") | 42 - 1234l | 1234 - new AtomicInteger(42) | 42 - Short.MAX_VALUE | Short.MAX_VALUE - Short.MIN_VALUE | Short.MIN_VALUE + value | result + "42" | 42 + "42.0000" | 42 + 42.0000d | 42 + Integer.valueOf(42) | 42 + "-1" | -1 + BigInteger.valueOf(42) | 42 + new BigDecimal("42") | 42 + 42.0f | 42 + 42.0d | 42 + Byte.valueOf("42") | 42 + Short.valueOf("42") | 42 + 1234l | 1234 + new AtomicInteger(42) | 42 + Short.MAX_VALUE | Short.MAX_VALUE + Short.MIN_VALUE | Short.MIN_VALUE } @Unroll def "serialize throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLShort.getCoercing().serialize(value) + ExtendedScalars.GraphQLShort.getCoercing().serialize(value, graphQLContext, locale) then: thrown(CoercingSerializeException) @@ -94,7 +95,7 @@ class ScalarsShortTest extends Specification { @Unroll def "parseValue throws exception for invalid input #value"() { when: - ExtendedScalars.GraphQLShort.getCoercing().parseValue(value) + ExtendedScalars.GraphQLShort.getCoercing().parseValue(value, graphQLContext, locale) then: thrown(CoercingParseValueException) diff --git a/src/test/groovy/graphql/scalars/locale/LocaleScalarTest.groovy b/src/test/groovy/graphql/scalars/locale/LocaleScalarTest.groovy index 9d2ed05..cbd944c 100644 --- a/src/test/groovy/graphql/scalars/locale/LocaleScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/locale/LocaleScalarTest.groovy @@ -2,13 +2,13 @@ package graphql.scalars.locale import graphql.language.StringValue import graphql.scalars.ExtendedScalars -import spock.lang.Specification +import graphql.scalars.util.AbstractScalarTest import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkLocale import static graphql.scalars.util.TestKit.mkStringValue -class LocaleScalarTest extends Specification { +class LocaleScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.Locale.getCoercing() @@ -16,7 +16,7 @@ class LocaleScalarTest extends Specification { def "full locale parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedValue where: @@ -30,7 +30,7 @@ class LocaleScalarTest extends Specification { @Unroll def "full Locale parseLiteral"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedValue where: @@ -41,7 +41,7 @@ class LocaleScalarTest extends Specification { @Unroll def "full Locale serialization"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedValue where: @@ -54,7 +54,7 @@ class LocaleScalarTest extends Specification { @Unroll def "full Locale valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedValue) where: diff --git a/src/test/groovy/graphql/scalars/numeric/NegativeFloatScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/NegativeFloatScalarTest.groovy index 8a8ca4e..d55e9cf 100644 --- a/src/test/groovy/graphql/scalars/numeric/NegativeFloatScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/NegativeFloatScalarTest.groovy @@ -1,19 +1,18 @@ package graphql.scalars.numeric - import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkFloatValue import static graphql.scalars.util.TestKit.mkIntValue -class NegativeFloatScalarTest extends Specification { +class NegativeFloatScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NegativeFloat.getCoercing() @Unroll @@ -21,7 +20,7 @@ class NegativeFloatScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -43,7 +42,7 @@ class NegativeFloatScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -65,7 +64,7 @@ class NegativeFloatScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/NegativeIntScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/NegativeIntScalarTest.groovy index ad5a315..dada6d4 100644 --- a/src/test/groovy/graphql/scalars/numeric/NegativeIntScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/NegativeIntScalarTest.groovy @@ -2,16 +2,16 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkIntValue -class NegativeIntScalarTest extends Specification { +class NegativeIntScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NegativeInt.getCoercing() @Unroll @@ -19,7 +19,7 @@ class NegativeIntScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -39,7 +39,7 @@ class NegativeIntScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -59,7 +59,7 @@ class NegativeIntScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/NonNegativeFloatScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/NonNegativeFloatScalarTest.groovy index e34d8a4..a6fe977 100644 --- a/src/test/groovy/graphql/scalars/numeric/NonNegativeFloatScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/NonNegativeFloatScalarTest.groovy @@ -2,17 +2,17 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkFloatValue import static graphql.scalars.util.TestKit.mkIntValue -class NonNegativeFloatScalarTest extends Specification { +class NonNegativeFloatScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NonNegativeFloat.getCoercing() @Unroll @@ -20,7 +20,7 @@ class NonNegativeFloatScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -42,7 +42,7 @@ class NonNegativeFloatScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -64,7 +64,7 @@ class NonNegativeFloatScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/NonNegativeIntScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/NonNegativeIntScalarTest.groovy index 1cf11da..56a1d61 100644 --- a/src/test/groovy/graphql/scalars/numeric/NonNegativeIntScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/NonNegativeIntScalarTest.groovy @@ -2,16 +2,16 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkIntValue -class NonNegativeIntScalarTest extends Specification { +class NonNegativeIntScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NonNegativeInt.getCoercing() @Unroll @@ -19,7 +19,7 @@ class NonNegativeIntScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -39,7 +39,7 @@ class NonNegativeIntScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -59,7 +59,7 @@ class NonNegativeIntScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/NonPositiveFloatScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/NonPositiveFloatScalarTest.groovy index cde1426..fa4e288 100644 --- a/src/test/groovy/graphql/scalars/numeric/NonPositiveFloatScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/NonPositiveFloatScalarTest.groovy @@ -2,17 +2,17 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkFloatValue import static graphql.scalars.util.TestKit.mkIntValue -class NonPositiveFloatScalarTest extends Specification { +class NonPositiveFloatScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NonPositiveFloat.getCoercing() @Unroll @@ -20,7 +20,7 @@ class NonPositiveFloatScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -41,7 +41,7 @@ class NonPositiveFloatScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -62,7 +62,7 @@ class NonPositiveFloatScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/NonPositiveIntScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/NonPositiveIntScalarTest.groovy index f5c9573..1944a11 100644 --- a/src/test/groovy/graphql/scalars/numeric/NonPositiveIntScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/NonPositiveIntScalarTest.groovy @@ -2,16 +2,16 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkIntValue -class NonPositiveIntScalarTest extends Specification { +class NonPositiveIntScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.NonPositiveInt.getCoercing() @Unroll @@ -19,7 +19,7 @@ class NonPositiveIntScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -39,7 +39,7 @@ class NonPositiveIntScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -59,7 +59,7 @@ class NonPositiveIntScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/PositiveFloatScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/PositiveFloatScalarTest.groovy index 4a0f468..06806b7 100644 --- a/src/test/groovy/graphql/scalars/numeric/PositiveFloatScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/PositiveFloatScalarTest.groovy @@ -2,17 +2,17 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkFloatValue import static graphql.scalars.util.TestKit.mkIntValue -class PositiveFloatScalarTest extends Specification { +class PositiveFloatScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.PositiveFloat.getCoercing() @Unroll @@ -20,7 +20,7 @@ class PositiveFloatScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -42,7 +42,7 @@ class PositiveFloatScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -64,7 +64,7 @@ class PositiveFloatScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/numeric/PositiveIntScalarTest.groovy b/src/test/groovy/graphql/scalars/numeric/PositiveIntScalarTest.groovy index 5841304..cb6200b 100644 --- a/src/test/groovy/graphql/scalars/numeric/PositiveIntScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/numeric/PositiveIntScalarTest.groovy @@ -2,16 +2,16 @@ package graphql.scalars.numeric import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.assertValueOrException import static graphql.scalars.util.TestKit.mkIntValue -class PositiveIntScalarTest extends Specification { +class PositiveIntScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.PositiveInt.getCoercing() @Unroll @@ -19,7 +19,7 @@ class PositiveIntScalarTest extends Specification { def result when: try { - result = coercing.serialize(input) + result = coercing.serialize(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -38,7 +38,7 @@ class PositiveIntScalarTest extends Specification { def result when: try { - result = coercing.parseValue(input) + result = coercing.parseValue(input, graphQLContext, locale) } catch (Exception e) { result = e } @@ -57,7 +57,7 @@ class PositiveIntScalarTest extends Specification { def result when: try { - result = coercing.parseLiteral(input) + result = coercing.parseLiteral(input, variables, graphQLContext, locale) } catch (Exception e) { result = e } diff --git a/src/test/groovy/graphql/scalars/object/ObjectScalarTest.groovy b/src/test/groovy/graphql/scalars/object/ObjectScalarTest.groovy index ca02f91..e892a80 100644 --- a/src/test/groovy/graphql/scalars/object/ObjectScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/object/ObjectScalarTest.groovy @@ -12,46 +12,51 @@ import graphql.language.StringValue import graphql.language.Value import graphql.language.VariableReference import graphql.scalars.ExtendedScalars -import spock.lang.Specification +import graphql.scalars.util.AbstractScalarTest import spock.lang.Unroll -class ObjectScalarTest extends Specification { +class ObjectScalarTest extends AbstractScalarTest { - def variables = [ - "varRef1": "value1" - ] def coercing = ExtendedScalars.Object.getCoercing() + @Override + void setup() { + variables = [ + "varRef1": "value1" + ] + + } + @Unroll def "test AST parsing"() { when: - def result = coercing.parseLiteral(input, variables) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedResult where: - input | expectedResult - mkStringValue("s") | "s" - mkFloatValue("99.9") | new BigDecimal("99.9") - mkIntValue(666) | 666 - mkBooleanValue(true) | true - mkEnumValue("enum") | "enum" - mkVarRef("varRef1") | "value1" + input | expectedResult + mkStringValue("s") | "s" + mkFloatValue("99.9") | new BigDecimal("99.9") + mkIntValue(666) | 666 + mkBooleanValue(true) | true + mkEnumValue("enum") | "enum" + mkVarRef("varRef1") | "value1" mkArrayValue([ mkStringValue("s"), mkIntValue(666) - ] as List) | ["s", 666] + ] as List) | ["s", 666] } @Unroll def "test AST object parsing"() { when: - def result = coercing.parseLiteral(input, variables) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedResult where: - input | expectedResult + input | expectedResult mkObjectValue([ fld1: mkStringValue("s"), fld2: mkIntValue(99), @@ -59,17 +64,17 @@ class ObjectScalarTest extends Specification { childFld1: mkStringValue("child1"), childFl2 : mkVarRef("varRef1") ] as Map) - ] as Map) | [fld1: "s", fld2: 99, fld3: [childFld1: "child1", childFl2: "value1"]] + ] as Map) | [fld1: "s", fld2: 99, fld3: [childFld1: "child1", childFl2: "value1"]] mkObjectValue([ field1: mkNullValue() - ] as Map) | [field1: null] // Nested NullValue inside ObjectValue + ] as Map) | [field1: null] // Nested NullValue inside ObjectValue } @Unroll def "test serialize is always in and out"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedResult where: @@ -81,7 +86,7 @@ class ObjectScalarTest extends Specification { @Unroll def "test parseValue is always in and out"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedResult where: @@ -93,7 +98,7 @@ class ObjectScalarTest extends Specification { @Unroll def "test valueToLiteral #input"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedResult) where: diff --git a/src/test/groovy/graphql/scalars/regex/RegexScalarTest.groovy b/src/test/groovy/graphql/scalars/regex/RegexScalarTest.groovy index c5eb5be..55e158b 100644 --- a/src/test/groovy/graphql/scalars/regex/RegexScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/regex/RegexScalarTest.groovy @@ -2,18 +2,18 @@ package graphql.scalars.regex import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException import graphql.schema.GraphQLScalarType -import spock.lang.Specification import spock.lang.Unroll import java.util.regex.Pattern import static graphql.scalars.util.TestKit.mkStringValue -class RegexScalarTest extends Specification { +class RegexScalarTest extends AbstractScalarTest { GraphQLScalarType phoneNumberScalar = ExtendedScalars.newRegexScalar("phoneNumber") .addPattern(Pattern.compile("\\([0-9]*\\)[0-9]*")) @@ -23,7 +23,7 @@ class RegexScalarTest extends Specification { def "basic regex parseValue"() { when: - def result = phoneNumberScalar.getCoercing().parseValue(input) + def result = phoneNumberScalar.getCoercing().parseValue(input, graphQLContext, locale) then: result == expectedResult where: @@ -34,7 +34,7 @@ class RegexScalarTest extends Specification { @Unroll def "basic regex parseValue bad input"() { when: - phoneNumberScalar.getCoercing().parseValue(input) + phoneNumberScalar.getCoercing().parseValue(input, graphQLContext, locale) then: thrown(expectedResult) where: @@ -46,7 +46,7 @@ class RegexScalarTest extends Specification { def "basic regex parseLiteral"() { when: - def result = phoneNumberScalar.getCoercing().parseLiteral(input) + def result = phoneNumberScalar.getCoercing().parseLiteral(input, variables, graphQLContext, locale) then: result == expectedResult where: @@ -57,19 +57,19 @@ class RegexScalarTest extends Specification { @Unroll def "basic regex parseLiteral bad input"() { when: - phoneNumberScalar.getCoercing().parseLiteral(input) + phoneNumberScalar.getCoercing().parseLiteral(input, variables, graphQLContext, locale) then: thrown(expectedResult) where: - input || expectedResult - "(02)abc123" || CoercingParseLiteralException + input || expectedResult + mkStringValue("(02)abc123") || CoercingParseLiteralException } @Unroll def "basic regex serialize"() { when: - def result = phoneNumberScalar.getCoercing().serialize(input) + def result = phoneNumberScalar.getCoercing().serialize(input, graphQLContext, locale) then: result == expectedResult where: @@ -81,7 +81,7 @@ class RegexScalarTest extends Specification { def "basic regex valueToLiteral"() { when: - def result = phoneNumberScalar.getCoercing().valueToLiteral(input) + def result = phoneNumberScalar.getCoercing().valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedResult) where: @@ -92,12 +92,12 @@ class RegexScalarTest extends Specification { @Unroll def "basic regex serialize bad input"() { when: - phoneNumberScalar.getCoercing().serialize(input) + phoneNumberScalar.getCoercing().serialize(input, graphQLContext, locale) then: thrown(expectedResult) where: - input || expectedResult - "(02)abc123" || CoercingSerializeException + input || expectedResult + mkStringValue("(02)abc123") || CoercingSerializeException } } diff --git a/src/test/groovy/graphql/scalars/url/UrlScalarTest.groovy b/src/test/groovy/graphql/scalars/url/UrlScalarTest.groovy index 32d717f..608e97b 100644 --- a/src/test/groovy/graphql/scalars/url/UrlScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/url/UrlScalarTest.groovy @@ -1,17 +1,18 @@ package graphql.scalars.url + import graphql.language.BooleanValue import graphql.language.StringValue import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest import graphql.schema.CoercingParseLiteralException import graphql.schema.CoercingParseValueException import graphql.schema.CoercingSerializeException -import spock.lang.Specification import spock.lang.Unroll import static graphql.scalars.util.TestKit.mkStringValue -class UrlScalarTest extends Specification { +class UrlScalarTest extends AbstractScalarTest { def coercing = ExtendedScalars.Url.getCoercing() @@ -19,7 +20,7 @@ class UrlScalarTest extends Specification { def "test serialize"() { when: - def result = coercing.serialize(input) + def result = coercing.serialize(input, graphQLContext, locale) then: result == expectedResult where: @@ -34,7 +35,7 @@ class UrlScalarTest extends Specification { def "test valueToLiteral"() { when: - def result = coercing.valueToLiteral(input) + def result = coercing.valueToLiteral(input, graphQLContext, locale) then: result.isEqualTo(expectedResult) where: @@ -48,7 +49,7 @@ class UrlScalarTest extends Specification { @Unroll def "test serialize bad inputs"() { when: - coercing.serialize(input) + coercing.serialize(input, graphQLContext, locale) then: thrown(exceptionClas) where: @@ -60,7 +61,7 @@ class UrlScalarTest extends Specification { @Unroll def "test parseValue"() { when: - def result = coercing.parseValue(input) + def result = coercing.parseValue(input, graphQLContext, locale) then: result == expectedResult where: @@ -74,7 +75,7 @@ class UrlScalarTest extends Specification { @Unroll def "test parseValue bad inputs"() { when: - coercing.parseValue(input) + coercing.parseValue(input, graphQLContext, locale) then: thrown(exceptionClas) where: @@ -86,7 +87,7 @@ class UrlScalarTest extends Specification { @Unroll def "test parseLiteral"() { when: - def result = coercing.parseLiteral(input) + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) then: result == expectedResult where: @@ -97,7 +98,7 @@ class UrlScalarTest extends Specification { @Unroll def "test parseLiteral bad inputs"() { when: - coercing.parseLiteral(input) + coercing.parseLiteral(input, variables, graphQLContext, locale) then: thrown(exceptionClas) where: diff --git a/src/test/groovy/graphql/scalars/util/AbstractScalarTest.groovy b/src/test/groovy/graphql/scalars/util/AbstractScalarTest.groovy new file mode 100644 index 0000000..3d19e99 --- /dev/null +++ b/src/test/groovy/graphql/scalars/util/AbstractScalarTest.groovy @@ -0,0 +1,22 @@ +package graphql.scalars.util + +import graphql.GraphQLContext +import graphql.execution.CoercedVariables +import spock.lang.Specification + +/** + * Base class for scalar test + */ +abstract class AbstractScalarTest extends Specification { + + GraphQLContext graphQLContext + Locale locale + CoercedVariables variables + + void setup() { + graphQLContext = GraphQLContext.newContext().build() + locale = Locale.getDefault() + variables = CoercedVariables.emptyVariables() + } + +} diff --git a/src/test/groovy/graphql/scalars/util/TestKit.groovy b/src/test/groovy/graphql/scalars/util/TestKit.groovy index d444b0b..27aafdd 100644 --- a/src/test/groovy/graphql/scalars/util/TestKit.groovy +++ b/src/test/groovy/graphql/scalars/util/TestKit.groovy @@ -5,8 +5,8 @@ import graphql.language.IntValue import graphql.language.StringValue import graphql.scalars.country.code.CountryCode +import java.awt.* import java.time.Duration -import java.awt.Color import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime @@ -119,6 +119,7 @@ class TestKit { static Color mkColor(int r, int g, int b, int a) { return new Color(r, g, b, a) } + static Color mkColor(int r, int g, int b) { return new Color(r, g, b) } From 39ce48725e0e6629d2d6bf6376237bb14e9b2597 Mon Sep 17 00:00:00 2001 From: bbaker Date: Sun, 15 Jun 2025 22:52:16 +1000 Subject: [PATCH 19/29] Updated to graphql-java 24.x --- build.gradle | 2 +- src/main/java/graphql/scalars/datetime/DateTimeScalar.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index c50928a..d28dd44 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ repositories { } dependencies { - implementation "com.graphql-java:graphql-java:22.3" + implementation "com.graphql-java:graphql-java:24.1" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" testImplementation "org.codehaus.groovy:groovy:3.0.24" diff --git a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java index 7777bcd..359ec7a 100644 --- a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java +++ b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java @@ -20,8 +20,8 @@ import static graphql.scalars.util.Kit.typeName; import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; -import static java.time.temporal.ChronoField.NANO_OF_SECOND; import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; @@ -33,7 +33,9 @@ public final class DateTimeScalar { public static final GraphQLScalarType INSTANCE; - private DateTimeScalar() {} + private DateTimeScalar() { + } + private static final DateTimeFormatter customOutputFormatter = getCustomDateTimeFormatter(); static { From a5d7f633a2d199dd2b7b8f5d916802e88597eb67 Mon Sep 17 00:00:00 2001 From: bbaker Date: Sun, 15 Jun 2025 22:56:00 +1000 Subject: [PATCH 20/29] Fixes master --- src/main/java/graphql/scalars/datetime/DateTimeScalar.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java index 7777bcd..359ec7a 100644 --- a/src/main/java/graphql/scalars/datetime/DateTimeScalar.java +++ b/src/main/java/graphql/scalars/datetime/DateTimeScalar.java @@ -20,8 +20,8 @@ import static graphql.scalars.util.Kit.typeName; import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; -import static java.time.temporal.ChronoField.NANO_OF_SECOND; import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; @@ -33,7 +33,9 @@ public final class DateTimeScalar { public static final GraphQLScalarType INSTANCE; - private DateTimeScalar() {} + private DateTimeScalar() { + } + private static final DateTimeFormatter customOutputFormatter = getCustomDateTimeFormatter(); static { From caf5c30220e82cd93ab2e0be00ee65376597890f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 18:00:34 +0000 Subject: [PATCH 21/29] Bump org.codehaus.groovy:groovy from 3.0.24 to 3.0.25 Bumps [org.codehaus.groovy:groovy](https://github.com/apache/groovy) from 3.0.24 to 3.0.25. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.codehaus.groovy:groovy dependency-version: 3.0.25 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d28dd44..e3419f6 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation "com.graphql-java:graphql-java:24.1" testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" - testImplementation "org.codehaus.groovy:groovy:3.0.24" + testImplementation "org.codehaus.groovy:groovy:3.0.25" } task sourcesJar(type: Jar, dependsOn: classes) { From 53c0605c9ea2653f608b629832b6d6b5e15b93c4 Mon Sep 17 00:00:00 2001 From: Igor Zarvanskyi Date: Tue, 17 Jun 2025 10:16:35 +0200 Subject: [PATCH 22/29] feat: add SecondsSinceEpochScalar Refs: #157 --- README.md | 22 ++- .../java/graphql/scalars/ExtendedScalars.java | 29 +++ .../datetime/SecondsSinceEpochScalar.java | 175 ++++++++++++++++++ .../SecondsSinceEpochScalarTest.groovy | 135 ++++++++++++++ 4 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java create mode 100644 src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy diff --git a/README.md b/README.md index e3b0e30..6bc588d 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,22 @@ scalar LocalTime

24-hour clock time string in the format hh:mm:ss.sss or hh:mm:ss if partial seconds is zero and produces java.time.LocalTime objects at runtime. + +
+scalar SecondsSinceEpoch
+
+A scalar that represents a point in time as seconds since the Unix epoch (January 1, 1970, 00:00:00 UTC). It accepts integers or strings containing integers as input values and produces java.time.ZonedDateTime objects at runtime (with UTC timezone).

+Using seconds since epoch is preferable to formatted date time strings in several scenarios: +
    +
  • When you need a universal representation of a point in time that is timezone-agnostic
  • +
  • For easier date/time arithmetic and comparison operations
  • +
  • When storage space or bandwidth efficiency is important (more compact representation)
  • +
  • To avoid complexities with different date formats and timezone conversions
  • +
  • For better interoperability with systems that natively work with Unix timestamps
  • +
  • When working with time-series data or logging systems where timestamps are commonly used
  • +
+However, human readability is sacrificed compared to formatted date strings, so consider your use case requirements when choosing between DateTime and SecondsSinceEpoch. + An example declaration in SDL might be: @@ -181,10 +197,11 @@ type Customer { birthDay: Date workStartTime: Time bornAt: DateTime + createdAtTimestamp: SecondsSinceEpoch } type Query { - customers(bornAfter: DateTime): [Customers] + customers(bornAfter: DateTime, createdAfter: SecondsSinceEpoch): [Customers] } ``` @@ -192,9 +209,10 @@ And example query might look like: ```graphql query { - customers(bornAfter: "1996-12-19T16:39:57-08:00") { + customers(bornAfter: "1996-12-19T16:39:57-08:00", createdAfter: 1609459200) { birthDay bornAt + createdAtTimestamp } } ``` diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index e3f7d9d..07124fc 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -10,6 +10,7 @@ import graphql.scalars.datetime.AccurateDurationScalar; import graphql.scalars.datetime.LocalTimeCoercing; import graphql.scalars.datetime.NominalDurationScalar; +import graphql.scalars.datetime.SecondsSinceEpochScalar; import graphql.scalars.datetime.TimeScalar; import graphql.scalars.datetime.YearMonthScalar; import graphql.scalars.datetime.YearScalar; @@ -138,6 +139,34 @@ public class ExtendedScalars { */ public static final GraphQLScalarType NominalDuration = NominalDurationScalar.INSTANCE; + /** + * A scalar that represents a point in time as seconds since the Unix epoch (Unix timestamp). + *

+ * It accepts integers or strings containing integers as input values and produces + * `java.time.ZonedDateTime` objects at runtime (with UTC timezone). + *

+ * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} method accepts various + * {@link java.time.temporal.TemporalAccessor} types and returns a string containing the number of seconds since epoch + * (January 1, 1970, 00:00:00 UTC). + *

+ * Using seconds since epoch is preferable to formatted date time strings in several scenarios: + *

    + *
  • When you need a universal representation of a point in time that is timezone-agnostic
  • + *
  • For easier date/time arithmetic and comparison operations
  • + *
  • When storage space or bandwidth efficiency is important (more compact representation)
  • + *
  • To avoid complexities with different date formats and timezone conversions
  • + *
  • For better interoperability with systems that natively work with Unix timestamps
  • + *
  • When working with time-series data or logging systems where timestamps are commonly used
  • + *
+ *

+ * However, human readability is sacrificed compared to formatted date strings, so consider your use case + * requirements when choosing between {@link #DateTime} and {@link #SecondsSinceEpoch}. + * + * @see java.time.Instant + * @see java.time.ZonedDateTime + */ + public static final GraphQLScalarType SecondsSinceEpoch = SecondsSinceEpochScalar.INSTANCE; + /** * An object scalar allows you to have a multi level data value without defining it in the graphql schema. *

diff --git a/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java b/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java new file mode 100644 index 0000000..2b0f07b --- /dev/null +++ b/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java @@ -0,0 +1,175 @@ +package graphql.scalars.datetime; + +import graphql.GraphQLContext; +import graphql.Internal; +import graphql.execution.CoercedVariables; +import graphql.language.IntValue; +import graphql.language.StringValue; +import graphql.language.Value; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.Locale; + +import static graphql.scalars.util.Kit.typeName; + +/** + * Access this via {@link graphql.scalars.ExtendedScalars#SecondsSinceEpoch} + */ +@Internal +public final class SecondsSinceEpochScalar { + + public static final GraphQLScalarType INSTANCE; + + private SecondsSinceEpochScalar() { + } + + private static Temporal convertToTemporal(String value) { + try { + if (value.matches("\\d+")) { + long epochSeconds = Long.parseLong(value); + return convertEpochSecondsToTemporal(epochSeconds); + } + throw new CoercingParseValueException( + "Invalid seconds since epoch value : '" + value + "'. Expected a string containing only digits." + ); + } catch (Exception e) { + throw new CoercingParseValueException( + "Invalid seconds since epoch value : '" + value + "'. " + e.getMessage() + ); + } + } + + private static Temporal convertEpochSecondsToTemporal(long epochSeconds) { + return Instant.ofEpochSecond(epochSeconds).atZone(ZoneOffset.UTC); + } + + static { + Coercing coercing = new Coercing<>() { + @Override + public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { + try { + if (input instanceof Number) { + Number number = (Number) input; + return Long.toString(number.longValue()); + } + if (input instanceof String) { + String string = (String) input; + if (string.matches("\\d+")) { + return string; + } + throw new CoercingSerializeException( + "Invalid seconds since epoch value : '" + string + "'. Expected a string containing only digits." + ); + } + if (input instanceof TemporalAccessor) { + TemporalAccessor temporalAccessor = (TemporalAccessor) input; + if (temporalAccessor instanceof Instant) { + Instant instant = (Instant) temporalAccessor; + return Long.toString(instant.getEpochSecond()); + } else if (temporalAccessor instanceof LocalDateTime) { + LocalDateTime localDateTime = (LocalDateTime) temporalAccessor; + return Long.toString(localDateTime.toEpochSecond(ZoneOffset.UTC)); + } else if (temporalAccessor instanceof ZonedDateTime) { + ZonedDateTime zonedDateTime = (ZonedDateTime) temporalAccessor; + return Long.toString(zonedDateTime.toEpochSecond()); + } else if (temporalAccessor instanceof OffsetDateTime) { + OffsetDateTime offsetDateTime = (OffsetDateTime) temporalAccessor; + return Long.toString(offsetDateTime.toEpochSecond()); + } else { + try { + Instant instant = Instant.from(temporalAccessor); + return Long.toString(instant.getEpochSecond()); + } catch (Exception e) { + throw new CoercingSerializeException( + "Unable to convert TemporalAccessor to seconds since epoch because of : '" + e.getMessage() + "'." + ); + } + } + } + throw new CoercingSerializeException( + "Expected a 'Number', 'String' or 'TemporalAccessor' but was '" + typeName(input) + "'." + ); + } catch (CoercingSerializeException e) { + throw e; + } catch (Exception e) { + throw new CoercingSerializeException( + "Unable to convert to seconds since epoch because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public TemporalAccessor parseValue(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingParseValueException { + try { + if (input instanceof Number) { + Number number = (Number) input; + return convertEpochSecondsToTemporal(number.longValue()); + } + if (input instanceof String) { + String string = (String) input; + return convertToTemporal(string); + } + throw new CoercingParseValueException( + "Expected a 'Number' or 'String' but was '" + typeName(input) + "'." + ); + } catch (CoercingParseValueException e) { + throw e; + } catch (Exception e) { + throw new CoercingParseValueException( + "Unable to parse value to seconds since epoch because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public TemporalAccessor parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) throws CoercingParseLiteralException { + try { + if (input instanceof StringValue) { + StringValue stringValue = (StringValue) input; + return convertToTemporal(stringValue.getValue()); + } + if (input instanceof IntValue) { + IntValue intValue = (IntValue) input; + long epochSeconds = intValue.getValue().longValue(); + return convertEpochSecondsToTemporal(epochSeconds); + } + throw new CoercingParseLiteralException( + "Expected AST type 'StringValue' or 'IntValue' but was '" + typeName(input) + "'." + ); + } catch (CoercingParseLiteralException e) { + throw e; + } catch (Exception e) { + throw new CoercingParseLiteralException( + "Unable to parse literal to seconds since epoch because of : '" + e.getMessage() + "'." + ); + } + } + + @Override + public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { + String s = serialize(input, graphQLContext, locale); + return StringValue.newStringValue(s).build(); + } + + }; + + INSTANCE = GraphQLScalarType.newScalar() + .name("SecondsSinceEpoch") + .description("Scalar that represents a point in time as seconds since the Unix epoch (Unix timestamp). " + + "Accepts integers or strings containing integers as input values. " + + "Returns a string containing the number of seconds since epoch (January 1, 1970, 00:00:00 UTC).") + .coercing(coercing) + .build(); + } +} diff --git a/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy new file mode 100644 index 0000000..1210a18 --- /dev/null +++ b/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy @@ -0,0 +1,135 @@ +package graphql.scalars.datetime + +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.scalars.util.AbstractScalarTest +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Unroll + +import java.time.Instant +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.ZonedDateTime + +import static graphql.scalars.util.TestKit.mkIntValue +import static graphql.scalars.util.TestKit.mkLocalDT +import static graphql.scalars.util.TestKit.mkOffsetDT +import static graphql.scalars.util.TestKit.mkStringValue +import static graphql.scalars.util.TestKit.mkZonedDT + +class SecondsSinceEpochScalarTest extends AbstractScalarTest { + + def coercing = ExtendedScalars.SecondsSinceEpoch.getCoercing() + + @Unroll + def "secondsSinceEpoch parseValue"() { + when: + def result = coercing.parseValue(input, graphQLContext, locale) + then: + result.toEpochSecond() == expectedValue + where: + input | expectedValue + "0" | 0L + "1" | 1L + "1609459200" | 1609459200L // 2021-01-01T00:00:00Z + "1640995200" | 1640995200L // 2022-01-01T00:00:00Z + 0 | 0L + 1 | 1L + 1609459200 | 1609459200L // 2021-01-01T00:00:00Z + 1640995200 | 1640995200L // 2022-01-01T00:00:00Z + } + + @Unroll + def "secondsSinceEpoch valueToLiteral"() { + when: + def result = coercing.valueToLiteral(input, graphQLContext, locale) + then: + result.isEqualTo(expectedValue) + where: + input | expectedValue + "0" | mkStringValue("0") + "1" | mkStringValue("1") + "1609459200" | mkStringValue("1609459200") + "1640995200" | mkStringValue("1640995200") + 0 | mkStringValue("0") + 1 | mkStringValue("1") + 1609459200 | mkStringValue("1609459200") + 1640995200 | mkStringValue("1640995200") + Instant.ofEpochSecond(1609459200) | mkStringValue("1609459200") + ZonedDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | mkStringValue("1609459200") + } + + @Unroll + def "secondsSinceEpoch parseValue bad inputs"() { + when: + coercing.parseValue(input, graphQLContext, locale) + then: + thrown(expectedValue) + where: + input | expectedValue + "not a number" | CoercingParseValueException + "123abc" | CoercingParseValueException + "2022-01-01" | CoercingParseValueException + "2022-01-01T00:00:00Z" | CoercingParseValueException + new Object() | CoercingParseValueException + } + + def "secondsSinceEpoch AST literal"() { + when: + def result = coercing.parseLiteral(input, variables, graphQLContext, locale) + then: + result.toEpochSecond() == expectedValue + where: + input | expectedValue + new StringValue("0") | 0L + new StringValue("1") | 1L + new StringValue("1609459200") | 1609459200L // 2021-01-01T00:00:00Z + new IntValue(0) | 0L + new IntValue(1) | 1L + new IntValue(1609459200) | 1609459200L // 2021-01-01T00:00:00Z + } + + def "secondsSinceEpoch serialisation"() { + when: + def result = coercing.serialize(input, graphQLContext, locale) + then: + result == expectedValue + where: + input | expectedValue + Instant.ofEpochSecond(0) | "0" + Instant.ofEpochSecond(1) | "1" + Instant.ofEpochSecond(1609459200) | "1609459200" + LocalDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | "1609459200" + ZonedDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | "1609459200" + OffsetDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | "1609459200" + } + + def "secondsSinceEpoch serialisation bad inputs"() { + when: + coercing.serialize(input, graphQLContext, locale) + then: + thrown(expectedValue) + where: + input | expectedValue + "not a temporal" | CoercingSerializeException + new Object() | CoercingSerializeException + } + + @Unroll + def "secondsSinceEpoch parseLiteral bad inputs"() { + when: + coercing.parseLiteral(input, variables, graphQLContext, locale) + then: + thrown(expectedValue) + where: + input | expectedValue + mkStringValue("not a number") | CoercingParseLiteralException + mkStringValue("123abc") | CoercingParseLiteralException + mkStringValue("2022-01-01") | CoercingParseLiteralException + mkStringValue("2022-01-01T00:00:00Z")| CoercingParseLiteralException + } +} \ No newline at end of file From f3d544a85c86f859a3c3072c1106a311cb33235f Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 18 Jun 2025 12:07:54 +1000 Subject: [PATCH 23/29] Adding new Sonatype URls --- .github/workflows/master.yml | 2 ++ .github/workflows/release.yml | 2 ++ build.gradle | 9 ++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 7c96d55..f7b1cef 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -10,6 +10,8 @@ jobs: env: MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }} MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + MAVEN_CENTRAL_USER_NEW: ${{ secrets.MAVEN_CENTRAL_USER_NEW }} + MAVEN_CENTRAL_PASSWORD_NEW: ${{ secrets.MAVEN_CENTRAL_PASSWORD_NEW }} MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21b31d3..2c1b828 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,8 @@ jobs: MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }} MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + MAVEN_CENTRAL_USER_NEW: ${{ secrets.MAVEN_CENTRAL_USER_NEW }} + MAVEN_CENTRAL_PASSWORD_NEW: ${{ secrets.MAVEN_CENTRAL_PASSWORD_NEW }} RELEASE_VERSION: ${{ github.event.inputs.version }} steps: diff --git a/build.gradle b/build.gradle index d28dd44..e194900 100644 --- a/build.gradle +++ b/build.gradle @@ -118,9 +118,12 @@ publishing { nexusPublishing { repositories { sonatype { - username = System.env.MAVEN_CENTRAL_USER - password = System.env.MAVEN_CENTRAL_PASSWORD - } + username = System.env.MAVEN_CENTRAL_USER_NEW + password = System.env.MAVEN_CENTRAL_PASSWORD_NEW + // https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + // GraphQL Java does not publish snapshots, but adding this URL for completeness + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) } } } From 594a1fb5eb9932a1cece91801a031fee26411a59 Mon Sep 17 00:00:00 2001 From: Igor Zarvanskyi Date: Wed, 18 Jun 2025 11:02:51 +0200 Subject: [PATCH 24/29] refactor: migrate Coercing in SecondsSinceEpochScalar to Long Refs: #157 --- .../datetime/SecondsSinceEpochScalar.java | 24 ++++++------- .../SecondsSinceEpochScalarTest.groovy | 34 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java b/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java index 2b0f07b..624bfa0 100644 --- a/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java +++ b/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java @@ -55,18 +55,18 @@ private static Temporal convertEpochSecondsToTemporal(long epochSeconds) { } static { - Coercing coercing = new Coercing<>() { + Coercing coercing = new Coercing<>() { @Override - public String serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { + public Long serialize(Object input, GraphQLContext graphQLContext, Locale locale) throws CoercingSerializeException { try { if (input instanceof Number) { Number number = (Number) input; - return Long.toString(number.longValue()); + return number.longValue(); } if (input instanceof String) { String string = (String) input; if (string.matches("\\d+")) { - return string; + return Long.parseLong(string); } throw new CoercingSerializeException( "Invalid seconds since epoch value : '" + string + "'. Expected a string containing only digits." @@ -76,20 +76,20 @@ public String serialize(Object input, GraphQLContext graphQLContext, Locale loca TemporalAccessor temporalAccessor = (TemporalAccessor) input; if (temporalAccessor instanceof Instant) { Instant instant = (Instant) temporalAccessor; - return Long.toString(instant.getEpochSecond()); + return instant.getEpochSecond(); } else if (temporalAccessor instanceof LocalDateTime) { LocalDateTime localDateTime = (LocalDateTime) temporalAccessor; - return Long.toString(localDateTime.toEpochSecond(ZoneOffset.UTC)); + return localDateTime.toEpochSecond(ZoneOffset.UTC); } else if (temporalAccessor instanceof ZonedDateTime) { ZonedDateTime zonedDateTime = (ZonedDateTime) temporalAccessor; - return Long.toString(zonedDateTime.toEpochSecond()); + return zonedDateTime.toEpochSecond(); } else if (temporalAccessor instanceof OffsetDateTime) { OffsetDateTime offsetDateTime = (OffsetDateTime) temporalAccessor; - return Long.toString(offsetDateTime.toEpochSecond()); + return offsetDateTime.toEpochSecond(); } else { try { Instant instant = Instant.from(temporalAccessor); - return Long.toString(instant.getEpochSecond()); + return instant.getEpochSecond(); } catch (Exception e) { throw new CoercingSerializeException( "Unable to convert TemporalAccessor to seconds since epoch because of : '" + e.getMessage() + "'." @@ -158,8 +158,8 @@ public TemporalAccessor parseLiteral(Value input, CoercedVariables variables, @Override public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Locale locale) { - String s = serialize(input, graphQLContext, locale); - return StringValue.newStringValue(s).build(); + Long value = serialize(input, graphQLContext, locale); + return IntValue.newIntValue(java.math.BigInteger.valueOf(value)).build(); } }; @@ -168,7 +168,7 @@ public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Loca .name("SecondsSinceEpoch") .description("Scalar that represents a point in time as seconds since the Unix epoch (Unix timestamp). " + "Accepts integers or strings containing integers as input values. " + - "Returns a string containing the number of seconds since epoch (January 1, 1970, 00:00:00 UTC).") + "Returns a Long representing the number of seconds since epoch (January 1, 1970, 00:00:00 UTC).") .coercing(coercing) .build(); } diff --git a/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy b/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy index 1210a18..a932273 100644 --- a/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy +++ b/src/test/groovy/graphql/scalars/datetime/SecondsSinceEpochScalarTest.groovy @@ -51,16 +51,16 @@ class SecondsSinceEpochScalarTest extends AbstractScalarTest { result.isEqualTo(expectedValue) where: input | expectedValue - "0" | mkStringValue("0") - "1" | mkStringValue("1") - "1609459200" | mkStringValue("1609459200") - "1640995200" | mkStringValue("1640995200") - 0 | mkStringValue("0") - 1 | mkStringValue("1") - 1609459200 | mkStringValue("1609459200") - 1640995200 | mkStringValue("1640995200") - Instant.ofEpochSecond(1609459200) | mkStringValue("1609459200") - ZonedDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | mkStringValue("1609459200") + "0" | mkIntValue(0) + "1" | mkIntValue(1) + "1609459200" | mkIntValue(1609459200) + "1640995200" | mkIntValue(1640995200) + 0 | mkIntValue(0) + 1 | mkIntValue(1) + 1609459200 | mkIntValue(1609459200) + 1640995200 | mkIntValue(1640995200) + Instant.ofEpochSecond(1609459200) | mkIntValue(1609459200) + ZonedDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | mkIntValue(1609459200) } @Unroll @@ -100,12 +100,12 @@ class SecondsSinceEpochScalarTest extends AbstractScalarTest { result == expectedValue where: input | expectedValue - Instant.ofEpochSecond(0) | "0" - Instant.ofEpochSecond(1) | "1" - Instant.ofEpochSecond(1609459200) | "1609459200" - LocalDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | "1609459200" - ZonedDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | "1609459200" - OffsetDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | "1609459200" + Instant.ofEpochSecond(0) | 0L + Instant.ofEpochSecond(1) | 1L + Instant.ofEpochSecond(1609459200) | 1609459200L + LocalDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | 1609459200L + ZonedDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | 1609459200L + OffsetDateTime.ofInstant(Instant.ofEpochSecond(1609459200), ZoneOffset.UTC) | 1609459200L } def "secondsSinceEpoch serialisation bad inputs"() { @@ -132,4 +132,4 @@ class SecondsSinceEpochScalarTest extends AbstractScalarTest { mkStringValue("2022-01-01") | CoercingParseLiteralException mkStringValue("2022-01-01T00:00:00Z")| CoercingParseLiteralException } -} \ No newline at end of file +} From c323191b082e3d48f1d3f22c02209b361d211394 Mon Sep 17 00:00:00 2001 From: Igor Zarvanskyi Date: Wed, 18 Jun 2025 11:08:22 +0200 Subject: [PATCH 25/29] refactor: get rid of regexp check Regexp decreases performance, so there is more sense to rely on parse exceptions in that case. Refs: #157 --- .../scalars/datetime/SecondsSinceEpochScalar.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java b/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java index 624bfa0..cc46d2b 100644 --- a/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java +++ b/src/main/java/graphql/scalars/datetime/SecondsSinceEpochScalar.java @@ -64,13 +64,14 @@ public Long serialize(Object input, GraphQLContext graphQLContext, Locale locale return number.longValue(); } if (input instanceof String) { - String string = (String) input; - if (string.matches("\\d+")) { - return Long.parseLong(string); + try { + return Long.parseLong((String) input); + } catch (NumberFormatException e) { + throw new CoercingSerializeException( + "Invalid seconds since epoch value : '" + input + "'. Expected a string containing only digits.", + e + ); } - throw new CoercingSerializeException( - "Invalid seconds since epoch value : '" + string + "'. Expected a string containing only digits." - ); } if (input instanceof TemporalAccessor) { TemporalAccessor temporalAccessor = (TemporalAccessor) input; From 29eb91472233eea0b91d44d0cc2123cb269ee3dd Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 22 Jun 2025 09:51:34 +1000 Subject: [PATCH 26/29] Update GitHub action to reduce CI flakes --- .github/workflows/master.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index f7b1cef..52024ea 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 7206a48..54c8abb 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c1b828..dd2ca38 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: From 4470f6089e1b697108808aee52914601e7672a75 Mon Sep 17 00:00:00 2001 From: Brad Baker Date: Wed, 25 Jun 2025 12:56:27 +1000 Subject: [PATCH 27/29] Update ExtendedScalars.java --- src/main/java/graphql/scalars/ExtendedScalars.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index 07124fc..e038c30 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -146,7 +146,7 @@ public class ExtendedScalars { * `java.time.ZonedDateTime` objects at runtime (with UTC timezone). *

* Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} method accepts various - * {@link java.time.temporal.TemporalAccessor} types and returns a string containing the number of seconds since epoch + * {@link java.time.temporal.TemporalAccessor} types and returns the number of seconds since epoch * (January 1, 1970, 00:00:00 UTC). *

* Using seconds since epoch is preferable to formatted date time strings in several scenarios: From d8a609c9644af29bb0c6d95ac65fc23338a53e43 Mon Sep 17 00:00:00 2001 From: bbaker Date: Mon, 7 Jul 2025 09:43:48 +1000 Subject: [PATCH 28/29] Fixed docos for #105 --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6bc588d..0e21589 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ For example, you would build it like this: ```java AliasedScalar socialMediaLink = ExtendedScalars.newAliasedScalar("SocialMediaLink") .aliasedScalar(Scalars.GraphQLString) - .build() + .build(); ``` And use it in a SDL schema like this : @@ -313,27 +313,27 @@ query { Description -

scalar GraphQLLong
+
scalar Long
A scalar which represents java.lang.Long -
scalar GraphQLShort
+
scalar Short
A scalar which represents java.lang.Short -
scalar GraphQLByte
+
scalar Byte
A scalar which represents java.lang.Byte -
scalar GraphQLBigDecimal
+
scalar BigDecimal
A scalar which represents java.math.BigDecimal -
scalar GraphQLBigInteger
+
scalar BigInteger
A scalar which represents java.math.BigInteger -
scalar GraphQLChar
+
scalar Char
A scalar which represents java.lang.Character From 2c86983566f474a80284ec215832bb0ca91b6cb6 Mon Sep 17 00:00:00 2001 From: bbaker Date: Mon, 7 Jul 2025 09:47:20 +1000 Subject: [PATCH 29/29] Updated doco for upcoming 24.0 --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0e21589..4c13e15 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Extended Scalars for graphql-java [![Build Status](https://github.com/graphql-java/graphql-java-extended-scalars/actions/workflows/master.yml/badge.svg)](https://github.com/graphql-java/graphql-java-extended-scalars/actions/workflows/master.yml) -[![Latest Release](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java-extended-scalars?versionPrefix=22.)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-scalars/) +[![Latest Release](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java-extended-scalars?versionPrefix=24.)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-scalars/) [![Latest Snapshot](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java-extended-scalars?label=maven-central%20snapshot)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-scalars/) [![MIT licensed](https://img.shields.io/badge/license-MIT-green)](https://github.com/graphql-java/graphql-java-extended-scalars/blob/master/LICENSE.md) @@ -23,7 +23,7 @@ You would use custom scalars when you want to describe more meaningful behavior To use this library put the following into your gradle config ```java -implementation 'com.graphql-java:graphql-java-extended-scalars:22.0' +implementation 'com.graphql-java:graphql-java-extended-scalars:24.0' ``` or the following into your Maven config @@ -32,12 +32,14 @@ or the following into your Maven config com.graphql-java graphql-java-extended-scalars - 22.0 + 24.0 ``` > Note: > +> use 24.0 or above for graphql-java 24.x and above +> > use 22.0 or above for graphql-java 22.x and above > > use 21.0 for graphql-java 21.x