Skip to content

Commit 23a291c

Browse files
authored
[plugin] fix client generation when selecting custom scalars (#916)
When custom scalars (with converters) were referenced multiple times from selection set (e.g. from a common fragment) we would attempt to unwrap the converted scalar type when comparing generated object properties and next selection set fields. This that even though it was the same selection we could still end up with multiple duplicate classes. Added explicit check to verify whether unwrapped property type is auto converted scalar type. Resolves: #903
1 parent 88b5b80 commit 23a291c

File tree

3 files changed

+116
-4
lines changed

3 files changed

+116
-4
lines changed

plugins/graphql-kotlin-plugin-core/src/main/kotlin/com/expediagroup/graphql/plugin/generator/types/generateTypeName.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,10 @@ private fun calculateGeneratedTypeProperties(context: GraphQLClientGeneratorCont
203203
}
204204
is ClassName -> {
205205
val fieldTypeName = propertyType.simpleNameWithoutWrapper()
206-
props.addAll(calculateGeneratedTypeProperties(context, fieldTypeName, "$path${property.name}."))
206+
// we need to check whether generated type is a custom scalar
207+
if (context.scalarTypeToConverterMapping[fieldTypeName] == null) {
208+
props.addAll(calculateGeneratedTypeProperties(context, fieldTypeName, "$path${property.name}."))
209+
}
207210
}
208211
}
209212
}

plugins/graphql-kotlin-plugin-core/src/test/kotlin/com/expediagroup/graphql/plugin/generator/GraphQLTestUtils.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
package com.expediagroup.graphql.plugin.generator
1818

19+
import com.expediagroup.graphql.client.converter.ScalarConverter
1920
import com.squareup.kotlinpoet.FileSpec
2021
import graphql.schema.idl.SchemaParser
2122
import graphql.schema.idl.TypeDefinitionRegistry
23+
import java.util.UUID
2224
import kotlin.test.assertEquals
2325

2426
internal fun testSchema(): TypeDefinitionRegistry {
@@ -48,3 +50,8 @@ internal fun verifyGeneratedFileSpecContents(
4850
val fileSpecs = generateTestFileSpec(query, graphQLConfig)
4951
assertEquals(expected, fileSpecs.first().toString().trim())
5052
}
53+
54+
class UUIDScalarConverter : ScalarConverter<UUID> {
55+
override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString())
56+
override fun toJson(value: UUID): String = value.toString()
57+
}

