@@ -8,11 +8,18 @@ import graphql.schema.*
88import graphql.schema.idl.RuntimeWiring
99import graphql.schema.idl.SchemaGenerator
1010import graphql.schema.idl.SchemaParser
11+ import graphql.schema.idl.TypeDefinitionRegistry
1112import org.antlr.v4.runtime.misc.ParseCancellationException
13+ import java.lang.RuntimeException
1214import java.util.*
1315
1416class Translator (val schema : GraphQLSchema ) {
15- data class Context @JvmOverloads constructor(val topLevelWhere : Boolean = true , val fragments : Map <String ,FragmentDefinition > = emptyMap(),val temporal : Boolean = false )
17+ data class Context @JvmOverloads constructor(val topLevelWhere : Boolean = true ,
18+ val fragments : Map <String ,FragmentDefinition > = emptyMap(),
19+ val temporal : Boolean = false ,
20+ val query : CRUDConfig = CRUDConfig (),
21+ val mutation : CRUDConfig = CRUDConfig ())
22+ data class CRUDConfig (val enabled : Boolean = true , val exclude : List <String > = emptyList())
1623 data class Cypher ( val query : String , val params : Map <String ,Any ?> = emptyMap()) {
1724 companion object {
1825 val EMPTY = Cypher (" " )
@@ -239,22 +246,68 @@ class Translator(val schema: GraphQLSchema) {
239246
240247
241248object SchemaBuilder {
242- @JvmStatic fun buildSchema (sdl : String ) : GraphQLSchema {
249+ @JvmStatic fun buildSchema (sdl : String , ctx : Translator . Context = Translator . Context () ) : GraphQLSchema {
243250 val schemaParser = SchemaParser ()
244- val typeDefinitionRegistry = schemaParser.parse(sdl)
251+ val typeDefinitionRegistry = augmentSchema( schemaParser.parse(sdl), schemaParser, ctx )
245252
246253 val runtimeWiring = RuntimeWiring .newRuntimeWiring()
247254 .type(" Query" )
248255 { it.dataFetcher(" hello" ) { env -> " Hello ${env.getArgument<Any >(" what" )} !" } }
249256 .build()
250257
251258 val schemaGenerator = SchemaGenerator ()
259+ return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring)
260+ .transform { bc -> bc.additionalDirectives(additionalDirectives()).build() }
261+ .transform { sc -> sc.build() } // todo add new queries, filters, enums etc.
262+ }
263+
264+ private fun additionalDirectives (): Set <GraphQLDirective > {
252265 val directives = setOf (GraphQLDirective (" relation" , " relation directive" ,
253- EnumSet .of(Introspection .DirectiveLocation .FIELD ,Introspection .DirectiveLocation .OBJECT ),
254- listOf (GraphQLArgument (" name" ,Scalars .GraphQLString ),
255- GraphQLArgument (" direction" ," relationship direction" ,Scalars .GraphQLString ," OUT" ),
256- GraphQLArgument (" from" ," from field name" ,Scalars .GraphQLString ," from" ),
257- GraphQLArgument (" to" ," to field name" ,Scalars .GraphQLString ," to" )),false ,false ,true ))
258- return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring).transform { bc -> bc.additionalDirectives(directives).build() }
266+ EnumSet .of(Introspection .DirectiveLocation .FIELD , Introspection .DirectiveLocation .OBJECT ),
267+ listOf (GraphQLArgument (" name" , Scalars .GraphQLString ),
268+ GraphQLArgument (" direction" , " relationship direction" , Scalars .GraphQLString , " OUT" ),
269+ GraphQLArgument (" from" , " from field name" , Scalars .GraphQLString , " from" ),
270+ GraphQLArgument (" to" , " to field name" , Scalars .GraphQLString , " to" )), false , false , true ))
271+ return directives
272+ }
273+
274+ private fun augmentSchema (typeDefinitionRegistry : TypeDefinitionRegistry , schemaParser : SchemaParser , ctx : Translator .Context ): TypeDefinitionRegistry {
275+
276+ val augmentations = typeDefinitionRegistry.types().values.filterIsInstance<ObjectTypeDefinition >().map { augmentedSchema(ctx, it) }
277+
278+ val augmentedTypesSdl = augmentations.flatMap { listOf (it.filterType, it.ordering, it.inputType).filter { it.isNotBlank() } }.joinToString(" \n " )
279+ typeDefinitionRegistry.merge(schemaParser.parse(augmentedTypesSdl))
280+
281+ val schemaDefinition = typeDefinitionRegistry.schemaDefinition().orElseGet { SchemaDefinition () }
282+ if (! typeDefinitionRegistry.schemaDefinition().isPresent) typeDefinitionRegistry.add(schemaDefinition).ifPresent { throw RuntimeException (it.toSpecification().toString()) }
283+
284+ val operations = schemaDefinition.operationTypeDefinitions.associate { it.name to typeDefinitionRegistry.getType(it.type).get() as ObjectTypeDefinition }.toMap()
285+
286+ val queryDefinition = operations.getOrElse(" query" ) {
287+ ObjectTypeDefinition (" Query" ).also {
288+ schemaDefinition.operationTypeDefinitions.add(OperationTypeDefinition (" query" ,TypeName (it.name)))
289+ typeDefinitionRegistry.add(it)
290+ }
291+ }
292+ val mutationDefinition = operations.getOrElse(" mutation" ) {
293+ ObjectTypeDefinition (" Mutation" ).also { schemaDefinition.operationTypeDefinitions.add(OperationTypeDefinition (" mutation" ,TypeName (it.name)))
294+ typeDefinitionRegistry.add(it)
295+ }
296+ }
297+
298+ augmentations.filter { it.query.isNotBlank() }.map { it.query }.let {
299+ if (! it.isEmpty()) {
300+ val newQueries = schemaParser.parse(" type AugmentedQuery { ${it.joinToString(" \n " )} }" ).getType(" AugmentedQuery" ).get() as ObjectTypeDefinition
301+ queryDefinition.fieldDefinitions.addAll(newQueries.fieldDefinitions)
302+ }
303+ }
304+ augmentations.flatMap { listOf (it.create,it.update,it.delete).filter{ it.isNotBlank() }}.let {
305+ if (! it.isEmpty()) {
306+ val newQueries = schemaParser.parse(" type AugmentedMutation { ${it.joinToString(" \n " )} }" ).getType(" AugmentedMutation" ).get() as ObjectTypeDefinition
307+ mutationDefinition.fieldDefinitions.addAll(newQueries.fieldDefinitions)
308+ }
309+ }
310+
311+ return typeDefinitionRegistry
259312 }
260313}
0 commit comments