diff --git a/src/jmh/kotlin/com/apurebase/kgraphql/BenchmarkSchema.kt b/src/jmh/kotlin/com/apurebase/kgraphql/BenchmarkSchema.kt index 4dc4293d..a6c1c2d4 100644 --- a/src/jmh/kotlin/com/apurebase/kgraphql/BenchmarkSchema.kt +++ b/src/jmh/kotlin/com/apurebase/kgraphql/BenchmarkSchema.kt @@ -11,40 +11,35 @@ data class ModelTwo(val one : ModelOne, val range: IntRange) data class ModelThree(val id : String, val twos : List) object BenchmarkSchema { - val ones = listOf( - ModelOne("DUDE"), - ModelOne("GUY"), - ModelOne("PAL"), - ModelOne("FELLA") - ) + val ones = listOf(ModelOne("DUDE"),ModelOne("GUY"),ModelOne("PAL"),ModelOne("FELLA")) val oneResolver : ()->List = { ones } val twoResolver : (name : String)-> ModelTwo? = { name -> - ones.find { it.name == name }?.let { - ModelTwo( - it, - it.quantity..12 - ) - } + ones.find { it.name == name }?.let { ModelTwo(it, it.quantity..12) } } - val threeResolver : ()-> ModelThree = { - ModelThree( - "", - ones.map { ModelTwo(it, it.quantity..10) }) + 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") { + query("one"){ resolver(oneResolver) } - query("two") { + query("two"){ resolver(twoResolver) } - query("three") { + query("three"){ resolver(threeResolver) } + query("threeKF"){ + HasOneResolver::oneResolver.toResolver() + } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/QueryOrMutationDSL.kt b/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/QueryOrMutationDSL.kt index f436a8a8..c8f54c8f 100644 --- a/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/QueryOrMutationDSL.kt +++ b/src/main/kotlin/com/apurebase/kgraphql/schema/dsl/QueryOrMutationDSL.kt @@ -5,6 +5,7 @@ import com.apurebase.kgraphql.schema.model.FunctionWrapper import com.apurebase.kgraphql.schema.model.InputValueDef import com.apurebase.kgraphql.schema.model.MutationDef import com.apurebase.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/apurebase/kgraphql/schema/model/FunctionWrapper.kt b/src/main/kotlin/com/apurebase/kgraphql/schema/model/FunctionWrapper.kt index 36596313..e610eeaa 100644 --- a/src/main/kotlin/com/apurebase/kgraphql/schema/model/FunctionWrapper.kt +++ b/src/main/kotlin/com/apurebase/kgraphql/schema/model/FunctionWrapper.kt @@ -8,6 +8,7 @@ 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 +21,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 +123,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/apurebase/kgraphql/schema/SchemaBuilderTest.kt b/src/test/kotlin/com/apurebase/kgraphql/schema/SchemaBuilderTest.kt index 085a6c51..10d1922d 100644 --- a/src/test/kotlin/com/apurebase/kgraphql/schema/SchemaBuilderTest.kt +++ b/src/test/kotlin/com/apurebase/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 {