Skip to content

Commit e73c477

Browse files
committed
Fixes #166
1 parent 783d64d commit e73c477

File tree

1 file changed

+67
-57
lines changed

1 file changed

+67
-57
lines changed

src/main/kotlin/com/coxautodev/graphql/tools/SchemaParser.kt

Lines changed: 67 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ import graphql.language.TypeDefinition
2323
import graphql.language.TypeName
2424
import graphql.language.UnionTypeDefinition
2525
import graphql.language.Value
26+
import graphql.schema.GraphQLArgument
2627
import graphql.schema.GraphQLDirective
2728
import graphql.schema.GraphQLEnumType
29+
import graphql.schema.GraphQLEnumValueDefinition
2830
import graphql.schema.GraphQLFieldDefinition
31+
import graphql.schema.GraphQLInputObjectField
2932
import graphql.schema.GraphQLInputObjectType
3033
import graphql.schema.GraphQLInputType
3134
import graphql.schema.GraphQLInterfaceType
@@ -42,8 +45,7 @@ import graphql.schema.idl.DirectiveBehavior
4245
import graphql.schema.idl.RuntimeWiring
4346
import graphql.schema.idl.ScalarInfo
4447
import graphql.schema.idl.SchemaGeneratorHelper
45-
import java.util.ArrayList
46-
import java.util.HashSet
48+
import java.util.*
4749
import kotlin.reflect.KClass
4850

