diff --git a/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt b/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt index 8f3ed4bf..d3053e9e 100644 --- a/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt +++ b/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt @@ -21,6 +21,12 @@ object BenchmarkSchema { val threeResolver : ()-> ModelThree = { ModelThree("", ones.map { ModelTwo(it, it.quantity..10) }) } + object HasOneResolver { + fun oneResolver(): List { + return ones + } + } + fun create(block : SchemaBuilder.()-> Unit): Schema = KGraphQL.schema { block() query("one"){ @@ -32,5 +38,8 @@ object BenchmarkSchema { query("three"){ resolver(threeResolver) } + query("threeKF"){ + HasOneResolver::oneResolver.toResolver() + } } } diff --git a/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/QueryOrMutationDSL.kt b/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/QueryOrMutationDSL.kt index fe64efef..3627722a 100644 --- a/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/QueryOrMutationDSL.kt +++ b/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/QueryOrMutationDSL.kt @@ -5,6 +5,7 @@ import com.github.pgutkowski.kgraphql.schema.model.FunctionWrapper import com.github.pgutkowski.kgraphql.schema.model.InputValueDef import com.github.pgutkowski.kgraphql.schema.model.MutationDef import com.github.pgutkowski.kgraphql.schema.model.QueryDef +import kotlin.reflect.KFunction class QueryOrMutationDSL( @@ -25,6 +26,8 @@ class QueryOrMutationDSL( return ResolverDSL(this) } + fun KFunction.toResolver() = resolver(FunctionWrapper.on(this)) + fun resolver(function: () -> T) = resolver(FunctionWrapper.on(function)) fun resolver(function: (R) -> T) = resolver(FunctionWrapper.on(function)) diff --git a/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/model/FunctionWrapper.kt b/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/model/FunctionWrapper.kt index c960befc..c5e4e17f 100644 --- a/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/model/FunctionWrapper.kt +++ b/src/main/kotlin/com/github/pgutkowski/kgraphql/schema/model/FunctionWrapper.kt @@ -4,10 +4,10 @@ package com.github.pgutkowski.kgraphql.schema.model import com.github.pgutkowski.kgraphql.schema.SchemaException import com.github.pgutkowski.kgraphql.schema.structure2.validateName -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlin.reflect.KFunction import kotlin.reflect.KType +import kotlin.reflect.full.extensionReceiverParameter import kotlin.reflect.full.valueParameters import kotlin.reflect.jvm.reflect @@ -20,6 +20,9 @@ import kotlin.reflect.jvm.reflect interface FunctionWrapper { //lots of boilerplate here, because kotlin-reflect doesn't support invoking lambdas, local and anonymous functions yet companion object { + fun on (function : KFunction) : FunctionWrapper + = FunctionWrapper.ArityN(function) + fun on (function : () -> T) : FunctionWrapper = FunctionWrapper.ArityZero(function) @@ -119,6 +122,17 @@ interface FunctionWrapper { } } + class ArityN(override val kFunction: KFunction): Base() { + override fun arity() = kFunction.parameters.size + + override val hasReceiver: Boolean + get() = kFunction.extensionReceiverParameter != null + + override fun invoke(vararg args: Any?): T? { + return kFunction.call(*args) + } + } + class ArityZero(val implementation : ()-> T, override val hasReceiver: Boolean = false ) : Base() { override val kFunction: KFunction by lazy { implementation.reflect()!! } override fun arity(): Int = 0 diff --git a/src/test/kotlin/com/github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt b/src/test/kotlin/com/github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt index b2b0a89f..dd6e191b 100644 --- a/src/test/kotlin/com/github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt +++ b/src/test/kotlin/com/github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt @@ -162,13 +162,50 @@ class SchemaBuilderTest { } val actorType = tested.model.queryTypes[Actor::class] - ?: throw Exception("Scenario type should be present in schema") + ?: throw Exception("Actor type should be present in schema") assertThat(actorType.kind, equalTo(TypeKind.OBJECT)) val property = actorType["linked"] ?: throw Exception("Actor should have ext property 'linked'") assertThat(property, notNullValue()) assertThat(property.returnType.unwrapped().name, equalTo("Actor")) } + @Test + fun `KFunction resolver`(){ + val actorService = object { + fun getMainActor() = Actor("Little John", 44) + fun getActor(id: Int) = when(id) { + 1 -> Actor("Joey", 4) + else -> Actor("Bobby", 5) + } + } + + val tested = defaultSchema { + query("mainActor") { + actorService::getMainActor.toResolver() + } + + query("actorById") { + actorService::getActor.toResolver() + } + + type { + property("linked") { + resolver { _ -> Actor("BIG John", 3234) } + } + } + } + + val actorType = tested.model.queryTypes[Actor::class] + ?: throw Exception("Actor type should be present in schema") + assertThat(actorType.kind, equalTo(TypeKind.OBJECT)) + val property = actorType["linked"] ?: throw Exception("Actor should have ext property 'linked'") + assertThat(property, notNullValue()) + assertThat(property.returnType.unwrapped().name, equalTo("Actor")) + + deserialize(tested.execute("{mainActor{name}}")) + deserialize(tested.execute("{actorById(id: 1){name}}")) + } + @Test fun ` _ is allowed as receiver argument name`(){ val schema = defaultSchema {