commonMain.com.apollographql.apollo3.api.CompiledGraphQL.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apollo-api-jvm Show documentation
Show all versions of apollo-api-jvm Show documentation
Apollo GraphQL API classes
@file:JvmName("CompiledGraphQL")
package com.apollographql.apollo3.api
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince.Version.v4_0_0
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.api.json.BufferedSinkJsonWriter
import com.apollographql.apollo3.api.json.writeAny
import okio.Buffer
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName
sealed class CompiledSelection
/**
* A compiled field from a GraphQL operation
*/
class CompiledField internal constructor(
val name: String,
val type: CompiledType,
val alias: String?,
val condition: List,
val arguments: List,
val selections: List,
) : CompiledSelection() {
val responseName: String
get() = alias ?: name
/**
* Resolves field argument value by [name]. If the argument contains variables, replace them with their actual value
*/
fun resolveArgument(
name: String,
variables: Executable.Variables,
): Any? {
return resolveVariables(arguments.firstOrNull { it.name == name }?.value, variables)
}
/**
* Returns a String containing the name of this field as well as encoded arguments. For an example:
* `hero({"episode": "Jedi"})`
* This is mostly used internally to compute records
*/
fun nameWithArguments(variables: Executable.Variables): String {
val filterOutPaginationArguments = arguments.any { it.isPagination }
val arguments = if (filterOutPaginationArguments) {
this.arguments.filterNot { it.isPagination }
} else {
this.arguments
}
if (arguments.isEmpty()) {
return name
}
val map = arguments.associateBy { it.name }.mapValues { it.value.value }
val resolvedArguments = resolveVariables(map, variables)
return try {
val buffer = Buffer()
val jsonWriter = BufferedSinkJsonWriter(buffer)
jsonWriter.writeAny(resolvedArguments)
jsonWriter.close()
"${name}(${buffer.readUtf8()})"
} catch (e: Exception) {
throw RuntimeException(e)
}
}
fun newBuilder(): Builder = Builder(this)
class Builder(val name: String, val type: CompiledType) {
private var alias: String? = null
private var condition: List = emptyList()
private var arguments: List = emptyList()
private var selections: List = emptyList()
constructor(compiledField: CompiledField) : this(compiledField.name, compiledField.type) {
this.alias = compiledField.alias
this.condition = compiledField.condition
this.arguments = compiledField.arguments
this.selections = compiledField.selections
}
fun alias(alias: String?) = apply {
this.alias = alias
}
fun condition(condition: List) = apply {
this.condition = condition
}
fun arguments(arguments: List) = apply {
this.arguments = arguments
}
fun selections(selections: List) = apply {
this.selections = selections
}
fun build(): CompiledField = CompiledField(
name = name,
alias = alias,
type = type,
condition = condition,
arguments = arguments,
selections = selections
)
}
}
/**
* A compiled inline fragment or fragment spread
*/
class CompiledFragment internal constructor(
val typeCondition: String,
val possibleTypes: List,
val condition: List,
val selections: List,
) : CompiledSelection() {
class Builder(val typeCondition: String, val possibleTypes: List) {
var condition: List = emptyList()
var selections: List = emptyList()
fun condition(condition: List) = apply {
this.condition = condition
}
fun selections(selections: List) = apply {
this.selections = selections
}
fun build() = CompiledFragment(typeCondition, possibleTypes, condition, selections)
}
}
data class CompiledCondition(val name: String, val inverted: Boolean)
sealed class CompiledType {
@Deprecated("Use rawType instead", ReplaceWith("rawType()"))
abstract fun leafType(): CompiledNamedType
abstract fun rawType(): CompiledNamedType
}
class CompiledNotNullType(val ofType: CompiledType) : CompiledType() {
@Deprecated("Use rawType instead", ReplaceWith("rawType()"))
override fun leafType() = ofType.rawType()
override fun rawType() = ofType.rawType()
}
class CompiledListType(val ofType: CompiledType) : CompiledType() {
@Deprecated("Use rawType instead", ReplaceWith("rawType()"))
override fun leafType() = ofType.rawType()
override fun rawType() = ofType.rawType()
}
sealed class CompiledNamedType(val name: String) : CompiledType() {
@Deprecated("Use rawType instead", ReplaceWith("rawType()"))
override fun leafType() = this
override fun rawType() = this
}
/**
* A GraphQL scalar type that is mapped to a Kotlin. This is named "Custom" for historical reasons
* but is also used for builtin scalars
*
* TODO v4: rename this to ScalarType
*/
class CustomScalarType(
/**
* GraphQL schema custom scalar type name (e.g. `ID`, `URL`, `DateTime` etc.)
*/
name: String,
/**
* Fully qualified class name this GraphQL scalar type is mapped to (e.g. `java.lang.String`, `java.net.URL`, `java.util.DateTime`)
*/
val className: String,
) : CompiledNamedType(name)
class ObjectType internal constructor(
name: String,
keyFields: List,
implements: List,
embeddedFields: List,
) : CompiledNamedType(name) {
val keyFields = keyFields
val implements = implements
val embeddedFields = embeddedFields
fun newBuilder(): Builder = Builder(this)
class Builder(internal val name: String) {
private var keyFields: List = emptyList()
private var implements: List = emptyList()
private var embeddedFields: List = emptyList()
constructor(objectType: ObjectType) : this(objectType.name) {
this.keyFields = objectType.keyFields
this.implements = objectType.implements
this.embeddedFields = objectType.embeddedFields
}
fun keyFields(keyFields: List) = apply {
this.keyFields = keyFields
}
// This method is named "interfaces" and not "implements" to avoid using a reserved Java keyword
fun interfaces(implements: List) = apply {
this.implements = implements
}
fun embeddedFields(embeddedFields: List) = apply {
this.embeddedFields = embeddedFields
}
fun build(): ObjectType = ObjectType(
name = name,
keyFields = keyFields,
implements = implements,
embeddedFields = embeddedFields
)
}
}
class InterfaceType internal constructor(
name: String,
keyFields: List,
implements: List,
embeddedFields: List,
) : CompiledNamedType(name) {
val keyFields = keyFields
val implements = implements
val embeddedFields = embeddedFields
fun newBuilder(): Builder = Builder(this)
class Builder(internal val name: String) {
private var keyFields: List = emptyList()
private var implements: List = emptyList()
private var embeddedFields: List = emptyList()
constructor(interfaceType: InterfaceType) : this(interfaceType.name) {
this.keyFields = interfaceType.keyFields
this.implements = interfaceType.implements
this.embeddedFields = interfaceType.embeddedFields
}
fun keyFields(keyFields: List) = apply {
this.keyFields = keyFields
}
// This method is named "interfaces" and not "implements" to avoid using a reserved Java keyword
fun interfaces(implements: List) = apply {
this.implements = implements
}
fun embeddedFields(embeddedFields: List) = apply {
this.embeddedFields = embeddedFields
}
fun build(): InterfaceType = InterfaceType(
name = name,
keyFields = keyFields,
implements = implements,
embeddedFields = embeddedFields
)
}
}
class UnionType(
name: String,
vararg val members: ObjectType,
) : CompiledNamedType(name)
class InputObjectType(
name: String,
) : CompiledNamedType(name)
class EnumType(
name: String,
val values: List
) : CompiledNamedType(name)
/**
* TODO v4: remove (see also [CustomScalarType] above
*/
class ScalarType(
name: String,
) : CompiledNamedType(name)
@JvmName("-notNull")
fun CompiledType.notNull() = CompiledNotNullType(this)
@JvmName("-list")
fun CompiledType.list() = CompiledListType(this)
/**
* The Kotlin representation of a GraphQL variable value
*/
class CompiledVariable(val name: String)
/**
* The Kotlin representation of a GraphQL argument
*
* value can be
* - String, Int, Double, Boolean
* - null
* - Map
* - List
* - [CompiledVariable]
*
* Note: for now, enums are mapped to Strings
*/
class CompiledArgument private constructor(
val name: String,
val value: Any?,
val isKey: Boolean = false,
@ApolloExperimental
val isPagination: Boolean = false,
) {
class Builder(
private val name: String,
private val value: Any?,
) {
private var isKey: Boolean = false
private var isPagination: Boolean = false
fun isKey(isKey: Boolean) = apply {
this.isKey = isKey
}
@ApolloExperimental
fun isPagination(isPagination: Boolean) = apply {
this.isPagination = isPagination
}
fun build(): CompiledArgument = CompiledArgument(
name = name,
value = value,
isKey = isKey,
isPagination = isPagination,
)
}
}
/**
* Resolve all variables that may be contained inside `value`
*/
@Suppress("UNCHECKED_CAST")
fun resolveVariables(value: Any?, variables: Executable.Variables): Any? {
return when (value) {
null -> null
is CompiledVariable -> {
variables.valueMap[value.name]
}
is Map<*, *> -> {
value as Map
value.mapValues {
resolveVariables(it.value, variables)
}.toList()
.sortedBy { it.first }
.toMap()
}
is List<*> -> {
value.map {
resolveVariables(it, variables)
}
}
else -> value
}
}
@Deprecated("Introspection types are now generated like other types. Use the generated class instead.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@JvmField
val CompiledSchemaType = ObjectType.Builder("__Schema").build()
@Deprecated("Introspection types are now generated like other types. Use the generated class instead.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@JvmField
val CompiledTypeType = ObjectType.Builder("__Type").build()
@Deprecated("Introspection types are now generated like other types. Use the generated class instead.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@JvmField
val CompiledFieldType = ObjectType.Builder("__Field").build()
@Deprecated("Introspection types are now generated like other types. Use the generated class instead.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@JvmField
val CompiledInputValueType = ObjectType.Builder("__InputValue").build()
@Deprecated("Introspection types are now generated like other types. Use the generated class instead.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@JvmField
val CompiledEnumValueType = ObjectType.Builder("__EnumValue").build()
@Deprecated("Introspection types are now generated like other types. Use the generated class instead.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@JvmField
val CompiledDirectiveType = ObjectType.Builder("__Directive").build()
fun CompiledNamedType.isComposite(): Boolean {
return when (this) {
is UnionType,
is InterfaceType,
is ObjectType,
-> true
else
-> false
}
}
fun CompiledNamedType.keyFields(): List {
return when (this) {
is InterfaceType -> keyFields
is ObjectType -> keyFields
else -> emptyList()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy