Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
162 lines (121 sloc) 4.03 KB
module Example05InterfacesAndUnions exposing (main)
import Browser
import Graphql.Document as Document
import Graphql.Http
import Graphql.Operation exposing (RootQuery)
import Graphql.OptionalArgument as OptionalArgument exposing (OptionalArgument(..))
import Graphql.SelectionSet as SelectionSet exposing (SelectionSet, hardcoded, with)
import Helpers.Main
import Html exposing (div, h1, p, pre, text)
import PrintAny
import RemoteData exposing (RemoteData)
import Swapi.Enum.Episode as Episode exposing (Episode)
import Swapi.Interface
import Swapi.Interface.Character as Character
import Swapi.Object
import Swapi.Object.Droid as Droid
import Swapi.Object.Human as Human
import Swapi.Query as Query
import Swapi.Scalar exposing (Id(..))
import Swapi.Union
import Swapi.Union.CharacterUnion
type alias Response =
{ heroUnion : HumanOrDroidDetails
, heroInterface : HumanOrDroidWithName
, nonExhaustiveFragment : Maybe String
}
query : SelectionSet Response RootQuery
query =
SelectionSet.map3 Response
(Query.heroUnion identity heroUnionSelection)
(Query.hero identity heroSelection)
(Query.heroUnion identity nonExhaustiveFragment)
type HumanOrDroidDetails
= HumanDetails (Maybe String)
| DroidDetails (Maybe String)
{-
GraphQL Union types are just like GraphQL Interfaces, except they don't have
any common fields. So with our `heroSelection`, we can't select common fields
like `name`, even though both Humans and Droids have them. With an interface,
you can define the common fields as well.
https://graphql.org/learn/schema/#union-types
-}
heroUnionSelection : SelectionSet HumanOrDroidDetails Swapi.Union.CharacterUnion
heroUnionSelection =
Swapi.Union.CharacterUnion.fragments
{ onHuman = SelectionSet.map HumanDetails Human.homePlanet
, onDroid = SelectionSet.map DroidDetails Droid.primaryFunction
}
type alias HumanOrDroidWithName =
{ name : String
, details : HumanOrDroidDetails
}
{-
A GraphQL Interface allows you to select both common fields shared between
the possible return types (like `name`), and type-specific fields (like
`primaryFunction` or `homePlanet`).
https://graphql.org/learn/schema/#interfaces
-}
heroSelection : SelectionSet HumanOrDroidWithName Swapi.Interface.Character
heroSelection =
SelectionSet.map2 HumanOrDroidWithName
Character.name
(Character.fragments
{ onHuman = SelectionSet.map HumanDetails Human.homePlanet
, onDroid = SelectionSet.map DroidDetails Droid.primaryFunction
}
)
nonExhaustiveFragment : SelectionSet (Maybe String) Swapi.Union.CharacterUnion
nonExhaustiveFragment =
let
maybeFragments =
Swapi.Union.CharacterUnion.maybeFragments
in
Swapi.Union.CharacterUnion.fragments
{ maybeFragments
| onHuman = Human.homePlanet
}
makeRequest : Cmd Msg
makeRequest =
query
|> Graphql.Http.queryRequest "https://elm-graphql.herokuapp.com"
|> Graphql.Http.send (RemoteData.fromResult >> GotResponse)
type Msg
= GotResponse Model
type alias Model =
RemoteData (Graphql.Http.Error Response) Response
init : () -> ( Model, Cmd Msg )
init _ =
( RemoteData.Loading
, makeRequest
)
view : Model -> Browser.Document Msg
view model =
{ title = "Starwars Demo"
, body =
[ div []
[ div []
[ h1 [] [ text "Generated Query" ]
, pre [] [ text (Document.serializeQuery query) ]
]
, div []
[ h1 [] [ text "Response" ]
, model |> PrintAny.view
]
]
]
}
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotResponse response ->
( response, Cmd.none )
type alias Flags =
()
main : Helpers.Main.Program Flags Model Msg
main =
Helpers.Main.document
{ init = init
, update = update
, queryString = Document.serializeQuery query
}