Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provider for creating missing resolver data fetcher to provide options and field definition to factory #742

10 changes: 10 additions & 0 deletions src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package graphql.kickstart.tools
import com.fasterxml.jackson.databind.ObjectMapper
import graphql.kickstart.tools.proxy.*
import graphql.kickstart.tools.relay.RelayConnectionFactory
import graphql.kickstart.tools.resolver.MissingResolverDataFetcherProvider
import graphql.kickstart.tools.util.JavaType
import graphql.kickstart.tools.util.ParameterizedTypeImpl
import graphql.schema.DataFetcher
Expand All @@ -23,7 +24,9 @@ data class SchemaParserOptions internal constructor(
val contextClass: Class<*>?,
val genericWrappers: List<GenericWrapper>,
val allowUnimplementedResolvers: Boolean,
@Deprecated("Use missingResolverDataFetcherProvider instead.", level = DeprecationLevel.WARNING)
oryan-block marked this conversation as resolved.
Show resolved Hide resolved
val missingResolverDataFetcher: DataFetcher<Any?>?,
val missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider?,
val objectMapperProvider: PerFieldObjectMapperProvider,
val proxyHandlers: List<ProxyHandler>,
val inputArgumentOptionalDetectOmission: Boolean,
Expand Down Expand Up @@ -53,6 +56,7 @@ data class SchemaParserOptions internal constructor(
private var useDefaultGenericWrappers = true
private var allowUnimplementedResolvers = false
private var missingResolverDataFetcher: DataFetcher<Any?>? = null
private var missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider? = null
private var objectMapperProvider: PerFieldObjectMapperProvider = PerFieldConfiguringObjectMapperProvider()
private val proxyHandlers: MutableList<ProxyHandler> = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler(), WeldProxyHandler())
private var inputArgumentOptionalDetectOmission = false
Expand Down Expand Up @@ -88,10 +92,15 @@ data class SchemaParserOptions internal constructor(
this.allowUnimplementedResolvers = allowUnimplementedResolvers
}

@Deprecated("Use missingResolverDataFetcherProvider instead.", level = DeprecationLevel.WARNING)
timward60 marked this conversation as resolved.
Show resolved Hide resolved
fun missingResolverDataFetcher(missingResolverDataFetcher: DataFetcher<Any?>?) = this.apply {
this.missingResolverDataFetcher = missingResolverDataFetcher
}

fun missingResolverDataFetcherProvider(missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider?) = this.apply {
this.missingResolverDataFetcherProvider = missingResolverDataFetcherProvider
}

fun inputArgumentOptionalDetectOmission(inputArgumentOptionalDetectOmission: Boolean) = this.apply {
this.inputArgumentOptionalDetectOmission = inputArgumentOptionalDetectOmission
}
Expand Down Expand Up @@ -175,6 +184,7 @@ data class SchemaParserOptions internal constructor(
wrappers,
allowUnimplementedResolvers,
missingResolverDataFetcher,
missingResolverDataFetcherProvider,
objectMapperProvider,
proxyHandlers,
inputArgumentOptionalDetectOmission,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
}

private fun missingFieldResolver(field: FieldDefinition, searches: List<Search>, scanProperties: Boolean): FieldResolver {
return if (options.allowUnimplementedResolvers || options.missingResolverDataFetcher != null) {
return if (options.allowUnimplementedResolvers
|| options.missingResolverDataFetcher != null
|| options.missingResolverDataFetcherProvider != null) {
if (options.allowUnimplementedResolvers) {
log.warn("Missing resolver for field: $field")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ internal class MissingFieldResolver(
options: SchemaParserOptions
) : FieldResolver(field, FieldResolverScanner.Search(Any::class.java, MissingResolverInfo(), null), options, Any::class.java) {

private val missingResolverDataFetcherProvider: MissingResolverDataFetcherProvider = options.missingResolverDataFetcherProvider ?: MissingResolverDataFetcherProvider { _, options -> options.missingResolverDataFetcher ?: DataFetcher<Any> { TODO("Schema resolver not implemented") } }
timward60 marked this conversation as resolved.
Show resolved Hide resolved

override fun scanForMatches(): List<TypeClassMatcher.PotentialMatch> = listOf()
override fun createDataFetcher(): DataFetcher<*> =
options.missingResolverDataFetcher ?: DataFetcher<Any> { TODO("Schema resolver not implemented") }
override fun createDataFetcher(): DataFetcher<*> = missingResolverDataFetcherProvider.createDataFetcher(field, options)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package graphql.kickstart.tools.resolver

import graphql.kickstart.tools.SchemaParserOptions
import graphql.language.FieldDefinition
import graphql.schema.DataFetcher

/**
* Provider for missing resolver data fetchers.
*/
fun interface MissingResolverDataFetcherProvider {
fun createDataFetcher(field: FieldDefinition,
timward60 marked this conversation as resolved.
Show resolved Hide resolved
options: SchemaParserOptions
): DataFetcher<*>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package graphql.kickstart.tools

import graphql.GraphQL
import graphql.kickstart.tools.resolver.FieldResolverError
import graphql.kickstart.tools.resolver.MissingResolverDataFetcherProvider
import graphql.language.FieldDefinition
import graphql.schema.DataFetcher
import graphql.schema.DataFetchingEnvironment
import org.junit.Test
Expand Down Expand Up @@ -65,9 +67,63 @@ class MissingFieldResolverTest {
assertEquals(result.getData(), expected)
}

@Test
fun `should call missing resolver data fetcher provider if provided`() {
val missingResolverDataFetcherProvider = TestMissingResolverDataFetcherProvider();
val options = SchemaParserOptions.newOptions()
timward60 marked this conversation as resolved.
Show resolved Hide resolved
.missingResolverDataFetcherProvider(missingResolverDataFetcherProvider)
.build();
val schema = SchemaParser.newParser()
.schemaString(
"""
type Query {
implementedField(input: String): String
missingField(input: Int): Int
}
"""
)
.resolvers(object : GraphQLQueryResolver {
fun implementedField(input: Optional<String>) = input.toString()
})
.options(options)
.build()
.makeExecutableSchema()

val gql = GraphQL.newGraphQL(schema).build()

val result = gql.execute(
"""
query {
implementedField(input: "test-value")
missingField(input: 1)
}
""")

val expected = mapOf(
"implementedField" to "Optional[test-value]",
"missingField" to 1
)

assertEquals(result.getData(), expected)

assertEquals(missingResolverDataFetcherProvider.field?.name, "missingField")
assertEquals(missingResolverDataFetcherProvider.options, options)
}

class TestMissingResolverDataFetcher : DataFetcher<Any?> {
override fun get(env: DataFetchingEnvironment?): Any? {
return env?.getArgument("input")
}
}

class TestMissingResolverDataFetcherProvider : MissingResolverDataFetcherProvider {
var field: FieldDefinition? = null
var options: SchemaParserOptions? = null

override fun createDataFetcher(field: FieldDefinition, options: SchemaParserOptions): DataFetcher<*> {
this.field = field;
this.options = options;
return TestMissingResolverDataFetcher()
}
}
}