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

jvmMain.definitions.RaptorObjectGraphDefinitionBuilder.kt Maven / Gradle / Ivy

There is a newer version: 0.26.0
Show 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)
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy