From 77dd5bb3ce397e97715029fd4b2ee66346ba2e11 Mon Sep 17 00:00:00 2001 From: Dariusz Kuc Date: Wed, 25 Aug 2021 17:32:19 -0500 Subject: [PATCH 1/2] [client] support optional input for kotlinx serialization It appears that using `@Required` annotation works on serialization and deserialization (https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/basic-serialization.md#required-properties) giving us the correct behavior for handling optional input. This PR also cleans up corresponding serialization tests to ensure we have consistent serialization between Jackson and Kotlinx Serialization. Resolves: https://github.com/ExpediaGroup/graphql-kotlin/issues/1151 --- .../GraphQLClientJacksonSerializerTest.kt | 161 +++++++++--------- .../{InputListQuery.kt => EmptyInputQuery.kt} | 17 +- .../graphql/client/jackson/data/InputQuery.kt | 13 +- .../client/jackson/data/OptionalInputQuery.kt | 6 +- .../GraphQLClientKotlinxSerializer.kt | 3 +- .../GraphQLClientKotlinXSerializerTest.kt | 139 +++++++++++---- .../serialization/data/EmptyInputQuery.kt | 46 +++++ .../client/serialization/data/EnumQuery.kt | 3 + .../client/serialization/data/FirstQuery.kt | 3 + .../client/serialization/data/InputQuery.kt | 13 +- .../serialization/data/OptionalInputQuery.kt | 49 ++++++ .../client/serialization/data/OtherQuery.kt | 3 + .../serialization/data/PolymorphicQuery.kt | 3 + .../client/serialization/data/ScalarQuery.kt | 3 + .../generator/GraphQLClientGenerator.kt | 27 ++- .../generator/GraphQLClientGeneratorConfig.kt | 2 +- .../GraphQLClientGeneratorContext.kt | 2 - .../generateGraphQLInputObjectTypeSpec.kt | 39 +++-- .../types/generateVariableTypeSpec.kt | 17 +- .../custom_scalars/CustomScalarQuery.kt | 3 + .../deprecated_opt_in/DeprecatedOptInQuery.kt | 3 + .../src/test/data/kotlinx/enums/EnumQuery.kt | 3 + .../InterfaceWithInlineFragmentsQuery.kt | 3 + .../kotlinx/multiple_queries/FirstQuery.kt | 3 + .../kotlinx/multiple_queries/SecondQuery.kt | 3 + .../data/kotlinx/object/ComplexObjectQuery.kt | 3 + .../union/UnionQueryWithInlineFragments.kt | 3 + .../kotlinx/variables/KotlinXInputQuery.kt | 3 + .../graphql-kotlin-gradle-plugin/README.md | 5 +- .../plugin/gradle/GraphQLPluginExtension.kt | 2 +- .../parameters/GenerateClientParameters.kt | 5 +- plugins/graphql-kotlin-maven-plugin/README.md | 7 +- .../maven/GenerateClientAbstractMojo.kt | 1 - website/docs/client/client-features.mdx | 4 +- website/docs/plugins/gradle-plugin-tasks.mdx | 6 +- website/docs/plugins/maven-plugin-goals.md | 4 +- 36 files changed, 411 insertions(+), 199 deletions(-) rename clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/{InputListQuery.kt => EmptyInputQuery.kt} (69%) create mode 100644 clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EmptyInputQuery.kt create mode 100644 clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OptionalInputQuery.kt diff --git a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/GraphQLClientJacksonSerializerTest.kt b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/GraphQLClientJacksonSerializerTest.kt index 9c1806c04a..a312ac1ea9 100644 --- a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/GraphQLClientJacksonSerializerTest.kt +++ b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/GraphQLClientJacksonSerializerTest.kt @@ -16,9 +16,9 @@ package com.expediagroup.graphql.client.jackson +import com.expediagroup.graphql.client.jackson.data.EmptyInputQuery import com.expediagroup.graphql.client.jackson.data.EnumQuery import com.expediagroup.graphql.client.jackson.data.FirstQuery -import com.expediagroup.graphql.client.jackson.data.InputListQuery import com.expediagroup.graphql.client.jackson.data.InputQuery import com.expediagroup.graphql.client.jackson.data.OptionalInputQuery import com.expediagroup.graphql.client.jackson.data.OtherQuery @@ -30,6 +30,7 @@ import com.expediagroup.graphql.client.jackson.types.JacksonGraphQLError import com.expediagroup.graphql.client.jackson.types.JacksonGraphQLResponse import com.expediagroup.graphql.client.jackson.types.JacksonGraphQLSourceLocation import com.expediagroup.graphql.client.jackson.types.OptionalInput +import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import org.junit.jupiter.api.Test import java.util.UUID @@ -38,6 +39,7 @@ import kotlin.test.assertEquals class GraphQLClientJacksonSerializerTest { private val testMapper = jacksonObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) private val serializer = GraphQLClientJacksonSerializer(testMapper) @Test @@ -45,32 +47,36 @@ class GraphQLClientJacksonSerializerTest { val testQuery = FirstQuery(FirstQuery.Variables(input = 1.0f)) val expected = """{ - | "query": "FIRST_QUERY", - | "operationName": "FirstQuery", - | "variables": { "input": 1.0 } + | "variables" : { + | "input" : 1.0 + | }, + | "query" : "FIRST_QUERY", + | "operationName" : "FirstQuery" |} """.trimMargin() - val result = serializer.serialize(testQuery) - assertEquals(testMapper.readTree(expected), testMapper.readTree(result)) + val serialized = serializer.serialize(testQuery) + assertEquals(expected, serialized) } @Test fun `verify we can serialize batch GraphQLClientRequest`() { val queries = listOf(FirstQuery(FirstQuery.Variables(input = 1.0f)), OtherQuery()) val expected = - """[{ - | "query": "FIRST_QUERY", - | "operationName": "FirstQuery", - | "variables": { "input": 1.0 } - |},{ - | "query": "OTHER_QUERY", - | "operationName": "OtherQuery" - |}] + """[ { + | "variables" : { + | "input" : 1.0 + | }, + | "query" : "FIRST_QUERY", + | "operationName" : "FirstQuery" + |}, { + | "query" : "OTHER_QUERY", + | "operationName" : "OtherQuery" + |} ] """.trimMargin() - val result = serializer.serialize(queries) - assertEquals(testMapper.readTree(expected), testMapper.readTree(result)) + val serialized = serializer.serialize(queries) + assertEquals(expected, serialized) } @Test @@ -173,16 +179,19 @@ class GraphQLClientJacksonSerializerTest { fun `verify we can serialize custom scalars`() { val randomUUID = UUID.randomUUID() val scalarQuery = ScalarQuery(variables = ScalarQuery.Variables(alias = "1234", custom = com.expediagroup.graphql.client.jackson.data.scalars.UUID(randomUUID))) - val rawQuery = + val expected = """{ - | "query": "SCALAR_QUERY", - | "operationName": "ScalarQuery", - | "variables": { "alias": "1234", "custom": "$randomUUID" } + | "variables" : { + | "alias" : "1234", + | "custom" : "$randomUUID" + | }, + | "query" : "SCALAR_QUERY", + | "operationName" : "ScalarQuery" |} """.trimMargin() val serialized = serializer.serialize(scalarQuery) - assertEquals(testMapper.readTree(rawQuery), testMapper.readTree(serialized)) + assertEquals(expected, serialized) } @Test @@ -217,16 +226,18 @@ class GraphQLClientJacksonSerializerTest { @Test fun `verify we can serialize enums with custom names`() { val query = EnumQuery(variables = EnumQuery.Variables(enum = TestEnum.THREE)) - val rawQuery = + val expected = """{ - | "query": "ENUM_QUERY", - | "operationName": "EnumQuery", - | "variables": { "enum": "three" } + | "variables" : { + | "enum" : "three" + | }, + | "query" : "ENUM_QUERY", + | "operationName" : "EnumQuery" |} """.trimMargin() val serialized = serializer.serialize(query) - assertEquals(testMapper.readTree(rawQuery), testMapper.readTree(serialized)) + assertEquals(expected, serialized) } @Test @@ -242,83 +253,69 @@ class GraphQLClientJacksonSerializerTest { @Test fun `verify we can serialize optional inputs`() { - val query = InputQuery( - variables = InputQuery.Variables( + val query = OptionalInputQuery( + variables = OptionalInputQuery.Variables( requiredInput = 123, optionalIntInput = OptionalInput.Defined(123), optionalStringInput = OptionalInput.Defined(null) + // optionalBooleanInput = OptionalInput.Undefined // use default ) ) - val rawQuery = + val expected = """{ - | "query": "INPUT_QUERY", - | "operationName": "InputQuery", - | "variables": { - | "requiredInput": 123, - | "optionalIntInput": 123, - | "optionalStringInput": null - | } + | "variables" : { + | "requiredInput" : 123, + | "optionalIntInput" : 123, + | "optionalStringInput" : null + | }, + | "query" : "OPTIONAL_INPUT_QUERY", + | "operationName" : "OptionalInputQuery" |} """.trimMargin() val serialized = serializer.serialize(query) - assertEquals(testMapper.readTree(rawQuery), testMapper.readTree(serialized)) + assertEquals(expected, serialized) } @Test - fun `verify list serialization`() { - val query = InputListQuery( - variables = InputListQuery.Variables( - nonNullableIds = listOf("ABC") + fun `verify serialization of null values and empty collections`() { + val query = InputQuery( + variables = InputQuery.Variables( + requiredInput = 123, + // nullableId = null, // use default + nullableListNullableElements = listOf(null), + nullableListNonNullableElements = null, // same as default + nullableElementList = listOf("foo", null), + nonNullableElementList = listOf() ) ) - val rawQuery = - """{ - | "query": "INPUT_LIST_QUERY", - | "operationName": "InputListQuery", - | "variables": { - | "nonNullableIds": ["ABC"] - | } - |} - """.trimMargin() + + val expected = """{ + | "variables" : { + | "requiredInput" : 123, + | "nullableListNullableElements" : [ null ], + | "nullableElementList" : [ "foo", null ], + | "nonNullableElementList" : [ ] + | }, + | "query" : "INPUT_QUERY", + | "operationName" : "InputQuery" + |}""".trimMargin() val serialized = serializer.serialize(query) - assertEquals(testMapper.readTree(rawQuery), testMapper.readTree(serialized)) + assertEquals(expected, serialized) } @Test - fun `verify nullable list serialization`() { - val query = InputListQuery( - variables = InputListQuery.Variables( - nullableIds = listOf("XYZ", null), - nullableIdList = null, - nonNullableIds = listOf() - ) + fun `verify serialization of empty variables`() { + val query = EmptyInputQuery( + variables = EmptyInputQuery.Variables() ) - val rawQuery = - """{ - | "query": "INPUT_LIST_QUERY", - | "operationName": "InputListQuery", - | "variables": { - | "nullableIds": ["XYZ", null], - | "nonNullableIds": [] - | } - |} - """.trimMargin() - val serialized = serializer.serialize(query) - assertEquals(testMapper.readTree(rawQuery), testMapper.readTree(serialized)) - } - @Test - fun `verify unspecified optional input serialization results in empty variables`() { - val query = OptionalInputQuery(variables = OptionalInputQuery.Variables()) - val rawQuery = - """{ - | "query": "OPTIONAL_INPUT_QUERY", - | "operationName": "OptionalInputQuery", - | "variables": {} - |} - """.trimMargin() + val expected = """{ + | "variables" : { }, + | "query" : "EMPTY_INPUT_QUERY", + | "operationName" : "EmptyInputQuery" + |}""".trimMargin() val serialized = serializer.serialize(query) - assertEquals(testMapper.readTree(rawQuery), testMapper.readTree(serialized)) + assertEquals(expected, serialized) } } diff --git a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputListQuery.kt b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/EmptyInputQuery.kt similarity index 69% rename from clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputListQuery.kt rename to clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/EmptyInputQuery.kt index 4d50af6800..89a3d7e55a 100644 --- a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputListQuery.kt +++ b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/EmptyInputQuery.kt @@ -17,26 +17,23 @@ package com.expediagroup.graphql.client.jackson.data import com.expediagroup.graphql.client.types.GraphQLClientRequest -import kotlin.String -import kotlin.collections.List import kotlin.reflect.KClass -class InputListQuery( +class EmptyInputQuery( override val variables: Variables -) : GraphQLClientRequest { - override val query: String = "INPUT_LIST_QUERY" +) : GraphQLClientRequest { - override val operationName: String = "InputListQuery" + override val query: String = "EMPTY_INPUT_QUERY" + + override val operationName: String = "EmptyInputQuery" override fun responseType(): KClass = Result::class data class Variables( - val nullableIds: List? = null, - val nullableIdList: List? = null, - val nonNullableIds: List + val nullable: Int? = null ) data class Result( - val inputListQuery: String? + val stringResult: String ) } diff --git a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputQuery.kt b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputQuery.kt index 060cf5891f..81036a1dfa 100644 --- a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputQuery.kt +++ b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/InputQuery.kt @@ -16,8 +16,9 @@ package com.expediagroup.graphql.client.jackson.data -import com.expediagroup.graphql.client.jackson.types.OptionalInput import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlin.String +import kotlin.collections.List import kotlin.reflect.KClass class InputQuery( @@ -31,12 +32,14 @@ class InputQuery( data class Variables( val requiredInput: Int, - val optionalIntInput: OptionalInput = OptionalInput.Undefined, - val optionalStringInput: OptionalInput = OptionalInput.Undefined, - val optionalBooleanInput: OptionalInput = OptionalInput.Undefined + val nullableId: Int? = null, + val nullableListNullableElements: List? = null, + val nullableListNonNullableElements: List? = null, + val nullableElementList: List, + val nonNullableElementList: List ) data class Result( - val stringResult: String + val inputListQuery: String? ) } diff --git a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/OptionalInputQuery.kt b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/OptionalInputQuery.kt index bde66ee5f0..92dad74f24 100644 --- a/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/OptionalInputQuery.kt +++ b/clients/graphql-kotlin-client-jackson/src/test/kotlin/com/expediagroup/graphql/client/jackson/data/OptionalInputQuery.kt @@ -16,6 +16,7 @@ package com.expediagroup.graphql.client.jackson.data +import com.expediagroup.graphql.client.jackson.types.OptionalInput import com.expediagroup.graphql.client.types.GraphQLClientRequest import kotlin.reflect.KClass @@ -29,7 +30,10 @@ class OptionalInputQuery( override fun responseType(): KClass = Result::class data class Variables( - val optional: String? = null + val requiredInput: Int, + val optionalIntInput: OptionalInput = OptionalInput.Undefined, + val optionalStringInput: OptionalInput = OptionalInput.Undefined, + val optionalBooleanInput: OptionalInput = OptionalInput.Undefined ) data class Result( diff --git a/clients/graphql-kotlin-client-serialization/src/main/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinxSerializer.kt b/clients/graphql-kotlin-client-serialization/src/main/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinxSerializer.kt index 060877f76a..7d6ae7835b 100644 --- a/clients/graphql-kotlin-client-serialization/src/main/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinxSerializer.kt +++ b/clients/graphql-kotlin-client-serialization/src/main/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinxSerializer.kt @@ -41,8 +41,7 @@ class GraphQLClientKotlinxSerializer(private val jsonBuilder: JsonBuilder.() -> apply(jsonBuilder) classDiscriminator = "__typename" coerceInputValues = true - // encodeDefaults = false // need this for optional - encodeDefaults = true + encodeDefaults = false } override fun serialize(request: GraphQLClientRequest<*>): String = json.encodeToString(requestSerializer(request), request) diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinXSerializerTest.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinXSerializerTest.kt index 241dae3745..ba6bcc30ce 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinXSerializerTest.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/GraphQLClientKotlinXSerializerTest.kt @@ -16,9 +16,11 @@ package com.expediagroup.graphql.client.serialization +import com.expediagroup.graphql.client.serialization.data.EmptyInputQuery import com.expediagroup.graphql.client.serialization.data.EnumQuery import com.expediagroup.graphql.client.serialization.data.FirstQuery import com.expediagroup.graphql.client.serialization.data.InputQuery +import com.expediagroup.graphql.client.serialization.data.OptionalInputQuery import com.expediagroup.graphql.client.serialization.data.OtherQuery import com.expediagroup.graphql.client.serialization.data.PolymorphicQuery import com.expediagroup.graphql.client.serialization.data.ScalarQuery @@ -28,39 +30,48 @@ import com.expediagroup.graphql.client.serialization.types.KotlinxGraphQLError import com.expediagroup.graphql.client.serialization.types.KotlinxGraphQLResponse import com.expediagroup.graphql.client.serialization.types.KotlinxGraphQLSourceLocation import com.expediagroup.graphql.client.serialization.types.OptionalInput -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json import org.junit.jupiter.api.Test import java.util.UUID -import kotlin.test.Ignore import kotlin.test.assertEquals class GraphQLClientKotlinXSerializerTest { - private val serializer = GraphQLClientKotlinxSerializer() - private val json = Json + private val serializer = GraphQLClientKotlinxSerializer { + prettyPrint = true + } @Test fun `verify we can serialize GraphQLClientRequest`() { val testQuery = FirstQuery(FirstQuery.Variables(input = 1.0f)) - val result = serializer.serialize(testQuery) - val deserialized: FirstQuery = json.decodeFromString(result) - assertEquals(testQuery.variables, deserialized.variables) + val serialized = serializer.serialize(testQuery) + val expected = """{ + | "variables": { + | "input": 1.0 + | }, + | "query": "FIRST_QUERY", + | "operationName": "FirstQuery" + |}""".trimMargin() + + assertEquals(expected, serialized) } @Test fun `verify we can serialize batch GraphQLClientRequest`() { val queries = listOf(FirstQuery(FirstQuery.Variables(input = 1.0f)), OtherQuery()) - val result = serializer.serialize(queries) - val serializedQueries = result.substring(1, result.length - 1).split(Regex("(?<=\\}),(?=\\{)")) - assertEquals(2, serializedQueries.size) + val serialized = serializer.serialize(queries) + val expected = """[{ + | "variables": { + | "input": 1.0 + | }, + | "query": "FIRST_QUERY", + | "operationName": "FirstQuery" + |},{ + | "query": "OTHER_QUERY", + | "operationName": "OtherQuery" + |}]""".trimMargin() - val first: FirstQuery = json.decodeFromString(serializedQueries[0]) - assertEquals(queries[0].variables, first.variables) - - val second: OtherQuery = json.decodeFromString(serializedQueries[1]) - assertEquals(queries[1].variables, second.variables) + assertEquals(expected, serialized) } @Test @@ -106,8 +117,7 @@ class GraphQLClientKotlinXSerializerTest { | "extNull": null, | "extString": "extra" | } - |} - """.trimMargin() + |}""".trimMargin() val result = serializer.deserialize(rawResponse, testQuery.responseType()) assertEquals(expected, result) @@ -165,8 +175,15 @@ class GraphQLClientKotlinXSerializerTest { val scalarQuery = ScalarQuery(variables = ScalarQuery.Variables(alias = "1234", custom = com.expediagroup.graphql.client.serialization.data.scalars.UUID(randomUUID))) val serialized = serializer.serialize(scalarQuery) - val deserialized: ScalarQuery = json.decodeFromString(serialized) - assertEquals(scalarQuery.variables, deserialized.variables) + val expected = """{ + | "variables": { + | "alias": "1234", + | "custom": "$randomUUID" + | }, + | "query": "SCALAR_QUERY", + | "operationName": "ScalarQuery" + |}""".trimMargin() + assertEquals(expected, serialized) } @Test @@ -203,8 +220,14 @@ class GraphQLClientKotlinXSerializerTest { val query = EnumQuery(variables = EnumQuery.Variables(enum = TestEnum.THREE)) val serialized = serializer.serialize(query) - val deserialized: EnumQuery = json.decodeFromString(serialized) - assertEquals(query.variables, deserialized.variables) + val expected = """{ + | "variables": { + | "enum": "three" + | }, + | "query": "ENUM_QUERY", + | "operationName": "EnumQuery" + |}""".trimMargin() + assertEquals(expected, serialized) } @Test @@ -219,28 +242,76 @@ class GraphQLClientKotlinXSerializerTest { } @Test - @Ignore("disabled until https://github.com/Kotlin/kotlinx.serialization/issues/1091 is resolved") fun `verify we can serialize optional inputs`() { - val query = InputQuery( - variables = InputQuery.Variables( + val query = OptionalInputQuery( + variables = OptionalInputQuery.Variables( requiredInput = 123, optionalIntInput = OptionalInput.Defined(123), optionalStringInput = OptionalInput.Defined(null) + // optionalBooleanInput = OptionalInput.Undefined // use default ) ) val rawQuery = """{ - | "query": "INPUT_QUERY", - | "operationName": "InputQuery", - | "variables": { - | "requiredInput": 123, - | "optionalIntInput": 123, - | "optionalStringInput": null - | } - |} - """.trimMargin() + | "variables": { + | "requiredInput": 123, + | "optionalIntInput": 123, + | "optionalStringInput": null + | }, + | "query": "OPTIONAL_INPUT_QUERY", + | "operationName": "OptionalInputQuery" + |}""".trimMargin() val serialized = serializer.serialize(query) assertEquals(rawQuery, serialized) } + + @Test + fun `verify serialization of null values and empty collections`() { + val query = InputQuery( + variables = InputQuery.Variables( + requiredInput = 123, + // nullableId = null, // use default + nullableListNullableElements = listOf(null), + nullableListNonNullableElements = null, // same as default + nullableElementList = listOf("foo", null), + nonNullableElementList = listOf() + ) + ) + + val expected = """{ + | "variables": { + | "requiredInput": 123, + | "nullableListNullableElements": [ + | null + | ], + | "nullableElementList": [ + | "foo", + | null + | ], + | "nonNullableElementList": [ + | ] + | }, + | "query": "INPUT_QUERY", + | "operationName": "InputQuery" + |}""".trimMargin() + val serialized = serializer.serialize(query) + assertEquals(expected, serialized) + } + + @Test + fun `verify serialization of empty variables`() { + val query = EmptyInputQuery( + variables = EmptyInputQuery.Variables() + ) + + val expected = """{ + | "variables": { + | }, + | "query": "EMPTY_INPUT_QUERY", + | "operationName": "EmptyInputQuery" + |}""".trimMargin() + val serialized = serializer.serialize(query) + assertEquals(expected, serialized) + } } diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EmptyInputQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EmptyInputQuery.kt new file mode 100644 index 0000000000..cc4d2896d0 --- /dev/null +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EmptyInputQuery.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2021 Expedia, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.expediagroup.graphql.client.serialization.data + +import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required +import kotlinx.serialization.Serializable +import kotlin.reflect.KClass + +@Serializable +class EmptyInputQuery( + override val variables: Variables +) : GraphQLClientRequest { + + @Required + override val query: String = "EMPTY_INPUT_QUERY" + + @Required + override val operationName: String = "EmptyInputQuery" + + override fun responseType(): KClass = Result::class + + @Serializable + data class Variables( + val nullable: Int? = null + ) + + @Serializable + data class Result( + val stringResult: String + ) +} diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EnumQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EnumQuery.kt index efac8ce38e..6494e4e4a1 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EnumQuery.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/EnumQuery.kt @@ -18,6 +18,7 @@ package com.expediagroup.graphql.client.serialization.data import com.expediagroup.graphql.client.serialization.data.enums.TestEnum import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import kotlin.reflect.KClass @@ -25,8 +26,10 @@ import kotlin.reflect.KClass class EnumQuery( override val variables: Variables ) : GraphQLClientRequest { + @Required override val query: String = "ENUM_QUERY" + @Required override val operationName: String = "EnumQuery" override fun responseType(): KClass = Result::class diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/FirstQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/FirstQuery.kt index facec7baf4..525675ba3f 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/FirstQuery.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/FirstQuery.kt @@ -17,6 +17,7 @@ package com.expediagroup.graphql.client.serialization.data import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import kotlin.reflect.KClass @@ -24,8 +25,10 @@ import kotlin.reflect.KClass class FirstQuery( override val variables: Variables ) : GraphQLClientRequest { + @Required override val query: String = "FIRST_QUERY" + @Required override val operationName: String = "FirstQuery" override fun responseType(): KClass = Result::class diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/InputQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/InputQuery.kt index 9c0a2faa10..66fe32d456 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/InputQuery.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/InputQuery.kt @@ -16,8 +16,8 @@ package com.expediagroup.graphql.client.serialization.data -import com.expediagroup.graphql.client.serialization.types.OptionalInput import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import kotlin.reflect.KClass @@ -25,8 +25,11 @@ import kotlin.reflect.KClass class InputQuery( override val variables: Variables ) : GraphQLClientRequest { + + @Required override val query: String = "INPUT_QUERY" + @Required override val operationName: String = "InputQuery" override fun responseType(): KClass = Result::class @@ -34,9 +37,11 @@ class InputQuery( @Serializable data class Variables( val requiredInput: Int, - val optionalIntInput: OptionalInput = OptionalInput.Undefined, - val optionalStringInput: OptionalInput = OptionalInput.Undefined, - val optionalBooleanInput: OptionalInput = OptionalInput.Undefined + val nullableId: Int? = null, + val nullableListNullableElements: List? = null, + val nullableListNonNullableElements: List? = null, + val nullableElementList: List, + val nonNullableElementList: List ) @Serializable diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OptionalInputQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OptionalInputQuery.kt new file mode 100644 index 0000000000..7aefcd6c61 --- /dev/null +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OptionalInputQuery.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2021 Expedia, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.expediagroup.graphql.client.serialization.data + +import com.expediagroup.graphql.client.serialization.types.OptionalInput +import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required +import kotlinx.serialization.Serializable +import kotlin.reflect.KClass + +@Serializable +class OptionalInputQuery( + override val variables: Variables +) : GraphQLClientRequest { + @Required + override val query: String = "OPTIONAL_INPUT_QUERY" + + @Required + override val operationName: String = "OptionalInputQuery" + + override fun responseType(): KClass = Result::class + + @Serializable + data class Variables( + val requiredInput: Int, + val optionalIntInput: OptionalInput = OptionalInput.Undefined, + val optionalStringInput: OptionalInput = OptionalInput.Undefined, + val optionalBooleanInput: OptionalInput = OptionalInput.Undefined + ) + + @Serializable + data class Result( + val stringResult: String + ) +} diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OtherQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OtherQuery.kt index 7807e6b2ab..8baedbc581 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OtherQuery.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/OtherQuery.kt @@ -17,13 +17,16 @@ package com.expediagroup.graphql.client.serialization.data import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import kotlin.reflect.KClass @Serializable class OtherQuery : GraphQLClientRequest { + @Required override val query: String = "OTHER_QUERY" + @Required override val operationName: String = "OtherQuery" override fun responseType(): KClass = Result::class diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/PolymorphicQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/PolymorphicQuery.kt index 6e868db96a..00eed196cc 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/PolymorphicQuery.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/PolymorphicQuery.kt @@ -18,13 +18,16 @@ package com.expediagroup.graphql.client.serialization.data import com.expediagroup.graphql.client.serialization.data.polymorphicquery.BasicInterface import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import kotlin.reflect.KClass @Serializable class PolymorphicQuery : GraphQLClientRequest { + @Required override val query: String = "POLYMORPHIC_QUERY" + @Required override val operationName: String = "PolymorphicQuery" override fun responseType(): KClass = Result::class diff --git a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/ScalarQuery.kt b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/ScalarQuery.kt index 9f321a9163..b100d03b6d 100644 --- a/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/ScalarQuery.kt +++ b/clients/graphql-kotlin-client-serialization/src/test/kotlin/com/expediagroup/graphql/client/serialization/data/ScalarQuery.kt @@ -18,6 +18,7 @@ package com.expediagroup.graphql.client.serialization.data import com.expediagroup.graphql.client.serialization.data.scalars.UUID import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import kotlin.reflect.KClass @@ -28,8 +29,10 @@ typealias ID = String class ScalarQuery( override val variables: Variables ) : GraphQLClientRequest { + @Required override val query: String = "SCALAR_QUERY" + @Required override val operationName: String = "ScalarQuery" override fun responseType(): KClass = Result::class diff --git a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGenerator.kt b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGenerator.kt index 24d7de4cce..ac0d067039 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGenerator.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGenerator.kt @@ -34,6 +34,7 @@ import graphql.language.OperationDefinition import graphql.parser.Parser import graphql.schema.idl.SchemaParser import graphql.schema.idl.TypeDefinitionRegistry +import kotlinx.serialization.Required import kotlinx.serialization.Serializable import java.io.File @@ -118,21 +119,29 @@ class GraphQLClientGenerator( val graphQLResponseTypeSpec = generateGraphQLObjectTypeSpec(context, rootType, operationDefinition.selectionSet, "Result") val kotlinResultTypeName = ClassName(context.packageName, "${context.operationName}.${graphQLResponseTypeSpec.name}") - val queryProperty = PropertySpec.builder("query", STRING, KModifier.OVERRIDE) - .initializer("%N", queryConstProp) - .build() val operationTypeSpec = TypeSpec.classBuilder(capitalizedOperationName) .addSuperinterface(ClassName(CORE_TYPES_PACKAGE, "GraphQLClientRequest").parameterizedBy(kotlinResultTypeName)) - .addProperty(queryProperty) + + var queryProperty: PropertySpec = PropertySpec.builder("query", STRING, KModifier.OVERRIDE) + .initializer("%N", queryConstProp) + .build() + var operationNameProperty: PropertySpec? = if (operationDefinition.name != null) { + PropertySpec.builder("operationName", STRING, KModifier.OVERRIDE) + .initializer("%S", operationDefinition.name) + .build() + } else { + null + } if (config.serializer == GraphQLSerializer.KOTLINX) { operationTypeSpec.addAnnotation(Serializable::class) + queryProperty = queryProperty.toBuilder().addAnnotation(Required::class).build() + operationNameProperty = operationNameProperty?.toBuilder()?.addAnnotation(Required::class)?.build() } - if (operationDefinition.name != null) { - val operationNameProperty = PropertySpec.builder("operationName", STRING, KModifier.OVERRIDE) - .initializer("%S", operationDefinition.name) - .build() - operationTypeSpec.addProperty(operationNameProperty) + + operationTypeSpec.addProperty(queryProperty) + operationNameProperty?.let { + operationTypeSpec.addProperty(it) } val variableType: TypeSpec? = generateVariableTypeSpec(context, operationDefinition.variableDefinitions) diff --git a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorConfig.kt b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorConfig.kt index 006716a5dd..896e83fa54 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorConfig.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorConfig.kt @@ -30,7 +30,7 @@ data class GraphQLClientGeneratorConfig( val customScalarMap: Map = emptyMap(), /** Type of JSON serializer to be used. */ val serializer: GraphQLSerializer = GraphQLSerializer.JACKSON, - /** Explicit opt-in flag to enable support for optional inputs, only available for JACKSON serializer. */ + /** Explicit opt-in flag to enable support for optional inputs. */ val useOptionalInputWrapper: Boolean = false ) diff --git a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorContext.kt b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorContext.kt index dc5418ef18..a11be16f09 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorContext.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/GraphQLClientGeneratorContext.kt @@ -69,5 +69,3 @@ sealed class ScalarConverterInfo { val serializerTypeSpec: TypeSpec ) : ScalarConverterInfo() } - -internal fun GraphQLClientGeneratorContext.isOptionalInputSupported() = useOptionalInputWrapper && serializer == GraphQLSerializer.JACKSON diff --git a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateGraphQLInputObjectTypeSpec.kt b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateGraphQLInputObjectTypeSpec.kt index 2a0c6485e8..59a6d82cdd 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateGraphQLInputObjectTypeSpec.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateGraphQLInputObjectTypeSpec.kt @@ -18,14 +18,15 @@ package com.expediagroup.graphql.plugin.client.generator.types import com.expediagroup.graphql.plugin.client.generator.GraphQLClientGeneratorContext import com.expediagroup.graphql.plugin.client.generator.GraphQLSerializer -import com.expediagroup.graphql.plugin.client.generator.isOptionalInputSupported import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.ParameterSpec import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeSpec import graphql.language.InputObjectTypeDefinition import kotlinx.serialization.Serializable @@ -49,13 +50,7 @@ internal fun generateGraphQLInputObjectTypeSpec(context: GraphQLClientGeneratorC val kotlinFieldType = generateTypeName(context, fieldDefinition.type) val fieldName = fieldDefinition.name - val inputFieldType = if (kotlinFieldType.isNullable && context.isOptionalInputSupported()) { - ClassName("com.expediagroup.graphql.client.jackson.types", "OptionalInput") - .parameterizedBy(kotlinFieldType.copy(nullable = false)) - } else { - kotlinFieldType - } - + val inputFieldType = kotlinFieldType.wrapOptionalInputType(context) val inputPropertySpecBuilder = PropertySpec.builder(fieldName, inputFieldType) .initializer(fieldName) fieldDefinition.description?.content?.let { kdoc -> @@ -67,11 +62,7 @@ internal fun generateGraphQLInputObjectTypeSpec(context: GraphQLClientGeneratorC val inputParameterSpec = ParameterSpec.builder(inputPropertySpec.name, inputPropertySpec.type) if (kotlinFieldType.isNullable) { - if (context.isOptionalInputSupported()) { - inputParameterSpec.defaultValue("%M", MemberName("com.expediagroup.graphql.client.jackson.types", "OptionalInput.Undefined")) - } else { - inputParameterSpec.defaultValue("null") - } + inputParameterSpec.defaultValue(nullableDefaultValueCodeBlock(context)) } constructorBuilder.addParameter(inputParameterSpec.build()) } @@ -79,3 +70,25 @@ internal fun generateGraphQLInputObjectTypeSpec(context: GraphQLClientGeneratorC return inputObjectTypeSpecBuilder.build() } + +internal fun TypeName.wrapOptionalInputType(context: GraphQLClientGeneratorContext): TypeName = if (this.isNullable && context.useOptionalInputWrapper) { + if (context.serializer == GraphQLSerializer.JACKSON) { + ClassName("com.expediagroup.graphql.client.jackson.types", "OptionalInput") + .parameterizedBy(this.copy(nullable = false)) + } else { + ClassName("com.expediagroup.graphql.client.serialization.types", "OptionalInput") + .parameterizedBy(this.copy(nullable = false)) + } +} else { + this +} + +internal fun nullableDefaultValueCodeBlock(context: GraphQLClientGeneratorContext): CodeBlock = if (context.useOptionalInputWrapper) { + if (context.serializer == GraphQLSerializer.JACKSON) { + CodeBlock.of("%M", MemberName("com.expediagroup.graphql.client.jackson.types", "OptionalInput.Undefined")) + } else { + CodeBlock.of("%M", MemberName("com.expediagroup.graphql.client.serialization.types", "OptionalInput.Undefined")) + } +} else { + CodeBlock.of("null") +} diff --git a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateVariableTypeSpec.kt b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateVariableTypeSpec.kt index 3a48309c39..8424e73032 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateVariableTypeSpec.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generateVariableTypeSpec.kt @@ -18,13 +18,9 @@ package com.expediagroup.graphql.plugin.client.generator.types import com.expediagroup.graphql.plugin.client.generator.GraphQLClientGeneratorContext import com.expediagroup.graphql.plugin.client.generator.GraphQLSerializer -import com.expediagroup.graphql.plugin.client.generator.isOptionalInputSupported -import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.TypeSpec import graphql.language.VariableDefinition @@ -43,20 +39,11 @@ internal fun generateVariableTypeSpec(context: GraphQLClientGeneratorContext, va val constructorSpec = FunSpec.constructorBuilder() variableDefinitions.forEach { variableDef -> val kotlinTypeName = generateTypeName(context, variableDef.type) - val variableTypeName = if (kotlinTypeName.isNullable && context.isOptionalInputSupported()) { - ClassName("com.expediagroup.graphql.client.jackson.types", "OptionalInput") - .parameterizedBy(kotlinTypeName.copy(nullable = false)) - } else { - kotlinTypeName - } + val variableTypeName = kotlinTypeName.wrapOptionalInputType(context) val parameterBuilder = ParameterSpec.builder(variableDef.name, variableTypeName) if (kotlinTypeName.isNullable) { - if (context.isOptionalInputSupported()) { - parameterBuilder.defaultValue("%M", MemberName("com.expediagroup.graphql.client.jackson.types", "OptionalInput.Undefined")) - } else { - parameterBuilder.defaultValue("null") - } + parameterBuilder.defaultValue(nullableDefaultValueCodeBlock(context)) } constructorSpec.addParameter(parameterBuilder.build()) variableTypeSpec.addProperty( diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/custom_scalars/CustomScalarQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/custom_scalars/CustomScalarQuery.kt index bacf8c370c..d4140d12ae 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/custom_scalars/CustomScalarQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/custom_scalars/CustomScalarQuery.kt @@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.types.GraphQLClientRequest import com.expediagroup.graphql.generated.customscalarquery.ScalarWrapper import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val CUSTOM_SCALAR_QUERY: String = @@ -11,8 +12,10 @@ public const val CUSTOM_SCALAR_QUERY: String = @Serializable public class CustomScalarQuery : GraphQLClientRequest { + @Required public override val query: String = CUSTOM_SCALAR_QUERY + @Required public override val operationName: String = "CustomScalarQuery" public override fun responseType(): KClass = diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/deprecated_opt_in/DeprecatedOptInQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/deprecated_opt_in/DeprecatedOptInQuery.kt index d83041e719..928ce5aa04 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/deprecated_opt_in/DeprecatedOptInQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/deprecated_opt_in/DeprecatedOptInQuery.kt @@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.types.GraphQLClientRequest import kotlin.Deprecated import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val DEPRECATED_OPT_IN_QUERY: String = @@ -11,8 +12,10 @@ public const val DEPRECATED_OPT_IN_QUERY: String = @Serializable public class DeprecatedOptInQuery : GraphQLClientRequest { + @Required public override val query: String = DEPRECATED_OPT_IN_QUERY + @Required public override val operationName: String = "DeprecatedOptInQuery" public override fun responseType(): KClass = diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/enums/EnumQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/enums/EnumQuery.kt index 5af5e434c7..66afa1ab78 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/enums/EnumQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/enums/EnumQuery.kt @@ -5,14 +5,17 @@ import com.expediagroup.graphql.generated.enums.CustomEnum import com.expediagroup.graphql.generated.enums.OtherEnum import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val ENUM_QUERY: String = "query EnumQuery {\n enumQuery\n otherEnumQuery\n}" @Serializable public class EnumQuery : GraphQLClientRequest { + @Required public override val query: String = ENUM_QUERY + @Required public override val operationName: String = "EnumQuery" public override fun responseType(): KClass = EnumQuery.Result::class diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/interface/InterfaceWithInlineFragmentsQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/interface/InterfaceWithInlineFragmentsQuery.kt index 12a62efab5..411bd11707 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/interface/InterfaceWithInlineFragmentsQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/interface/InterfaceWithInlineFragmentsQuery.kt @@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.types.GraphQLClientRequest import com.expediagroup.graphql.generated.interfacewithinlinefragmentsquery.BasicInterface import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val INTERFACE_WITH_INLINE_FRAGMENTS_QUERY: String = @@ -12,8 +13,10 @@ public const val INTERFACE_WITH_INLINE_FRAGMENTS_QUERY: String = @Serializable public class InterfaceWithInlineFragmentsQuery : GraphQLClientRequest { + @Required public override val query: String = INTERFACE_WITH_INLINE_FRAGMENTS_QUERY + @Required public override val operationName: String = "InterfaceWithInlineFragmentsQuery" public override fun responseType(): KClass = diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/FirstQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/FirstQuery.kt index 7063efc946..e56a091a33 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/FirstQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/FirstQuery.kt @@ -9,6 +9,7 @@ import com.expediagroup.graphql.generated.inputs.ComplexArgumentInput import kotlin.Boolean import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val FIRST_QUERY: String = @@ -18,8 +19,10 @@ public const val FIRST_QUERY: String = public class FirstQuery( public override val variables: FirstQuery.Variables ) : GraphQLClientRequest { + @Required public override val query: String = FIRST_QUERY + @Required public override val operationName: String = "FirstQuery" public override fun responseType(): KClass = FirstQuery.Result::class diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/SecondQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/SecondQuery.kt index 66908b60c1..023e862875 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/SecondQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/multiple_queries/SecondQuery.kt @@ -9,6 +9,7 @@ import com.expediagroup.graphql.generated.secondquery.ScalarWrapper import kotlin.Boolean import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val SECOND_QUERY: String = @@ -18,8 +19,10 @@ public const val SECOND_QUERY: String = public class SecondQuery( public override val variables: SecondQuery.Variables ) : GraphQLClientRequest { + @Required public override val query: String = SECOND_QUERY + @Required public override val operationName: String = "SecondQuery" public override fun responseType(): KClass = SecondQuery.Result::class diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/object/ComplexObjectQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/object/ComplexObjectQuery.kt index 5ccb862260..c329fa3a46 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/object/ComplexObjectQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/object/ComplexObjectQuery.kt @@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.types.GraphQLClientRequest import com.expediagroup.graphql.generated.complexobjectquery.ComplexObject import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val COMPLEX_OBJECT_QUERY: String = @@ -11,8 +12,10 @@ public const val COMPLEX_OBJECT_QUERY: String = @Serializable public class ComplexObjectQuery : GraphQLClientRequest { + @Required public override val query: String = COMPLEX_OBJECT_QUERY + @Required public override val operationName: String = "ComplexObjectQuery" public override fun responseType(): KClass = diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/union/UnionQueryWithInlineFragments.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/union/UnionQueryWithInlineFragments.kt index 586aa39daa..aa89ca170b 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/union/UnionQueryWithInlineFragments.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/union/UnionQueryWithInlineFragments.kt @@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.types.GraphQLClientRequest import com.expediagroup.graphql.generated.unionquerywithinlinefragments.BasicUnion import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val UNION_QUERY_WITH_INLINE_FRAGMENTS: String = @@ -12,8 +13,10 @@ public const val UNION_QUERY_WITH_INLINE_FRAGMENTS: String = @Serializable public class UnionQueryWithInlineFragments : GraphQLClientRequest { + @Required public override val query: String = UNION_QUERY_WITH_INLINE_FRAGMENTS + @Required public override val operationName: String = "UnionQueryWithInlineFragments" public override fun responseType(): KClass = diff --git a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/variables/KotlinXInputQuery.kt b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/variables/KotlinXInputQuery.kt index fa23f3d10f..ed86625bf0 100644 --- a/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/variables/KotlinXInputQuery.kt +++ b/plugins/client/graphql-kotlin-client-generator/src/test/data/kotlinx/variables/KotlinXInputQuery.kt @@ -5,6 +5,7 @@ import com.expediagroup.graphql.generated.inputs.SimpleArgumentInput import kotlin.Boolean import kotlin.String import kotlin.reflect.KClass +import kotlinx.serialization.Required import kotlinx.serialization.Serializable public const val KOTLIN_X_INPUT_QUERY: String = @@ -14,8 +15,10 @@ public const val KOTLIN_X_INPUT_QUERY: String = public class KotlinXInputQuery( public override val variables: KotlinXInputQuery.Variables ) : GraphQLClientRequest { + @Required public override val query: String = KOTLIN_X_INPUT_QUERY + @Required public override val operationName: String = "KotlinXInputQuery" public override fun responseType(): KClass = diff --git a/plugins/graphql-kotlin-gradle-plugin/README.md b/plugins/graphql-kotlin-gradle-plugin/README.md index 99327c76f4..fe9889c764 100755 --- a/plugins/graphql-kotlin-gradle-plugin/README.md +++ b/plugins/graphql-kotlin-gradle-plugin/README.md @@ -56,7 +56,6 @@ graphql { read = 15_000 } // Opt-in flag to wrap nullable arguments in OptionalInput that distinguish between null and undefined value. - // Only supported for JACKSON serializer useOptionalInputWrapper = false } schema { @@ -107,7 +106,7 @@ resulting generated code will be automatically added to the project main source | `queryFileDirectory` | Directory | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/main/resources`. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | File | yes | GraphQL schema file that will be used to generate client code. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | ### graphqlGenerateSDL @@ -154,7 +153,7 @@ test source set. | `queryFileDirectory` | Directory | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/test/resources`. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | File | yes | GraphQL schema file that will be used to generate client code. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | ### graphqlIntrospectSchema diff --git a/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLPluginExtension.kt b/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLPluginExtension.kt index d112cd0020..7308245d9b 100644 --- a/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLPluginExtension.kt +++ b/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLPluginExtension.kt @@ -75,7 +75,7 @@ open class GraphQLPluginClientExtension { var queryFileDirectory: String? = null /** JSON serializer that will be used to generate the data classes. */ var serializer: GraphQLSerializer = GraphQLSerializer.JACKSON - /** Opt-in flag to wrap nullable arguments in OptionalInput that supports both null and undefined. Only supported for JACKSON serializer. */ + /** Opt-in flag to wrap nullable arguments in OptionalInput that supports both null and undefined. */ var useOptionalInputWrapper: Boolean = false /** Connect and read timeout configuration for executing introspection query/download schema */ diff --git a/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/parameters/GenerateClientParameters.kt b/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/parameters/GenerateClientParameters.kt index 39458799f7..9205aab0fb 100644 --- a/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/parameters/GenerateClientParameters.kt +++ b/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/parameters/GenerateClientParameters.kt @@ -42,9 +42,6 @@ interface GenerateClientParameters : WorkParameters { val queryFiles: ListProperty /** Directory where to save the generated source files. */ val targetDirectory: Property - /** - * Explicit opt-in flag to wrap nullable arguments in OptionalInput that supports both null and undefined values. - * Only supported for JACKSON serializer. - */ + /** Explicit opt-in flag to wrap nullable arguments in OptionalInput that supports both null and undefined values. */ val useOptionalInputWrapper: Property } diff --git a/plugins/graphql-kotlin-maven-plugin/README.md b/plugins/graphql-kotlin-maven-plugin/README.md index afd9af8898..96ecb71e18 100755 --- a/plugins/graphql-kotlin-maven-plugin/README.md +++ b/plugins/graphql-kotlin-maven-plugin/README.md @@ -46,8 +46,7 @@ Plugin should be configured as part of your `pom.xml` build file. 1000 30000 - + false ${project.basedir}/src/main/resources/queries/MyQuery.graphql @@ -114,7 +113,7 @@ Generate GraphQL client code based on the provided GraphQL schema and target que | `queryFiles` | List | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | String | | GraphQL schema file that will be used to generate client code.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | **Parameter Details** @@ -182,7 +181,7 @@ Generate GraphQL test client code based on the provided GraphQL schema and targe | `queryFiles` | List | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | String | | GraphQL schema file that will be used to generate client code.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | **Parameter Details** diff --git a/plugins/graphql-kotlin-maven-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/maven/GenerateClientAbstractMojo.kt b/plugins/graphql-kotlin-maven-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/maven/GenerateClientAbstractMojo.kt index c5be2987ba..b4d46fe66b 100644 --- a/plugins/graphql-kotlin-maven-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/maven/GenerateClientAbstractMojo.kt +++ b/plugins/graphql-kotlin-maven-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/maven/GenerateClientAbstractMojo.kt @@ -94,7 +94,6 @@ abstract class GenerateClientAbstractMojo : AbstractMojo() { /** * Explicit opt-in flag to wrap nullable arguments in OptionalInput that supports both null and undefined values. - * Only supported for JACKSON serializer. */ @Parameter(defaultValue = "\${graphql.useOptionalInputWrapper}", name = "useOptionalInputWrapper") private var useOptionalInputWrapper: Boolean = false diff --git a/website/docs/client/client-features.mdx b/website/docs/client/client-features.mdx index 5477b71669..288ba8b1dd 100644 --- a/website/docs/client/client-features.mdx +++ b/website/docs/client/client-features.mdx @@ -199,12 +199,12 @@ val secondQuery = SecondQuery(variables = SecondQuery.Variables(foo = "baz")) val results: List> = client.execute(listOf(firstQuery, secondQuery)) ``` -## Optional Input Support (Jackson only) +## Optional Input Support In the GraphQL world, input types can be optional which means that the client can specify a value, specify a `null` value OR don't specify any value. This is in contrast with the JVM world where objects can either have some specific value or don't have any value (i.e. are `null`). By default, GraphQL Kotlin Client treats `null` Kotlin values as unspecified, which -means it will skip all `null` values when serializing the request, e.g. given following query +means they will skip all `null` values when serializing the request, e.g. given following query ```graphql query OptionalInputQuery($optionalValue: String) { diff --git a/website/docs/plugins/gradle-plugin-tasks.mdx b/website/docs/plugins/gradle-plugin-tasks.mdx index 446c274021..80890b55bc 100644 --- a/website/docs/plugins/gradle-plugin-tasks.mdx +++ b/website/docs/plugins/gradle-plugin-tasks.mdx @@ -143,7 +143,6 @@ graphql { read = 15_000 } // Opt-in flag to wrap nullable arguments in OptionalInput that distinguish between null and undefined value. - // Only supported for JACKSON serializer useOptionalInputWrapper = false } schema { @@ -190,7 +189,6 @@ graphql { t.read = 15000 } // Opt-in flag to wrap nullable arguments in OptionalInput that distinguish between null and undefined value. - // Only supported for JACKSON serializer useOptionalInputWrapper = false } schema { @@ -264,7 +262,7 @@ resulting generated code will be automatically added to the project main source | `queryFileDirectory` | Directory | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/main/resources`. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | File | yes | GraphQL schema file that will be used to generate client code. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | By default, this task will generate Jackson compatible data models. See [client serialization documentation](../client/client-serialization.mdx) for details on how to update this process to use `kotlinx.serialization` instead. @@ -313,7 +311,7 @@ test source set. | `queryFileDirectory` | Directory | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/test/resources`. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | File | yes | GraphQL schema file that will be used to generate client code. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | By default, this task will generate Jackson compatible data models. See [client serialization documentation](../client/client-serialization.mdx) for details on how to update this process to use `kotlinx.serialization` instead. diff --git a/website/docs/plugins/maven-plugin-goals.md b/website/docs/plugins/maven-plugin-goals.md index c7ab50752c..5ea008404b 100644 --- a/website/docs/plugins/maven-plugin-goals.md +++ b/website/docs/plugins/maven-plugin-goals.md @@ -72,7 +72,7 @@ Generate GraphQL client code based on the provided GraphQL schema and target que | `queryFiles` | `List` | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | String | | GraphQL schema file that will be used to generate client code.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | **Parameter Details** @@ -140,7 +140,7 @@ Generate GraphQL test client code based on the provided GraphQL schema and targe | `queryFiles` | `List` | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. | | `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | | `schemaFile` | String | | GraphQL schema file that will be used to generate client code.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | -| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value. Only supported for JACKSON serializer.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | **Parameter Details** From 22e388e6520c103e0d2376a6d3f85035fb5fd926 Mon Sep 17 00:00:00 2001 From: Dariusz Kuc Date: Wed, 25 Aug 2021 22:27:08 -0500 Subject: [PATCH 2/2] lower code coverage from auto generated code JaCoCo already filters Kotlin auto generated code by checking for the line numbers. It appears it does not work for static methods and since `kotlinx.serialization` does not apply `@Generated` annotation (another JaCoCo mechanism to skip analysis), auto generated `write\$Self` static method is included in coverage which singificantly lowers the code coverage. See https://github.com/Kotlin/kotlinx.serialization/issues/961 for details --- clients/graphql-kotlin-client-serialization/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clients/graphql-kotlin-client-serialization/build.gradle.kts b/clients/graphql-kotlin-client-serialization/build.gradle.kts index e206a099d2..320d50f504 100644 --- a/clients/graphql-kotlin-client-serialization/build.gradle.kts +++ b/clients/graphql-kotlin-client-serialization/build.gradle.kts @@ -20,7 +20,8 @@ tasks { limit { counter = "INSTRUCTION" value = "COVEREDRATIO" - minimum = "0.73".toBigDecimal() + // increase it when https://github.com/Kotlin/kotlinx.serialization/issues/961 is resolved + minimum = "0.70".toBigDecimal() } } }