Skip to content
New issue

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

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

Already on GitHub? # 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.")
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.")
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,10 @@ 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") }
}
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,12 @@
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, 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()
.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()
}
}
}