4951
/**
@@ -56,9 +58,11 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
5658
companion object {
5759
const val DEFAULT_DEPRECATION_MESSAGE = "No longer supported"
5860

59-
@JvmStatic fun newParser() = SchemaParserBuilder()
61+
@JvmStatic
62+
fun newParser() = SchemaParserBuilder()
63+
6064
internal fun getDocumentation(node: AbstractNode<*>): String? = node.comments?.asSequence()
61-
?.filter {!it.content.startsWith("#")}
65+
?.filter { !it.content.startsWith("#") }
6266
?.joinToString("\n") { it.content.trimEnd() }
6367
?.trimIndent()
6468
}
@@ -110,9 +114,12 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
110114
val mutationName = rootInfo.getMutationName()
111115
val subscriptionName = rootInfo.getSubscriptionName()
112116

113-
val query = objects.find { it.name == queryName } ?: throw SchemaError("Expected a Query object with name '$queryName' but found none!")
114-
val mutation = objects.find { it.name == mutationName } ?: if(rootInfo.isMutationRequired()) throw SchemaError("Expected a Mutation object with name '$mutationName' but found none!") else null
115-
val subscription = objects.find { it.name == subscriptionName } ?: if (rootInfo.isSubscriptionRequired()) throw SchemaError("Expected a Subscription object with name '$subscriptionName' but found none!") else null
117+
val query = objects.find { it.name == queryName }
118+
?: throw SchemaError("Expected a Query object with name '$queryName' but found none!")
119+
val mutation = objects.find { it.name == mutationName }
120+
?: if (rootInfo.isMutationRequired()) throw SchemaError("Expected a Mutation object with name '$mutationName' but found none!") else null
121+
val subscription = objects.find { it.name == subscriptionName }
122+
?: if (rootInfo.isSubscriptionRequired()) throw SchemaError("Expected a Subscription object with name '$subscriptionName' but found none!") else null
116123

117124
return SchemaObjects(query, mutation, subscription, (objects + inputObjects + enums + interfaces + unions).toSet())
118125
}
@@ -130,22 +137,24 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
130137
private fun createObject(definition: ObjectTypeDefinition, interfaces: List<GraphQLInterfaceType>): GraphQLObjectType {
131138
val name = definition.name
132139
val builder = GraphQLObjectType.newObject()
133-
.name(name)
134-
.definition(definition)
135-
.description(getDocumentation(definition))
140+
.name(name)
141+
.definition(definition)
142+
.description(getDocumentation(definition))
136143

137144
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.OBJECT))
138145

139146
definition.implements.forEach { implementsDefinition ->
140147
val interfaceName = (implementsDefinition as TypeName).name
141-
builder.withInterface(interfaces.find { it.name == interfaceName } ?: throw SchemaError("Expected interface type with name '$interfaceName' but found none!"))
148+
builder.withInterface(interfaces.find { it.name == interfaceName }
149+
?: throw SchemaError("Expected interface type with name '$interfaceName' but found none!"))
142150
}
143151

144152
definition.getExtendedFieldDefinitions(extensionDefinitions).forEach { fieldDefinition ->
145153
fieldDefinition.description
146154
builder.field { field ->
147155
createField(field, fieldDefinition)
148-
field.dataFetcher(fieldResolversByType[definition]?.get(fieldDefinition)?.createDataFetcher() ?: throw SchemaError("No resolver method found for object type '${definition.name}' and field '${fieldDefinition.name}', this is most likely a bug with graphql-java-tools"))
156+
field.dataFetcher(fieldResolversByType[definition]?.get(fieldDefinition)?.createDataFetcher()
157+
?: throw SchemaError("No resolver method found for object type '${definition.name}' and field '${fieldDefinition.name}', this is most likely a bug with graphql-java-tools"))
149158

150159
val wiredField = directiveGenerator.onField(field.build(), DirectiveBehavior.Params(runtimeWiring))
151160
GraphQLFieldDefinition.Builder(wiredField)
@@ -172,21 +181,21 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
172181

173182
private fun createInputObject(definition: InputObjectTypeDefinition): GraphQLInputObjectType {
174183
val builder = GraphQLInputObjectType.newInputObject()
175-
.name(definition.name)
176-
.definition(definition)
177-
.description(getDocumentation(definition))
184+
.name(definition.name)
185+
.definition(definition)
186+
.description(getDocumentation(definition))
178187

179188
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.INPUT_OBJECT))
180189

181190
definition.inputValueDefinitions.forEach { inputDefinition ->
182-
builder.field { field ->
183-
field.name(inputDefinition.name)
184-
field.definition(inputDefinition)
185-
field.description(getDocumentation(inputDefinition))
186-
field.defaultValue(inputDefinition.defaultValue)
187-
field.type(determineInputType(inputDefinition.type))
188-
field.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
189-
}
191+
val fieldBuilder = GraphQLInputObjectField.newInputObjectField()
192+
.name(inputDefinition.name)
193+
.definition(inputDefinition)
194+
.description(getDocumentation(inputDefinition))
195+
.defaultValue(inputDefinition.defaultValue)
196+
.type(determineInputType(inputDefinition.type))
197+
.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
198+
builder.field(directiveGenerator.onInputObjectField(fieldBuilder.build(), DirectiveBehavior.Params(runtimeWiring)))
190199
}
191200

192201
return directiveGenerator.onInputObject(builder.build(), DirectiveBehavior.Params(runtimeWiring))
@@ -198,20 +207,20 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
198207
if (!type.unwrap().isEnum) throw SchemaError("Type '$name' is declared as an enum in the GraphQL schema but is not a Java enum!")
199208

200209
val builder = GraphQLEnumType.newEnum()
201-
.name(name)
202-
.definition(definition)
203-
.description(getDocumentation(definition))
210+
.name(name)
211+
.definition(definition)
212+
.description(getDocumentation(definition))
204213

205214
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.ENUM))
206215

207216
definition.enumValueDefinitions.forEach { enumDefinition ->
208217
val enumName = enumDefinition.name
209-
val enumValue = type.unwrap().enumConstants.find { (it as Enum<*>).name == enumName } ?: throw SchemaError("Expected value for name '$enumName' in enum '${type.unwrap().simpleName}' but found none!")
218+
val enumValue = type.unwrap().enumConstants.find { (it as Enum<*>).name == enumName }
219+
?: throw SchemaError("Expected value for name '$enumName' in enum '${type.unwrap().simpleName}' but found none!")
220+
val enumValueDirectives = buildDirectives(enumDefinition.directives, setOf(), Introspection.DirectiveLocation.ENUM_VALUE).toMutableList()
210221
getDeprecated(enumDefinition.directives).let {
211-
when (it) {
212-
is String -> builder.value(enumName, enumValue, getDocumentation(enumDefinition), it)
213-
else -> builder.value(enumName, enumValue, getDocumentation(enumDefinition))
214-
}
222+
val enumValueDefinition = GraphQLEnumValueDefinition(enumName, getDocumentation(enumDefinition), enumValue, it, enumValueDirectives)
223+
builder.value(directiveGenerator.onEnumValue(enumValueDefinition, DirectiveBehavior.Params(runtimeWiring)))
215224
}
216225
}
217226

@@ -221,10 +230,10 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
221230
private fun createInterfaceObject(definition: InterfaceTypeDefinition): GraphQLInterfaceType {
222231
val name = definition.name
223232
val builder = GraphQLInterfaceType.newInterface()
224-
.name(name)
225-
.definition(definition)
226-
.description(getDocumentation(definition))
227-
.typeResolver(TypeResolverProxy())
233+
.name(name)
234+
.definition(definition)
235+
.description(getDocumentation(definition))
236+
.typeResolver(TypeResolverProxy())
228237

229238
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.INTERFACE))
230239

@@ -238,10 +247,10 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
238247
private fun createUnionObject(definition: UnionTypeDefinition, types: List<GraphQLObjectType>): GraphQLUnionType {
239248
val name = definition.name
240249
val builder = GraphQLUnionType.newUnionType()
241-
.name(name)
242-
.definition(definition)
243-
.description(getDocumentation(definition))
244-
.typeResolver(TypeResolverProxy())
250+
.name(name)
251+
.definition(definition)
252+
.description(getDocumentation(definition))
253+
.typeResolver(TypeResolverProxy())
245254

246255
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.UNION))
247256

@@ -257,40 +266,40 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
257266
val typeName = (it as TypeName).name
258267

259268
// Is this a nested union? If so, expand
260-
val nestedUnion : UnionTypeDefinition? = unionDefinitions.find { otherDefinition -> typeName == otherDefinition.name }
269+
val nestedUnion: UnionTypeDefinition? = unionDefinitions.find { otherDefinition -> typeName == otherDefinition.name }
261270

262271
if (nestedUnion != null) {
263272
leafObjects.addAll(getLeafUnionObjects(nestedUnion, types))
264273
} else {
265-
leafObjects.add(types.find { it.name == typeName } ?: throw SchemaError("Expected object type '$typeName' for union type '$name', but found none!"))
274+
leafObjects.add(types.find { it.name == typeName }
275+
?: throw SchemaError("Expected object type '$typeName' for union type '$name', but found none!"))
266276
}
267277
}
268278
return leafObjects
269279
}
270280

271-
private fun createField(field: GraphQLFieldDefinition.Builder, fieldDefinition : FieldDefinition): GraphQLFieldDefinition.Builder {
281+
private fun createField(field: GraphQLFieldDefinition.Builder, fieldDefinition: FieldDefinition): GraphQLFieldDefinition.Builder {
272282
field.name(fieldDefinition.name)
273283
field.description(getDocumentation(fieldDefinition))
274284
field.definition(fieldDefinition)
275285
getDeprecated(fieldDefinition.directives)?.let { field.deprecate(it) }
276286
field.type(determineOutputType(fieldDefinition.type))
277287
fieldDefinition.inputValueDefinitions.forEach { argumentDefinition ->
278-
field.argument { argument ->
279-
argument.name(argumentDefinition.name)
280-
argument.definition(argumentDefinition)
281-
argument.description(getDocumentation(argumentDefinition))
282-
argument.defaultValue(buildDefaultValue(argumentDefinition.defaultValue))
283-
argument.type(determineInputType(argumentDefinition.type))
284-
argument.withDirectives(*buildDirectives(argumentDefinition.directives, setOf(), Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
285-
286-
}
288+
val argumentBuilder = GraphQLArgument.newArgument()
289+
.name(argumentDefinition.name)
290+
.definition(argumentDefinition)
291+
.description(getDocumentation(argumentDefinition))
292+
.defaultValue(buildDefaultValue(argumentDefinition.defaultValue))
293+
.type(determineInputType(argumentDefinition.type))
294+
.withDirectives(*buildDirectives(argumentDefinition.directives, setOf(), Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
295+
field.argument(directiveGenerator.onArgument(argumentBuilder.build(), DirectiveBehavior.Params(runtimeWiring)))
287296
}
288297
field.withDirectives(*buildDirectives(fieldDefinition.directives, setOf(), Introspection.DirectiveLocation.FIELD_DEFINITION))
289298
return field
290299
}
291300

292301
private fun buildDefaultValue(value: Value<*>?): Any? {
293-
return when(value) {
302+
return when (value) {
294303
null -> null
295304
is IntValue -> value.value
296305
is FloatValue -> value.value
@@ -305,10 +314,11 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
305314

306315
private fun determineOutputType(typeDefinition: Type<*>) =
307316
determineType(GraphQLOutputType::class, typeDefinition, permittedTypesForObject) as GraphQLOutputType
317+
308318
private fun determineInputType(typeDefinition: Type<*>) =
309319
determineType(GraphQLInputType::class, typeDefinition, permittedTypesForInputObject) as GraphQLInputType
310320

311-
private fun <T: Any> determineType(expectedType: KClass<T>, typeDefinition: Type<*>, allowedTypeReferences: Set<String>): GraphQLType =
321+
private fun <T : Any> determineType(expectedType: KClass<T>, typeDefinition: Type<*>, allowedTypeReferences: Set<String>): GraphQLType =
312322
when (typeDefinition) {
313323
is ListType -> GraphQLList(determineType(expectedType, typeDefinition.type, allowedTypeReferences))
314324
is NonNullType -> GraphQLNonNull(determineType(expectedType, typeDefinition.type, allowedTypeReferences))
@@ -335,10 +345,10 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
335345
* indicating no deprecation directive was found within the directives list.
336346
*/
337347
private fun getDeprecated(directives: List<Directive>): String? =
338-
getDirective(directives, "deprecated")?.let { directive ->
339-
(directive.arguments.find { it.name == "reason" }?.value as? StringValue)?.value ?:
340-
DEFAULT_DEPRECATION_MESSAGE
341-
}
348+
getDirective(directives, "deprecated")?.let { directive ->
349+
(directive.arguments.find { it.name == "reason" }?.value as? StringValue)?.value
350+
?: DEFAULT_DEPRECATION_MESSAGE
351+
}
342352

343353
private fun getDirective(directives: List<Directive>, name: String): Directive? = directives.find {
344354
it.name == name

0 commit comments

Comments
 (0)