/
Variables.purs
181 lines (162 loc) · 5.33 KB
/
Variables.purs
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
module GraphQL.Client.Variables
( class GetVar
, class VarsTypeChecked
, GetVarRec
, WithVars
, getVarsJson
, getVarsTypeNames
, getQuery
, getQueryVars
, getVar
, withVars
, withVarsEncode
) where
import Prelude
import Control.Apply (lift2)
import Data.Argonaut.Core (Json, jsonEmptyObject)
import Data.Argonaut.Encode (class EncodeJson, encodeJson)
import Data.Symbol (class IsSymbol)
import GraphQL.Client.Alias (Alias)
import GraphQL.Client.Alias.Dynamic (Spread)
import GraphQL.Client.Args (AndArg, Args, OrArg)
import GraphQL.Client.Variable (Var)
import GraphQL.Client.Variables.TypeName (VarTypeNameProps, varTypeNameRecord)
import Heterogeneous.Folding (class Folding, class HFoldl, class HFoldlWithIndex, hfoldl)
import Prim.Row as Row
import Record as Record
import Type.Proxy (Proxy(..))
class GetVar :: forall k. Type -> k -> Constraint
class GetVar query var | query -> var where
getVar :: Proxy query -> Proxy var
instance getVarVar ::
( IsSymbol name
, Row.Cons name a () var
) =>
GetVar (Var name a) { | var } where
getVar _ = lift2 (Record.insert (Proxy :: Proxy name)) (Proxy :: Proxy a) (Proxy :: Proxy {})
else instance getVarAlias ::
( GetVar query var
) =>
GetVar (Alias name query) var where
getVar _ = getVar (Proxy :: _ query)
else instance getVarSpread ::
( GetVar l { | varL }
, GetVar r { | varR }
, Row.Union varR varL trash
, Row.Union varL varR trash -- keep both union directions to make sure value type is the same
, Row.Nub trash var
) =>
GetVar (Spread name l r) { | var } where
getVar _ =
let
varL :: Proxy { | varL }
varL = getVar (Proxy :: _ l)
varR :: Proxy { | varR }
varR = getVar (Proxy :: _ r)
in
lift2 Record.merge varL varR
else instance getVarArg ::
( GetVar arg { | varArg }
, GetVar t { | varT }
, Row.Union varT varArg trash
, Row.Union varArg varT trash -- keep both union directions to make sure value type is the same
, Row.Nub trash var
) =>
GetVar (Args arg t) { | var } where
getVar _ =
let
varArg :: Proxy { | varArg }
varArg = getVar (Proxy :: _ arg)
varT :: Proxy { | varT }
varT = getVar (Proxy :: _ t)
in
lift2 Record.merge varArg varT
else instance getVarAndArg ::
( GetVar l { | varL }
, GetVar r { | varR }
, Row.Union varR varL trash
, Row.Union varL varR trash -- keep both union directions to make sure value type is the same
, Row.Nub trash var
) =>
GetVar (AndArg l r) { | var } where
getVar _ =
let
varL :: Proxy { | varL }
varL = getVar (Proxy :: _ l)
varR :: Proxy { | varR }
varR = getVar (Proxy :: _ r)
in
lift2 Record.merge varL varR
else instance getVarOrArg ::
( GetVar l { | varL }
, GetVar r { | varR }
, Row.Union varR varL trash
, Row.Union varL varR trash -- keep both union directions to make sure value type is the same
, Row.Nub trash var
) =>
GetVar (OrArg l r) { | var } where
getVar _ =
let
varL :: Proxy { | varL }
varL = getVar (Proxy :: _ l)
varR :: Proxy { | varR }
varR = getVar (Proxy :: _ r)
in
lift2 Record.merge varL varR
else instance getVarRecord ::
( HFoldl GetVarRec (Proxy {}) { | query } (Proxy { | var })
) =>
GetVar { | query } { | var } where
getVar q = q >>= \query -> hfoldl GetVarRec (Proxy :: _ {}) (query :: { | query })
else instance getVarSkip :: GetVar a {} where
getVar _ = Proxy
-- | Get variables from a record, recursively
data GetVarRec
= GetVarRec
instance getVarRec ::
( GetVar val { | subRes }
, Row.Union acc subRes trash
, Row.Union subRes acc trash
, Row.Nub trash res
) =>
Folding GetVarRec (Proxy { | acc }) val (Proxy { | res }) where
folding GetVarRec acc _ = lift2 Record.merge acc $ getVar (Proxy :: _ val)
getQueryVars :: forall query vars. GetVar query vars => query -> Proxy vars
getQueryVars _ = getVar (Proxy :: _ query)
data WithVars :: forall k. Type -> k -> Type
data WithVars query vars
= WithVars query String Json
-- | Add variables to a query with a custom encoder
withVarsEncode ::
forall query vars.
HFoldlWithIndex VarTypeNameProps String {|vars} String =>
HFoldl GetVarRec (Proxy {}) query (Proxy {|vars}) =>
({|vars} -> Json) ->
query -> {|vars} -> WithVars query {|vars}
withVarsEncode encode query vars = WithVars query (varTypeNameRecord vars) $ encode vars
-- | Add variables to a query
withVars ::
forall query vars.
HFoldlWithIndex VarTypeNameProps String {|vars} String =>
HFoldl GetVarRec (Proxy {}) query (Proxy {|vars}) =>
EncodeJson {|vars} =>
query -> {|vars} -> WithVars query {|vars}
withVars = withVarsEncode encodeJson
getQuery :: forall query vars. WithVars query vars -> query
getQuery (WithVars query _ _) = query
class VarsTypeChecked query where
getVarsJson :: query -> Json
getVarsTypeNames :: query -> String
instance varsTypeCheckedWithVars :: VarsTypeChecked (WithVars query vars) where
getVarsJson (WithVars _ _ json) = json
getVarsTypeNames (WithVars _ varsTypeNames _) = varsTypeNames
else instance varsTypeCheckedWithoutVars ::
GetVar { | query } {} =>
VarsTypeChecked { | query } where
getVarsJson _ = jsonEmptyObject
getVarsTypeNames _ = ""
else instance varsTypeCheckedSpread ::
GetVar (Spread alias arg fields) {} =>
VarsTypeChecked (Spread alias arg fields) where
getVarsJson _ = jsonEmptyObject
getVarsTypeNames _ = ""