Skip to content

Commit 88c6eeb

Browse files
smyrickdariuszkuc
authored andcommitted
feat: pass DataFetcherEnvironment to arguments (#173)
* feat: pass DataFetcherEnvironment to arguments test: update test to fix detekt issues * address pr comments
1 parent 2928c8c commit 88c6eeb

File tree

9 files changed

+84
-11
lines changed

9 files changed

+84
-11
lines changed

example/src/main/kotlin/com/expedia/graphql/sample/model/ContextualResponse.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ package com.expedia.graphql.sample.model
33
import com.expedia.graphql.annotations.GraphQLDescription
44

55
@GraphQLDescription("simple response that contains value read from context")
6-
data class ContextualResponse(val passedInValue: Int, val contextValue: String)
6+
data class ContextualResponse(val passedInValue: Int, val contextValue: String)

example/src/main/kotlin/com/expedia/graphql/sample/query/ContextualQuery.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.springframework.stereotype.Component
1111
* schema and will be automatically autowired at runtime using value from the environment.
1212
*
1313
* @see com.expedia.graphql.sample.context.MyGraphQLContextBuilder
14-
* @see com.expedia.graphql.FunctionDataFetcher
14+
* @see com.expedia.graphql.execution.FunctionDataFetcher
1515
*/
1616
@Component
1717
class ContextualQuery: Query {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.expedia.graphql.sample.query
2+
3+
import graphql.schema.DataFetchingEnvironment
4+
import org.springframework.stereotype.Component
5+
6+
@Component
7+
class EnvironmentQuery : Query {
8+
fun nestedEnvironment(value: Int) = NestedNode(value)
9+
}
10+
11+
data class NestedNode(
12+
val value: Int,
13+
val parentValue: Int? = null
14+
) {
15+
fun nested(environment: DataFetchingEnvironment, value: Int): NestedNode {
16+
val parentValue: Int? = if (environment.executionStepInfo.hasParent()) {
17+
environment.executionStepInfo.parent.getArgument("value")
18+
} else {
19+
null
20+
}
21+
22+
return NestedNode(value, parentValue)
23+
}
24+
}

src/main/kotlin/com/expedia/graphql/execution/FunctionDataFetcher.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expedia.graphql.execution
22

33
import com.expedia.graphql.generator.extensions.getName
4+
import com.expedia.graphql.generator.extensions.isDataFetchingEnvironment
45
import com.expedia.graphql.generator.extensions.isGraphQLContext
56
import com.expedia.graphql.generator.extensions.javaTypeClass
67
import com.fasterxml.jackson.databind.ObjectMapper
@@ -51,14 +52,18 @@ class FunctionDataFetcher(
5152
}
5253

5354
private fun mapParameterToValue(param: KParameter, environment: DataFetchingEnvironment): Any? =
54-
if (param.isGraphQLContext()) {
55-
environment.getContext()
56-
} else {
57-
val name = param.getName()
58-
val klazz = param.javaTypeClass()
59-
val value = objectMapper.convertValue(environment.arguments[name], klazz)
60-
val predicateResult = executionPredicate?.evaluate(value = value, parameter = param, environment = environment)
61-
62-
predicateResult ?: value
55+
when {
56+
param.isGraphQLContext() -> environment.getContext()
57+
param.isDataFetchingEnvironment() -> environment
58+
else -> convertParameterValue(param, environment)
6359
}
60+
61+
private fun convertParameterValue(param: KParameter, environment: DataFetchingEnvironment): Any? {
62+
val name = param.getName()
63+
val klazz = param.javaTypeClass()
64+
val value = objectMapper.convertValue(environment.arguments[name], klazz)
65+
val predicateResult = executionPredicate?.evaluate(value = value, parameter = param, environment = environment)
66+
67+
return predicateResult ?: value
68+
}
6469
}

src/main/kotlin/com/expedia/graphql/generator/extensions/kParameterExtensions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package com.expedia.graphql.generator.extensions
22

33
import com.expedia.graphql.annotations.GraphQLContext
44
import com.expedia.graphql.exceptions.CouldNotGetNameOfKParameterException
5+
import graphql.schema.DataFetchingEnvironment
56
import kotlin.reflect.KParameter
67
import kotlin.reflect.full.findAnnotation
78

89
internal fun KParameter.isInterface() = this.type.getKClass().isInterface()
910

1011
internal fun KParameter.isGraphQLContext() = this.findAnnotation<GraphQLContext>() != null
1112

13+
internal fun KParameter.isDataFetchingEnvironment() = this.type.classifier == DataFetchingEnvironment::class
14+
1215
@Throws(CouldNotGetNameOfKParameterException::class)
1316
internal fun KParameter.getName(): String =
1417
this.name ?: throw CouldNotGetNameOfKParameterException(this)

src/main/kotlin/com/expedia/graphql/generator/types/FunctionTypeBuilder.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.expedia.graphql.generator.extensions.getDeprecationReason
77
import com.expedia.graphql.generator.extensions.getGraphQLDescription
88
import com.expedia.graphql.generator.extensions.getName
99
import com.expedia.graphql.generator.extensions.getTypeOfFirstArgument
10+
import com.expedia.graphql.generator.extensions.isDataFetchingEnvironment
1011
import com.expedia.graphql.generator.extensions.isGraphQLContext
1112
import com.expedia.graphql.generator.extensions.isInterface
1213
import com.expedia.graphql.generator.extensions.safeCast
@@ -37,6 +38,7 @@ internal class FunctionTypeBuilder(generator: SchemaGenerator) : TypeBuilder(gen
3738

3839
fn.valueParameters
3940
.filterNot { it.isGraphQLContext() }
41+
.filterNot { it.isDataFetchingEnvironment() }
4042
.forEach {
4143
// deprecation of arguments is currently unsupported: https://github.com/facebook/graphql/issues/197
4244
builder.argument(argument(it))

src/test/kotlin/com/expedia/graphql/execution/FunctionDataFetcherTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ internal class FunctionDataFetcherTest {
2020
fun printList(items: List<String>) = items.joinToString(separator = ":")
2121

2222
fun context(@GraphQLContext string: String) = string
23+
24+
fun dataFetchingEnvironment(environment: DataFetchingEnvironment) = environment.field.name
2325
}
2426

2527
@Test
@@ -93,4 +95,14 @@ internal class FunctionDataFetcherTest {
9395
dataFetcher.get(mockEnvironmet)
9496
}
9597
}
98+
99+
@Test
100+
fun `dataFetchingEnvironement is passed as an argument`() {
101+
val dataFetcher = FunctionDataFetcher(target = MyClass(), fn = MyClass::dataFetchingEnvironment)
102+
val mockEnvironmet: DataFetchingEnvironment = mockk()
103+
every { mockEnvironmet.field } returns mockk {
104+
every { name } returns "fooBarBaz"
105+
}
106+
assertEquals(expected = "fooBarBaz", actual = dataFetcher.get(mockEnvironmet))
107+
}
96108
}

src/test/kotlin/com/expedia/graphql/generator/extensions/KParameterExtensionsKtTest.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.expedia.graphql.generator.extensions
22

33
import com.expedia.graphql.annotations.GraphQLDescription
44
import com.expedia.graphql.exceptions.CouldNotGetNameOfKParameterException
5+
import graphql.schema.DataFetchingEnvironment
56
import io.mockk.every
67
import io.mockk.mockk
78
import org.junit.jupiter.api.Test
@@ -29,6 +30,8 @@ internal class KParameterExtensionsKtTest {
2930
internal fun noDescription(myClass: MyClass) = myClass
3031

3132
internal fun paramDescription(@GraphQLDescription("param description") myClass: MyClass) = myClass
33+
34+
internal fun dataFetchingEnvironment(environment: DataFetchingEnvironment) = environment.field.name
3235
}
3336

3437
@Test
@@ -69,4 +72,16 @@ internal class KParameterExtensionsKtTest {
6972
val param = Container::interfaceInput.findParameterByName("myInterface")
7073
assertTrue(param?.isInterface().isTrue())
7174
}
75+
76+
@Test
77+
fun `valid DataFetchingEnvironment passes`() {
78+
val param = Container::dataFetchingEnvironment.findParameterByName("environment")
79+
assertTrue(param?.isDataFetchingEnvironment().isTrue())
80+
}
81+
82+
@Test
83+
fun `invalid DataFetchingEnvironment fails`() {
84+
val param = Container::interfaceInput.findParameterByName("myInterface")
85+
assertFalse(param?.isDataFetchingEnvironment().isTrue())
86+
}
7287
}

src/test/kotlin/com/expedia/graphql/generator/types/FunctionTypeBuilderTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.expedia.graphql.annotations.GraphQLDirective
66
import com.expedia.graphql.execution.FunctionDataFetcher
77
import graphql.Scalars
88
import graphql.introspection.Introspection
9+
import graphql.schema.DataFetchingEnvironment
910
import graphql.schema.GraphQLNonNull
1011
import org.junit.jupiter.api.Test
1112
import java.util.UUID
@@ -52,6 +53,8 @@ internal class FunctionTypeBuilderTest : TypeTestHelper() {
5253
fun context(@GraphQLContext context: String, string: String) = "$context and $string"
5354

5455
fun completableFuture(num: Int): CompletableFuture<Int> = CompletableFuture.completedFuture(num)
56+
57+
fun dataFetchingEnvironment(environment: DataFetchingEnvironment): String = environment.field.name
5558
}
5659

5760
@Test
@@ -160,4 +163,13 @@ internal class FunctionTypeBuilderTest : TypeTestHelper() {
160163
assertEquals(expected = 1, actual = result.arguments.size)
161164
assertEquals("Int", (result.type as? GraphQLNonNull)?.wrappedType?.name)
162165
}
166+
167+
@Test
168+
fun `DataFetchingEnvironment argument type is ignored`() {
169+
val kFunction = Happy::dataFetchingEnvironment
170+
val result = builder.function(fn = kFunction)
171+
172+
assertEquals(expected = 0, actual = result.arguments.size)
173+
assertEquals("String", (result.type as? GraphQLNonNull)?.wrappedType?.name)
174+
}
163175
}

0 commit comments

Comments
 (0)