Skip to content

Commit 542840c

Browse files
authored
[client 3.x.x] fix generation of duplicate classes (ExpediaGroup#884)
Backport of ExpediaGroup#883 to 3.x.x branch
1 parent b66d30e commit 542840c

File tree

3 files changed

+395
-8
lines changed

3 files changed

+395
-8
lines changed

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

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.squareup.kotlinpoet.ClassName
2222
import com.squareup.kotlinpoet.FLOAT
2323
import com.squareup.kotlinpoet.INT
2424
import com.squareup.kotlinpoet.LIST
25+
import com.squareup.kotlinpoet.ParameterizedTypeName
2526
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
2627
import com.squareup.kotlinpoet.STRING
2728
import com.squareup.kotlinpoet.TypeName
@@ -97,7 +98,7 @@ internal fun generateCustomClassName(context: GraphQLClientGeneratorContext, gra
9798
} else {
9899
// verify we got same selection set for interface and/or objects (unions shouldn't have any fields)
99100
for (cachedType in cachedTypeNames) {
100-
if (isCachedTypeApplicable(context, cachedType.simpleName, graphQLTypeDefinition, selectionSet)) {
101+
if (isCachedTypeApplicable(context, cachedType.simpleNameWithoutWrapper(), graphQLTypeDefinition, selectionSet)) {
101102
return cachedType
102103
}
103104
}
@@ -111,11 +112,13 @@ internal fun generateCustomClassName(context: GraphQLClientGeneratorContext, gra
111112
else -> throw RuntimeException("should never happen")
112113
}
113114
val className = ClassName(context.packageName, "${context.rootType}.${typeSpec.name}")
114-
context.classNameCache[overriddenName]?.add(className)
115+
context.classNameCache[graphQLTypeName]?.add(className)
115116
className
116117
}
117118
}
118119

120+
private fun ClassName.simpleNameWithoutWrapper() = this.simpleName.substringAfter(".")
121+
119122
private fun isCachedTypeApplicable(context: GraphQLClientGeneratorContext, graphQLTypeName: String, graphQLTypeDefinition: TypeDefinition<*>, selectionSet: SelectionSet): Boolean =
120123
when (graphQLTypeDefinition) {
121124
is UnionTypeDefinition -> {
@@ -148,21 +151,28 @@ private fun isCachedTypeApplicable(context: GraphQLClientGeneratorContext, graph
148151

149152
private fun verifySelectionSet(context: GraphQLClientGeneratorContext, graphQLTypeName: String, selectionSet: SelectionSet): Boolean {
150153
val selectedFields = calculateSelectedFields(context, graphQLTypeName, selectionSet)
151-
val typeSpec = context.typeSpecs[graphQLTypeName]
152-
val properties = typeSpec?.propertySpecs?.map { it.name }?.toSet() ?: emptySet()
153-
return selectedFields == properties ||
154-
(selectedFields.minus(properties).size == 1 && selectedFields.contains("__typename") && context.objectsWithTypeNameSelection.contains(graphQLTypeName))
154+
val properties = calculateGeneratedTypeProperties(context, graphQLTypeName)
155+
if (context.objectsWithTypeNameSelection.contains(graphQLTypeName)) {
156+
properties.add("__typename")
157+
}
158+
return selectedFields == properties
155159
}
156160

157161
private fun calculateSelectedFields(
158162
context: GraphQLClientGeneratorContext,
159163
targetType: String,
160-
selectionSet: SelectionSet
164+
selectionSet: SelectionSet,
165+
path: String = ""
161166
): Set<String> {
162167
val result = mutableSetOf<String>()
163168
selectionSet.selections.forEach { selection ->
164169
when (selection) {
165-
is Field -> result.add(selection.name)
170+
is Field -> {
171+
result.add(path + selection.name)
172+
if (selection.selectionSet != null) {
173+
result.addAll(calculateSelectedFields(context, targetType, selection.selectionSet, "$path${selection.name}."))
174+
}
175+
}
166176
is InlineFragment -> if (selection.typeCondition.name == targetType) {
167177
result.addAll(calculateSelectedFields(context, targetType, selection.selectionSet))
168178
}
@@ -178,3 +188,24 @@ private fun calculateSelectedFields(
178188
}
179189
return result
180190
}
191+
192+
private fun calculateGeneratedTypeProperties(context: GraphQLClientGeneratorContext, graphQLTypeName: String, path: String = ""): MutableSet<String> {
193+
val props = mutableSetOf<String>()
194+
195+
val typeSpec = context.typeSpecs[graphQLTypeName]
196+
for (property in typeSpec?.propertySpecs ?: emptyList()) {
197+
props.add(path + property.name)
198+
when (val propertyType = property.type) {
199+
is ParameterizedTypeName -> {
200+
val genericType = propertyType.typeArguments.firstOrNull() as? ClassName
201+
val genericTypeName = genericType?.simpleNameWithoutWrapper() ?: ""
202+
props.addAll(calculateGeneratedTypeProperties(context, genericTypeName, "$path${property.name}."))
203+
}
204+
is ClassName -> {
205+
val fieldTypeName = propertyType.simpleNameWithoutWrapper()
206+
props.addAll(calculateGeneratedTypeProperties(context, fieldTypeName, "$path${property.name}."))
207+
}
208+
}
209+
}
210+
return props
211+
}

0 commit comments

Comments
 (0)