Skip to content

Commit

Permalink
Merge f589aea into 4a4aef8
Browse files Browse the repository at this point in the history
  • Loading branch information
dispalt committed Aug 30, 2018
2 parents 4a4aef8 + f589aea commit 8a42a96
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
15 changes: 11 additions & 4 deletions src/main/scala/sangria/execution/Resolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -904,12 +904,19 @@ class Resolver[Ctx](
case abst: AbstractType
if (isUndefinedValue(value))
Result(ErrorRegistry.empty, None)
else
abst.typeOf(value, schema) match {
case Some(obj) resolveValue(path, astFields, obj, field, value, userCtx)
else {
val actualValue =
abst match {
case abst: MappedAbstractType[Any @unchecked] abst.contraMap(value)
case _ value
}

abst.typeOf(actualValue, schema) match {
case Some(obj) resolveValue(path, astFields, obj, field, actualValue, userCtx)
case None Result(ErrorRegistry(path,
UndefinedConcreteTypeError(path, abst, schema.possibleTypes.getOrElse(abst.name, Vector.empty), value, exceptionHandler, sourceMapper, astFields.head.location.toList)), None)
UndefinedConcreteTypeError(path, abst, schema.possibleTypes.getOrElse(abst.name, Vector.empty), actualValue, exceptionHandler, sourceMapper, astFields.head.location.toList)), None)
}
}
}

def isUndefinedValue(value: Any) =
Expand Down
9 changes: 8 additions & 1 deletion src/main/scala/sangria/schema/Schema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ sealed trait AbstractType extends Type with Named {
schema.possibleTypes get name flatMap (_.find(_ isInstanceOf value).asInstanceOf[Option[ObjectType[Ctx, _]]])
}

sealed trait MappedAbstractType[T] extends Type with AbstractType with OutputType[T] {
def contraMap(value: T): Any
}

sealed trait NullableType
sealed trait UnmodifiedType

Expand Down Expand Up @@ -295,6 +299,9 @@ case class UnionType[Ctx](
astNodes: Vector[ast.AstNode] = Vector.empty) extends OutputType[Any] with CompositeType[Any] with AbstractType with NullableType with UnmodifiedType with HasAstInfo {
def rename(newName: String) = copy(name = newName).asInstanceOf[this.type]
def toAst: ast.TypeDefinition = SchemaRenderer.renderType(this)
def mapValue[T](func: T => Any): OutputType[T] with MappedAbstractType[T] = new UnionType[Ctx](name, description, types, astDirectives, astNodes) with MappedAbstractType[T] {
override def contraMap(value: T): Any = func(value)
}.asInstanceOf[OutputType[T] with MappedAbstractType[T]]
}

case class Field[Ctx, Val](
Expand Down Expand Up @@ -760,7 +767,7 @@ case class Schema[Ctx, Val](

def renderPretty: String = toAst.renderPretty
def renderPretty(filter: SchemaFilter): String = toAst(filter).renderPretty

def renderCompact: String = toAst.renderCompact
def renderCompact(filter: SchemaFilter): String = toAst(filter).renderCompact

Expand Down
51 changes: 50 additions & 1 deletion src/test/scala/sangria/execution/UnionInterfaceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ class UnionInterfaceSpec extends WordSpec with Matchers with FutureResultSupport

case class Dog(name: Option[String], barks: Option[Boolean]) extends Named
case class Cat(name: Option[String], meows: Option[Boolean]) extends Named
case class Person(name: Option[String], pets: Option[List[Option[Any]]], friends: Option[List[Option[Named]]]) extends Named
case class Person(name: Option[String], pets: Option[List[Option[Any]]], friends: Option[List[Option[Named]]]) extends Named {
def eitherPets: Option[List[Option[Either[Dog, Cat]]]] = pets.map(_.map(_.map {
case d: Dog => Left(d)
case c: Cat => Right(c)
}))
}

val NamedType = InterfaceType("Named", fields[Unit, Named](
Field("name", OptionType(StringType), resolve = _.value.name)))
Expand All @@ -26,8 +31,11 @@ class UnionInterfaceSpec extends WordSpec with Matchers with FutureResultSupport

val PetType = UnionType[Unit]("Pet", types = DogType :: CatType :: Nil)

val Pet2Type = UnionType[Unit]("Pet2", types = DogType :: CatType :: Nil).mapValue[Either[Dog, Cat]](_.fold(dog => dog: Any, cat => cat: Any))

val PersonType = ObjectType("Person", interfaces[Unit, Person](NamedType), fields[Unit, Person](
Field("pets", OptionType(ListType(OptionType(PetType))), resolve = _.value.pets),
Field("pets2", OptionType(ListType(OptionType(Pet2Type))), resolve = _.value.eitherPets),
Field("favouritePet", PetType, resolve = _.value.pets.flatMap(_.headOption.flatMap(identity)).get),
Field("favouritePetList", ListType(PetType), resolve = _.value.pets.getOrElse(Nil).flatMap(x x).toSeq),
Field("favouritePetOpt", OptionType(PetType), resolve = _.value.pets.flatMap(_.headOption.flatMap(identity))),
Expand Down Expand Up @@ -131,6 +139,47 @@ class UnionInterfaceSpec extends WordSpec with Matchers with FutureResultSupport
validateQuery = false
)

"executes using mapped union types" in check(
bob,
"""
{
__typename
name
favouritePet {name}
favouritePetOpt {name}
pets {
__typename
name
barks
meows
}
pets2 {
__typename
name
barks
meows
}
}
""",
Map(
"data" Map(
"__typename" "Person",
"name" "Bob",
"favouritePet" Map("name" "Garfield"),
"favouritePetOpt" Map("name" "Garfield"),
"pets" List(
Map("__typename" "Cat", "name" "Garfield", "meows" false),
Map("__typename" "Dog", "name" "Odie", "barks" true)
),
"pets2" List(
Map("__typename" "Cat", "name" "Garfield", "meows" false),
Map("__typename" "Dog", "name" "Odie", "barks" true)
)
)
) ,
validateQuery = false
)

"executes union types with inline fragments" in check(
bob,
"""
Expand Down

0 comments on commit 8a42a96

Please sign in to comment.