summaryrefslogtreecommitdiff
path: root/tests/Test/StarWars.hs
blob: ffafd666476fa08245a034390891115e0677f332 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE RecordWildCards #-}
module Test.StarWars where

import Data.Functor.Identity (Identity(..))
import Data.Text (Text)

import Data.Attoparsec.Text (parseOnly)
import qualified Data.Aeson as Aeson

import Test.Tasty (TestTree)
import Test.Tasty.HUnit

import Data.GraphQL.AST
import Data.GraphQL.Execute
import qualified Data.GraphQL.Parser as Parser
import Data.GraphQL.Schema

-- * Test

test :: TestTree
test = testCase "R2-D2" $ execute schema heroQuery @=? Identity expected
  where
    heroQuery :: Document
    heroQuery = either (error "Parsing error") id $ parseOnly Parser.document
      "{ query HeroNameQuery { hero { name } } }"

    expected :: Response
    expected = Aeson.Object
        [ ( "hero" , Aeson.Object [ ("name", "R2-D2") ] ) ]

-- * Schema

type ID = Text

schema :: Applicative f => Schema f
schema = Schema query Nothing

query :: Applicative f => QueryRoot f
query = [ ("hero", hero)
        , ("human", human)
        , ("droid", droid)
        ]

hero :: Applicative f => Resolver f
hero (InputScalar (ScalarInt ep)) = OutputMap $ getHeroF ep
hero _ = InputError

human :: Applicative f => Resolver f
human (InputScalar (ScalarString id_)) = OutputScalar $ ScalarString <$> getHumanF id_
human _ = InputError

droid :: Applicative f => Resolver f
droid (InputScalar (ScalarString id_)) = OutputScalar $ ScalarString <$> getDroidF id_
droid _ = InputError

-- * Data

-- ** Characters

data Character = Character
  { id_ :: ID
  , name :: Text
  , friends :: [ID]
  , appearsIn :: [Int]
  , homePlanet :: Text
  }

luke :: Character
luke = Character
  { id_ = "1000"
  , name = "Luke Skywalker"
  , friends = ["1002","1003","2000","2001"]
  , appearsIn = [4,5,6]
  , homePlanet = "Tatoonie"
  }

artoo :: Character
artoo = Character
  { id_ = "2001"
  , name = "R2-D2"
  , friends = ["1000","1002","1003"]
  , appearsIn = [4,5,6]
  , homePlanet = "Astrometch"
  }

type CharacterMap f = Map f

character :: Applicative f => Character -> CharacterMap f
character (Character{..}) =
  [ ("id_", const . OutputScalar . pure $ ScalarID id_)
  , ("name", const . OutputScalar . pure $ ScalarString name)
  , ("friends", const . OutputList $ OutputScalar . pure . ScalarID <$> friends)
  , ("appearsIn", const . OutputList $ OutputScalar . pure . ScalarInt <$> appearsIn)
  , ("homePlanet", const . OutputScalar . pure $ ScalarString homePlanet)
  ]

-- ** Hero

getHero :: Int -> Character
getHero 5 = luke
getHero _ = artoo

getHeroF :: Applicative f => Int -> CharacterMap f
getHeroF = character . getHero

-- ** Human

getHuman :: ID -> Text
getHuman "1000" = "luke"
getHuman "1001" = "vader"
getHuman "1002" = "han"
getHuman "1003" = "leia"
getHuman "1004" = "tarkin"
getHuman _      = ""

getHumanF :: Applicative f => ID -> f Text
getHumanF = pure . getHuman

getHumanIO :: ID -> IO Text
getHumanIO = getHumanF

-- ** Droid

getDroid :: ID -> Text
getDroid "2000" = "threepio"
getDroid "2001" = "artoo"
getDroid _ = ""

getDroidF :: Applicative f => ID -> f Text
getDroidF = pure . getDroid

getDroidIO :: ID -> IO Text
getDroidIO = getDroidF