-
-
Notifications
You must be signed in to change notification settings - Fork 20
Description
I'll just document this here, sadly I don't have the time to fix it right now.
Version used: 0.16.4
Given the following query:
query Test {
content {
__typename
... on Foo {
slug
}
... on Bar {
id
foo {
slug
}
}
}
}
The generated code looks like this (only the relevant part):
object Content {
case class Foo(__typename: String, slug: String) extends Content
object Foo {
implicit val jsonDecoder: Decoder[Foo] = deriveDecoder[Foo]
implicit val jsonEncoder: Encoder[Foo] = deriveEncoder[Foo]
}
case class Bar(__typename: String, id: Int, foo: Content.Foo) extends Content
object Bar {
case class Foo(__typename: String, slug: String)
object Foo {
implicit val jsonDecoder: Decoder[Foo] = deriveDecoder[Foo]
implicit val jsonEncoder: Encoder[Foo] = deriveEncoder[Foo]
}
implicit val jsonDecoder: Decoder[Bar] = deriveDecoder[Bar]
implicit val jsonEncoder: Encoder[Bar] = deriveEncoder[Bar]
}
implicit val jsonDecoder: Decoder[Content] = for {
typeDiscriminator <- Decoder[String].prepare(_.downField("__typename"))
value <- typeDiscriminator match {
case "Foo" =>
Decoder[Foo]
case "Bar" =>
Decoder[Bar]
case other =>
Decoder.failedWithMessage("invalid type: " + other)
}
} yield value
implicit val jsonEncoder: Encoder[Content] = Encoder.instance[Content]({
case v: Foo =>
deriveEncoder[Foo].apply(v)
case v: Bar =>
deriveEncoder[Bar].apply(v)
})
}
There are two bugs here:
Foo
andBar
have case class fields for__typename
, which means that we have to request__typename
in the query for both of them or the decoding will fail for no good reason. It would make more sense to generate constants, since we already know the value anyway and it never changes.
// Instead of
case class Foo(__typename: String, slug: String)
// we should generate
case class Foo(slug: String) {
def __typename: String = "Foo"
}
// or maybe even
case class Foo(slug: String) {
def __typename: String = Foo.__typename
}
object Foo {
def __typename: String = "Foo"
}
-
Inside of
Bar
we referenceFoo
for the second union case in the query. In the generated code we have a dedicatedBar.Foo
generated but for some dumb reason, we useContent.Foo
inBar
andBar.Foo
is unused. This means the whole thing doesn't work if the two cases use different fields fromFoo
.
I'm not sure if there is a reason for this (fragments?) or if it's just an honest mistake. -
Not really a bug but strange: The implementation for
Encoder[Content]
derives encoders inline instead of using the existing ones. The equivalentDecoder
doesn't do this. Imo we shouldn't derive something inline, especially if it already exists.