Skip to content

Commit 12a3b17

Browse files
committed
Rework directives
1 parent b97e207 commit 12a3b17

File tree

6 files changed

+423
-716
lines changed

6 files changed

+423
-716
lines changed

src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt

Lines changed: 14 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package graphql.kickstart.tools
22

3-
import graphql.Scalars
43
import graphql.introspection.Introspection
5-
import graphql.kickstart.tools.directive.SchemaGeneratorDirectiveHelper
4+
import graphql.kickstart.tools.directive.DirectiveWiringHelper
65
import graphql.kickstart.tools.util.getDocumentation
76
import graphql.kickstart.tools.util.getExtendedFieldDefinitions
87
import graphql.kickstart.tools.util.unwrap
@@ -57,9 +56,7 @@ class SchemaParser internal constructor(
5756
(inputObjectDefinitions.map { it.name } + enumDefinitions.map { it.name }).toSet()
5857

5958
private val codeRegistryBuilder = GraphQLCodeRegistry.newCodeRegistry()
60-
61-
private val schemaGeneratorDirectiveHelper = SchemaGeneratorDirectiveHelper()
62-
private val schemaDirectiveParameters = SchemaGeneratorDirectiveHelper.Parameters(null, runtimeWiring, null, codeRegistryBuilder)
59+
private val directiveWiringHelper = DirectiveWiringHelper(options, runtimeWiring, codeRegistryBuilder)
6360

6461
/**
6562
* Parses the given schema with respect to the given dictionary and returns GraphQL objects.
@@ -124,9 +121,7 @@ class SchemaParser internal constructor(
124121
.name(name)
125122
.definition(objectDefinition)
126123
.description(getDocumentation(objectDefinition, options))
127-
128-
builder.withDirectives(*buildDirectives(objectDefinition.directives, Introspection.DirectiveLocation.OBJECT))
129-
builder.withAppliedDirectives(*buildAppliedDirectives(objectDefinition.directives))
124+
.withAppliedDirectives(*buildAppliedDirectives(objectDefinition.directives))
130125

131126
objectDefinition.implements.forEach { implementsDefinition ->
132127
val interfaceName = (implementsDefinition as TypeName).name
@@ -150,10 +145,7 @@ class SchemaParser internal constructor(
150145
}
151146
}
152147

153-
val objectType = builder.build()
154-
val directiveHelperParameters = SchemaGeneratorDirectiveHelper.Parameters(null, runtimeWiring, null, codeRegistryBuilder)
155-
156-
return schemaGeneratorDirectiveHelper.onObject(objectType, directiveHelperParameters)
148+
return directiveWiringHelper.wireObject(builder.build())
157149
}
158150

159151
private fun createInputObject(definition: InputObjectTypeDefinition, inputObjects: List<GraphQLInputObjectType>,
@@ -165,9 +157,7 @@ class SchemaParser internal constructor(
165157
.definition(definition)
166158
.extensionDefinitions(extensionDefinitions)
167159
.description(getDocumentation(definition, options))
168-
169-
builder.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.INPUT_OBJECT))
170-
builder.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
160+
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
171161

172162
referencingInputObjects.add(definition.name)
173163

@@ -179,13 +169,12 @@ class SchemaParser internal constructor(
179169
.description(getDocumentation(inputDefinition, options))
180170
.apply { inputDefinition.defaultValue?.let { v -> defaultValueLiteral(v) } }
181171
.type(determineInputType(inputDefinition.type, inputObjects, referencingInputObjects))
182-
.withDirectives(*buildDirectives(inputDefinition.directives, Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
183172
.withAppliedDirectives(*buildAppliedDirectives(inputDefinition.directives))
184173
builder.field(fieldBuilder.build())
185174
}
186175
}
187176

188-
return schemaGeneratorDirectiveHelper.onInputObjectType(builder.build(), schemaDirectiveParameters)
177+
return directiveWiringHelper.wireInputObject(builder.build())
189178
}
190179

191180
private fun createEnumObject(definition: EnumTypeDefinition): GraphQLEnumType {
@@ -198,24 +187,20 @@ class SchemaParser internal constructor(
198187
.name(name)
199188
.definition(definition)
200189
.description(getDocumentation(definition, options))
201-
202-
builder.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.ENUM))
203-
builder.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
190+
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
204191

205192
definition.enumValueDefinitions.forEach { enumDefinition ->
206193
val enumName = enumDefinition.name
207194
val enumValue = type.unwrap().enumConstants.find { (it as Enum<*>).name == enumName }
208195
?: throw SchemaError("Expected value for name '$enumName' in enum '${type.unwrap().simpleName}' but found none!")
209196

210-
val enumValueDirectives = buildDirectives(enumDefinition.directives, Introspection.DirectiveLocation.ENUM_VALUE)
211197
val enumValueAppliedDirectives = buildAppliedDirectives(enumDefinition.directives)
212198
getDeprecated(enumDefinition.directives).let {
213199
val enumValueDefinition = GraphQLEnumValueDefinition.newEnumValueDefinition()
214200
.name(enumName)
215201
.description(getDocumentation(enumDefinition, options))
216202
.value(enumValue)
217203
.deprecationReason(it)
218-
.withDirectives(*enumValueDirectives)
219204
.withAppliedDirectives(*enumValueAppliedDirectives)
220205
.definition(enumDefinition)
221206
.build()
@@ -224,7 +209,7 @@ class SchemaParser internal constructor(
224209
}
225210
}
226211

227-
return schemaGeneratorDirectiveHelper.onEnum(builder.build(), schemaDirectiveParameters)
212+
return directiveWiringHelper.wireEnum(builder.build())
228213
}
229214

230215
private fun createInterfaceObject(interfaceDefinition: InterfaceTypeDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLInterfaceType {
@@ -233,9 +218,7 @@ class SchemaParser internal constructor(
233218
.name(name)
234219
.definition(interfaceDefinition)
235220
.description(getDocumentation(interfaceDefinition, options))
236-
237-
builder.withDirectives(*buildDirectives(interfaceDefinition.directives, Introspection.DirectiveLocation.INTERFACE))
238-
builder.withAppliedDirectives(*buildAppliedDirectives(interfaceDefinition.directives))
221+
.withAppliedDirectives(*buildAppliedDirectives(interfaceDefinition.directives))
239222

240223
interfaceDefinition.fieldDefinitions.forEach { fieldDefinition ->
241224
builder.field { field -> createField(field, fieldDefinition, inputObjects) }
@@ -246,7 +229,7 @@ class SchemaParser internal constructor(
246229
builder.withInterface(GraphQLTypeReference(interfaceName))
247230
}
248231

249-
return schemaGeneratorDirectiveHelper.onInterface(builder.build(), schemaDirectiveParameters)
232+
return directiveWiringHelper.wireInterFace(builder.build())
250233
}
251234

252235
private fun createUnionObject(definition: UnionTypeDefinition, types: List<GraphQLObjectType>): GraphQLUnionType {
@@ -255,12 +238,10 @@ class SchemaParser internal constructor(
255238
.name(name)
256239
.definition(definition)
257240
.description(getDocumentation(definition, options))
258-
259-
builder.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.UNION))
260-
builder.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
241+
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
261242

262243
getLeafUnionObjects(definition, types).forEach { builder.possibleType(it) }
263-
return schemaGeneratorDirectiveHelper.onUnion(builder.build(), schemaDirectiveParameters)
244+
return directiveWiringHelper.wireUnion(builder.build())
264245
}
265246

266247
private fun getLeafUnionObjects(definition: UnionTypeDefinition, types: List<GraphQLObjectType>): List<GraphQLObjectType> {
@@ -290,6 +271,7 @@ class SchemaParser internal constructor(
290271
.definition(fieldDefinition)
291272
.apply { getDeprecated(fieldDefinition.directives)?.let { deprecate(it) } }
292273
.type(determineOutputType(fieldDefinition.type, inputObjects))
274+
.withAppliedDirectives(*buildAppliedDirectives(fieldDefinition.directives))
293275

294276
fieldDefinition.inputValueDefinitions.forEach { argumentDefinition ->
295277
val argumentBuilder = GraphQLArgument.newArgument()
@@ -298,13 +280,10 @@ class SchemaParser internal constructor(
298280
.description(getDocumentation(argumentDefinition, options))
299281
.type(determineInputType(argumentDefinition.type, inputObjects, setOf()))
300282
.apply { argumentDefinition.defaultValue?.let { defaultValueLiteral(it) } }
301-
.withDirectives(*buildDirectives(argumentDefinition.directives, Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
302283
.withAppliedDirectives(*buildAppliedDirectives(argumentDefinition.directives))
303284

304285
field.argument(argumentBuilder.build())
305286
}
306-
field.withDirectives(*buildDirectives(fieldDefinition.directives, Introspection.DirectiveLocation.FIELD_DEFINITION))
307-
field.withAppliedDirectives(*buildAppliedDirectives(fieldDefinition.directives))
308287

309288
return field
310289
}
@@ -327,7 +306,6 @@ class SchemaParser internal constructor(
327306
.description(getDocumentation(arg, options))
328307
.type(determineInputType(arg.type, inputObjects, setOf()))
329308
.apply { arg.defaultValue?.let { defaultValueLiteral(it) } }
330-
.withDirectives(*buildDirectives(arg.directives, Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
331309
.withAppliedDirectives(*buildAppliedDirectives(arg.directives))
332310
.build())
333311
}
@@ -337,36 +315,6 @@ class SchemaParser internal constructor(
337315
return graphQLDirective
338316
}
339317

340-
private fun buildDirectives(directives: List<Directive>, directiveLocation: Introspection.DirectiveLocation): Array<GraphQLDirective> {
341-
val names = mutableSetOf<String>()
342-
343-
val output = mutableListOf<GraphQLDirective>()
344-
for (directive in directives) {
345-
if (!names.contains(directive.name)) {
346-
names.add(directive.name)
347-
val graphQLDirective = GraphQLDirective.newDirective()
348-
.name(directive.name)
349-
.description(getDocumentation(directive, options))
350-
.comparatorRegistry(runtimeWiring.comparatorRegistry)
351-
.validLocation(directiveLocation)
352-
.apply {
353-
directive.arguments.forEach { arg ->
354-
argument(GraphQLArgument.newArgument()
355-
.name(arg.name)
356-
.type(buildDirectiveInputType(arg.value))
357-
.valueLiteral(arg.value)
358-
.build())
359-
}
360-
}
361-
.build()
362-
363-
output.add(graphQLDirective)
364-
}
365-
}
366-
367-
return output.toTypedArray()
368-
}
369-
370318
private fun buildAppliedDirectives(directives: List<Directive>): Array<GraphQLAppliedDirective> {
371319
val names = mutableSetOf<String>()
372320

@@ -382,7 +330,7 @@ class SchemaParser internal constructor(
382330
directive.arguments.forEach { arg ->
383331
argument(GraphQLAppliedDirectiveArgument.newArgument()
384332
.name(arg.name)
385-
.type(buildDirectiveInputType(arg.value))
333+
.type(directiveWiringHelper.buildDirectiveInputType(arg.value))
386334
.valueLiteral(arg.value)
387335
.build())
388336
}
@@ -396,45 +344,6 @@ class SchemaParser internal constructor(
396344
return output.toTypedArray()
397345
}
398346

399-
private fun buildDirectiveInputType(value: Value<*>): GraphQLInputType? {
400-
return when (value) {
401-
is NullValue -> Scalars.GraphQLString
402-
is FloatValue -> Scalars.GraphQLFloat
403-
is StringValue -> Scalars.GraphQLString
404-
is IntValue -> Scalars.GraphQLInt
405-
is BooleanValue -> Scalars.GraphQLBoolean
406-
is ArrayValue -> GraphQLList.list(buildDirectiveInputType(getArrayValueWrappedType(value)))
407-
else -> throw SchemaError("Directive values of type '${value::class.simpleName}' are not supported yet.")
408-
}
409-
}
410-
411-
private fun getArrayValueWrappedType(value: ArrayValue): Value<*> {
412-
// empty array [] is equivalent to [null]
413-
if (value.values.isEmpty()) {
414-
return NullValue.newNullValue().build()
415-
}
416-
417-
// get rid of null values
418-
val nonNullValueList = value.values.filter { v -> v !is NullValue }
419-
420-
// [null, null, ...] unwrapped is null
421-
if (nonNullValueList.isEmpty()) {
422-
return NullValue.newNullValue().build()
423-
}
424-
425-
// make sure the array isn't polymorphic
426-
val distinctTypes = nonNullValueList
427-
.map { it::class.java }
428-
.distinct()
429-
430-
if (distinctTypes.size > 1) {
431-
throw SchemaError("Arrays containing multiple types of values are not supported yet.")
432-
}
433-
434-
// peek at first value, value exists and is assured to be non-null
435-
return nonNullValueList[0]
436-
}
437-
438347
private fun determineOutputType(typeDefinition: Type<*>, inputObjects: List<GraphQLInputObjectType>) =
439348
determineType(GraphQLOutputType::class, typeDefinition, permittedTypesForObject, inputObjects) as GraphQLOutputType
440349

0 commit comments

Comments
 (0)