All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.kickstart.tools.relay.RelayConnectionFactory.kt Maven / Gradle / Ivy

There is a newer version: 14.0.0
Show newest version
package graphql.kickstart.tools.relay

import graphql.kickstart.tools.TypeDefinitionFactory
import graphql.language.*

class RelayConnectionFactory : TypeDefinitionFactory {

    override fun create(existing: List>): List> {
        val definitions = mutableListOf>()
        val definitionsByName = existing.filterIsInstance>()
                .associateBy { it.name }
                .toMutableMap()

        findConnectionDirectives(existing)
                .flatMap { createDefinitions(it) }
                .forEach {
                    if (!definitionsByName.containsKey(it.name)) {
                        definitionsByName[it.name] = it
                        definitions.add(it)
                    }
                }

        if (!definitionsByName.containsKey("PageInfo")) {
            definitions.add(createPageInfo())
        }

        return definitions
    }

    private fun findConnectionDirectives(definitions: List>): List {
        return definitions.filterIsInstance()
                .flatMap { it.fieldDefinitions }
                .flatMap { it.directivesWithField() }
                .filter { it.name == "connection" }
    }

    private fun createDefinitions(directive: DirectiveWithField): List {
        val definitions = mutableListOf()
        definitions.add(createConnectionDefinition(directive.getTypeName()))
        definitions.add(createEdgeDefinition(directive.getTypeName(), directive.forTypeName()))
        return definitions.toList()
    }

    private fun createConnectionDefinition(type: String): ObjectTypeDefinition =
            ObjectTypeDefinition.newObjectTypeDefinition()
                    .name(type)
                    .fieldDefinition(FieldDefinition("edges", ListType(TypeName(type + "Edge"))))
                    .fieldDefinition(FieldDefinition("pageInfo", TypeName("PageInfo")))
                    .build()

    private fun createEdgeDefinition(connectionType: String, nodeType: String): ObjectTypeDefinition =
            ObjectTypeDefinition.newObjectTypeDefinition()
                    .name(connectionType + "Edge")
                    .fieldDefinition(FieldDefinition("cursor", TypeName("String")))
                    .fieldDefinition(FieldDefinition("node", TypeName(nodeType)))
                    .build()

    private fun createPageInfo(): ObjectTypeDefinition =
            ObjectTypeDefinition.newObjectTypeDefinition()
                    .name("PageInfo")
                    .fieldDefinition(FieldDefinition("hasPreviousPage", NonNullType(TypeName("Boolean"))))
                    .fieldDefinition(FieldDefinition("hasNextPage", NonNullType(TypeName("Boolean"))))
                    .fieldDefinition(FieldDefinition("startCursor", TypeName("String")))
                    .fieldDefinition(FieldDefinition("endCursor", TypeName("String")))
                    .build()

    private fun Directive.forTypeName(): String {
        return (this.getArgument("for").value as StringValue).value
    }

    private fun Directive.withField(field: FieldDefinition): DirectiveWithField {
        return DirectiveWithField(field, this.name, this.arguments, this.sourceLocation, this.comments)
    }

    private fun FieldDefinition.directivesWithField(): List {
        return this.directives.map { it.withField(this) }
    }

    class DirectiveWithField(val field: FieldDefinition, name: String, arguments: List, sourceLocation: SourceLocation, comments: List) : Directive(name, arguments, sourceLocation, comments, IgnoredChars.EMPTY, emptyMap()) {
        fun getTypeName(): String {
            val type = field.type
            if (type is NonNullType) {
                return (type.type as TypeName).name
            }
            return (field.type as TypeName).name
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy