diff --git a/build.sbt b/build.sbt index bbcc314b..6b914e87 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val scala3Version = "3.4.2" lazy val rulesCrossVersions = Seq(V.scala213) lazy val allVersions = rulesCrossVersions :+ scala3Version -ThisBuild / tlBaseVersion := "0.36" +ThisBuild / tlBaseVersion := "0.37" ThisBuild / tlCiReleaseBranches := Seq("master") ThisBuild / tlJdkRelease := Some(8) ThisBuild / githubWorkflowJavaVersions := Seq("11", "17").map(JavaSpec.temurin(_)) diff --git a/gen/input/src/main/scala/test/StarWarsQuery2.scala b/gen/input/src/main/scala/test/StarWarsQuery2.scala index 4369e43d..fb1314f3 100644 --- a/gen/input/src/main/scala/test/StarWarsQuery2.scala +++ b/gen/input/src/main/scala/test/StarWarsQuery2.scala @@ -17,19 +17,22 @@ object Wrapper /* gql: extends Something */ { @GraphQL trait StarWarsQuery2 extends GraphQLOperation[StarWars] { override val document: String = """ + fragment fields on Character { + id + name + ... on Human { + homePlanet + } + friends { + name + } + ... on Droid { + primaryFunction + } + } query ($charId: ID!) { character(id: $charId) { - id - name - ... on Human { - homePlanet - } - friends { - name - } - ... on Droid { - primaryFunction - } + ...fields } } """ diff --git a/gen/output/src/main/scala/test/StarWarsQuery2.scala b/gen/output/src/main/scala/test/StarWarsQuery2.scala index 50f9fc7e..b4412639 100644 --- a/gen/output/src/main/scala/test/StarWarsQuery2.scala +++ b/gen/output/src/main/scala/test/StarWarsQuery2.scala @@ -18,19 +18,22 @@ object Wrapper extends Something { import StarWars.Types._ ignoreUnusedImportTypes() override val document: String = """ + fragment fields on Character { + id + name + ... on Human { + homePlanet + } + friends { + name + } + ... on Droid { + primaryFunction + } + } query ($charId: ID!) { character(id: $charId) { - id - name - ... on Human { - homePlanet - } - friends { - name - } - ... on Droid { - primaryFunction - } + ...fields } } """ diff --git a/gen/rules/src/main/scala/clue/gen/GraphQLGen.scala b/gen/rules/src/main/scala/clue/gen/GraphQLGen.scala index d064d913..6d129c83 100644 --- a/gen/rules/src/main/scala/clue/gen/GraphQLGen.scala +++ b/gen/rules/src/main/scala/clue/gen/GraphQLGen.scala @@ -133,15 +133,16 @@ class GraphQLGen(config: GraphQLGenConfig) s"Warning parsing document: ${queryResult.toProblems.map(_.toString).toList.mkString("\n")}" ) ) >> IO { + val (operations, fragments) = queryResult.toOption.get // TODO Support multi-operation queries? - val operation: UntypedOperation = queryResult.toOption.get._1.head + val operation = operations.head // Modifications to add the missing definitions. val modObjDefs = scala.Function.chain( List( addImports(schemaType.value), addVars(schema, operation, config), - addData(schema, operation, config, document.subqueries), + addData(schema, operation, config, document.subqueries, fragments), addVarEncoder, addDataDecoder, addConvenienceMethod(schemaType, operation, objName) @@ -209,8 +210,9 @@ class GraphQLGen(config: GraphQLGenConfig) s"Warning parsing document: ${queryResult.toProblems.map(_.toString).toList.mkString("\n")}" ) ) >> IO { + val (operations, fragments) = queryResult.toOption.get // TODO Support multi-operation queries? - val operation: UntypedOperation = queryResult.toOption.get._1.head + val operation = operations.head // Modifications to add the missing definitions. val modObjDefs = scala.Function.chain( @@ -221,6 +223,7 @@ class GraphQLGen(config: GraphQLGenConfig) operation, config, subquery.subqueries, + fragments, schema.types.find(_.name == rootTypeName) ), addDataDecoder, diff --git a/gen/rules/src/main/scala/clue/gen/QueryGen.scala b/gen/rules/src/main/scala/clue/gen/QueryGen.scala index ba06199a..2ca67096 100644 --- a/gen/rules/src/main/scala/clue/gen/QueryGen.scala +++ b/gen/rules/src/main/scala/clue/gen/QueryGen.scala @@ -222,10 +222,13 @@ trait QueryGen extends Generator { schema: Schema, algebra: Query, subqueries: List[Term], + fragments: List[UntypedFragment], rootType: Option[GType] ): CaseClass = { import Query._ + val fragmentsMap: Map[String, UntypedFragment] = fragments.map(f => f.name -> f).toMap + def getType(typeName: String): NamedType = schema .definition(typeName) @@ -302,6 +305,9 @@ trait QueryGen extends Generator { case UntypedInlineFragment(typeName, _, child) => // Single element in inline fragment go(child, typeName.map(getType).orElse(currentType)) + case UntypedFragmentSpread(name, _) => + val fragment: UntypedFragment = fragmentsMap(name) + go(fragment.child, getType(fragment.tpnme).some) case Group(selections) => // A Group in an inline fragment "... on X" will be represented as Group(List(UntypedInlineFragment(X, ...), UntypedInlineFragment(X, ...))). // We fix that to UntypedInlineFragment(X, Group(List(..., ...))) @@ -394,16 +400,18 @@ trait QueryGen extends Generator { operation: UntypedOperation, config: GraphQLGenConfig, subqueries: List[Term], + fragments: List[UntypedFragment], rootTypeOverride: Option[NamedType] = None ): List[Stat] => List[Stat] = parentBody => mustDefineType("Data")(parentBody) match { case Skip => - addModuleDefs("Data", - config.catsEq, - config.catsShow, - config.scalaJSReactReuse, - circeDecoder = true + addModuleDefs( + "Data", + config.catsEq, + config.catsShow, + config.scalaJSReactReuse, + circeDecoder = true )(parentBody) case Define(_, _, _) => // For now, we don't allow specifying Data class parents. // For some reason, schema.schemaType only returns the Query type. @@ -424,7 +432,13 @@ trait QueryGen extends Generator { case _: UntypedSubscription => schemaType.field("subscription").flatMap(_.asNamed) } - resolveData(schema, operation.query, subqueries, rootTypeOverride.orElse(rootType)) + resolveData( + schema, + operation.query, + subqueries, + fragments, + rootTypeOverride.orElse(rootType) + ) .addToParentBody( config.catsEq, config.catsShow,