Skip to content

Commit

Permalink
Add offsetTime Scalar to Typefunction (#84)
Browse files Browse the repository at this point in the history
Add offsetTime Scalar to Typefunction
  • Loading branch information
pavan-traceable authored Dec 1, 2021
1 parent e7d83ae commit e91dff6
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.hypertrace.core.graphql.common.schema.typefunctions.AttributeScopeDynamicEnum;
import org.hypertrace.core.graphql.common.schema.typefunctions.DateTimeScalar;
import org.hypertrace.core.graphql.common.schema.typefunctions.DurationScalar;
import org.hypertrace.core.graphql.common.schema.typefunctions.OffsetTimeScalar;
import org.hypertrace.core.graphql.common.schema.typefunctions.UnknownScalar;
import org.hypertrace.core.graphql.spi.schema.GraphQlSchemaFragment;

Expand All @@ -16,17 +17,20 @@ class CommonSchemaFragment implements GraphQlSchemaFragment {
private final UnknownScalar unknownScalar;
private final AttributeScopeDynamicEnum attributeScopeDynamicEnum;
private final DurationScalar durationScalar;
private final OffsetTimeScalar offsetTimeScalar;

@Inject
CommonSchemaFragment(
DateTimeScalar dateTimeScalar,
UnknownScalar unknownScalar,
AttributeScopeDynamicEnum attributeScopeDynamicEnum,
DurationScalar durationScalar) {
DurationScalar durationScalar,
OffsetTimeScalar offsetTimeScalar) {
this.dateTimeScalar = dateTimeScalar;
this.unknownScalar = unknownScalar;
this.attributeScopeDynamicEnum = attributeScopeDynamicEnum;
this.durationScalar = durationScalar;
this.offsetTimeScalar = offsetTimeScalar;
}

@Override
Expand All @@ -41,6 +45,7 @@ public List<TypeFunction> typeFunctions() {
this.unknownScalar,
this.dateTimeScalar,
this.attributeScopeDynamicEnum,
this.durationScalar);
this.durationScalar,
this.offsetTimeScalar);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ private <E extends GraphqlErrorException> Instant toInstant(

@Override
public boolean canBuildType(Class<?> aClass, AnnotatedType annotatedType) {
return TemporalAccessor.class.isAssignableFrom(aClass);
return Instant.class.isAssignableFrom(aClass);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.hypertrace.core.graphql.common.schema.typefunctions;

import graphql.GraphqlErrorException;
import graphql.annotations.processor.ProcessingElementsContainer;
import graphql.annotations.processor.typeFunctions.TypeFunction;
import graphql.language.StringValue;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLScalarType;
import java.lang.reflect.AnnotatedType;
import java.time.DateTimeException;
import java.time.OffsetTime;
import java.time.temporal.TemporalAccessor;
import java.util.function.Function;

public class OffsetTimeScalar implements TypeFunction {

private static final GraphQLScalarType OFFSET_TIME_SCALAR =
GraphQLScalarType.newScalar()
.name("OffsetTime")
.description("An ISO-8601 formatted OffsetTime Scalar")
.coercing(
new Coercing<OffsetTime, String>() {
@Override
public String serialize(Object fetcherResult) throws CoercingSerializeException {
return toOffsetTime(fetcherResult, CoercingSerializeException::new).toString();
}

@Override
public OffsetTime parseValue(Object input) throws CoercingParseValueException {
return toOffsetTime(input, CoercingParseValueException::new);
}

@Override
public OffsetTime parseLiteral(Object input) throws CoercingParseLiteralException {
return toOffsetTime(input, CoercingParseLiteralException::new);
}

private <E extends GraphqlErrorException> OffsetTime toOffsetTime(
Object offsetInput, Function<Exception, E> errorWrapper) throws E {
try {
if (offsetInput instanceof TemporalAccessor) {
return OffsetTime.from((TemporalAccessor) offsetInput);
}
if (offsetInput instanceof CharSequence) {
return OffsetTime.parse((CharSequence) offsetInput);
}
if (offsetInput instanceof StringValue) {
return OffsetTime.parse(((StringValue) offsetInput).getValue());
}
} catch (DateTimeException exception) {
throw errorWrapper.apply(exception);
}
throw errorWrapper.apply(
new DateTimeException(
String.format(
"Cannot convert provided format '%s' to OffsetTime",
offsetInput.getClass().getCanonicalName())));
}
})
.build();

@Override
public boolean canBuildType(Class<?> aClass, AnnotatedType annotatedType) {
return OffsetTime.class.isAssignableFrom(aClass);
}

@Override
public GraphQLScalarType buildType(
boolean input,
Class<?> aClass,
AnnotatedType annotatedType,
ProcessingElementsContainer container) {
return OFFSET_TIME_SCALAR;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@
import graphql.schema.GraphQLScalarType;
import java.lang.reflect.AnnotatedType;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDateTime;
import org.hypertrace.core.graphql.common.schema.typefunctions.DateTimeScalar;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -44,11 +40,6 @@ void beforeEach() {
@Test
void canDetermineIfConvertible() {
assertTrue(this.dateTimeFunction.canBuildType(Instant.class, this.mockAnnotatedType));
assertTrue(this.dateTimeFunction.canBuildType(OffsetDateTime.class, this.mockAnnotatedType));
assertTrue(this.dateTimeFunction.canBuildType(LocalDateTime.class, this.mockAnnotatedType));
assertTrue(
this.dateTimeFunction.canBuildType(ChronoLocalDateTime.class, this.mockAnnotatedType));
assertTrue(this.dateTimeFunction.canBuildType(ZonedDateTime.class, this.mockAnnotatedType));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.hypertrace.core.graphql.common.schema.scalars;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import graphql.annotations.processor.ProcessingElementsContainer;
import graphql.language.StringValue;
import graphql.schema.GraphQLScalarType;
import java.lang.reflect.AnnotatedType;
import java.time.OffsetTime;
import java.time.ZoneOffset;
import org.hypertrace.core.graphql.common.schema.typefunctions.OffsetTimeScalar;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class OffsetTimeScalarTest {

private static final String TEST_SCALAR_TIME_STRING = "21:30:12.748+12:30";
private static final OffsetTime TEST_OFFSET_TIME = OffsetTime.parse(TEST_SCALAR_TIME_STRING);
private OffsetTimeScalar offsetTimeFunction;
private GraphQLScalarType offsetTimeType;
@Mock AnnotatedType mockAnnotatedType;
// Can't actually mock class, but it's not used so to convey intent using the Mock class.
private final Class<?> mockAnnotatedClass = Mock.class;
@Mock ProcessingElementsContainer mockProcessingElementsContainer;

@BeforeEach
void beforeEach() {
this.offsetTimeFunction = new OffsetTimeScalar();
// Can't actually mock class, but it's not used so to convey intent using
this.offsetTimeType =
this.offsetTimeFunction.buildType(
false, mockAnnotatedClass, mockAnnotatedType, mockProcessingElementsContainer);
}

@Test
void canDetermineIfConvertible() {
assertTrue(this.offsetTimeFunction.canBuildType(OffsetTime.class, this.mockAnnotatedType));
}

@Test
void canConvertFromLiteral() {
assertEquals(
TEST_OFFSET_TIME, offsetTimeType.getCoercing().parseLiteral(TEST_SCALAR_TIME_STRING));
}

@Test
void canSerialize() {
assertEquals(TEST_SCALAR_TIME_STRING, offsetTimeType.getCoercing().serialize(TEST_OFFSET_TIME));
assertEquals(
TEST_SCALAR_TIME_STRING, offsetTimeType.getCoercing().serialize(TEST_SCALAR_TIME_STRING));

assertEquals(
TEST_SCALAR_TIME_STRING,
offsetTimeType
.getCoercing()
.serialize(TEST_OFFSET_TIME.withOffsetSameLocal(ZoneOffset.ofHoursMinutes(12, 30))));
}

@Test
void canConvertFromValue() {
assertEquals(
TEST_OFFSET_TIME,
offsetTimeType
.getCoercing()
.parseValue(StringValue.newStringValue().value(TEST_SCALAR_TIME_STRING).build()));
}
}

0 comments on commit e91dff6

Please sign in to comment.