GraphQLSchema generate()

in grails-data-graphql/core/src/main/groovy/org/grails/gorm/graphql/Schema.groovy [255:529]


    GraphQLSchema generate() {

        if (!initialized) {
            initialize()
        }
        final String queryTypeName = 'Query'
        final String mutationTypeName = 'Mutation'

        GraphQLObjectType.Builder queryType = newObject().name(queryTypeName)
        GraphQLObjectType.Builder mutationType = newObject().name(mutationTypeName)

        Set<PersistentEntity> childrenNotMapped = []

        for (MappingContext mappingContext : mappingContexts) {
            for (PersistentEntity entity : mappingContext.persistentEntities) {

                GraphQLMapping mapping = GraphQLEntityHelper.getMapping(entity)
                if (mapping == null) {
                    if (!entity.root) {
                        childrenNotMapped.add(entity)
                    }
                    continue
                } else if (!mapping.operations.all.enabled) {
                    continue
                }

                List<GraphQLFieldDefinition.Builder> queryFields = []
                List<GraphQLFieldDefinition.Builder> mutationFields = []

                final GraphQLOutputType objectType = typeManager.getQueryType(entity, GraphQLPropertyType.OUTPUT)

                List<GraphQLFieldDefinition.Builder> requiresIdentityArguments = []
                List<Closure> postIdentityExecutables = []
                InterceptorInvoker queryInterceptorInvoker = new QueryInterceptorInvoker()

                ProvidedOperation queryOperation = mapping.operations.query
                ProvidedOperation mutationOperation = mapping.operations.mutation

                ProvidedOperation getOperation = mapping.operations.get
                if (queryOperation.enabled && getOperation.enabled) {

                    DataFetcher getFetcher = dataFetcherManager.getReadingFetcher(entity, GET).orElse(new SingleEntityDataFetcher(entity))

                    final String getFieldName = namingConvention.getGet(entity)

                    GraphQLFieldDefinition.Builder queryOne = newFieldDefinition()
                            .name(getFieldName)
                            .type(objectType)
                            .description(getOperation.description)
                            .deprecate(getOperation.deprecationReason)

                    codeRegistry
                            .dataFetcher(
                                    coordinates(queryTypeName, getFieldName),
                                    new InterceptingDataFetcher(entity, serviceManager, queryInterceptorInvoker, GET, getFetcher)
                            )

                    requiresIdentityArguments.add(queryOne)
                    queryFields.add(queryOne)
                }

                ListOperation listOperation = mapping.operations.list
                if (queryOperation.enabled && listOperation.enabled) {

                    DataFetcher listFetcher = dataFetcherManager.getReadingFetcher(entity, LIST).orElse(null)

                    final String listFieldName = namingConvention.getList(entity)
                    GraphQLFieldDefinition.Builder queryAll = newFieldDefinition()
                            .name(listFieldName)
                            .description(listOperation.description)
                            .deprecate(listOperation.deprecationReason)

                    GraphQLOutputType listOutputType
                    if (listOperation.paginate) {
                        if (listFetcher == null) {
                            listFetcher = new PaginatedEntityDataFetcher(entity)
                        }
                        listOutputType = typeManager.getQueryType(entity, GraphQLPropertyType.OUTPUT_PAGED)
                    } else {
                        if (listFetcher == null) {
                            listFetcher = new EntityDataFetcher(entity)
                        }
                        listOutputType = list(objectType)
                    }
                    queryAll.type(listOutputType)

                    if (listFetcher instanceof PaginatingGormDataFetcher) {
                        ((PaginatingGormDataFetcher) listFetcher).responseHandler = paginationResponseHandler
                    }

                    codeRegistry.dataFetcher(
                            coordinates(queryTypeName, listFieldName),
                            new InterceptingDataFetcher(entity, serviceManager, queryInterceptorInvoker, LIST, listFetcher)
                    )

                    queryFields.add(queryAll)

                    for (Map.Entry<String, GraphQLInputType> argument : listArguments) {
                        queryAll.argument(
                                newArgument()
                                        .name(argument.key)
                                        .type(argument.value))
                    }
                }

                ProvidedOperation countOperation = mapping.operations.count
                if (queryOperation.enabled && countOperation.enabled) {

                    DataFetcher countFetcher = dataFetcherManager.getReadingFetcher(entity, COUNT).orElse(new CountEntityDataFetcher(entity))

                    final String countFieldName = namingConvention.getCount(entity)
                    final GraphQLOutputType countOutputType = (GraphQLOutputType) typeManager.getType(Integer)

                    GraphQLFieldDefinition.Builder queryCount = newFieldDefinition()
                            .name(countFieldName)
                            .type(countOutputType)
                            .description(countOperation.description)
                            .deprecate(countOperation.deprecationReason)

                    codeRegistry.dataFetcher(
                            coordinates(queryTypeName, countFieldName),
                            new InterceptingDataFetcher(entity, serviceManager, queryInterceptorInvoker, COUNT, countFetcher)
                    )

                    queryFields.add(queryCount)
                }

                InterceptorInvoker mutationInterceptorInvoker = new MutationInterceptorInvoker()

                GraphQLDataBinder dataBinder = dataBinderManager.getDataBinder(entity.javaClass)

                ProvidedOperation createOperation = mapping.operations.create
                if (mutationOperation.enabled && createOperation.enabled && !Modifier.isAbstract(entity.javaClass.modifiers)) {
                    if (dataBinder == null) {
                        throw new DataBinderNotFoundException(entity)
                    }
                    GraphQLInputType createObjectType = typeManager.getMutationType(entity, GraphQLPropertyType.CREATE, true)

                    if (!createObjectType.children.empty) {
                        BindingGormDataFetcher createFetcher = dataFetcherManager.getBindingFetcher(entity, CREATE).orElse(new CreateEntityDataFetcher(entity))
                        createFetcher.dataBinder = dataBinder

                        final String createFieldName = namingConvention.getCreate(entity)

                        GraphQLFieldDefinition.Builder create = newFieldDefinition()
                                .name(createFieldName)
                                .type(objectType)
                                .description(createOperation.description)
                                .deprecate(createOperation.deprecationReason)
                                .argument(newArgument()
                                        .name(entity.decapitalizedName)
                                        .type(createObjectType))

                        codeRegistry.dataFetcher(
                                coordinates(mutationTypeName, createFieldName),
                                new InterceptingDataFetcher(entity, serviceManager, mutationInterceptorInvoker, CREATE, createFetcher)
                        )

                        mutationFields.add(create)
                    }
                }

                ProvidedOperation updateOperation = mapping.operations.update
                if (mutationOperation.enabled && updateOperation.enabled) {
                    if (dataBinder == null) {
                        throw new DataBinderNotFoundException(entity)
                    }
                    GraphQLInputType updateObjectType = typeManager.getMutationType(entity, GraphQLPropertyType.UPDATE, true)

                    BindingGormDataFetcher updateFetcher = dataFetcherManager.getBindingFetcher(entity, UPDATE).orElse(new UpdateEntityDataFetcher(entity))

                    updateFetcher.dataBinder = dataBinder

                    final String updateFieldName = namingConvention.getUpdate(entity)

                    GraphQLFieldDefinition.Builder update = newFieldDefinition()
                            .name(updateFieldName)
                            .type(objectType)
                            .description(updateOperation.description)
                            .deprecate(updateOperation.deprecationReason)

                    codeRegistry.dataFetcher(
                            coordinates(mutationTypeName, updateFieldName),
                            new InterceptingDataFetcher(entity, serviceManager, mutationInterceptorInvoker, UPDATE, updateFetcher)
                    )

                    postIdentityExecutables.add {
                        update.argument(newArgument()
                                .name(entity.decapitalizedName)
                                .type(updateObjectType))
                    }

                    requiresIdentityArguments.add(update)
                    mutationFields.add(update)
                }

                ProvidedOperation deleteOperation = mapping.operations.delete
                if (mutationOperation.enabled && deleteOperation.enabled) {

                    DeletingGormDataFetcher deleteFetcher = dataFetcherManager.getDeletingFetcher(entity).orElse(new DeleteEntityDataFetcher(entity))

                    deleteFetcher.responseHandler = deleteResponseHandler

                    final String deleteFieldName = namingConvention.getDelete(entity)
                    final GraphQLObjectType deleteObjectType = deleteResponseHandler.getObjectType(typeManager)

                    GraphQLFieldDefinition.Builder delete = newFieldDefinition()
                            .name(deleteFieldName)
                            .type(deleteObjectType)
                            .description(deleteOperation.description)
                            .deprecate(deleteOperation.deprecationReason)

                    codeRegistry.dataFetcher(
                            coordinates(mutationTypeName, deleteFieldName),
                            new InterceptingDataFetcher(entity, serviceManager, mutationInterceptorInvoker, DELETE, deleteFetcher)
                    )

                    requiresIdentityArguments.add(delete)
                    mutationFields.add(delete)
                }

                final GraphQLFieldDefinition.Builder[] builders = requiresIdentityArguments as GraphQLFieldDefinition.Builder[]
                populateIdentityArguments(entity, builders)

                for (Closure c : postIdentityExecutables) {
                    c.call()
                }

                for (CustomOperation operation : mapping.customQueryOperations) {
                    queryFields.add(operation.createField(entity, serviceManager, mappingContext, listArguments))
                }

                for (CustomOperation operation : mapping.customMutationOperations) {
                    mutationFields.add(operation.createField(entity, serviceManager, mappingContext, Collections.emptyMap()))
                }

                for (GraphQLSchemaInterceptor schemaInterceptor : interceptorManager.interceptors) {
                    schemaInterceptor.interceptEntity(entity, queryFields, mutationFields)
                }

                queryType.fields((List<GraphQLFieldDefinition>) queryFields*.build())

                mutationType.fields((List<GraphQLFieldDefinition>) mutationFields*.build())
            }
        }

        Set<GraphQLType> additionalTypes = []

        for (PersistentEntity entity : childrenNotMapped) {
            GraphQLMapping mapping = GraphQLEntityHelper.getMapping(entity.rootEntity)
            if (mapping == null) {
                continue
            }

            additionalTypes.add(typeManager.getQueryType(entity, GraphQLPropertyType.OUTPUT))
        }

        for (GraphQLSchemaInterceptor schemaInterceptor : interceptorManager.interceptors) {
            schemaInterceptor.interceptSchema(queryType, mutationType, additionalTypes)
        }

        GraphQLSchema.Builder schema = GraphQLSchema.newSchema()
                .codeRegistry(codeRegistry.build())
                .additionalTypes(additionalTypes)

        GraphQLObjectType mutation = mutationType.build()
        if (mutation.fieldDefinitions) {
            schema.mutation(mutation)
        }
        GraphQLObjectType query = queryType.build()
        if (query.fieldDefinitions) {
            schema.query(query)
            return schema.build()
        }
    }