diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/input/test/QueryTest.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/input/test/QueryTest.kt index dcc4d9e2c..8281b2648 100644 --- a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/input/test/QueryTest.kt +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/input/test/QueryTest.kt @@ -18,12 +18,34 @@ package com.netflix.graphql.dgs.codegen.cases.input.test +import com.netflix.graphql.dgs.client.codegen.InputValueSerializer +import com.netflix.graphql.dgs.codegen.InputValueSerializerProvider import com.netflix.graphql.dgs.codegen.cases.input.expected.DgsClient import com.netflix.graphql.dgs.codegen.cases.input.expected.types.MovieFilter +import graphql.language.StringValue +import graphql.language.Value +import graphql.schema.Coercing import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test class QueryTest { + private val movieCoercing = object : Coercing { + override fun serialize(filter: Any): String { + return (filter as? MovieFilter)?.genre ?: "" + } + + override fun parseValue(input: Any): MovieFilter { + return MovieFilter(input.toString()) + } + + override fun parseLiteral(input: Any): MovieFilter { + return MovieFilter(input.toString()) + } + + override fun valueToLiteral(input: Any): Value<*> { + return StringValue.of(serialize(input)) + } + } @Test fun testQueryWithNoFilter() { @@ -109,4 +131,53 @@ class QueryTest { query ) } + + @Test + fun testQueryWithFilterAndCustomCoercing() { + try { + InputValueSerializerProvider.serializer = InputValueSerializer( + mapOf(MovieFilter::class.java to movieCoercing) + ) + val query = DgsClient.buildQuery { + movies(filter = MovieFilter(genre = "horror")) + } + + Assertions.assertEquals( + """{ + | __typename + | movies(filter: "horror") + |} + | + """.trimMargin(), + query + ) + } finally { + InputValueSerializerProvider.reset() + } + } + + @Test + fun testResetInputValueSerializerProvider() { + try { + InputValueSerializerProvider.serializer = InputValueSerializer( + mapOf(MovieFilter::class.java to movieCoercing) + ) + InputValueSerializerProvider.reset() + + val query = DgsClient.buildQuery { + movies(filter = MovieFilter(genre = "horror")) + } + Assertions.assertEquals( + """{ + | __typename + | movies(filter: {genre : "horror"}) + |} + | + """.trimMargin(), + query + ) + } finally { + InputValueSerializerProvider.reset() + } + } } diff --git a/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2Core.kt b/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2Core.kt index 10131e10f..1cc5359cf 100644 --- a/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2Core.kt +++ b/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2Core.kt @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen import com.netflix.graphql.dgs.client.codegen.InputValue import com.netflix.graphql.dgs.client.codegen.InputValueSerializer +import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface import graphql.language.Argument import graphql.language.AstPrinter import graphql.language.Document @@ -50,13 +51,26 @@ object DefaultTracker { } } +object InputValueSerializerProvider { + private val default: ThreadLocal = ThreadLocal.withInitial { InputValueSerializer() } + + var serializer + get(): InputValueSerializerInterface = default.get() + set(value) = default.set(value) + + fun reset() { + serializer = InputValueSerializer() + } +} + @QueryProjectionMarker -abstract class GraphQLProjection(defaultFields: Set = setOf("__typename")) { +abstract class GraphQLProjection( + defaultFields: Set = setOf("__typename"), + private val inputValueSerializer: InputValueSerializerInterface = InputValueSerializerProvider.serializer +) { companion object { - private val inputSerializer = InputValueSerializer() - @JvmStatic protected fun default0(arg: String): T? { DefaultTracker.add(this::class.qualifiedName!!, arg) @@ -105,7 +119,7 @@ abstract class GraphQLProjection(defaultFields: Set = setOf("__typename" .map { (arg, value) -> Argument.newArgument() .name(arg) - .value(inputSerializer.toValue(value)) + .value(inputValueSerializer.toValue(value)) .build() } } diff --git a/graphql-dgs-codegen-shared-core/src/test/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializerTest.kt b/graphql-dgs-codegen-shared-core/src/test/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializerTest.kt index 59897eab4..c3f59baca 100644 --- a/graphql-dgs-codegen-shared-core/src/test/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializerTest.kt +++ b/graphql-dgs-codegen-shared-core/src/test/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializerTest.kt @@ -16,10 +16,12 @@ package com.netflix.graphql.dgs.client.codegen +import graphql.scalars.id.UUIDScalar import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import java.time.LocalDate import java.time.LocalDateTime +import java.util.UUID class InputValueSerializerTest { @@ -151,6 +153,15 @@ class InputValueSerializerTest { assertThat(serialize).isEqualTo("ACTION") } + @Test + fun `UUID value`() { + val expected = UUID.randomUUID() + val actual = InputValueSerializer( + mapOf(UUID::class.java to UUIDScalar.INSTANCE.coercing) + ).serialize(expected) + assertThat(actual).isEqualTo(""""$expected"""") + } + @Test fun `overridden properties are serialized`() { abstract class Base {