From cc27bddc0b2b5f0b168eb864834acb603d7f8562 Mon Sep 17 00:00:00 2001 From: Juan Liska Date: Thu, 21 Mar 2019 21:59:00 -0600 Subject: [PATCH 1/2] add ArityN and KFunction support --- .../pgutkowski/kgraphql/BenchmarkSchema.kt | 9 +++++ .../kgraphql/schema/dsl/QueryOrMutationDSL.kt | 3 ++ .../kgraphql/schema/model/FunctionWrapper.kt | 16 +++++++- .../kgraphql/schema/SchemaBuilderTest.kt | 39 ++++++++++++++++++- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt b/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt index 8f3ed4bf..745e8190 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"){ + resolverKF(HasOneResolver::oneResolver) + } } } 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..832faa54 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 resolverKF(function: KFunction) = resolver(FunctionWrapper.on(function)) + 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..99c7b13f 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") { + resolverKF(actorService::getMainActor) + } + + query("actorById") { + resolverKF(actorService::getActor) + } + + 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 { From e8dfd028478321325b7a323f46eab03f768c803a Mon Sep 17 00:00:00 2001 From: Juan Liska Date: Thu, 21 Mar 2019 22:34:45 -0600 Subject: [PATCH 2/2] use extension function instead of resolverKF --- .../kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt | 2 +- .../pgutkowski/kgraphql/schema/dsl/QueryOrMutationDSL.kt | 2 +- .../github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt b/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt index 745e8190..d3053e9e 100644 --- a/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt +++ b/src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt @@ -39,7 +39,7 @@ object BenchmarkSchema { resolver(threeResolver) } query("threeKF"){ - resolverKF(HasOneResolver::oneResolver) + 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 832faa54..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 @@ -26,7 +26,7 @@ class QueryOrMutationDSL( return ResolverDSL(this) } - fun resolverKF(function: KFunction) = resolver(FunctionWrapper.on(function)) + fun KFunction.toResolver() = resolver(FunctionWrapper.on(this)) fun resolver(function: () -> T) = resolver(FunctionWrapper.on(function)) 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 99c7b13f..dd6e191b 100644 --- a/src/test/kotlin/com/github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt +++ b/src/test/kotlin/com/github/pgutkowski/kgraphql/schema/SchemaBuilderTest.kt @@ -181,11 +181,11 @@ class SchemaBuilderTest { val tested = defaultSchema { query("mainActor") { - resolverKF(actorService::getMainActor) + actorService::getMainActor.toResolver() } query("actorById") { - resolverKF(actorService::getActor) + actorService::getActor.toResolver() } type {