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

commonMain.com.apollographql.execution.internal.introspection.kt Maven / Gradle / Ivy

The newest version!
package com.apollographql.execution.internal

import com.apollographql.apollo.api.getOrElse
import com.apollographql.apollo.ast.GQLDirectiveDefinition
import com.apollographql.apollo.ast.GQLEnumTypeDefinition
import com.apollographql.apollo.ast.GQLEnumValueDefinition
import com.apollographql.apollo.ast.GQLFieldDefinition
import com.apollographql.apollo.ast.GQLInputObjectTypeDefinition
import com.apollographql.apollo.ast.GQLInputValueDefinition
import com.apollographql.apollo.ast.GQLInterfaceTypeDefinition
import com.apollographql.apollo.ast.GQLListType
import com.apollographql.apollo.ast.GQLNamedType
import com.apollographql.apollo.ast.GQLNonNullType
import com.apollographql.apollo.ast.GQLObjectTypeDefinition
import com.apollographql.apollo.ast.GQLScalarTypeDefinition
import com.apollographql.apollo.ast.GQLType
import com.apollographql.apollo.ast.GQLTypeDefinition
import com.apollographql.apollo.ast.GQLUnionTypeDefinition
import com.apollographql.apollo.ast.Schema
import com.apollographql.apollo.ast.builtinDefinitions
import com.apollographql.apollo.ast.findDeprecationReason
import com.apollographql.apollo.ast.findSpecifiedBy
import com.apollographql.apollo.ast.toUtf8
import com.apollographql.execution.Resolver
import com.apollographql.execution.StringCoercing

private inline fun  Any?.cast() = this as T

private object SchemaObject

internal val introspectionCoercings = mapOf(
    "__TypeKind" to StringCoercing,
    "__DirectiveLocation" to StringCoercing,
)

