Comments (3)
Hi @ellenlight
Thanks for your detailed and comprehensive issue report
TL;DR codeGen
is the way to go at the moment.
Sangria Style
The sangria style code generation was the initial implementation from Jonas from another plugin.
My focus is the Apollo Code generation and I'm playing with the though to remove the sangria style
as it adds a bit of confusion and unnecessary complexity for the plugin.
What is causing the compilation error
Union types and fragments are quite tricky to get right in the code generation. I spent several hours to find a way to implement this, but without success so far. Any help is welcome as this project is purely maintained in my freetime (and the one of others I assume) π€
This is also the reason codeGen
was introduced. To have a simple and stable workaround for all code gen related issues.
from sbt-graphql.
Hi @ellenlight
Thanks for your detailed and comprehensive issue report
βΊοΈ TL;DR
codeGen
is the way to go at the moment.Sangria Style
The sangria style code generation was the initial implementation from Jonas from another plugin.
My focus is the Apollo Code generation and I'm playing with the though to remove the sangria style
as it adds a bit of confusion and unnecessary complexity for the plugin.What is causing the compilation error
Union types and fragments are quite tricky to get right in the code generation. I spent several hours to find a way to implement this, but without success so far. Any help is welcome as this project is purely maintained in my freetime (and the one of others I assume) π€
This is also the reason
codeGen
was introduced. To have a simple and stable workaround for all code gen related issues.
Sounds good and thank you for the quick reply!
from sbt-graphql.
Hello @muuki88! Thank you for writing this excellent plugin! I am using it to generate the client code for a project and I am running into some problems related to this issue.
Reproducing the issue
This issue occurs with the Apollo codegen style.
The schema is
union Animal = Cat | Dog
type Cat {
catName: String!
}
type Dog {
dogName: String!
favoriteToys: [Toy!]!
}
type Toy {
toyName: String!
boughtAt: Store!
}
type Store {
storeName: String!
}
type Query {
animals: [Animal!]!
}
The query is
query AllAnimals {
animals {
...AnimalName
}
}
fragment AnimalName on Animal {
__typename
...DogName
...CatName
}
fragment DogName on Dog {
dogName
favoriteToys {
...ToyName
}
}
fragment ToyName on Toy {
toyName
boughtAt {
...StoreName
}
}
fragment StoreName on Store {
storeName
}
fragment CatName on Cat {
catName
}
The compile error is
[error] web/target/scala-2.13/src_managed/main/sbt-graphql/Pets.scala:48:86: type FavoriteToys is not a member of object graphql.codegen.Pets.AllAnimals.Animals
[error] case class Dog(__typename: String, dogName: String, favoriteToys: List[Animals.FavoriteToys]) extends Animals
The problem is that the generated code should be
Dog(__typename: String, dogName: String, favoriteToys: List[Dog.FavoriteToys])
but instead it is
Dog(__typename: String, dogName: String, favoriteToys: List[Animals.FavoriteToys])
Here is the full generated code:
Click to expand!
package graphql.codegen
import io.circe.{ Decoder, Encoder }
import io.circe.generic.semiauto.{ deriveDecoder, deriveEncoder }
import sangria.macros._
import types._
object Pets {
object AllAnimals extends GraphQLQuery {
val document: sangria.ast.Document = graphql"""query AllAnimals {
animals {
...AnimalName
}
}
fragment DogName on Dog {
dogName
favoriteToys {
...ToyName
}
}
fragment CatName on Cat {
catName
}
fragment StoreName on Store {
storeName
}
fragment ToyName on Toy {
toyName
boughtAt {
...StoreName
}
}
fragment AnimalName on Animal {
__typename
...DogName
...CatName
}"""
case class Variables()
object Variables { implicit val jsonEncoder: Encoder[Variables] = deriveEncoder[Variables] }
case class Data(animals: List[Animals])
object Data { implicit val jsonDecoder: Decoder[Data] = deriveDecoder[Data] }
sealed trait Animals { def __typename: String }
object Animals {
case class Cat(__typename: String, catName: String) extends Animals
object Cat {
implicit val jsonDecoder: Decoder[Cat] = deriveDecoder[Cat]
implicit val jsonEncoder: Encoder[Cat] = deriveEncoder[Cat]
}
case class Dog(__typename: String, dogName: String, favoriteToys: List[Animals.FavoriteToys]) extends Animals
object Dog {
case class FavoriteToys(toyName: String, boughtAt: FavoriteToys.BoughtAt) extends ToyName
object FavoriteToys {
implicit val jsonDecoder: Decoder[FavoriteToys] = deriveDecoder[FavoriteToys]
implicit val jsonEncoder: Encoder[FavoriteToys] = deriveEncoder[FavoriteToys]
case class BoughtAt(storeName: String) extends StoreName
object BoughtAt {
implicit val jsonDecoder: Decoder[BoughtAt] = deriveDecoder[BoughtAt]
implicit val jsonEncoder: Encoder[BoughtAt] = deriveEncoder[BoughtAt]
}
}
implicit val jsonDecoder: Decoder[Dog] = deriveDecoder[Dog]
implicit val jsonEncoder: Encoder[Dog] = deriveEncoder[Dog]
}
implicit val jsonDecoder: Decoder[Animals] = for (typeDiscriminator <- Decoder[String].prepare(_.downField("__typename")); value <- typeDiscriminator match {
case "Cat" =>
Decoder[Cat]
case "Dog" =>
Decoder[Dog]
case other =>
Decoder.failedWithMessage("invalid type: " + other)
}) yield value
}
}
}
I believe the problem also occurs in the unit tests here: https://github.com/muuki88/sbt-graphql/compare/issue-76/fix-fragment-union-codegen#diff-045de0b210c8e206e71c3ab7f73d3bf9b84f88653bdf74bb2c2cfb949b7a75f0R9
I believe it should be
case class Article(id: ID, __typename: String, title: String, status: ArticleStatus, author: Search.Article.Author) extends Search
instead?
Possible Short-Term Workarounds
This issue does not occur with the Sangria codegen style. The generated code is
Click to expand!
package graphql.codegen
object GraphQLCodegen {
case class AllAnimals(animals: List[GraphQLCodegen.AllAnimals.Animals])
object AllAnimals {
case class AllAnimalsVariables()
sealed trait Animals
object Animals {
case class Cat(__typename: String, catName: String) extends GraphQLCodegen.AllAnimals.Animals
case class Dog(__typename: String, dogName: String, favoriteToys: List[GraphQLCodegen.AllAnimals.Animals.Dog.FavoriteToys]) extends GraphQLCodegen.AllAnimals.Animals
object Dog {
case class FavoriteToys(toyName: String, boughtAt: GraphQLCodegen.AllAnimals.Animals.Dog.FavoriteToys.BoughtAt)
object FavoriteToys { case class BoughtAt(storeName: String) }
}
}
}
}
which compiles successfully. However, I was wondering whether you could provide an example of generating the request body with the Sangria style since there is no Sangria Document
generated?
The other possible workaround is to write the problematic class by hand using the codeGen
directive, but I would prefer to use the Sangria style instead if possible.
Questions
- What is causing this compile error?
- As a temporary work-around, I'd like to use the Sangria codegen style, but am confused about how to generate the request body?
Thanks!
from sbt-graphql.
Related Issues (20)
- Code generation for unions is flawed HOT 1
- codegen support for 'URI' scalar type HOT 1
- Yet another trouble getting codegen to work HOT 2
- Code generation - The output directory for generated files should be configurable. HOT 1
- Missing Sangria Custom Scalars In Schema Generation HOT 1
- Fix .scalafmt.conf
- Stable ordering of output HOT 3
- Add toString to graphqlCodegenStyle, Json HOT 2
- [question] Can I annotate generated classes? HOT 1
- Schema generation from Introspection HOT 5
- How to reorder execution of sbt-graphql plugins? HOT 9
- Code generation question HOT 5
- Examples for common use-cases HOT 5
- about graphql-Java HOT 7
- Multiple schemas generation, is it possible? HOT 8
- Only regenerate Scala files from GraphQL schema if schema changes HOT 1
- Move to github actions HOT 2
- Weird published version v0.1.6 HOT 2
- Question about code generation issue in test phase HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sbt-graphql.