jvmMain.definitions.RaptorObjectGraphDefinitionBuilder.kt Maven / Gradle / Ivy
The newest version!
package io.fluidsonic.raptor
import io.fluidsonic.raptor.graphql.internal.*
import io.fluidsonic.stdlib.*
import kotlin.reflect.*
import kotlin.reflect.full.*
@RaptorDsl
public class RaptorObjectGraphDefinitionBuilder internal constructor(
kotlinType: KotlinType,
name: String,
private val stackTrace: List,
) : RaptorStructuredGraphTypeDefinitionBuilder(
kotlinType = kotlinType,
name = name
) {
private val fieldDefinitions: MutableList = mutableListOf()
private var hasInputObject = false
override fun build(description: String?, additionalDefinitions: Collection): ObjectGraphDefinition {
val fieldDefinitions = fieldDefinitions.toMutableList()
if (fieldDefinitions.isEmpty()) {
when (kotlinType.classifier.objectInstance) {
null -> error("At least one field must be defined: field(…)")
else -> fieldDefinitions += GraphFieldDefinition.Resolvable(
argumentDefinitions = emptyList(),
argumentResolver = ArgumentResolver(factoryName = "field"),
description = "Dummy. See https://github.com/graphql/graphql-spec/issues/568",
kotlinType = KotlinType(classifier = Unit::class, isNullable = false),
name = "_",
resolve = {},
stackTrace = stackTrace,
)
}
}
return ObjectGraphDefinition(
additionalDefinitions = additionalDefinitions,
description = description,
fieldDefinitions = fieldDefinitions,
kotlinType = kotlinType,
name = name,
stackTrace = stackTrace
)
}
@RaptorDsl
public inline fun field(
name: String,
@BuilderInference noinline configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit,
) {
field(name = name, type = typeOf(), configure = configure)
}
@RaptorDsl
public inline fun field(
property: KProperty1,
noinline configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit = {},
) {
field(
property = property,
type = typeOf(),
configure = configure
)
}
@RaptorDsl
public fun field(
property: KProperty1,
type: KType,
configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit = {},
) {
field(
name = property.name,
type = type,
stackTrace = stackTrace(skipCount = 1),
implicitResolver = { property.get(it as Type) }, // TODO
configure = configure
)
}
@RaptorDsl
public fun field(
function: KFunction2,
configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit = {},
) {
field(
name = function.name,
type = function.returnType,
stackTrace = stackTrace(skipCount = 1),
implicitResolver = { function(it as Type, context) }, // TODO
configure = configure
)
}
@JvmName("fieldSuspend")
@RaptorDsl
public fun field(
function: KSuspendFunction2,
configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit = {},
) {
field(
name = function.name,
type = function.returnType,
stackTrace = stackTrace(skipCount = 1),
implicitResolver = { function(it as Type, context) }, // TODO
configure = configure
)
}
@RaptorDsl
public fun field(
name: String,
type: KType,
configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit,
) {
field(
name = name,
type = type,
stackTrace = stackTrace(skipCount = 1),
implicitResolver = null,
configure = configure
)
}
private fun field(
name: String,
type: KType,
stackTrace: List,
implicitResolver: (suspend RaptorGraphOutputScope.(parent: Any) -> Any?)?,
configure: RaptorGraphFieldBuilder.WithResolver.() -> Unit,
) {
if (fieldDefinitions.any { it.name === name })
error("Cannot define multiple fields named '$name'.")
fieldDefinitions += RaptorGraphFieldBuilder.WithResolver(
kotlinType = KotlinType.of(
type = type,
containingType = kotlinType,
allowMaybe = false,
allowNull = true,
allowedVariance = KVariance.OUT,
requireSpecialization = true
),
implicitResolver = implicitResolver,
name = name,
parentKotlinType = kotlinType,
stackTrace = stackTrace
)
.apply(configure)
.build()
if (type.classifier == RaptorUnion2::class)
nestedDefinitions += RaptorUnionGraphDefinitionBuilder>(
kotlinType = KotlinType.of(
type = type.withNullability(false),
containingType = null,
allowMaybe = false,
allowNull = false,
allowedVariance = KVariance.OUT,
requireSpecialization = true,
),
name = "${this.name}_$name",
stackTrace = stackTrace,
)
}
@RaptorDsl
public fun inputObject(
name: String = RaptorGraphDefinition.defaultName,
configure: RaptorInputObjectGraphDefinitionBuilder.() -> Unit,
) {
check(!hasInputObject) { "Cannot define multiple input objects for object '${this.name}'." }
hasInputObject = true
nestedDefinitions += RaptorInputObjectGraphDefinitionBuilder(
kotlinType = kotlinType,
name = when (name) {
RaptorGraphDefinition.defaultName -> "${this.name}Input"
else -> name
},
stackTrace = stackTrace(skipCount = 1)
)
.apply(configure)
}
}