internal fun introspectionResolvers(schema: Schema): Map {
  return mapOf(
      schema.queryTypeDefinition.name to mapOf(
          "__schema" to Resolver { SchemaObject },
          "__type" to Resolver {
            val name = it.getRequiredArgument("name").cast()
            IntrospectionType(GQLNamedType(name = name), schema)
          }
      ),
      "__Schema" to mapOf(
          "description" to Resolver { null },
          "types" to Resolver {
            schema.typeDefinitions.keys.map {
              IntrospectionType(GQLNamedType(name = it), schema)
            }
          },
          "queryType" to Resolver { IntrospectionType(GQLNamedType(name = schema.queryTypeDefinition.name), schema) },
          "mutationType" to Resolver {
            schema.mutationTypeDefinition?.let {
              IntrospectionType(
                  GQLNamedType(name = it.name),
                  schema
              )
            }
          },
          "subscriptionType" to Resolver {
            schema.subscriptionTypeDefinition?.let {
              IntrospectionType(
                  GQLNamedType(name = it.name),
                  schema
              )
            }
          },
          "directives" to Resolver { schema.directiveDefinitions.values.toList() },
      ),
      "__Type" to mapOf(
          "kind" to Resolver {
            val type = it.parentObject.cast()
            when (type.typeDefinition) {
              is GQLEnumTypeDefinition -> __TypeKind.ENUM.name
              is GQLInputObjectTypeDefinition -> __TypeKind.INPUT_OBJECT.name
              is GQLInterfaceTypeDefinition -> __TypeKind.INTERFACE.name
              is GQLObjectTypeDefinition -> __TypeKind.OBJECT.name
              is GQLScalarTypeDefinition -> __TypeKind.SCALAR.name
              is GQLUnionTypeDefinition -> __TypeKind.UNION.name
              null -> {
                when (type.type) {
                  is GQLNonNullType -> __TypeKind.NON_NULL.name
                  is GQLListType -> __TypeKind.LIST.name
                  else -> null
                }
              }
            }
          },
          "name" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            typeDefinition?.name
          },
          "description" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            typeDefinition?.description
          },
          "specifiedByURL" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            typeDefinition?.directives?.findSpecifiedBy()
          },
          "fields" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            val definitions = when (typeDefinition) {
              is GQLObjectTypeDefinition -> typeDefinition.fields
              is GQLInterfaceTypeDefinition -> typeDefinition.fields
              else -> null
            }

            if (definitions == null) {
              return@Resolver null
            }

            val includeDeprecated = it.getRequiredArgument("includeDeprecated").cast()
            definitions.filter {
              includeDeprecated || it.directives.findDeprecationReason() == null
            }
          },
          "interfaces" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            val interfaces = when (typeDefinition) {
              is GQLObjectTypeDefinition -> typeDefinition.implementsInterfaces.map { IntrospectionType(GQLNamedType(null, it), schema.typeDefinition(it)) }
              is GQLInterfaceTypeDefinition -> typeDefinition.implementsInterfaces.map { IntrospectionType(GQLNamedType(null, it), schema.typeDefinition(it)) }
              else -> null
            }

            if (interfaces == null) {
              return@Resolver null
            }

            interfaces
          },
          "possibleTypes" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            val possibleTypes = when (typeDefinition) {
              is GQLInterfaceTypeDefinition -> schema.possibleTypes(typeDefinition.name)
              is GQLUnionTypeDefinition -> schema.possibleTypes(typeDefinition.name)
              else -> null
            }

            if (possibleTypes == null) {
              return@Resolver null
            }

            possibleTypes.map { IntrospectionType(GQLNamedType(null, it), schema.typeDefinition(it)) }
          },
          "enumValues" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            if (typeDefinition !is GQLEnumTypeDefinition) {
              return@Resolver null
            }

            val includeDeprecated = it.getRequiredArgument("includeDeprecated").cast()

            typeDefinition.enumValues.filter {
              includeDeprecated || it.directives.findDeprecationReason() == null
            }
          },
          "inputFields" to Resolver {
            val typeDefinition = it.parentObject.cast().typeDefinition
            if (typeDefinition !is GQLInputObjectTypeDefinition) {
              return@Resolver null
            }

            val includeDeprecated = it.getRequiredArgument("includeDeprecated").cast()

            typeDefinition.inputFields.filter {
              includeDeprecated || it.directives.findDeprecationReason() == null
            }
          },
          "ofType" to Resolver {
            val type = it.parentObject.cast()
            when (type.type) {
              is GQLNamedType -> null
              is GQLListType -> IntrospectionType(type.type.type, schema)
              is GQLNonNullType -> IntrospectionType(type.type.type, schema)
            }
          }
      ),
      "__Field" to mapOf(
          "name" to Resolver {
            val fieldDefinition = it.parentObject.cast()
            fieldDefinition.name
          },
          "description" to Resolver {
            val fieldDefinition = it.parentObject.cast()
            fieldDefinition.description
          },
          "args" to Resolver {
            val includeDeprecated = it.getRequiredArgument("includeDeprecated").cast()

            val fieldDefinition = it.parentObject.cast()
            fieldDefinition.arguments.filter {
              includeDeprecated || it.directives.findDeprecationReason() == null
            }
          },
          "type" to Resolver {
            val fieldDefinition = it.parentObject.cast()
            IntrospectionType(fieldDefinition.type, schema)
          },
          "isDeprecated" to Resolver {
            val fieldDefinition = it.parentObject.cast()
            fieldDefinition.directives.findDeprecationReason() != null
          },
          "deprecationReason" to Resolver {
            val fieldDefinition = it.parentObject.cast()
            fieldDefinition.directives.findDeprecationReason()
          }
      ),
      "__InputValue" to mapOf(
          "name" to Resolver {
            val inputValueDefinition = it.parentObject.cast()
            inputValueDefinition.name
          },
          "description" to Resolver {
            val inputValueDefinition = it.parentObject.cast()
            inputValueDefinition.description
          },
          "type" to Resolver {
            val inputValueDefinition = it.parentObject.cast()
            IntrospectionType(inputValueDefinition.type, schema)
          },
          "defaultValue" to Resolver {
            val inputValueDefinition = it.parentObject.cast()
            inputValueDefinition.defaultValue?.toUtf8()
          },
          "isDeprecated" to Resolver {
            val inputValueDefinition = it.parentObject.cast()
            inputValueDefinition.directives.findDeprecationReason() != null
          },
          "deprecationReason" to Resolver {
            val inputValueDefinition = it.parentObject.cast()
            inputValueDefinition.directives.findDeprecationReason()
          },
      ),
      "__EnumValue" to mapOf(
          "name" to Resolver {
            it.parentObject.cast().name
          },
          "description" to Resolver {
            it.parentObject.cast().description
          },
          "isDeprecated" to Resolver {
            it.parentObject.cast().directives.findDeprecationReason() != null
          },
          "deprecationReason" to Resolver {
            it.parentObject.cast().directives.findDeprecationReason()
          },
      ),
      "__Directive" to mapOf(
          "name" to Resolver {
            it.parentObject.cast().name
          },
          "description" to Resolver {
            it.parentObject.cast().description
          },
          "isRepeatable" to Resolver {
            it.parentObject.cast().repeatable
          },
          "locations" to Resolver {
            it.parentObject.cast().locations.map {
              it.name
            }
          },
          "args" to Resolver {
            val includeDeprecated = it.getRequiredArgument("includeDeprecated").cast()

            it.parentObject.cast().arguments.filter {
              includeDeprecated || it.directives.findDeprecationReason() == null
            }
          }
      )
  ).entries.flatMap { (type, fields) ->
    fields.entries.map { (field, resolver) ->
      "$type.$field" to resolver
    }
  }.toMap()
}


private fun IntrospectionType(type: GQLType, schema: Schema): IntrospectionType {
  return IntrospectionType(
      type,
      (type as? GQLNamedType)?.name?.let { schema.typeDefinition(it) }
  )
}

private class IntrospectionType(
    val type: GQLType,
    val typeDefinition: GQLTypeDefinition?,
)

internal enum class __TypeKind {
  SCALAR,
  OBJECT,
  INTERFACE,
  UNION,
  ENUM,
  INPUT_OBJECT,
  LIST,
  NON_NULL,
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy