@@ -11,6 +11,8 @@ import qualified Data.HashMap.Strict as Map
11
11
import qualified Data.HashSet as Set
12
12
import qualified Data.Text as T
13
13
import qualified Language.GraphQL.Draft.Syntax as G
14
+ import qualified Hasura.SQL.Value as S
15
+ import qualified Hasura.SQL.Types as S
14
16
15
17
import Hasura.GraphQL.Context
16
18
import Hasura.GraphQL.Resolve.Context
@@ -56,38 +58,40 @@ retJT = pure . J.toJSON
56
58
57
59
-- 4.5.2.1
58
60
scalarR
59
- :: (Monad m )
61
+ :: (MonadReusability m , MonadError QErr m )
60
62
=> ScalarTyInfo
61
63
-> Field
62
64
-> m J. Object
63
- scalarR (ScalarTyInfo descM name _ _) fld =
65
+ scalarR (ScalarTyInfo descM name _ _) fld = do
66
+ dummyReadIncludeDeprecated fld
64
67
withSubFields (_fSelSet fld) $ \ subFld ->
65
- case _fName subFld of
66
- " __typename" -> retJT " __Type"
67
- " kind" -> retJ TKSCALAR
68
- " description" -> retJ $ fmap G. unDescription descM
69
- " name" -> retJ name
70
- _ -> return J. Null
68
+ case _fName subFld of
69
+ " __typename" -> retJT " __Type"
70
+ " kind" -> retJ TKSCALAR
71
+ " description" -> retJ $ fmap G. unDescription descM
72
+ " name" -> retJ name
73
+ _ -> return J. Null
71
74
72
75
-- 4.5.2.2
73
76
objectTypeR
74
77
:: ( MonadReader r m , Has TypeMap r
75
- , MonadError QErr m )
78
+ , MonadError QErr m , MonadReusability m )
76
79
=> ObjTyInfo
77
80
-> Field
78
81
-> m J. Object
79
- objectTypeR objectType fld =
82
+ objectTypeR objectType fld = do
83
+ dummyReadIncludeDeprecated fld
80
84
withSubFields (_fSelSet fld) $ \ subFld ->
81
- case _fName subFld of
82
- " __typename" -> retJT " __Type"
83
- " kind" -> retJ TKOBJECT
84
- " name" -> retJ $ namedTyToTxt n
85
- " description" -> retJ $ fmap G. unDescription descM
86
- " interfaces" -> fmap J. toJSON $ mapM (`ifaceR` subFld) $ Set. toList iFaces
87
- " fields" -> fmap J. toJSON $ mapM (`fieldR` subFld) $
88
- sortOn _fiName $
89
- filter notBuiltinFld $ Map. elems flds
90
- _ -> return J. Null
85
+ case _fName subFld of
86
+ " __typename" -> retJT " __Type"
87
+ " kind" -> retJ TKOBJECT
88
+ " name" -> retJ $ namedTyToTxt n
89
+ " description" -> retJ $ fmap G. unDescription descM
90
+ " interfaces" -> fmap J. toJSON $ mapM (`ifaceR` subFld) $ Set. toList iFaces
91
+ " fields" -> fmap J. toJSON $ mapM (`fieldR` subFld) $
92
+ sortOn _fiName $
93
+ filter notBuiltinFld $ Map. elems flds
94
+ _ -> return J. Null
91
95
where
92
96
descM = _otiDesc objectType
93
97
n = _otiName objectType
@@ -108,23 +112,24 @@ getImplTypes aot = do
108
112
109
113
-- 4.5.2.3
110
114
unionR
111
- :: (MonadReader t m , MonadError QErr m , Has TypeMap t )
115
+ :: (MonadReader t m , MonadError QErr m , Has TypeMap t , MonadReusability m )
112
116
=> UnionTyInfo -> Field -> m J. Object
113
- unionR u@ (UnionTyInfo descM n _) fld =
117
+ unionR u@ (UnionTyInfo descM n _) fld = do
118
+ dummyReadIncludeDeprecated fld
114
119
withSubFields (_fSelSet fld) $ \ subFld ->
115
- case _fName subFld of
116
- " __typename" -> retJT " __Field"
117
- " kind" -> retJ TKUNION
118
- " name" -> retJ $ namedTyToTxt n
119
- " description" -> retJ $ fmap G. unDescription descM
120
- " possibleTypes" -> fmap J. toJSON $
121
- mapM (`objectTypeR` subFld) =<< getImplTypes (AOTUnion u)
122
- _ -> return J. Null
120
+ case _fName subFld of
121
+ " __typename" -> retJT " __Field"
122
+ " kind" -> retJ TKUNION
123
+ " name" -> retJ $ namedTyToTxt n
124
+ " description" -> retJ $ fmap G. unDescription descM
125
+ " possibleTypes" -> fmap J. toJSON $
126
+ mapM (`objectTypeR` subFld) =<< getImplTypes (AOTUnion u)
127
+ _ -> return J. Null
123
128
124
129
-- 4.5.2.4
125
130
ifaceR
126
131
:: ( MonadReader r m , Has TypeMap r
127
- , MonadError QErr m )
132
+ , MonadError QErr m , MonadReusability m )
128
133
=> G. NamedType
129
134
-> Field
130
135
-> m J. Object
@@ -136,63 +141,115 @@ ifaceR n fld = do
136
141
137
142
ifaceR'
138
143
:: ( MonadReader r m , Has TypeMap r
139
- , MonadError QErr m )
144
+ , MonadError QErr m , MonadReusability m )
140
145
=> IFaceTyInfo
141
146
-> Field
142
147
-> m J. Object
143
- ifaceR' i@ (IFaceTyInfo descM n flds) fld =
148
+ ifaceR' i@ (IFaceTyInfo descM n flds) fld = do
149
+ dummyReadIncludeDeprecated fld
144
150
withSubFields (_fSelSet fld) $ \ subFld ->
145
- case _fName subFld of
146
- " __typename" -> retJT " __Type"
147
- " kind" -> retJ TKINTERFACE
148
- " name" -> retJ $ namedTyToTxt n
149
- " description" -> retJ $ fmap G. unDescription descM
150
- " fields" -> fmap J. toJSON $ mapM (`fieldR` subFld) $
151
- sortOn _fiName $
152
- filter notBuiltinFld $ Map. elems flds
153
- " possibleTypes" -> fmap J. toJSON $ mapM (`objectTypeR` subFld)
154
- =<< getImplTypes (AOTIFace i)
155
- _ -> return J. Null
151
+ case _fName subFld of
152
+ " __typename" -> retJT " __Type"
153
+ " kind" -> retJ TKINTERFACE
154
+ " name" -> retJ $ namedTyToTxt n
155
+ " description" -> retJ $ fmap G. unDescription descM
156
+ " fields" -> fmap J. toJSON $ mapM (`fieldR` subFld) $
157
+ sortOn _fiName $
158
+ filter notBuiltinFld $ Map. elems flds
159
+ " possibleTypes" -> fmap J. toJSON $ mapM (`objectTypeR` subFld)
160
+ =<< getImplTypes (AOTIFace i)
161
+ _ -> return J. Null
156
162
157
163
-- 4.5.2.5
158
164
enumTypeR
159
- :: ( Monad m )
165
+ :: ( Monad m , MonadReusability m , MonadError QErr m )
160
166
=> EnumTyInfo
161
167
-> Field
162
168
-> m J. Object
163
- enumTypeR (EnumTyInfo descM n vals _) fld =
169
+ enumTypeR (EnumTyInfo descM n vals _) fld = do
170
+ dummyReadIncludeDeprecated fld
164
171
withSubFields (_fSelSet fld) $ \ subFld ->
165
- case _fName subFld of
166
- " __typename" -> retJT " __Type"
167
- " kind" -> retJ TKENUM
168
- " name" -> retJ $ namedTyToTxt n
169
- " description" -> retJ $ fmap G. unDescription descM
170
- " enumValues" -> fmap J. toJSON $ mapM (enumValueR subFld) $
171
- sortOn _eviVal $ Map. elems (normalizeEnumValues vals)
172
- _ -> return J. Null
172
+ case _fName subFld of
173
+ " __typename" -> retJT " __Type"
174
+ " kind" -> retJ TKENUM
175
+ " name" -> retJ $ namedTyToTxt n
176
+ " description" -> retJ $ fmap G. unDescription descM
177
+ " enumValues" -> do
178
+ includeDeprecated <- readIncludeDeprecated subFld
179
+ fmap J. toJSON $
180
+ mapM (enumValueR subFld) $
181
+ filter (\ val -> includeDeprecated || not (_eviIsDeprecated val)) $
182
+ sortOn _eviVal $
183
+ Map. elems (normalizeEnumValues vals)
184
+ _ -> return J. Null
185
+
186
+ readIncludeDeprecated
187
+ :: ( Monad m , MonadReusability m , MonadError QErr m )
188
+ => Field
189
+ -> m Bool
190
+ readIncludeDeprecated subFld = do
191
+ let argM = Map. lookup " includeDeprecated" (_fArguments subFld)
192
+ case argM of
193
+ Nothing -> pure False
194
+ Just arg -> asScalarVal arg S. PGBoolean >>= \ case
195
+ S. PGValBoolean b -> pure b
196
+ _ -> throw500 " unexpected non-Boolean argument for includeDeprecated"
197
+
198
+ {- Note [Reusability of introspection queries with variables]
199
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
200
+ Introspection queries can have variables, too, in particular to influence one of
201
+ two arguments: the @name@ argument of the @__type@ field, and the
202
+ @includeDeprecated@ argument of the @fields@ and @enumValues@ fields. The
203
+ current code does not cache all introspection queries with variables correctly.
204
+ As a workaround to this, whenever a variable is passed to an @includeDeprecated@
205
+ argument, we mark the query as unreusable. This is the purpose of
206
+ 'dummyReadIncludeDeprecated'.
207
+
208
+ Now @fields@ and @enumValues@ are intended to be used when introspecting,
209
+ respectively [object and interface types] and enum types. However, it does not
210
+ suffice to only call 'dummyReadIncludeDeprecated' for such types, since @fields@
211
+ and @enumValues@ are valid GraphQL fields regardless of what type we are looking
212
+ at. So precisely because @__Type@ is _thought of_ as a union, but _not
213
+ actually_ a union, we need to call 'dummyReadIncludeDeprecated' in all cases.
214
+
215
+ See also issue #4547.
216
+ -}
217
+
218
+ dummyReadIncludeDeprecated
219
+ :: ( Monad m , MonadReusability m , MonadError QErr m )
220
+ => Field
221
+ -> m ()
222
+ dummyReadIncludeDeprecated fld =
223
+ void $ forM (toList (_fSelSet fld)) $ \ subFld ->
224
+ case _fName subFld of
225
+ " fields" -> readIncludeDeprecated subFld
226
+ " enumValues" -> readIncludeDeprecated subFld
227
+ _ -> return False
228
+
173
229
174
230
-- 4.5.2.6
175
231
inputObjR
176
232
:: ( MonadReader r m , Has TypeMap r
177
- , MonadError QErr m )
233
+ , MonadError QErr m , MonadReusability m )
178
234
=> InpObjTyInfo
179
235
-> Field
180
236
-> m J. Object
181
- inputObjR (InpObjTyInfo descM nt flds _) fld =
237
+ inputObjR (InpObjTyInfo descM nt flds _) fld = do
238
+ dummyReadIncludeDeprecated fld
182
239
withSubFields (_fSelSet fld) $ \ subFld ->
183
- case _fName subFld of
184
- " __typename" -> retJT " __Type"
185
- " kind" -> retJ TKINPUT_OBJECT
186
- " name" -> retJ $ namedTyToTxt nt
187
- " description" -> retJ $ fmap G. unDescription descM
188
- " inputFields" -> fmap J. toJSON $ mapM (inputValueR subFld) $
189
- sortOn _iviName $ Map. elems flds
190
- _ -> return J. Null
240
+ case _fName subFld of
241
+ " __typename" -> retJT " __Type"
242
+ " kind" -> retJ TKINPUT_OBJECT
243
+ " name" -> retJ $ namedTyToTxt nt
244
+ " description" -> retJ $ fmap G. unDescription descM
245
+ " inputFields" -> fmap J. toJSON $ mapM (inputValueR subFld) $
246
+ sortOn _iviName $ Map. elems flds
247
+ _ -> return J. Null
191
248
192
249
-- 4.5.2.7
193
250
listTypeR
194
251
:: ( MonadReader r m , Has TypeMap r
195
- , MonadError QErr m )
252
+ , MonadError QErr m , MonadReusability m )
196
253
=> G. ListType -> Field -> m J. Object
197
254
listTypeR (G. ListType ty) fld =
198
255
withSubFields (_fSelSet fld) $ \ subFld ->
@@ -205,7 +262,7 @@ listTypeR (G.ListType ty) fld =
205
262
-- 4.5.2.8
206
263
nonNullR
207
264
:: ( MonadReader r m , Has TypeMap r
208
- , MonadError QErr m )
265
+ , MonadError QErr m , MonadReusability m )
209
266
=> G. GType -> Field -> m J. Object
210
267
nonNullR gTyp fld =
211
268
withSubFields (_fSelSet fld) $ \ subFld ->
@@ -220,7 +277,7 @@ nonNullR gTyp fld =
220
277
221
278
namedTypeR
222
279
:: ( MonadReader r m , Has TypeMap r
223
- , MonadError QErr m )
280
+ , MonadError QErr m , MonadReusability m )
224
281
=> G. NamedType
225
282
-> Field
226
283
-> m J. Object
@@ -230,22 +287,25 @@ namedTypeR nt fld = do
230
287
231
288
namedTypeR'
232
289
:: ( MonadReader r m , Has TypeMap r
233
- , MonadError QErr m )
290
+ , MonadError QErr m , MonadReusability m )
234
291
=> Field
235
292
-> TypeInfo
236
293
-> m J. Object
237
- namedTypeR' fld = \ case
238
- TIScalar colTy -> scalarR colTy fld
239
- TIObj objTyInfo -> objectTypeR objTyInfo fld
240
- TIEnum enumTypeInfo -> enumTypeR enumTypeInfo fld
241
- TIInpObj inpObjTyInfo -> inputObjR inpObjTyInfo fld
242
- TIIFace iFaceTyInfo -> ifaceR' iFaceTyInfo fld
243
- TIUnion unionTyInfo -> unionR unionTyInfo fld
294
+ namedTypeR' fld tyInfo = do
295
+ -- Now fetch the required type information from the corresponding
296
+ -- information generator
297
+ case tyInfo of
298
+ TIScalar colTy -> scalarR colTy fld
299
+ TIObj objTyInfo -> objectTypeR objTyInfo fld
300
+ TIEnum enumTypeInfo -> enumTypeR enumTypeInfo fld
301
+ TIInpObj inpObjTyInfo -> inputObjR inpObjTyInfo fld
302
+ TIIFace iFaceTyInfo -> ifaceR' iFaceTyInfo fld
303
+ TIUnion unionTyInfo -> unionR unionTyInfo fld
244
304
245
305
-- 4.5.3
246
306
fieldR
247
307
:: ( MonadReader r m , Has TypeMap r
248
- , MonadError QErr m )
308
+ , MonadError QErr m , MonadReusability m )
249
309
=> ObjFldInfo -> Field -> m J. Object
250
310
fieldR (ObjFldInfo descM n params ty _) fld =
251
311
withSubFields (_fSelSet fld) $ \ subFld ->
@@ -262,7 +322,7 @@ fieldR (ObjFldInfo descM n params ty _) fld =
262
322
-- 4.5.4
263
323
inputValueR
264
324
:: ( MonadReader r m , Has TypeMap r
265
- , MonadError QErr m )
325
+ , MonadError QErr m , MonadReusability m )
266
326
=> Field -> InpValInfo -> m J. Object
267
327
inputValueR fld (InpValInfo descM n defM ty) =
268
328
withSubFields (_fSelSet fld) $ \ subFld ->
@@ -291,7 +351,7 @@ enumValueR fld (EnumValInfo descM enumVal isDeprecated) =
291
351
-- 4.5.6
292
352
directiveR
293
353
:: ( MonadReader r m , Has TypeMap r
294
- , MonadError QErr m )
354
+ , MonadError QErr m , MonadReusability m )
295
355
=> Field -> DirectiveInfo -> m J. Object
296
356
directiveR fld (DirectiveInfo descM n args locs) =
297
357
withSubFields (_fSelSet fld) $ \ subFld ->
@@ -311,7 +371,7 @@ showDirLoc = \case
311
371
312
372
gtypeR
313
373
:: ( MonadReader r m , Has TypeMap r
314
- , MonadError QErr m )
374
+ , MonadError QErr m , MonadReusability m )
315
375
=> G. GType -> Field -> m J. Object
316
376
gtypeR ty fld =
317
377
case ty of
@@ -322,7 +382,7 @@ gtypeR ty fld =
322
382
323
383
schemaR
324
384
:: ( MonadReader r m , Has TypeMap r
325
- , MonadError QErr m )
385
+ , MonadError QErr m , MonadReusability m )
326
386
=> Field -> m J. Object
327
387
schemaR fld =
328
388
withSubFields (_fSelSet fld) $ \ subFld -> do
@@ -348,7 +408,7 @@ typeR fld = do
348
408
args = _fArguments fld
349
409
350
410
typeR'
351
- :: (MonadReader r m , Has TypeMap r , MonadError QErr m )
411
+ :: (MonadReader r m , Has TypeMap r , MonadError QErr m , MonadReusability m )
352
412
=> G. NamedType -> Field -> m J. Value
353
413
typeR' n fld = do
354
414
tyMap <- asks getter
0 commit comments