Skip to content

Commit

Permalink
Fix Scala 3 enum and union member name sorting (#2275)
Browse files Browse the repository at this point in the history
Ensure Scala 3 derivation sorts enums and union members by type name to
match Scala 2.
  • Loading branch information
guymers authored Jun 10, 2024
1 parent f8c9f60 commit 76d87de
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 3 deletions.
4 changes: 2 additions & 2 deletions core/src/main/scala-3/caliban/schema/DerivationUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ private object DerivationUtils {
makeEnum(
Some(getName(annotations, info)),
getDescription(annotations),
subTypes.collect { case (name, __Type(_, _, description, _, _, _, _, _, _, _, _, _), annotations) =>
subTypes.map { case (name, __Type(_, _, description, _, _, _, _, _, _, _, _, _), annotations) =>
__EnumValue(
getName(annotations, name),
description,
getDeprecatedReason(annotations).isDefined,
getDeprecatedReason(annotations),
Some(annotations.collect { case GQLDirective(dir) => dir }.toList).filter(_.nonEmpty)
)
},
}.sortBy(_.name),
Some(info.full),
Some(getDirectives(annotations))
)
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala-3/caliban/schema/SumSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ final private class SumSchema[R, A](
makeUnion(
Some(getName(annotations, info)),
getDescription(annotations),
subTypes.map(_._2).distinctBy(_.name).map(SchemaUtils.fixEmptyUnionObject),
subTypes.map(_._2).distinctBy(_.name).map(SchemaUtils.fixEmptyUnionObject).sortBy(_.name),
Some(info.full),
Some(getDirectives(annotations))
)
Expand Down
115 changes: 115 additions & 0 deletions core/src/test/scala/caliban/schema/SchemaDerivationIssuesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,66 @@ object SchemaDerivationIssuesSpec extends ZIOSpecDefault {
expected =
"""{"widget":{"__typename":"WidgetB","name":"a","children":{"total":1,"nodes":[{"name":"a","foo":"FOO"}]}}}"""
} yield assertTrue(data1 == expected, data2 == expected)
},
test("sum types are sorted by name") {
import sorting._
val rendered = schema.render
assertTrue(
rendered ==
"""schema {
| query: Queries
|}
|
|union Union = A | B | C | ChildE | ChildY | D | Z
|
|enum Enum {
| B
| C
| ChildE
| ChildY
| D
| Z
|}
|
|type A {
| field: String!
|}
|
|type B {
| "Fake field because GraphQL does not support empty objects. Do not query, use __typename instead."
| _: Boolean
|}
|
|type C {
| "Fake field because GraphQL does not support empty objects. Do not query, use __typename instead."
| _: Boolean
|}
|
|type ChildE {
| "Fake field because GraphQL does not support empty objects. Do not query, use __typename instead."
| _: Boolean
|}
|
|type ChildY {
| "Fake field because GraphQL does not support empty objects. Do not query, use __typename instead."
| _: Boolean
|}
|
|type D {
| "Fake field because GraphQL does not support empty objects. Do not query, use __typename instead."
| _: Boolean
|}
|
|type Queries {
| e: Enum!
| u: Union!
|}
|
|type Z {
| "Fake field because GraphQL does not support empty objects. Do not query, use __typename instead."
| _: Boolean
|}""".stripMargin
)
}
)
}
Expand Down Expand Up @@ -616,3 +676,58 @@ object i2076 {
graphQL(RootResolver(queries))
}
}

object sorting {
sealed trait Enum
object Enum {
implicit val schema: Schema[Any, Enum] = Schema.gen
}

sealed trait Union
object Union {
implicit val schema: Schema[Any, Union] = Schema.gen
}

case object Z extends Enum with Union {
implicit val schema: Schema[Any, Z.type] = Schema.gen
}

@GQLName("ChildY")
case object Y extends Enum with Union {
implicit val schema: Schema[Any, Y.type] = Schema.gen
}

@GQLName("B")
case object B extends Enum with Union {
implicit val schema: Schema[Any, B.type] = Schema.gen
}

case class A(field: String) extends Union
object A {
implicit val schema: Schema[Any, A] = Schema.gen
}

case object C extends Enum with Union {
implicit val schema: Schema[Any, C.type] = Schema.gen
}

case object D extends Enum with Union {
implicit val schema: Schema[Any, D.type] = Schema.gen
}

@GQLName("ChildE")
case object E extends Enum with Union {
implicit val schema: Schema[Any, E.type] = Schema.gen
}

case class Queries(e: Enum, u: Union)

object Queries {
implicit val schema: Schema[Any, Queries] = Schema.gen
}

val schema = {
val queries = Queries(e = Z, u = Z)
caliban.graphQL(RootResolver(queries))
}
}

0 comments on commit 76d87de

Please sign in to comment.