muuki88 / sbt-graphql

SBT plugin to generate and validate graphql schemas written with Sangria
Apache License 2.0
96 stars 20 forks source link

Work #76 Fix union types for fragments #79

Open muuki88 opened 5 years ago

muuki88 commented 5 years ago
yuqihuang-rally commented 3 years ago

Really appreciate for providing this great tool.

Wonder what's the current status of this issue?

I have been working on generating query models from a schema with union type Actor of two subtypes Human and Organization, but the generated code is complaining about missing encoder and failed the application at compile time,

And, I was using CirceJsonCodeGen in my project, looks like the implementation of the encoder generation for union type is not there, wonder if this is intentional and if there are some alternatives to deal with union type query generation from schema?

schemas I used

union Actor = Human | Organization

query Schedules(...) {
    schedules(...) {
        actor {
            __typename
            ... on Human {
                firstname
                lastname
            }
             ... on Organization {
                orgname
                  }
        }
    }
 }
felixbr commented 3 years ago

looks like the implementation of the encoder generation for union type is not there, wonder if this is intentional and if there are some alternatives to deal with union type query generation from schema?

On the client-side Encoder for unions is probably useless as GraphQL doesn't support union-types in arguments (at least that was the case a year ago).

The query example you posted would need a Decoder instance for the actor so it can decode it for all cases of the union. (based on __typename as a discriminator).

edit: I think this PR is only about unions in fragments. If you don't use fragments, it is probably already supported.

muuki88 commented 3 years ago

Fragments are really really nasty and complex for this niche project :sweat:

However you can now override types and specify your own if the plugin does not generate proper code. See the 0.16.0 release notes

yuqihuang-rally commented 3 years ago

@felixbr The query example you posted would need a Decoder instance for the actor so it can decode it for all cases of the union. (based on __typename as a discriminator).

I agree that such encoder for union type is not helpful, but in this case, the derived Encoder of Schedules requires an instance of the Actor encoder to be present to complete the encoder hierarchy, otherwise missing the instance triggers compile error

The generated code.

    case class Schedules(...otherArguments, actor: Option[Schedules.Actor])
    object Schedules {
      implicit val jsonDecoder: Decoder[Schedules] = deriveDecoder[Schedules]
      implicit val jsonEncoder: Encoder[Schedules] = deriveEncoder[Schedules]
      sealed trait Actor { def __typename: String }
      object Actor {
            case class Human(__typename: String, firstname: Option[String], lastname: Option[String]) extends Actor
            object Human {
              implicit val jsonDecoder: Decoder[Human] = deriveDecoder[Practitioner]
              implicit val jsonEncoder: Encoder[Human] = deriveEncoder[Practitioner]
            }
            case class Organization(__typename: String, orgname: Option[String]) extends Actor
            object Organization {
              implicit val jsonDecoder: Decoder[Organization] = deriveDecoder[Organization]
              implicit val jsonEncoder: Encoder[Organization] = deriveEncoder[Organization]
            }

             implicit val jsonDecoder: Decoder[Actor] = for (typeDiscriminator <- Decoder[String].prepare(_.downField("__typename")); value <- typeDiscriminator match {
             //missing encoder for Actor
      }
   ...otherArguments
}

This is the error I have after "sbt compile"


[error] .../code/vcdo-scheduling/web/target/scala-2.13/src_managed/main/sbt-graphql/Schedules.scala:51:67: could not find Lazy implicit value of type io.circe.generic.encoding.DerivedAsObjectEncoder[graphql.codegen.Schedules.Schedules.Schedules]
[error]    implicit val jsonEncoder: Encoder[Schedules] = deriveEncoder[Schedules]
yuqihuang-rally commented 3 years ago

@muuki88 thanks for the suggestion, using my own type really solved the issue!