Skip to content

Commit 8c2fd4f

Browse files
sjschmidt93Steven Schmidt
andauthored
feat: add fields field to filter what resolverInterfaces.classMethods applies to (#186)
Co-authored-by: Steven Schmidt <stschmidt@expediagroup.com>
1 parent 4ecf5eb commit 8c2fd4f

9 files changed

Lines changed: 124 additions & 23 deletions

File tree

src/config/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export const configSchema = object({
161161
array(
162162
object({
163163
typeName: string(),
164+
fields: optional(array(string())),
164165
classMethods: optional(
165166
union([literal("SUSPEND"), literal("COMPLETABLE_FUTURE")]),
166167
),

src/definitions/field.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,22 @@ export function buildConstructorFieldDefinition({
8787
fieldNode,
8888
schema,
8989
config,
90+
typeInResolverInterfacesConfigOverride,
9091
}: {
9192
node: ObjectTypeDefinitionNode;
9293
fieldNode: FieldDefinitionNode;
9394
schema: GraphQLSchema;
9495
config: CodegenConfigWithDefaults;
96+
typeInResolverInterfacesConfigOverride?: ReturnType<
97+
typeof findTypeInResolverInterfacesConfig
98+
> | null;
9599
}) {
96-
const typeInResolverInterfacesConfig = findTypeInResolverInterfacesConfig(
97-
node,
98-
config,
99-
);
100+
const typeInResolverInterfacesConfig: ReturnType<
101+
typeof findTypeInResolverInterfacesConfig
102+
> =
103+
typeInResolverInterfacesConfigOverride === undefined
104+
? findTypeInResolverInterfacesConfig(node, config)
105+
: (typeInResolverInterfacesConfigOverride ?? undefined);
100106
const functionDefinition = buildConstructorFunctionDefinition(
101107
node,
102108
fieldNode,

src/definitions/object.ts

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,15 @@ export function buildObjectTypeDefinition(
7272
node,
7373
config,
7474
);
75+
const resolverFields = typeInResolverInterfacesConfig?.fields;
7576
const fieldsWithArguments = node.fields?.filter(
7677
(fieldNode) => fieldNode.arguments?.length,
7778
);
78-
const fieldNodes = typeInResolverInterfacesConfig
79-
? node.fields
80-
: fieldsWithArguments;
79+
const fieldNodes = !typeInResolverInterfacesConfig
80+
? fieldsWithArguments
81+
: resolverFields
82+
? node.fields?.filter((f) => resolverFields.includes(f.name.value))
83+
: node.fields;
8184

8285
const isTopLevelType =
8386
node.name.value === "Query" || node.name.value === "Mutation";
@@ -101,23 +104,12 @@ ${getClassMembers({ node, fieldNodes, schema, config })}
101104
typeInResolverInterfacesConfig,
102105
);
103106
if (shouldGenerateFunctions) {
104-
const atLeastOneFieldHasNoArguments = node.fields?.some(
105-
(fieldNode) => !fieldNode.arguments?.length,
107+
const constructor = buildConstructor(
108+
node,
109+
typeInResolverInterfacesConfig,
110+
schema,
111+
config,
106112
);
107-
const constructor =
108-
!typeInResolverInterfacesConfig && atLeastOneFieldHasNoArguments
109-
? `(\n${node.fields
110-
?.map((fieldNode) => {
111-
return buildConstructorFieldDefinition({
112-
node,
113-
fieldNode,
114-
schema,
115-
config,
116-
});
117-
})
118-
.join(",\n")}\n)`
119-
: "";
120-
121113
return `${annotations}${outputRestrictionAnnotation}open class ${name}${constructor}${interfaceInheritance} {
122114
${getClassMembers({ node, fieldNodes, schema, config })}
123115
}`;
@@ -128,6 +120,50 @@ ${getClassMembers({ node, schema, config })}
128120
)${interfaceInheritance}`;
129121
}
130122

123+
function buildConstructor(
124+
node: ObjectTypeDefinitionNode,
125+
typeInResolverInterfacesConfig: ReturnType<
126+
typeof findTypeInResolverInterfacesConfig
127+
>,
128+
schema: GraphQLSchema,
129+
config: CodegenConfigWithDefaults,
130+
): string {
131+
const resolverFields = typeInResolverInterfacesConfig?.fields;
132+
133+
if (resolverFields) {
134+
const nonResolverFields = node.fields?.filter(
135+
(f) => !resolverFields.includes(f.name.value),
136+
);
137+
if (!nonResolverFields?.length) return "";
138+
return `(\n${nonResolverFields
139+
.map((fieldNode) =>
140+
buildConstructorFieldDefinition({
141+
node,
142+
fieldNode,
143+
schema,
144+
config,
145+
typeInResolverInterfacesConfigOverride: null,
146+
}).replace(/,$/, ""),
147+
)
148+
.join(",\n")}\n)`;
149+
}
150+
151+
if (typeInResolverInterfacesConfig) return "";
152+
153+
const fieldsForConstructor = node.fields?.filter((f) => !f.arguments?.length);
154+
if (!fieldsForConstructor?.length) return "";
155+
return `(\n${node.fields
156+
?.map((fieldNode) =>
157+
buildConstructorFieldDefinition({
158+
node,
159+
fieldNode,
160+
schema,
161+
config,
162+
}),
163+
)
164+
.join(",\n")}\n)`;
165+
}
166+
131167
function getClassMembers({
132168
node,
133169
fieldNodes,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { GraphQLKotlinCodegenConfig } from "../../../src/plugin";
2+
3+
export default {
4+
resolverInterfaces: [
5+
{
6+
typeName: "MyCompletableFutureFieldsType",
7+
classMethods: "COMPLETABLE_FUTURE",
8+
fields: ["completableFutureField", "nullableCompletableFutureField"],
9+
},
10+
],
11+
} satisfies GraphQLKotlinCodegenConfig;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.kotlin.generated
2+
3+
import com.expediagroup.graphql.generator.annotations.*
4+
5+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6+
open class MyCompletableFutureFieldsType(
7+
val normalField: String,
8+
val normalNullableField: String? = null
9+
) {
10+
open fun completableFutureField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String> = throw NotImplementedError("MyCompletableFutureFieldsType.completableFutureField must be implemented.")
11+
open fun nullableCompletableFutureField(dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): java.util.concurrent.CompletableFuture<String?> = java.util.concurrent.CompletableFuture.completedFuture(null)
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type MyCompletableFutureFieldsType {
2+
completableFutureField: String!
3+
normalField: String!
4+
normalNullableField: String
5+
nullableCompletableFutureField: String
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { GraphQLKotlinCodegenConfig } from "../../../src/plugin";
2+
3+
export default {
4+
resolverInterfaces: [
5+
{
6+
typeName: "MySuspendFieldsType",
7+
classMethods: "SUSPEND",
8+
fields: ["suspendField", "nullableSuspendField"],
9+
},
10+
],
11+
} satisfies GraphQLKotlinCodegenConfig;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.kotlin.generated
2+
3+
import com.expediagroup.graphql.generator.annotations.*
4+
5+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
6+
open class MySuspendFieldsType(
7+
val normalField: String,
8+
val nullableNormalField: String? = null
9+
) {
10+
open suspend fun suspendField(input: String? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String = throw NotImplementedError("MySuspendFieldsType.suspendField must be implemented.")
11+
open suspend fun nullableSuspendField(input: String? = null, dataFetchingEnvironment: graphql.schema.DataFetchingEnvironment): String? = null
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type MySuspendFieldsType {
2+
suspendField(input: String): String!
3+
nullableSuspendField(input: String): String
4+
normalField: String!
5+
nullableNormalField: String
6+
}

0 commit comments

Comments
 (0)