package tv.miracle.backend.graphql import sangria.execution.deferred.{ Fetcher, HasId } import sangria.schema._ import scala.concurrent.Future /** * Defines a GraphQL schema for the current project */ object SchemaDefinition { /** * Resolves the lists of characters. These resolutions are batched and * cached for the duration of a query. */ val characters: Fetcher[CharacterRepo, Character, Character, String] = Fetcher.caching( (ctx: CharacterRepo, ids: Seq[String]) => Future.successful(ids.flatMap(id => ctx.getHuman(id) orElse ctx.getDroid(id))))(HasId(_.id)) val EpisodeEnum: EnumType[Episode.Value] = EnumType( "Episode", Some("One of the films in the Star Wars Trilogy"), List( EnumValue( "NEWHOPE", value = Episode.NEWHOPE, description = Some("Released in 1977.")), EnumValue( "EMPIRE", value = Episode.EMPIRE, description = Some("Released in 1980.")), EnumValue( "JEDI", value = Episode.JEDI, description = Some("Released in 1983.")))) val Character: InterfaceType[CharacterRepo, Character] = InterfaceType( "Character", "A character in the Star Wars Trilogy", () => fields[CharacterRepo, Character]( Field("id", StringType, Some("The id of the character."), resolve = _.value.id), Field("name", OptionType(StringType), Some("The name of the character."), resolve = _.value.name), Field("friends", ListType(Character), Some("The friends of the character, or an empty list if they have none."), resolve = ctx => characters.deferSeqOpt(ctx.value.friends)), Field("appearsIn", OptionType(ListType(OptionType(EpisodeEnum))), Some("Which movies they appear in."), resolve = _.value.appearsIn map (e => Some(e))))) val Human: ObjectType[CharacterRepo, Human] = ObjectType( "Human", "A humanoid creature in the Star Wars universe.", interfaces[CharacterRepo, Human](Character), fields[CharacterRepo, Human]( Field("id", StringType, Some("The id of the human."), resolve = _.value.id), Field("name", OptionType(StringType), Some("The name of the human."), resolve = _.value.name), Field("friends", ListType(Character), Some("The friends of the human, or an empty list if they have none."), resolve = ctx => characters.deferSeqOpt(ctx.value.friends)), Field("appearsIn", OptionType(ListType(OptionType(EpisodeEnum))), Some("Which movies they appear in."), resolve = _.value.appearsIn map (e => Some(e))), Field("homePlanet", OptionType(StringType), Some("The home planet of the human, or null if unknown."), resolve = _.value.homePlanet))) val Droid: ObjectType[CharacterRepo, Droid] = ObjectType( "Droid", "A mechanical creature in the Star Wars universe.", interfaces[CharacterRepo, Droid](Character), fields[CharacterRepo, Droid]( Field("id", StringType, Some("The id of the droid."), resolve = _.value.id), Field("name", OptionType(StringType), Some("The name of the droid."), resolve = ctx => Future.successful(ctx.value.name)), Field("friends", ListType(Character), Some("The friends of the droid, or an empty list if they have none."), resolve = ctx => characters.deferSeqOpt(ctx.value.friends)), Field("appearsIn", OptionType(ListType(OptionType(EpisodeEnum))), Some("Which movies they appear in."), resolve = _.value.appearsIn map (e => Some(e))), Field("primaryFunction", OptionType(StringType), Some("The primary function of the droid."), resolve = _.value.primaryFunction))) val ID: Argument[String] = Argument("id", StringType, description = "id of the character") val EpisodeArg: Argument[Option[Episode.Value]] = Argument("episode", OptionInputType(EpisodeEnum), description = "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.") val LimitArg: Argument[Int] = Argument("limit", OptionInputType(IntType), defaultValue = 20) val OffsetArg: Argument[Int] = Argument("offset", OptionInputType(IntType), defaultValue = 0) val Query: ObjectType[CharacterRepo, Unit] = ObjectType( "Query", fields[CharacterRepo, Unit]( Field("hero", Character, arguments = EpisodeArg :: Nil, deprecationReason = Some("Use `human` or `droid` fields instead"), resolve = ctx => ctx.ctx.getHero(ctx.arg(EpisodeArg))), Field("human", OptionType(Human), arguments = ID :: Nil, resolve = ctx => ctx.ctx.getHuman(ctx arg ID)), Field("droid", Droid, arguments = ID :: Nil, resolve = ctx => ctx.ctx.getDroid(ctx arg ID).get), Field("humans", ListType(Human), arguments = LimitArg :: OffsetArg :: Nil, resolve = ctx => ctx.ctx.getHumans(ctx arg LimitArg, ctx arg OffsetArg)), Field("droids", ListType(Droid), arguments = LimitArg :: OffsetArg :: Nil, resolve = ctx => ctx.ctx.getDroids(ctx arg LimitArg, ctx arg OffsetArg)))) val StarWarsSchema: Schema[CharacterRepo, Unit] = Schema(Query) }