Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save OlegIlyenko/b36891a7bfc272e7db33 to your computer and use it in GitHub Desktop.
Save OlegIlyenko/b36891a7bfc272e7db33 to your computer and use it in GitHub Desktop.
import sangria.schema._
import sangria.ast
import sangria.macros._
import sangria.execution._
case class MyContext(originalQuery: ast.Document) {
def loadEntity(id: String, typeHints: Set[String]): Option[Identifiable] = {
println(typeHints)
None // your entity loagic goes here
}
}
trait Identifiable {
def id: String
}
case class Account(id: String, name: Option[String]) extends Identifiable
case class Order(id: String, orderNumber: String) extends Identifiable
val IdentifiableType = InterfaceType("Identifiable", fields[Unit, Identifiable](
Field("id", StringType, resolve = _.value.id)))
val AccountType = ObjectType("Account", interfaces[Unit, Account](IdentifiableType),
fields[Unit, Account](
Field("name", OptionType(StringType), resolve = _.value.name)))
val OrderType = ObjectType("Order", interfaces[Unit, Order](IdentifiableType),
fields[Unit, Order](
Field("orderNumber", StringType, resolve = _.value.orderNumber)))
val IdArg = Argument("id", StringType)
// Collects all of the fragment type conditions.
// Please note, that directives are not considered here. It's posible that
// particular directive will exclude the fragment. Ideally such fragments should be ignored
def collectTypeConditions(query: ast.Document, fields: Vector[ast.Field]) =
fields.toSet.flatMap((field: ast.Field) ⇒ field.selections.collect {
case ast.InlineFragment(Some(ast.NamedType(name, _)), _, _, _) ⇒
name
case ast.FragmentSpread(name, _, _) ⇒
query.fragments(name).typeCondition.name
})
val QueryType = ObjectType("Query", fields[MyContext, Unit](
Field("node", OptionType(IdentifiableType),
arguments = IdArg :: Nil,
resolve = c ⇒ {
val possibleTypes = collectTypeConditions(c.ctx.originalQuery, c.astFields)
c.ctx.loadEntity(c.arg(IdArg), typeHints = possibleTypes)
})))
val schema = Schema(QueryType, additionalTypes = AccountType :: OrderType :: Nil)
val query =
graphql"""
query myQuery1 {
node(id: "123") {
id
__typename
...MyAccountFrag
}
}
query myQuery2 {
node(id: "123") {
id
__typename
... on Order {
orderNumber
}
}
}
query myQuery3 {
node(id: "123") {
id
__typename
...MyAccountFrag
...MyOrderFrag
}
}
fragment MyAccountFrag on Account {
name
}
fragment MyOrderFrag on Order {
orderNumber
}
"""
Executor.execute(schema, query, Some("myQuery1"), userContext = MyContext(query)).await
Executor.execute(schema, query, Some("myQuery2"), userContext = MyContext(query)).await
Executor.execute(schema, query, Some("myQuery3"), userContext = MyContext(query)).await
// Will print:
// Set(Account)
// Set(Order)
// Set(Account, Order)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment