Skip to content

Commit e94e736

Browse files
committed
Introduce support for custom context type for resolvers
1 parent 613bbeb commit e94e736

35 files changed

+306
-103
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
build
22
.gradle
3-
.idea
3+
.idea
4+
/out

README.MD

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Build Status](https://travis-ci.org/pgutkowski/KGraphQL.svg?branch=master)](https://travis-ci.org/pgutkowski/KGraphQL)
44
[![codebeat badge](https://codebeat.co/badges/b26d3c87-7cd1-4358-93cd-45d395669bdc)](https://codebeat.co/projects/github-com-pgutkowski-kgraphql-master)
55
[![Coverage Status](https://coveralls.io/repos/github/pgutkowski/KGraphQL/badge.svg?branch=master)](https://coveralls.io/github/pgutkowski/KGraphQL?branch=master)
6-
[ ![Download](https://api.bintray.com/packages/pgutkowski/Maven/KGraphQL/images/download.svg) ](https://bintray.com/pgutkowski/Maven/KGraphQL/_latestVersion)
6+
[![Download](https://api.bintray.com/packages/pgutkowski/Maven/KGraphQL/images/download.svg) ](https://bintray.com/pgutkowski/Maven/KGraphQL/_latestVersion)
77
[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)
88

99
KGraphQL is [Kotlin](https://kotlinlang.org/) implementation of [GraphQL](http://graphql.org/). It provides rich DSL to setup GraphQL schema.

build.gradle

+1-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ group 'com.github.pgutkowski'
22
version '0.2.3'
33

44
buildscript {
5-
ext.kotlin_version = '1.1.3'
5+
ext.kotlin_version = '1.1.4'
66

77
repositories {
88
mavenCentral()
@@ -30,9 +30,6 @@ apply plugin: "com.jfrog.bintray"
3030

3131
repositories {
3232
mavenCentral()
33-
maven {
34-
url "http://dl.bintray.com/kotlin/kotlin-eap-1.1"
35-
}
3633
jcenter()
3734
}
3835

src/jmh/kotlin/com/github/pgutkowski/kgraphql/BenchmarkSchema.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object BenchmarkSchema {
2121

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

24-
fun create(block : SchemaBuilder.()-> Unit): Schema = KGraphQL.schema {
24+
fun create(block : SchemaBuilder<Unit>.()-> Unit): Schema<Unit> = KGraphQL.schema {
2525
block()
2626
query("one"){
2727
resolver(oneResolver)

src/jmh/kotlin/com/github/pgutkowski/kgraphql/ParallelExecutionBenchmark.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit
2222
@Fork(value = 5)
2323
open class ParallelExecutionBenchmark {
2424

25-
var schema : Schema = KGraphQL.schema { }
25+
var schema : Schema<Unit> = KGraphQL.schema { }
2626

2727
@Setup
2828
fun setup(){

src/jmh/kotlin/com/github/pgutkowski/kgraphql/RequestCachingBenchmark.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ open class RequestCachingBenchmark {
2323
@Param("true", "false")
2424
var caching = true
2525

26-
lateinit var schema : Schema
26+
lateinit var schema : Schema<Unit>
2727

2828
@Setup
2929
fun setup(){

src/jmh/kotlin/com/github/pgutkowski/kgraphql/SimpleExecutionOverheadBenchmark.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ open class SimpleExecutionOverheadBenchmark {
2828
@Param("true", "false")
2929
var withKGraphQL = true
3030

31-
lateinit var schema : Schema
31+
lateinit var schema : Schema<Unit>
3232

3333
lateinit var objectMapper : ObjectMapper
3434

src/main/kotlin/com/github/pgutkowski/kgraphql/KGraphQL.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ package com.github.pgutkowski.kgraphql
22

33
import com.github.pgutkowski.kgraphql.schema.Schema
44
import com.github.pgutkowski.kgraphql.schema.dsl.SchemaBuilder
5+
import kotlin.reflect.KClass
56

67

78
class KGraphQL {
89
companion object {
9-
fun schema(init : SchemaBuilder.() -> Unit) : Schema {
10-
return SchemaBuilder(init).build()
10+
fun schema(init : SchemaBuilder<Unit>.() -> Unit) = schema(Unit::class, init)
11+
12+
/**
13+
* accepts instance of [KClass], instead of reified generic to avoid method signature clash
14+
*/
15+
fun <Context : Any> schema(contextClass: KClass<Context>, init : SchemaBuilder<Context>.() -> Unit) : Schema<Context> {
16+
return SchemaBuilder(init).build(contextClass)
1117
}
1218
}
1319
}

src/main/kotlin/com/github/pgutkowski/kgraphql/request/Variables.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import kotlin.reflect.KType
1010

1111
@Suppress("UNCHECKED_CAST")
1212
data class Variables(
13-
private val typeDefinitionProvider: LookupSchema,
13+
private val typeDefinitionProvider: LookupSchema<*>,
1414
private val variablesJson: VariablesJson,
1515
private val variables: List<OperationVariable>?
1616
) {

src/main/kotlin/com/github/pgutkowski/kgraphql/request/VariablesJson.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import kotlin.reflect.jvm.jvmErasure
1414
/**
1515
* Represents already parsed variables json
1616
*/
17-
interface VariablesJson{
17+
interface VariablesJson {
1818

1919
fun <T : Any>get(kClass: KClass<T>, kType: KType, key : String) : T?
2020

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/DefaultSchema.kt

+11-6
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@ import kotlin.reflect.KType
1717
import kotlin.reflect.full.starProjectedType
1818
import kotlin.reflect.jvm.jvmErasure
1919

20-
class DefaultSchema(
20+
class DefaultSchema<Context : Any>(
21+
internal val contextClass: KClass<Context>,
2122
internal val configuration: SchemaConfiguration,
2223
internal val model : SchemaModel
23-
) : Schema, __Schema by model, LookupSchema {
24+
) : Schema<Context>, __Schema by model, LookupSchema<Context> {
2425

2526
companion object {
2627
const val OPERATION_NAME_PARAM = "operationName"
2728
}
2829

29-
val requestExecutor : RequestExecutor = ParallelRequestExecutor(this)
30+
val requestExecutor : RequestExecutor<Context> = ParallelRequestExecutor(this)
3031

3132
val requestInterpreter : RequestInterpreter = RequestInterpreter(model)
3233

@@ -39,7 +40,7 @@ class DefaultSchema(
3940
DocumentParser()
4041
}
4142

42-
override fun execute(request: String, variables: String?): String {
43+
override fun execute(request: String, variables: String?, context: Context?): String {
4344
val parsedVariables = variables
4445
?.let { VariablesJson.Defined(configuration.objectMapper, variables) }
4546
?: VariablesJson.Empty()
@@ -50,7 +51,11 @@ class DefaultSchema(
5051
throw RequestException("Must provide any operation")
5152
}
5253
1 -> {
53-
return requestExecutor.execute(requestInterpreter.createExecutionPlan(operations.first()), parsedVariables)
54+
return requestExecutor.execute(
55+
plan = requestInterpreter.createExecutionPlan(operations.first()),
56+
variables = parsedVariables,
57+
context = context
58+
)
5459
}
5560
else -> {
5661
if(operations.any { it.name == null }){
@@ -64,7 +69,7 @@ class DefaultSchema(
6469
val executionPlan = executionPlans[operationName]
6570
?: throw RequestException("Must provide an operation name from: ${executionPlans.keys}, found $operationName")
6671

67-
return requestExecutor.execute(executionPlan, parsedVariables)
72+
return requestExecutor.execute(executionPlan, parsedVariables, context)
6873
}
6974
}
7075
}

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/Schema.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package com.github.pgutkowski.kgraphql.schema
33
import com.github.pgutkowski.kgraphql.schema.introspection.__Schema
44

55

6-
interface Schema : __Schema {
7-
fun execute(request: String, variables: String? = null) : String
6+
interface Schema<Context> : __Schema {
7+
fun execute(request: String, variables: String? = null, context: Context? = null) : String
8+
9+
fun execute(request: String, context: Context) : String = execute(request, null, context)
810
}

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/PropertyDSL.kt

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class PropertyDSL<out T, R>(val name : String, block : PropertyDSL<T, R>.() -> U
2828

2929
fun <E, W, Q>resolver(function: (T, E, W, Q) -> R) = resolver(FunctionWrapper.on(function, true))
3030

31+
fun <E, W, Q, A>resolver(function: (T, E, W, Q, A) -> R) = resolver(FunctionWrapper.on(function, true))
32+
33+
fun <E, W, Q, A, S>resolver(function: (T, E, W, Q, A, S) -> R) = resolver(FunctionWrapper.on(function, true))
34+
3135
fun toKQLProperty() = PropertyDef.Function(
3236
name = name,
3337
resolver = functionWrapper,

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/QueryOrMutationDSL.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import com.github.pgutkowski.kgraphql.schema.model.MutationDef
66
import com.github.pgutkowski.kgraphql.schema.model.QueryDef
77

88

9-
class QueryOrMutationDSL(val name : String, block : QueryOrMutationDSL.() -> Unit) : DepreciableItemDSL(), ResolverDSL.Target {
9+
class QueryOrMutationDSL<Context : Any>(
10+
val name : String,
11+
block : QueryOrMutationDSL<Context>.() -> Unit
12+
) : DepreciableItemDSL(), ResolverDSL.Target {
1013

1114
private val inputValues = mutableListOf<InputValueDef<*>>()
1215

@@ -31,6 +34,10 @@ class QueryOrMutationDSL(val name : String, block : QueryOrMutationDSL.() -> Uni
3134

3235
fun <T, R, E, W, Q>resolver(function: (R, E, W, Q) -> T) = resolver(FunctionWrapper.on(function))
3336

37+
fun <T, R, E, W, Q, A>resolver(function: (R, E, W, Q, A) -> T) = resolver(FunctionWrapper.on(function))
38+
39+
fun <T, R, E, W, Q, A, S>resolver(function: (R, E, W, Q, A, S) -> T) = resolver(FunctionWrapper.on(function))
40+
3441
override fun addInputValues(inputValues: Collection<InputValueDef<*>>) {
3542
this.inputValues.addAll(inputValues)
3643
}

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/SchemaBuilder.kt

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import kotlin.reflect.KClass
1111
/**
1212
* SchemaBuilder exposes rich DSL to setup GraphQL schema
1313
*/
14-
class SchemaBuilder(private val init: SchemaBuilder.() -> Unit) {
14+
class SchemaBuilder<Context : Any>(private val init: SchemaBuilder<Context>.() -> Unit) {
1515

1616
private val model = MutableSchemaDefinition()
1717

1818
private var configuration = SchemaConfigurationDSL()
1919

20-
fun build(): Schema {
20+
fun build(kClass: KClass<Context>): Schema<Context> {
2121
init()
22-
return SchemaCompilation(configuration.build(), model.toSchemaDefinition()).perform()
22+
return SchemaCompilation(kClass, configuration.build(), model.toSchemaDefinition()).perform()
2323
}
2424

2525
fun configure(block: SchemaConfigurationDSL.() -> Unit){
@@ -30,11 +30,11 @@ class SchemaBuilder(private val init: SchemaBuilder.() -> Unit) {
3030
// OPERATIONS
3131
//================================================================================
3232

33-
fun query(name : String, init: QueryOrMutationDSL.() -> Unit){
33+
fun query(name : String, init: QueryOrMutationDSL<Context>.() -> Unit){
3434
model.addQuery(QueryOrMutationDSL(name, init).toKQLQuery())
3535
}
3636

37-
fun mutation(name : String, init: QueryOrMutationDSL.() -> Unit){
37+
fun mutation(name : String, init: QueryOrMutationDSL<Context>.() -> Unit){
3838
model.addMutation(QueryOrMutationDSL(name, init).toKQLMutation())
3939
}
4040

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/TypeDSL.kt

+8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ open class TypeDSL<T : Any>(private val supportedUnions: Collection<TypeDef.Unio
3434
transformationProperties.add(Transformation(kProperty, FunctionWrapper.on(function, true)))
3535
}
3636

37+
fun <R, E, W, Q, A> transformation(kProperty: KProperty1<T, R>, function: (R, E, W, Q, A) -> R) {
38+
transformationProperties.add(Transformation(kProperty, FunctionWrapper.on(function, true)))
39+
}
40+
41+
fun <R, E, W, Q, A, S> transformation(kProperty: KProperty1<T, R>, function: (R, E, W, Q, A, S) -> R) {
42+
transformationProperties.add(Transformation(kProperty, FunctionWrapper.on(function, true)))
43+
}
44+
3745
fun property(kProperty: KProperty1<T, *>, block : KotlinPropertyDSL<T>.() -> Unit){
3846
val dsl = KotlinPropertyDSL(kProperty, block)
3947
describedKotlinProperties[kProperty] = dsl.toKQLProperty()

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/dsl/UnionPropertyDSL.kt

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class UnionPropertyDSL<T>(val name : String, block: UnionPropertyDSL<T>.() -> Un
3131

3232
fun <E, W, Q>resolver(function: (T, E, W, Q) -> Any?) = resolver(FunctionWrapper.on(function, true))
3333

34+
fun <E, W, Q, A>resolver(function: (T, E, W, Q, A) -> Any?) = resolver(FunctionWrapper.on(function, true))
35+
36+
fun <E, W, Q, A, S>resolver(function: (T, E, W, Q, A, S) -> Any?) = resolver(FunctionWrapper.on(function, true))
37+
3438
fun toKQLProperty(union : TypeDef.Union) = PropertyDef.Union (
3539
name = name,
3640
resolver = functionWrapper,

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/execution/ArgumentTransformer.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import kotlin.reflect.KType
1212
import kotlin.reflect.jvm.jvmErasure
1313

1414

15-
open class ArgumentTransformer(val schema : DefaultSchema) {
15+
open class ArgumentTransformer(val schema : DefaultSchema<*>) {
1616

1717
fun transformValue(type: Type, value: String, variables: Variables) : Any? {
1818
val kType = type.toKType()

src/main/kotlin/com/github/pgutkowski/kgraphql/schema/execution/ArgumentsHandler.kt

+9-5
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import com.github.pgutkowski.kgraphql.schema.introspection.TypeKind
99
import com.github.pgutkowski.kgraphql.schema.structure2.InputValue
1010

1111

12-
internal class ArgumentsHandler(schema : DefaultSchema) : ArgumentTransformer(schema) {
12+
internal class ArgumentsHandler<in Context: Any>(schema : DefaultSchema<Context>) : ArgumentTransformer(schema) {
1313

1414
fun transformArguments (
1515
funName: String,
1616
inputValues: List<InputValue<*>>,
1717
args: Arguments?,
18-
variables: Variables
18+
variables: Variables,
19+
requestContext: Context?
1920
) : List<Any?>{
2021
val unsupportedArguments = args?.filter { arg -> inputValues.none { value -> value.name == arg.key }}
2122

@@ -28,24 +29,27 @@ internal class ArgumentsHandler(schema : DefaultSchema) : ArgumentTransformer(sc
2829
return inputValues.map { parameter ->
2930
val value = args?.get(parameter.name)
3031

32+
parameter.type.isInstance(requestContext)
3133
when {
34+
//inject request context
35+
parameter.type.isInstance(requestContext) -> requestContext
3236
value == null && parameter.type.kind != TypeKind.NON_NULL -> parameter.default
3337
value == null && parameter.type.kind == TypeKind.NON_NULL -> {
34-
parameter.default ?: throw RequestException (
38+
parameter.default ?: throw RequestException(
3539
"argument '${parameter.name}' of type ${schema.typeReference(parameter.type)} " +
3640
"on field '$funName' is not nullable, value cannot be null"
3741
)
3842
}
3943
value is String -> {
4044
val transformedValue = transformPropertyValue(parameter, value, variables)
41-
if(transformedValue == null && parameter.type.isNotNullable()){
45+
if (transformedValue == null && parameter.type.isNotNullable()) {
4246
throw RequestException("argument ${parameter.name} is not optional, value cannot be null")
4347
}
4448
transformedValue
4549
}
4650
value is List<*> && parameter.type.isList() -> {
4751
value.map { element ->
48-
if(element is String){
52+
if (element is String) {
4953
transformCollectionElementValue(parameter, element, variables)
5054
} else {
5155
throw ExecutionException("Unexpected non-string list element")

0 commit comments

Comments
 (0)