Skip to content

This removes all the deprecated Coercing methods and replaces them with the desired ones #159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,22 @@ scalar LocalTime
</pre></td>
<td>24-hour clock time string in the format <code>hh:mm:ss.sss</code> or <code>hh:mm:ss</code> if partial seconds is zero and produces <code>java.time.LocalTime</code> objects at runtime.</td>
</tr>
<tr>
<td><pre lang="graphql">
scalar SecondsSinceEpoch
</pre></td>
<td>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 <code>java.time.ZonedDateTime</code> objects at runtime (with UTC timezone).<br><br>
Using seconds since epoch is preferable to formatted date time strings in several scenarios:
<ul>
<li>When you need a universal representation of a point in time that is timezone-agnostic</li>
<li>For easier date/time arithmetic and comparison operations</li>
<li>When storage space or bandwidth efficiency is important (more compact representation)</li>
<li>To avoid complexities with different date formats and timezone conversions</li>
<li>For better interoperability with systems that natively work with Unix timestamps</li>
<li>When working with time-series data or logging systems where timestamps are commonly used</li>
</ul>
However, human readability is sacrificed compared to formatted date strings, so consider your use case requirements when choosing between <code>DateTime</code> and <code>SecondsSinceEpoch</code>.</td>
</tr>
</table>

An example declaration in SDL might be:
Expand All @@ -181,20 +197,22 @@ type Customer {
birthDay: Date
workStartTime: Time
bornAt: DateTime
createdAtTimestamp: SecondsSinceEpoch
}

type Query {
customers(bornAfter: DateTime): [Customers]
customers(bornAfter: DateTime, createdAfter: SecondsSinceEpoch): [Customers]
}
```

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
}
}
```
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/graphql/scalars/ExtendedScalars.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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).
* <p>
* It accepts integers or strings containing integers as input values and produces
* `java.time.ZonedDateTime` objects at runtime (with UTC timezone).
* <p>
* Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} method accepts various
* {@link java.time.temporal.TemporalAccessor} types and returns the number of seconds since epoch
* (January 1, 1970, 00:00:00 UTC).
* <p>
* Using seconds since epoch is preferable to formatted date time strings in several scenarios:
* <ul>
* <li>When you need a universal representation of a point in time that is timezone-agnostic</li>
* <li>For easier date/time arithmetic and comparison operations</li>
* <li>When storage space or bandwidth efficiency is important (more compact representation)</li>
* <li>To avoid complexities with different date formats and timezone conversions</li>
* <li>For better interoperability with systems that natively work with Unix timestamps</li>
* <li>When working with time-series data or logging systems where timestamps are commonly used</li>
* </ul>
* <p>
* 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.
* <p>
Expand Down
31 changes: 14 additions & 17 deletions src/main/java/graphql/scalars/alias/AliasedScalar.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
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;
import graphql.schema.CoercingParseValueException;
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)}
*/
@Internal
public final class AliasedScalar {

private AliasedScalar() {}
private AliasedScalar() {
}

/**
* A builder for {@link graphql.scalars.alias.AliasedScalar}
Expand Down Expand Up @@ -75,31 +78,25 @@ public GraphQLScalarType build() {

private static GraphQLScalarType aliasedScalarImpl(String name, String description, GraphQLScalarType aliasedScalar) {
Assert.assertNotNull(aliasedScalar);
Coercing<Object, Object> coercing = new Coercing<Object, Object>() {
@Override
public Object serialize(Object input) throws CoercingSerializeException {
return aliasedScalar.getCoercing().serialize(input);
}

Coercing<Object, Object> 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<String, Object> 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()
Expand Down
24 changes: 16 additions & 8 deletions src/main/java/graphql/scalars/color/hex/HexColorCodeScalar.java
Original file line number Diff line number Diff line change
@@ -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 <a href="https://en.wikipedia.org/wiki/Web_colors">Web colors</a> for more details.
Expand All @@ -21,28 +29,28 @@ public class HexColorCodeScalar {


static {
Coercing<Color, String> coercing = new Coercing<Color, String>() {
Coercing<Color, String> 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());
}
}

@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) + "'.");
}
Expand All @@ -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();
}

Expand Down
21 changes: 14 additions & 7 deletions src/main/java/graphql/scalars/country/code/CountryCodeScalar.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -18,21 +25,21 @@ public class CountryCodeScalar {
public static final GraphQLScalarType INSTANCE;

static {
Coercing<CountryCode, String> coercing = new Coercing<CountryCode, String>() {
Coercing<CountryCode, String> 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) + "'.");
}
Expand All @@ -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();
}

Expand Down
21 changes: 14 additions & 7 deletions src/main/java/graphql/scalars/currency/CurrencyScalar.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -19,21 +26,21 @@ public class CurrencyScalar {
public static final GraphQLScalarType INSTANCE;

static {
Coercing<Currency, String> coercing = new Coercing<Currency, String>() {
Coercing<Currency, String> 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) + "'.");
}
Expand All @@ -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();
}

Expand Down
Loading