@@ -4,13 +4,10 @@ import graphql.introspection.Introspection
44import graphql.introspection.Introspection.DirectiveLocation.*
55import graphql.kickstart.tools.directive.SchemaDirectiveWiringEnvironmentImpl.Parameters
66import graphql.language.NamedNode
7- import graphql.language.Node
87import graphql.language.NodeParentTree
98import graphql.schema.*
109import graphql.schema.idl.RuntimeWiring
1110import graphql.schema.idl.SchemaDirectiveWiring
12- import graphql.util.TraversalControl
13- import graphql.util.TraverserContext
1411import java.util.*
1512
1613internal class DirectiveWiringHelper (
@@ -21,46 +18,40 @@ internal class DirectiveWiringHelper(
2118
2219 val isWiringRequired = runtimeWiring.registeredDirectiveWiring.isNotEmpty() || runtimeWiring.directiveWiring.isNotEmpty()
2320
24- fun wireSchema (schema : GraphQLSchema ): GraphQLSchema = SchemaTransformer .transformSchema(schema, object : GraphQLTypeVisitorStub () {
25- private val references = TypeReferences (schema)
26-
27- override fun visitGraphQLObjectType (node : GraphQLObjectType , context : TraverserContext <GraphQLSchemaElement >) =
28- wire(node, node.definition, context, ::wireObject)
29-
30- override fun visitGraphQLInterfaceType (node : GraphQLInterfaceType , context : TraverserContext <GraphQLSchemaElement >) =
31- wire(node, node.definition, context, ::wireInterFace)
32-
33- override fun visitGraphQLInputObjectType (node : GraphQLInputObjectType , context : TraverserContext <GraphQLSchemaElement >) =
34- wire(node, node.definition, context, ::wireInputObject)
35-
36- override fun visitGraphQLEnumType (node : GraphQLEnumType , context : TraverserContext <GraphQLSchemaElement >) =
37- wire(node, node.definition, context, ::wireEnum)
38-
39- override fun visitGraphQLUnionType (node : GraphQLUnionType , context : TraverserContext <GraphQLSchemaElement >) =
40- wire(node, node.definition, context, ::wireUnion)
41-
42- // types without a definition, like the introspection types or types a wiring builds in code, aren't wired
43- private fun <T : GraphQLNamedType > wire (node : T , definition : Node <* >? , context : TraverserContext <GraphQLSchemaElement >, wireType : (T ) -> T ): TraversalControl {
44- if (definition != null ) {
45- val wired = wireType(node)
46- if (wired != = node) changeNode(context, references.inFields(wired))
21+ /* *
22+ * Runs the wirings on the given types of the assembled schema. If they change any, returns every type by name with type references to
23+ * the others, so that the next build resolves them to the wired types.
24+ */
25+ fun wireTypes (schema : GraphQLSchema , types : List <GraphQLNamedType >): Map <String , GraphQLNamedType > {
26+ val changed = linkedMapOf<String , GraphQLNamedType >()
27+ types.forEach { type ->
28+ val wired = when (type) {
29+ is GraphQLObjectType -> wireObject(type)
30+ is GraphQLInterfaceType -> wireInterFace(type)
31+ is GraphQLInputObjectType -> wireInputObject(type)
32+ is GraphQLEnumType -> wireEnum(type)
33+ is GraphQLUnionType -> wireUnion(type)
34+ else -> type
4735 }
48- return TraversalControl . CONTINUE
36+ if (wired != = type) changed[type.name] = wired
4937 }
50- })
38+ if (changed.isEmpty()) return changed
39+ val references = TypeReferences (schema)
40+ return types.associate { it.name to references.inType(changed[it.name] ? : it) }
41+ }
5142
5243 /* *
53- * Swaps the schema's own types in the fields of a wired type for type references, like they were before the schema was built.
54- * Otherwise a type whose fields refer to itself contains itself, which the schema transformer can't rebuild.
44+ * Swaps the schema's own types that a type refers to for type references, like they were before the schema was built.
5545 */
5646 private class TypeReferences (private val schema : GraphQLSchema ) {
5747 // the types wirings build in code, rebuilt once each
5848 private val built = IdentityHashMap <GraphQLType , GraphQLType >()
5949
6050 @Suppress(" UNCHECKED_CAST" )
61- fun <T : GraphQLNamedType > inFields (type : T ): T = when (type) {
62- is GraphQLObjectType -> type.transform { it.clearFields().fields(type.fields.map(::inField)) }
63- is GraphQLInterfaceType -> type.transform { it.clearFields().fields(type.fields.map(::inField)) }
51+ fun <T : GraphQLNamedType > inType (type : T ): T = when (type) {
52+ is GraphQLObjectType -> type.transform { it.clearFields().fields(type.fields.map(::inField)).replaceInterfaces(of(type.interfaces)) }
53+ is GraphQLInterfaceType -> type.transform { it.clearFields().fields(type.fields.map(::inField)).replaceInterfacesOrReferences(of(type.interfaces)) }
54+ is GraphQLUnionType -> type.transform { it.replacePossibleTypes(of(type.types)) }
6455 is GraphQLInputObjectType -> type.transform { it.clearFields().fields(type.fields.map(::inInputField)) }
6556 else -> type
6657 } as T
@@ -76,11 +67,13 @@ internal class DirectiveWiringHelper(
7667 private fun of (type : GraphQLType ): GraphQLType = when (type) {
7768 is GraphQLNonNull -> GraphQLNonNull .nonNull(of(type.wrappedType))
7869 is GraphQLList -> GraphQLList .list(of(type.wrappedType))
79- // only these can lead back to the wired type. Scalars stay, since a reference only finds a scalar another field uses
80- is GraphQLFieldsContainer , is GraphQLUnionType , is GraphQLInputObjectType ->
81- if (schema.typeMap[type.name] == = type) GraphQLTypeReference .typeRef(type.name) else built.getOrPut(type) { inFields (type) }
70+ // scalars aren't wired, and a reference only finds a scalar another field uses
71+ is GraphQLScalarType -> type
72+ is GraphQLNamedType -> if (schema.typeMap[type.name] == = type) GraphQLTypeReference .typeRef(type.name) else built.getOrPut(type) { inType (type) }
8273 else -> type
8374 }
75+
76+ private fun of (types : List <GraphQLNamedOutputType >) = types.map { of(it) as GraphQLNamedOutputType }
8477 }
8578
8679 private fun wireObject (objectType : GraphQLObjectType ): GraphQLObjectType {
0 commit comments