GithubHelp home page GithubHelp logo

Comments (3)

muuki88 avatar muuki88 commented on May 29, 2024 1

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.

ellenlight avatar ellenlight commented on May 29, 2024 1

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.

ellenlight avatar ellenlight commented on May 29, 2024

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

  1. What is causing this compile error?
  2. 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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.