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

Work #76 Fix union types for fragments #79

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

muuki88
Copy link
Owner

@muuki88 muuki88 commented Nov 5, 2019

  • write failing tests
  • fix failing tests

@muuki88 muuki88 changed the title Work #76 Add test cases Work #76 Fix union types for fragments Nov 22, 2019
Base automatically changed from master to main January 25, 2021 07:45
@yuqihuang-rally
Copy link

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
Copy link
Collaborator

felixbr commented Mar 17, 2021

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
Copy link
Owner Author

muuki88 commented Mar 17, 2021

Fragments are really really nasty and complex for this niche project 😓

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
Copy link

yuqihuang-rally commented Mar 18, 2021

@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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants