Skip to content
This repository has been archived by the owner on May 16, 2019. It is now read-only.

enable building graphql schema using KFunction method references #61

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ object BenchmarkSchema {

val threeResolver : ()-> ModelThree = { ModelThree("", ones.map { ModelTwo(it, it.quantity..10) }) }

object HasOneResolver {
fun oneResolver(): List<ModelOne> {
return ones
}
}

fun create(block : SchemaBuilder<Unit>.()-> Unit): Schema = KGraphQL.schema {
block()
query("one"){
Expand All @@ -32,5 +38,8 @@ object BenchmarkSchema {
query("three"){
resolver(threeResolver)
}
query("threeKF"){
HasOneResolver::oneResolver.toResolver()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -25,6 +26,8 @@ class QueryOrMutationDSL(
return ResolverDSL(this)
}

fun <T>KFunction<T>.toResolver() = resolver(FunctionWrapper.on(this))

fun <T>resolver(function: () -> T) = resolver(FunctionWrapper.on(function))

fun <T, R>resolver(function: (R) -> T) = resolver(FunctionWrapper.on(function))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -20,6 +20,9 @@ import kotlin.reflect.jvm.reflect
interface FunctionWrapper <T>{
//lots of boilerplate here, because kotlin-reflect doesn't support invoking lambdas, local and anonymous functions yet
companion object {
fun <T> on (function : KFunction<T>) : FunctionWrapper<T>
= FunctionWrapper.ArityN(function)

fun <T> on (function : () -> T) : FunctionWrapper<T>
= FunctionWrapper.ArityZero(function)

Expand Down Expand Up @@ -119,6 +122,17 @@ interface FunctionWrapper <T>{
}
}

class ArityN<T>(override val kFunction: KFunction<T>): Base<T>() {
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<T>(val implementation : ()-> T, override val hasReceiver: Boolean = false ) : Base<T>() {
override val kFunction: KFunction<T> by lazy { implementation.reflect()!! }
override fun arity(): Int = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Actor> {
property<Actor>("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 {
Expand Down