plugins/graphql-kotlin-plugin-core/src/test/kotlin/com/expediagroup/graphql/plugin/generator/types/GenerateGraphQLCustomScalarTypeSpecIT.kt

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class GenerateGraphQLCustomScalarTypeSpecIT {
3131
3232
import com.expediagroup.graphql.client.GraphQLClient
3333
import com.expediagroup.graphql.client.execute
34-
import com.expediagroup.graphql.plugin.generator.UUIDConverter
34+
import com.expediagroup.graphql.plugin.generator.UUIDScalarConverter
3535
import com.expediagroup.graphql.types.GraphQLResponse
3636
import com.fasterxml.jackson.annotation.JsonCreator
3737
import com.fasterxml.jackson.annotation.JsonValue
@@ -58,7 +58,7 @@ class GenerateGraphQLCustomScalarTypeSpecIT {
5858
fun rawValue() = converter.toJson(value)
5959
6060
companion object {
61-
val converter: UUIDConverter = UUIDConverter()
61+
val converter: UUIDScalarConverter = UUIDScalarConverter()
6262
6363
@JsonCreator
6464
@JvmStatic
@@ -99,7 +99,109 @@ class GenerateGraphQLCustomScalarTypeSpecIT {
9999
expected,
100100
GraphQLClientGeneratorConfig(
101101
packageName = "com.expediagroup.graphql.plugin.generator.integration",
102-
scalarTypeToConverterMapping = mapOf("UUID" to ScalarConverterMapping("java.util.UUID", "com.expediagroup.graphql.plugin.generator.UUIDConverter"))
102+
scalarTypeToConverterMapping = mapOf("UUID" to ScalarConverterMapping("java.util.UUID", "com.expediagroup.graphql.plugin.generator.UUIDScalarConverter"))
103+
)
104+
)
105+
}
106+
107+
@Test
108+
fun `verify selection sets can reference custom scalars`() {
109+
val expected =
110+
"""
111+
package com.expediagroup.graphql.plugin.generator.integration
112+
113+
import com.expediagroup.graphql.client.GraphQLClient
114+
import com.expediagroup.graphql.client.execute
115+
import com.expediagroup.graphql.plugin.generator.UUIDScalarConverter
116+
import com.expediagroup.graphql.types.GraphQLResponse
117+
import com.fasterxml.jackson.annotation.JsonCreator
118+
import com.fasterxml.jackson.annotation.JsonValue
119+
import kotlin.Any
120+
import kotlin.Int
121+
import kotlin.String
122+
import kotlin.jvm.JvmStatic
123+
124+
const val CUSTOM_SCALAR_TEST_QUERY: String =
125+
"query CustomScalarTestQuery {\n first: scalarQuery {\n ... scalarSelections\n }\n second: scalarQuery {\n ... scalarSelections\n }\n}\nfragment scalarSelections on ScalarWrapper {\n count\n custom\n id\n}"
126+
127+
class CustomScalarTestQuery(
128+
private val graphQLClient: GraphQLClient
129+
) {
130+
suspend fun execute(): GraphQLResponse<CustomScalarTestQuery.Result> =
131+
graphQLClient.execute(CUSTOM_SCALAR_TEST_QUERY, "CustomScalarTestQuery", null)
132+
133+
/**
134+
* Custom scalar representing UUID
135+
*/
136+
data class UUID(
137+
val value: java.util.UUID
138+
) {
139+
@JsonValue
140+
fun rawValue() = converter.toJson(value)
141+
142+
companion object {
143+
val converter: UUIDScalarConverter = UUIDScalarConverter()
144+
145+
@JsonCreator
146+
@JvmStatic
147+
fun create(rawValue: Any) = UUID(converter.toScalar(rawValue))
148+
}
149+
}
150+
151+
/**
152+
* Wrapper that holds all supported scalar types
153+
*/
154+
data class ScalarWrapper(
155+
/**
156+
* A signed 32-bit nullable integer value
157+
*/
158+
val count: Int?,
159+
/**
160+
* Custom scalar
161+
*/
162+
val custom: CustomScalarTestQuery.UUID,
163+
/**
164+
* ID represents unique identifier that is not intended to be human readable
165+
*/
166+
val id: ID
167+
)
168+
169+
data class Result(
170+
/**
171+
* Query that returns wrapper object with all supported scalar types
172+
*/
173+
val first: CustomScalarTestQuery.ScalarWrapper,
174+
/**
175+
* Query that returns wrapper object with all supported scalar types
176+
*/
177+
val second: CustomScalarTestQuery.ScalarWrapper
178+
)
179+
}
180+
""".trimIndent()
181+
182+
val query =
183+
"""
184+
query CustomScalarTestQuery {
185+
first: scalarQuery {
186+
... scalarSelections
187+
}
188+
second: scalarQuery {
189+
... scalarSelections
190+
}
191+
}
192+
fragment scalarSelections on ScalarWrapper {
193+
count
194+
custom
195+
id
196+
}
197+
""".trimIndent()
198+
199+
verifyGeneratedFileSpecContents(
200+
query,
201+
expected,
202+
GraphQLClientGeneratorConfig(
203+
packageName = "com.expediagroup.graphql.plugin.generator.integration",
204+
scalarTypeToConverterMapping = mapOf("UUID" to ScalarConverterMapping("java.util.UUID", "com.expediagroup.graphql.plugin.generator.UUIDScalarConverter"))
103205
)
104206
)
105207
}

0 commit comments

Comments
 (0)