Open eduardb opened 2 years ago
In my use case, even just being able to parse the custom scalars as specified in customScalarsMapping
in build.gradle
by default would be great!
@adapap can you elaborate a bit more? This should work already:
// build.gradle.kts
apollo {
service("service") {
packageName.set("com.example")
generateDataBuilders.set(true)
mapScalar("Long", "com.example.MyLong")
}
}
val data = GetCustomScalarQuery.Data {
long = MyLong(42)
}
Or do you need something else?
@martinbonnin In my case, the default fake resolver does not seem to be respecting the scalars defined in build.gradle
. For example, if I define my apollo config as such:
apollo {
service("example") {
packageName.set("com.example.app")
generateDataBuilders.set(true)
mapScalar("int64", "kotlin.Long")
// We actually define custom scalars as such:
// customScalarsMapping = rootProject.ext.universalApolloScalarAdapters
schemaFile.set(file("../schema-copied.json"))
srcDir(file("src/main/graphql/"))
}
}
When I try to use DefaultFakeResolver
with a query that uses an int64
type, I get the following error:
Don't know how to instantiate leaf int64
java.lang.IllegalStateException: Don't know how to instantiate leaf int64
at com.apollographql.apollo3.api.DefaultFakeResolver.resolveLeaf(fakeResolver.kt:269)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfNonNullType(fakeResolver.kt:212)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfType(fakeResolver.kt:156)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfNonNullType(fakeResolver.kt:209)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfType(fakeResolver.kt:156)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfType(fakeResolver.kt:151)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfNonNullType(fakeResolver.kt:209)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfType(fakeResolver.kt:156)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfType(fakeResolver.kt:151)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfNonNullType(fakeResolver.kt:197)
at com.apollographql.apollo3.api.FakeResolverKt.buildFieldOfType(fakeResolver.kt:156)
at com.apollographql.apollo3.api.FakeResolverKt.buildFakeObject(fakeResolver.kt:112)
at com.apollographql.apollo3.api.FakeResolverKt.buildData(fakeResolver.kt:327)
Update: I also get an issue using data builders where there is a conflict trying to construct the data:
Cannot access class 'com.example.app.MyQuery.InnerType'. Check your module classpath for missing or conflicting dependencies
MyQuery.Data {
user = buildUser {
innerType = buildInnerType {
name = "test"
}
}
}
@adapap thanks for sending this! As a side note for next time, can you open different issues? It helps keeping the discussion focused. But now that you're here, let's dive in!
When I try to use DefaultFakeResolver with a query that uses an int64 type, I get the following error
The DefaultFakeResolver
doesn't know about the int64 custom scalar adapter as it's registered at runtime.
You can register the int64 custom scalar adapter it at build time to have this working:
apollo {
service("example") {
// This will use the builtin LongAdapter (you can remove the call to `addCustomScalarAdapter()`)
mapScalarToKotlinLong("int64")
// ...
}
}
I also get an issue using data builders where there is a conflict trying to construct the data
That's unexpected. Can you share your schema ?
@martinbonnin I believe the issue was related to the issue described here: https://github.com/apollographql/apollo-kotlin/issues/4669
I'm curious in relation to the above - the issue is marked as closed in both this repository and in the issue filed in Google's issue tracker (https://issuetracker.google.com/issues/268218176). Is the expected resolution going forward to always include this snippet for Android modules?
outputDirConnection {
connectToAndroidSourceSet("main")
}
You can register the int64 custom scalar adapter it at build time to have this working:
apollo { service("example") { // This will use the builtin LongAdapter (you can remove the call to `addCustomScalarAdapter()`) mapScalarToKotlinLong("int64") // ... } }
@martinbonnin This solution did not solve the issue for me, and in v3.8.1 I am not able to use data builders for tests without passing in a custom resolver. I get the
Don't know how to instantiate leaf int64
error even if I manually specify all of the fields in the builder.
This is very much needed! cc @martinbonnin
I'm encountering this one as well -
In my schema module, I have:
apollo {
service("ServiceName") {
...
mapScalarToKotlinLong("ScalarName")
}
}
I experimented with adding
ApolloClient.Builder()
.addCustomScalarAdapter(ScalarName.type, LongAdapter)
But that seemed to make things worse.
I can get the tests to pass if I provide this resolver to my data builder's constructor:
class Resolver : DefaultFakeResolver(__Schema.all) {
override fun resolveLeaf(context: FakeResolverContext): Any {
return when (context.mergedField.type.rawType().name) {
"ScalarName" -> 100L
else -> super.resolveLeaf(context)
}
}
}
But, it would be sweet if mapScalarToKotlinLong
could do it alone!
For what it's worth, the generated __Schema.all
list does not include my ScalarName.type
. (Not sure if it should!)
@jamesonwilliams indeed scalars are a bit awkward because they are a runtime thing only. The codegen doesn't know how to instanciate a given custom scalar. For Long, 100L
is a valid initializer but for a date, maybe we want Instant.now()
or DateTime.parse(isoString)
, the sky is the limit in how complex that expression can be...
Use case
Using data builders when having custom scalars requires a custom
FakeResolver
that implementsresolveLeaf
for those custom scalars if you want those scalars to be generated instead of having to manually specify them for each operation. The problem is that you need to pass this every single time you want to use a data builder for an operation, which can become a bit tiresome, and error-prone (e.g. if you forget to actually pass it down, and your tests start failing 😄).Describe the solution you'd like
No strong opinions on how this should look like, I imagine that it could be a Gradle config like
customFakeResolver.set("fully.qualified.class.name")
, or some other API to specify a class that implementsFakeResolver
that would be used instead ofDefaultFakeResolver
by each generated data builder.PS: I would keep the
DefaultFakeResolver
class though, as it's very useful to delegate to it for non-custom scalar leafs.