Skip to content

Commit

Permalink
Allow union types to reuse the same member
Browse files Browse the repository at this point in the history
closes #826
  • Loading branch information
AlixBa committed Jul 5, 2021
1 parent 7ad3837 commit 475270e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 18 deletions.
33 changes: 25 additions & 8 deletions tools/src/main/scala/caliban/tools/SchemaWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object SchemaWriter {
.map(union => (union, union.memberTypes.flatMap(schema.objectTypeDefinition)))
.toMap

val unions = unionTypes.map { case (union, objects) => writeUnion(union, objects) }.mkString("\n")
val unions = writeUnions(unionTypes)

val objects = schema.objectTypeDefinitions
.filterNot(obj =>
Expand Down Expand Up @@ -146,17 +146,34 @@ object SchemaWriter {
}
"""

def writeUnion(typedef: UnionTypeDefinition, objects: List[ObjectTypeDefinition])(implicit
def writeUnions(unions: Map[UnionTypeDefinition, List[ObjectTypeDefinition]])(implicit
scalarMappings: ScalarMappings
): String =
s"""${writeDescription(typedef.description)}sealed trait ${typedef.name} extends scala.Product with scala.Serializable

object ${typedef.name} {
${objects
.map(o => s"${writeObject(o)} extends ${typedef.name}")
.mkString("\n")}
if (unions.nonEmpty) {
val invertedUnions = unions.foldLeft(Map.empty[ObjectTypeDefinition, List[UnionTypeDefinition]]) {
case (map, (unionType, objectTypes)) =>
objectTypes.foldLeft(map) { case (map, objectType) =>
map.updated(objectType, map.getOrElse(objectType, List.empty) :+ unionType)
}
}

val codegenUnions = unions.keys.map { union =>
s"""${writeDescription(
union.description
)}sealed trait ${union.name} extends scala.Product with scala.Serializable"""
}
.mkString("\n")

val codegenObjects = invertedUnions.map { case (obj, unions) =>
s"${writeObject(obj)} extends ${unions.map(_.name).mkString(" with ")}"
}
.mkString("\n")

s"""$codegenUnions
$codegenObjects
"""
} else ""

def writeField(field: FieldDefinition, of: ObjectTypeDefinition)(implicit scalarMappings: ScalarMappings): String =
if (field.args.nonEmpty) {
Expand Down
33 changes: 23 additions & 10 deletions tools/src/test/scala/caliban/tools/SchemaWriterSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,19 @@ object SchemaWriterSpec extends DefaultRunnableSpec {
Captain or Pilot
\"\"\"
"""
val role2 =
s"""
\"\"\"
role2
Captain or Pilot
\"\"\"
"""
val schema =
s"""
$role
union Role = Captain | Pilot
$role2
union Role2 = Captain | Pilot
type Captain {
"ship" shipName: String!
Expand All @@ -237,23 +246,27 @@ object SchemaWriterSpec extends DefaultRunnableSpec {

assertM(gen(schema))(
equalTo {
val role =
val role =
s"""\"\"\"role
Captain or Pilot\"\"\""""
val role2 =
s"""\"\"\"role2
Captain or Pilot\"\"\""""
s"""import caliban.schema.Annotations._

object Types {

@GQLDescription($role)
sealed trait Role extends scala.Product with scala.Serializable

object Role {
case class Captain(
@GQLDescription("ship")
shipName: String
) extends Role
case class Pilot(shipName: String) extends Role
}
sealed trait Role extends scala.Product with scala.Serializable
@GQLDescription($role2)
sealed trait Role2 extends scala.Product with scala.Serializable

case class Captain(
@GQLDescription("ship")
shipName: String
) extends Role
with Role2
case class Pilot(shipName: String) extends Role with Role2

}
"""
Expand Down

0 comments on commit 475270e

Please sign in to comment.