graphql-java-tools icon indicating copy to clipboard operation
graphql-java-tools copied to clipboard

Generic wrapper for Arrow library Option

Open Herlevsen opened this issue 4 years ago • 4 comments

Hi,

I am trying to create a generic wrapper for the Option type in the Kotlin library, Arrow.

I get the following error: Can't resolve value (/user/register/errors) : type mismatch error, expected type LIST got class arrow.core.None

The error makes sense to me: I am returning an instance of arrow.core.None. "/user/register/errors" is a nullable list of the Error type. GraphQL java tools does not understand that i want to convert the None instance to null.

Im worried if this is even possible at the moment? I was looking at the source code, and it seems that Javas Optional type is handled as a special case, not just a generic wrapper (i think).

I'm hoping someone can tell me if this is possible at the moment, and if not what it would take to make it possible.

Apologies if it is documented somewhere, i couldn't find it :-(

Here is the relevant code:

@Configuration
class GraphQLConfiguration {
  @ExperimentalCoroutinesApi
  @Bean
  fun options(): SchemaParserOptions.Builder {
    return SchemaParserOptions.newOptions().apply {
      genericWrappers(
        optionGenericWrapper,
        noneGenericWrapper,
        justGenericWrapper
      )
    }
  }
}

val optionGenericWrapper = SchemaParserOptions.GenericWrapper.withTransformer(
  Option::class.java,
  0,
  { result, _ -> result.orNull() }
)

val noneGenericWrapper = SchemaParserOptions.GenericWrapper.withTransformer(
  None::class.java,
  0,
  { _, _ -> null }
)

val justGenericWrapper = SchemaParserOptions.GenericWrapper.withTransformer(
  Some::class.java,
  0,
  { result, _ -> result.orNull() }
)

The relevant schema type looks like:

type RegisterUserPayload {
  errors : [Error!]
  data   : User
}

And the resolver simply returns:

return MutationPayload(
  errors = Option.empty(),
  data = Option.just(user)
)

And here is the source for the Option class: https://github.com/arrow-kt/arrow-core/blob/0.10.4/arrow-core-data/src/main/kotlin/arrow/core/Option.kt

Thanks!

Herlevsen avatar Mar 03 '20 23:03 Herlevsen

I am encountering the same problem, all other wrappers are fine, 'Left', 'Right', 'Some'. All except the 'None' data structure.

ReinierRothuis avatar May 08 '20 13:05 ReinierRothuis

Note: Returning the nullable type in the transformer works on None. So if it is a String? returning "" would work (but is not the ideal solution, we want a null or other None-like scalar).

A workaround I am using now is creating a Union type for every type that I want to have optional. So MaybeUser = User | None and adding the None to the dictionary. Far from ideal.

ReinierRothuis avatar May 08 '20 14:05 ReinierRothuis

I think we need to provide a configurable option to handle nullable input argument mapping. Users could provide their own mapping of omitted/null/value to the correct types. It should also solve https://github.com/graphql-java-kickstart/graphql-java-tools/issues/388

Edit: Now I see that this is more about the return type than the input argument type.

vojtapol avatar May 21 '20 01:05 vojtapol

Yes, Optional is handled as a special case here: https://github.com/graphql-java-kickstart/graphql-java-tools/blob/e4690db3475889b1b32ad674d3ace48e5192875a/src/main/kotlin/graphql/kickstart/tools/TypeClassMatcher.kt#L53

The challenge for adding support for Arrow's Option will be to do it without adding dependency on Arrow which we definitely do not want to add.

vojtapol avatar May 21 '20 02:05 vojtapol