Skip to content

Commit f674fd4

Browse files
dariuszkucbrennantaylor
authored andcommitted
Force manual wirings to take precedence over wiring factory (#96)
* Force manual wirings to take precedence over wiring factory * Update directive wiring helper unit tests
1 parent 78a63e2 commit f674fd4

File tree

13 files changed

+261
-231
lines changed

13 files changed

+261
-231
lines changed

example/src/main/kotlin/com.expedia.graphql.sample/Application.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import com.expedia.graphql.TopLevelObjectDef
44
import com.expedia.graphql.sample.context.MyGraphQLContextBuilder
55
import com.expedia.graphql.sample.dataFetchers.SpringDataFetcherFactory
66
import com.expedia.graphql.sample.directives.DirectiveWiringFactory
7+
import com.expedia.graphql.sample.directives.LowercaseDirectiveWiring
78
import com.expedia.graphql.sample.exceptions.CustomDataFetcherExceptionHandler
89
import com.expedia.graphql.sample.extension.CustomSchemaGeneratorHooks
910
import com.expedia.graphql.sample.mutation.Mutation
1011
import com.expedia.graphql.sample.query.Query
1112
import com.expedia.graphql.schema.SchemaGeneratorConfig
13+
import com.expedia.graphql.schema.generator.directive.DirectiveWiringHelper
1214
import com.expedia.graphql.toSchema
1315
import com.fasterxml.jackson.module.kotlin.KotlinModule
1416
import graphql.execution.AsyncExecutionStrategy
@@ -42,7 +44,7 @@ class Application {
4244
@Bean
4345
fun schemaConfig(dataFetcherFactory: SpringDataFetcherFactory, validator: Validator, wiringFactory: DirectiveWiringFactory): SchemaGeneratorConfig = SchemaGeneratorConfig(
4446
supportedPackages = listOf("com.expedia"),
45-
hooks = CustomSchemaGeneratorHooks(validator, wiringFactory),
47+
hooks = CustomSchemaGeneratorHooks(validator, DirectiveWiringHelper(wiringFactory, mapOf("lowercase" to LowercaseDirectiveWiring()))),
4648
dataFetcherFactory = dataFetcherFactory
4749
)
4850

@@ -61,7 +63,14 @@ class Application {
6163
mutations = mutations.toTopLevelObjectDefs(),
6264
config = schemaConfig
6365
)
64-
logger.info(SchemaPrinter().print(schema))
66+
logger.info(SchemaPrinter(
67+
SchemaPrinter.Options.defaultOptions()
68+
.includeScalarTypes(true)
69+
.includeExtendedScalarTypes(true)
70+
.includeIntrospectionTypes(true)
71+
.includeSchemaDefintion(true)
72+
).print(schema)
73+
)
6574
return schema
6675
}
6776

example/src/main/kotlin/com.expedia.graphql.sample/directives/CakeOnly.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ package com.expedia.graphql.sample.directives
22

33
import com.expedia.graphql.annotations.GraphQLDirective
44

5-
@GraphQLDirective(description = "This validates string input")
5+
@GraphQLDirective(description = "This validates inputted string is equal to cake")
66
annotation class CakeOnly

example/src/main/kotlin/com.expedia.graphql.sample/directives/CakeOnlyDirectiveWiring.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ class CakeOnlyDirectiveWiring : DirectiveWiring {
99
override fun isApplicable(environment: SchemaDirectiveWiringEnvironment<*>): Boolean =
1010
environment.directive.name == getDirectiveName(CakeOnly::class)
1111

12-
1312
override fun onField(wiringEnv: SchemaDirectiveWiringEnvironment<GraphQLFieldDefinition>): GraphQLFieldDefinition {
1413
val field = wiringEnv.element
1514
val originalDataFetcher: DataFetcher<Any> = field.dataFetcher
1615
val cakeOnlyFetcher = DataFetcher<Any> { dataEnv ->
1716
val strArg: String? = dataEnv.getArgument(wiringEnv.element.arguments[0].name) as String?
18-
if (strArg != "Cake") {
17+
if (!"cake".equals(other = strArg, ignoreCase = true)) {
1918
throw RuntimeException("The cake is a lie!")
2019
}
2120
originalDataFetcher.get(dataEnv)

example/src/main/kotlin/com.expedia.graphql.sample/directives/DirectiveWiringFactory.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ class DirectiveWiringFactory : WiringFactory {
1313
override fun providesSchemaDirectiveWiring(environment: SchemaDirectiveWiringEnvironment<*>): Boolean = true
1414

1515
override fun getSchemaDirectiveWiring(environment: SchemaDirectiveWiringEnvironment<*>): SchemaDirectiveWiring? =
16-
wiring.asSequence()
17-
.filter { it.isApplicable(environment) }
18-
.singleOrNull()
19-
16+
wiring.firstOrNull {
17+
it.isApplicable(environment)
18+
}
2019
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.expedia.graphql.sample.directives
2+
3+
import com.expedia.graphql.annotations.GraphQLDirective
4+
5+
@GraphQLDirective(name = "lowercase", description = "Modifies the string field to lowercase")
6+
annotation class LowercaseDirective
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.expedia.graphql.sample.directives
2+
3+
import graphql.schema.DataFetcher
4+
import graphql.schema.GraphQLFieldDefinition
5+
import graphql.schema.idl.SchemaDirectiveWiring
6+
import graphql.schema.idl.SchemaDirectiveWiringEnvironment
7+
8+
class LowercaseDirectiveWiring : SchemaDirectiveWiring {
9+
10+
override fun onField(environment: SchemaDirectiveWiringEnvironment<GraphQLFieldDefinition>): GraphQLFieldDefinition {
11+
val field = environment.element
12+
val originalDataFetcher: DataFetcher<Any> = field.dataFetcher
13+
14+
val lowerCaseFetcher = DataFetcher<String> { dataEnv ->
15+
originalDataFetcher.get(dataEnv).toString().toLowerCase()
16+
}
17+
return field.transform { it.dataFetcher(lowerCaseFetcher) }
18+
}
19+
}

example/src/main/kotlin/com.expedia.graphql.sample/directives/StringEval.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.expedia.graphql.sample.directives
22

33
import com.expedia.graphql.annotations.GraphQLDirective
4+
import graphql.introspection.Introspection.DirectiveLocation
45

5-
@GraphQLDirective(description = "This validates string input")
6+
@GraphQLDirective(
7+
description = "This validates string input",
8+
locations = [DirectiveLocation.FIELD, DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ARGUMENT_DEFINITION])
69
annotation class StringEval(
710
val default: String = "",
811
val lowerCase: Boolean = false

example/src/main/kotlin/com.expedia.graphql.sample/directives/StringEvalDirectiveWiring.kt

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,55 @@ package com.expedia.graphql.sample.directives
22

33
import graphql.schema.DataFetcher
44
import graphql.schema.DataFetchingEnvironmentBuilder
5+
import graphql.schema.GraphQLArgument
56
import graphql.schema.GraphQLFieldDefinition
67
import graphql.schema.idl.SchemaDirectiveWiringEnvironment
78

89
class StringEvalDirectiveWiring : DirectiveWiring {
9-
private val dirName = getDirectiveName(StringEval::class)
10+
private val directiveName = getDirectiveName(StringEval::class)
1011

11-
override fun isApplicable(environment: SchemaDirectiveWiringEnvironment<*>): Boolean =
12-
(environment.element as? GraphQLFieldDefinition)?.arguments?.any { it.getDirective(dirName) != null }
13-
?: false
12+
override fun isApplicable(environment: SchemaDirectiveWiringEnvironment<*>): Boolean {
13+
val element = environment.element
14+
return when (element) {
15+
is GraphQLFieldDefinition -> element.getDirective(directiveName) != null || element.arguments.any { it.getDirective(directiveName) != null }
16+
is GraphQLArgument -> element.getDirective(directiveName) != null
17+
else -> false
18+
}
19+
}
1420

1521
override fun onField(wiringEnv: SchemaDirectiveWiringEnvironment<GraphQLFieldDefinition>): GraphQLFieldDefinition {
1622
val field = wiringEnv.element
1723
val originalDataFetcher: DataFetcher<Any> = field.dataFetcher
1824

1925
val defaultValueFetcher = DataFetcher<Any> { dataEnv ->
2026
val newArguments = HashMap(dataEnv.arguments)
21-
wiringEnv.element.arguments.asSequence()
22-
.map { gqlArg ->
23-
val strArg: String? = dataEnv.getArgument(gqlArg.name) as String?
24-
Pair(gqlArg, strArg)
25-
}
26-
.forEach { (gqlArg, value) ->
27-
if (gqlArg.getDirective(dirName).getArgument(StringEval::lowerCase.name).value as Boolean) {
28-
newArguments[gqlArg.name] = value?.toLowerCase()
29-
}
30-
if (value.isNullOrEmpty()) {
31-
newArguments[gqlArg.name] = gqlArg.getDirective(dirName).getArgument(StringEval::default.name).value as String
32-
}
33-
}
27+
wiringEnv.element.arguments.associate {
28+
Pair(it, dataEnv.getArgument(it.name) as String?)
29+
}.forEach { (graphQLArgumentType, value) ->
30+
if (graphQLArgumentType.getDirective(directiveName).getArgument(StringEval::lowerCase.name).value as Boolean) {
31+
newArguments[graphQLArgumentType.name] = value?.toLowerCase()
32+
}
33+
if (value.isNullOrEmpty()) {
34+
newArguments[graphQLArgumentType.name] = graphQLArgumentType.defaultValue
35+
}
36+
}
3437
val newEnv = DataFetchingEnvironmentBuilder.newDataFetchingEnvironment(dataEnv)
3538
.arguments(newArguments)
3639
.build()
3740
originalDataFetcher.get(newEnv)
3841
}
3942
return field.transform { it.dataFetcher(defaultValueFetcher) }
4043
}
44+
45+
override fun onArgument(wiringEnv: SchemaDirectiveWiringEnvironment<GraphQLArgument>): GraphQLArgument {
46+
val argument = wiringEnv.element
47+
val directive = wiringEnv.directive
48+
49+
val default = directive.getArgument(StringEval::default.name).value as String
50+
return if (default.isNotEmpty()) {
51+
argument.transform { it.defaultValue(default) }
52+
} else {
53+
argument
54+
}
55+
}
4156
}

example/src/main/kotlin/com.expedia.graphql.sample/extension/CustomSchemaGeneratorHooks.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.expedia.graphql.sample.extension
22

3-
import com.expedia.graphql.sample.directives.DirectiveWiringFactory
43
import com.expedia.graphql.sample.validation.DataFetcherExecutionValidator
54
import com.expedia.graphql.schema.generator.directive.DirectiveWiringHelper
65
import com.expedia.graphql.schema.hooks.DataFetcherExecutionPredicate
@@ -9,16 +8,16 @@ import graphql.language.StringValue
98
import graphql.schema.Coercing
109
import graphql.schema.GraphQLScalarType
1110
import graphql.schema.GraphQLType
12-
import java.util.*
11+
import java.util.UUID
1312
import javax.validation.Validator
1413
import kotlin.reflect.KClass
1514
import kotlin.reflect.KType
1615

1716
/**
1817
* Schema generator hook that adds additional scalar types.
1918
*/
20-
class CustomSchemaGeneratorHooks(validator: Validator, wiringFactory: DirectiveWiringFactory) : SchemaGeneratorHooks {
21-
private val directiveWiringHelper = DirectiveWiringHelper(wiringFactory)
19+
class CustomSchemaGeneratorHooks(validator: Validator, private val directiveWiringHelper: DirectiveWiringHelper) : SchemaGeneratorHooks {
20+
2221
/**
2322
* Register additional GraphQL scalar types.
2423
*/

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@ package com.expedia.graphql.sample.query
22

33
import com.expedia.graphql.annotations.GraphQLDescription
44
import com.expedia.graphql.sample.directives.CakeOnly
5+
import com.expedia.graphql.sample.directives.LowercaseDirective
56
import com.expedia.graphql.sample.directives.StringEval
67
import org.springframework.stereotype.Component
78

89
@Component
910
class CustomDirectiveQuery : Query {
1011

1112
@GraphQLDescription("Returns a message modified by directives, lower case and non-empty")
12-
fun justWhisper(@StringEval(default = "Default String", lowerCase = true) msg: String): String = msg
13+
fun justWhisper(@StringEval(default = "default string", lowerCase = true) msg: String?): String? = msg
1314

1415
@GraphQLDescription("This will only accept 'Cake' as input")
1516
@CakeOnly
1617
fun onlyCake(msg: String): String = "<3"
18+
19+
@GraphQLDescription("Returns message modified by the manually wired directive to force lowercase")
20+
@LowercaseDirective
21+
fun forceLowercaseEcho(msg: String) = msg
1722
}

0 commit comments

Comments
 (0)