Skip to content

Commit 5d5bf15

Browse files
committed
feat: make class consolidation configurable
1 parent 4b70211 commit 5d5bf15

File tree

9 files changed

+350
-8
lines changed

9 files changed

+350
-8
lines changed

src/config/build-config-with-defaults.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export function buildConfigWithDefaults(
2626
unionGeneration: "MARKER_INTERFACE",
2727
extraImports: ["com.expediagroup.graphql.generator.annotations.*"],
2828
resolverInterfaces: [{ typeName: "Query" }, { typeName: "Mutation" }],
29+
classConsolidationEnabled: true,
2930
} as const satisfies GraphQLKotlinCodegenConfig;
3031

3132
return merge(defaultConfig, config) as GraphQLKotlinCodegenConfig &

src/config/schema.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ export const configSchema = object({
6464
}),
6565
),
6666
),
67+
/**
68+
* Denotes whether to consolidate classes for input and output types whose fields are equivalent.
69+
*
70+
* @default true
71+
*
72+
* @link https://opensource.expediagroup.com/graphql-kotlin-codegen/docs/class-consolidation
73+
*/
74+
classConsolidationEnabled: optional(boolean()),
6775
/**
6876
* Denotes Kotlin classes representing union types to be treated as interfaces rather than annotation classes.
6977
*

src/definitions/input.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { buildTypeMetadata } from "../utils/build-type-metadata";
1717
import { buildAnnotations } from "../annotations/build-annotations";
1818
import { indent } from "@graphql-codegen/visitor-plugin-common";
1919
import { CodegenConfigWithDefaults } from "../config/build-config-with-defaults";
20-
import { inputTypeHasMatchingOutputType } from "../utils/input-type-has-matching-output-type";
20+
import { shouldConsolidateTypes } from "../utils/should-consolidate-types";
2121
import { sanitizeName } from "../utils/sanitize-name";
2222

2323
export function buildInputObjectDefinition(
@@ -29,7 +29,7 @@ export function buildInputObjectDefinition(
2929
return "";
3030
}
3131

32-
const typeWillBeConsolidated = inputTypeHasMatchingOutputType(node, schema);
32+
const typeWillBeConsolidated = shouldConsolidateTypes(node, schema, config);
3333
if (typeWillBeConsolidated) {
3434
return "";
3535
}

src/definitions/object.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
buildObjectFieldDefinition,
2929
} from "./field";
3030
import { CodegenConfigWithDefaults } from "../config/build-config-with-defaults";
31-
import { inputTypeHasMatchingOutputType } from "../utils/input-type-has-matching-output-type";
31+
import { shouldConsolidateTypes } from "../utils/should-consolidate-types";
3232
import { findTypeInResolverInterfacesConfig } from "../config/find-type-in-resolver-interfaces-config";
3333
import { sanitizeName } from "../utils/sanitize-name";
3434

@@ -61,7 +61,7 @@ export function buildObjectTypeDefinition(
6161
const typeWillBeConsolidated =
6262
isInputObjectType(potentialMatchingInputType) &&
6363
potentialMatchingInputType.astNode &&
64-
inputTypeHasMatchingOutputType(potentialMatchingInputType.astNode, schema);
64+
shouldConsolidateTypes(potentialMatchingInputType.astNode, schema, config);
6565
const outputRestrictionAnnotation = typeWillBeConsolidated
6666
? ""
6767
: "@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])\n";

src/utils/build-type-metadata.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import { wrapTypeWithModifiers } from "@graphql-codegen/java-common";
2525
import { CodegenConfigWithDefaults } from "../config/build-config-with-defaults";
2626
import {
2727
getTypeNameWithoutInput,
28-
inputTypeHasMatchingOutputType,
29-
} from "./input-type-has-matching-output-type";
28+
shouldConsolidateTypes,
29+
} from "./should-consolidate-types";
3030

3131
export interface TypeMetadata {
3232
typeName: string;
@@ -78,9 +78,10 @@ export function buildTypeMetadata(
7878
),
7979
};
8080
} else if (isInputObjectType(schemaType) && schemaType.astNode) {
81-
const typeWillBeConsolidated = inputTypeHasMatchingOutputType(
81+
const typeWillBeConsolidated = shouldConsolidateTypes(
8282
schemaType.astNode,
8383
schema,
84+
config,
8485
);
8586
const typeName = typeWillBeConsolidated
8687
? getTypeNameWithoutInput(schemaType.name)

src/utils/input-type-has-matching-output-type.ts renamed to src/utils/should-consolidate-types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,17 @@ import {
1818
isObjectType,
1919
} from "graphql";
2020
import { getBaseTypeNode } from "@graphql-codegen/visitor-plugin-common";
21+
import { CodegenConfigWithDefaults } from "../config/build-config-with-defaults";
2122

22-
export function inputTypeHasMatchingOutputType(
23+
export function shouldConsolidateTypes(
2324
inputNode: InputObjectTypeDefinitionNode,
2425
schema: GraphQLSchema,
26+
config: CodegenConfigWithDefaults,
2527
) {
28+
if (!config.classConsolidationEnabled) {
29+
return false;
30+
}
31+
2632
const inputName = inputNode.name.value;
2733
const typeNameWithoutInput = getTypeNameWithoutInput(inputName);
2834
const matchingTypeName =
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { GraphQLKotlinCodegenConfig } from "../../../src/plugin";
2+
3+
export default {
4+
classConsolidationEnabled: false,
5+
} satisfies GraphQLKotlinCodegenConfig;
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package com.kotlin.generated
2+
3+
import com.expediagroup.graphql.generator.annotations.*
4+
5+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6+
data class MyTypeToConsolidateWithConfig(
7+
val field: List<String>? = null,
8+
val field2: NestedTypeToConsolidateWithConfig? = null
9+
)
10+
11+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
12+
data class MyTypeToConsolidateWithConfigInput(
13+
val field: List<String>? = null,
14+
val field2: NestedTypeToConsolidateWithConfigInput? = null
15+
)
16+
17+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
18+
data class NestedTypeToConsolidateWithConfig(
19+
val field: String? = null
20+
)
21+
22+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
23+
data class NestedTypeToConsolidateWithConfigInput(
24+
val field: String? = null
25+
)
26+
27+
@GraphQLDescription("A description for MyTypeToConsolidate2")
28+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
29+
data class MyTypeToConsolidate2WithConfig(
30+
val field: String? = null
31+
)
32+
33+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
34+
data class MyTypeToConsolidate2WithConfigInput(
35+
val field: String? = null
36+
)
37+
38+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
39+
data class MyTypeToConsolidate3WithConfig(
40+
val field: String? = null
41+
)
42+
43+
@GraphQLDescription("It ignores the description on the input when consolidating")
44+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
45+
data class MyTypeToConsolidate3WithConfigInput(
46+
val field: String? = null
47+
)
48+
49+
@GraphQLDescription("It always uses the type description when consolidating")
50+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
51+
data class MyTypeToConsolidate4WithConfig(
52+
val field: String? = null
53+
)
54+
55+
@GraphQLDescription("A description for MyTypeToConsolidateInput4")
56+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
57+
data class MyTypeToConsolidate4WithConfigInput(
58+
val field: String? = null
59+
)
60+
61+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
62+
data class MyTypeNotToConsolidateWithConfig(
63+
val field: String? = null
64+
)
65+
66+
@GraphQLDescription("The type name must exactly match in order to consolidate")
67+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
68+
data class MyTypeToNotConsolidateWithConfigInput(
69+
val field: String? = null
70+
)
71+
72+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
73+
data class MyTypeToNotConsolidate2WithConfig(
74+
val field: String? = null
75+
)
76+
77+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
78+
data class MyTypeInputToNotConsolidate2WithConfig(
79+
val field: String? = null
80+
)
81+
82+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
83+
data class MyTypeWhereFieldsDoNotMatchWithConfig(
84+
val field: String? = null,
85+
val field2: String? = null
86+
)
87+
88+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
89+
data class MyTypeWhereFieldsDoNotMatchWithConfigInput(
90+
val field: String? = null,
91+
val field2: Int? = null
92+
)
93+
94+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
95+
data class MyTypeToConsolidateParentWithConfig(
96+
val field: MyTypeToConsolidateWithConfig? = null
97+
)
98+
99+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
100+
data class MyTypeToConsolidateInputParentWithConfig(
101+
val field: MyTypeToConsolidateWithConfigInput? = null
102+
)
103+
104+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
105+
open class MyTypeToConsolidateParent2WithConfig {
106+
open fun field(input: MyTypeToConsolidateWithConfigInput, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = throw NotImplementedError("MyTypeToConsolidateParent2WithConfig.field must be implemented.")
107+
}
108+
109+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
110+
data class MyTypeNotToConsolidateParentWithConfig(
111+
val field: MyTypeNotToConsolidate2WithConfig? = null
112+
)
113+
114+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
115+
data class MyTypeNotToConsolidateParentWithConfigInput(
116+
val field: MyTypeNotToConsolidate2WithConfigInput? = null
117+
)
118+
119+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
120+
data class MyTypeNotToConsolidate2WithConfig(
121+
val field1: String? = null,
122+
val field2: String? = null
123+
)
124+
125+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
126+
data class MyTypeNotToConsolidate2WithConfigInput(
127+
val field1: String? = null
128+
)
129+
130+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
131+
data class MySuperSetTypeWithConfig(
132+
val field: String? = null,
133+
val field2: String? = null
134+
)
135+
136+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
137+
data class MySuperSetTypeWithConfigInput(
138+
val field: String? = null,
139+
val field2: String? = null,
140+
val field3: Int? = null
141+
)
142+
143+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
144+
data class MyTypeWithEnumsWithConfig(
145+
val field1: List<Enum1WithConfig>? = null,
146+
val field2: List<Enum2WithConfig>? = null
147+
)
148+
149+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
150+
data class MyTypeWithEnumsWithConfigInput(
151+
val field1: List<Enum1WithConfig>? = null,
152+
val field2: List<Enum2WithConfig>? = null
153+
)
154+
155+
enum class Enum1WithConfig {
156+
This,
157+
That;
158+
159+
companion object {
160+
fun findByName(name: String, ignoreCase: Boolean = false): Enum1WithConfig? = values().find { it.name.equals(name, ignoreCase = ignoreCase) }
161+
}
162+
}
163+
164+
enum class Enum2WithConfig {
165+
The_Other;
166+
167+
companion object {
168+
fun findByName(name: String, ignoreCase: Boolean = false): Enum2WithConfig? = values().find { it.name.equals(name, ignoreCase = ignoreCase) }
169+
}
170+
}

0 commit comments

Comments
 (0)