Skip to content

Commit 515c4f1

Browse files
Auke Booijtirumaraiselvan
authored andcommitted
server: fix an introspection query caching issue (fix hasura#4547) (hasura#4661)
Introspection queries accept variables, but we need to make sure to also touch the variables that we ignore, so that an introspection query is marked not reusable if we are not able to build a correct query plan for it. A better solution here would be to deal with such unused variables correctly, so that more introspection queries become reusable. An even better solution would be to type-safely track *how* to reuse which variables, rather than to split the reusage marking from the planning. Co-authored-by: Tirumarai Selvan <[email protected]>
1 parent 9f07e09 commit 515c4f1

File tree

3 files changed

+86
-60
lines changed

3 files changed

+86
-60
lines changed

server/commit_diff.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ Date: Thu May 21 13:43:44 2020 +0530
308308

309309
* add changelog
310310

311+
(Done, but we should re-visit this, if we do query plan caching)
311312
commit 20cbe9cfd3e90b91d3f4faf370b081fc3859cbde
312313
Author: Auke Booij <[email protected]>
313314
Date: Mon May 18 14:27:56 2020 +0200

server/src-lib/Hasura/GraphQL/Resolve/InputValue.hs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ module Hasura.GraphQL.Resolve.InputValue
1010
, asPGColumnValueM
1111
, asPGColumnValue
1212

13+
, asScalarValM
14+
, asScalarVal
1315
, asEnumVal
1416
, asEnumValM
1517
, withObject
@@ -26,6 +28,8 @@ module Hasura.GraphQL.Resolve.InputValue
2628

2729
import Hasura.Prelude
2830

31+
import qualified Text.Builder as TB
32+
2933
import qualified Language.GraphQL.Draft.Syntax as G
3034

3135
import qualified Hasura.RQL.Types as RQL
@@ -120,6 +124,19 @@ asPGColumnValue v = do
120124
openInputValue :: (MonadReusability m) => AnnInpVal -> m AnnGValue
121125
openInputValue v = when (isJust $ _aivVariable v) markNotReusable $> _aivValue v
122126

127+
asScalarValM :: (MonadReusability m, MonadError QErr m) => AnnInpVal -> PGScalarType -> m (Maybe PGScalarValue)
128+
asScalarValM v tp = openInputValue v >>= \case
129+
AGScalar tp' vM ->
130+
if tp == tp'
131+
then pure vM
132+
else tyMismatch "scalar" v
133+
_ -> tyMismatch "scalar" v
134+
135+
asScalarVal :: (MonadReusability m, MonadError QErr m) => AnnInpVal -> PGScalarType -> m PGScalarValue
136+
asScalarVal v tp = asScalarValM v tp >>= \case
137+
Just val -> pure val
138+
Nothing -> throw500 $ "unexpected null for ty " <> TB.run (toSQL tp)
139+
123140
-- | Note: only handles “synthetic” enums (see 'EnumValuesInfo'). Enum table references are handled
124141
-- by 'asPGColumnType' and its variants.
125142
asEnumVal :: (MonadReusability m, MonadError QErr m) => AnnInpVal -> m (G.NamedType, G.EnumValue)

server/src-lib/Hasura/GraphQL/Resolve/Introspect.hs

Lines changed: 68 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -58,38 +58,40 @@ retJT = pure . J.toJSON
5858

5959
-- 4.5.2.1
6060
scalarR
61-
:: (Monad m)
61+
:: (MonadReusability m, MonadError QErr m)
6262
=> ScalarTyInfo
6363
-> Field
6464
-> m J.Object
65-
scalarR (ScalarTyInfo descM name _ _) fld =
65+
scalarR (ScalarTyInfo descM name _ _) fld = do
66+
dummyReadIncludeDeprecated fld
6667
withSubFields (_fSelSet fld) $ \subFld ->
67-
case _fName subFld of
68-
"__typename" -> retJT "__Type"
69-
"kind" -> retJ TKSCALAR
70-
"description" -> retJ $ fmap G.unDescription descM
71-
"name" -> retJ name
72-
_ -> 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
7374

7475
-- 4.5.2.2
7576
objectTypeR
7677
:: ( MonadReader r m, Has TypeMap r
77-
, MonadError QErr m)
78+
, MonadError QErr m, MonadReusability m)
7879
=> ObjTyInfo
7980
-> Field
8081
-> m J.Object
81-
objectTypeR objectType fld =
82+
objectTypeR objectType fld = do
83+
dummyReadIncludeDeprecated fld
8284
withSubFields (_fSelSet fld) $ \subFld ->
83-
case _fName subFld of
84-
"__typename" -> retJT "__Type"
85-
"kind" -> retJ TKOBJECT
86-
"name" -> retJ $ namedTyToTxt n
87-
"description" -> retJ $ fmap G.unDescription descM
88-
"interfaces" -> fmap J.toJSON $ mapM (`ifaceR` subFld) $ Set.toList iFaces
89-
"fields" -> fmap J.toJSON $ mapM (`fieldR` subFld) $
90-
sortOn _fiName $
91-
filter notBuiltinFld $ Map.elems flds
92-
_ -> 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
9395
where
9496
descM = _otiDesc objectType
9597
n = _otiName objectType
@@ -110,23 +112,24 @@ getImplTypes aot = do
110112

111113
-- 4.5.2.3
112114
unionR
113-
:: (MonadReader t m, MonadError QErr m, Has TypeMap t)
115+
:: (MonadReader t m, MonadError QErr m, Has TypeMap t, MonadReusability m)
114116
=> UnionTyInfo -> Field -> m J.Object
115-
unionR u@(UnionTyInfo descM n _) fld =
117+
unionR u@(UnionTyInfo descM n _) fld = do
118+
dummyReadIncludeDeprecated fld
116119
withSubFields (_fSelSet fld) $ \subFld ->
117-
case _fName subFld of
118-
"__typename" -> retJT "__Field"
119-
"kind" -> retJ TKUNION
120-
"name" -> retJ $ namedTyToTxt n
121-
"description" -> retJ $ fmap G.unDescription descM
122-
"possibleTypes" -> fmap J.toJSON $
123-
mapM (`objectTypeR` subFld) =<< getImplTypes (AOTUnion u)
124-
_ -> 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
125128

126129
-- 4.5.2.4
127130
ifaceR
128131
:: ( MonadReader r m, Has TypeMap r
129-
, MonadError QErr m)
132+
, MonadError QErr m, MonadReusability m)
130133
=> G.NamedType
131134
-> Field
132135
-> m J.Object
@@ -138,7 +141,7 @@ ifaceR n fld = do
138141

139142
ifaceR'
140143
:: ( MonadReader r m, Has TypeMap r
141-
, MonadError QErr m)
144+
, MonadError QErr m, MonadReusability m)
142145
=> IFaceTyInfo
143146
-> Field
144147
-> m J.Object
@@ -163,11 +166,12 @@ ifaceR' ifaceTyInfo fld = do
163166

164167
-- 4.5.2.5
165168
enumTypeR
166-
:: ( Monad m )
169+
:: ( Monad m, MonadReusability m, MonadError QErr m )
167170
=> EnumTyInfo
168171
-> Field
169172
-> m J.Object
170-
enumTypeR (EnumTyInfo descM n vals _) fld =
173+
enumTypeR (EnumTyInfo descM n vals _) fld = do
174+
dummyReadIncludeDeprecated fld
171175
withSubFields (_fSelSet fld) $ \subFld ->
172176
case _fName subFld of
173177
"__typename" -> retJT "__Type"
@@ -231,25 +235,26 @@ dummyReadIncludeDeprecated fld = do
231235
-- 4.5.2.6
232236
inputObjR
233237
:: ( MonadReader r m, Has TypeMap r
234-
, MonadError QErr m)
238+
, MonadError QErr m, MonadReusability m)
235239
=> InpObjTyInfo
236240
-> Field
237241
-> m J.Object
238-
inputObjR (InpObjTyInfo descM nt flds _) fld =
242+
inputObjR (InpObjTyInfo descM nt flds _) fld = do
243+
dummyReadIncludeDeprecated fld
239244
withSubFields (_fSelSet fld) $ \subFld ->
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
245+
case _fName subFld of
246+
"__typename" -> retJT "__Type"
247+
"kind" -> retJ TKINPUT_OBJECT
248+
"name" -> retJ $ namedTyToTxt nt
249+
"description" -> retJ $ fmap G.unDescription descM
250+
"inputFields" -> fmap J.toJSON $ mapM (inputValueR subFld) $
251+
sortOn _iviName $ Map.elems flds
252+
_ -> return J.Null
248253

249254
-- 4.5.2.7
250255
listTypeR
251256
:: ( MonadReader r m, Has TypeMap r
252-
, MonadError QErr m)
257+
, MonadError QErr m, MonadReusability m)
253258
=> G.ListType -> Field -> m J.Object
254259
listTypeR (G.ListType ty) fld =
255260
withSubFields (_fSelSet fld) $ \subFld ->
@@ -262,7 +267,7 @@ listTypeR (G.ListType ty) fld =
262267
-- 4.5.2.8
263268
nonNullR
264269
:: ( MonadReader r m, Has TypeMap r
265-
, MonadError QErr m)
270+
, MonadError QErr m, MonadReusability m)
266271
=> G.GType -> Field -> m J.Object
267272
nonNullR gTyp fld =
268273
withSubFields (_fSelSet fld) $ \subFld ->
@@ -277,7 +282,7 @@ nonNullR gTyp fld =
277282

278283
namedTypeR
279284
:: ( MonadReader r m, Has TypeMap r
280-
, MonadError QErr m)
285+
, MonadError QErr m, MonadReusability m)
281286
=> G.NamedType
282287
-> Field
283288
-> m J.Object
@@ -287,22 +292,25 @@ namedTypeR nt fld = do
287292

288293
namedTypeR'
289294
:: ( MonadReader r m, Has TypeMap r
290-
, MonadError QErr m)
295+
, MonadError QErr m, MonadReusability m)
291296
=> Field
292297
-> TypeInfo
293298
-> m J.Object
294-
namedTypeR' fld = \case
295-
TIScalar colTy -> scalarR colTy fld
296-
TIObj objTyInfo -> objectTypeR objTyInfo fld
297-
TIEnum enumTypeInfo -> enumTypeR enumTypeInfo fld
298-
TIInpObj inpObjTyInfo -> inputObjR inpObjTyInfo fld
299-
TIIFace iFaceTyInfo -> ifaceR' iFaceTyInfo fld
300-
TIUnion unionTyInfo -> unionR unionTyInfo fld
299+
namedTypeR' fld tyInfo = do
300+
-- Now fetch the required type information from the corresponding
301+
-- information generator
302+
case tyInfo of
303+
TIScalar colTy -> scalarR colTy fld
304+
TIObj objTyInfo -> objectTypeR objTyInfo fld
305+
TIEnum enumTypeInfo -> enumTypeR enumTypeInfo fld
306+
TIInpObj inpObjTyInfo -> inputObjR inpObjTyInfo fld
307+
TIIFace iFaceTyInfo -> ifaceR' iFaceTyInfo fld
308+
TIUnion unionTyInfo -> unionR unionTyInfo fld
301309

302310
-- 4.5.3
303311
fieldR
304312
:: ( MonadReader r m, Has TypeMap r
305-
, MonadError QErr m)
313+
, MonadError QErr m, MonadReusability m)
306314
=> ObjFldInfo -> Field -> m J.Object
307315
fieldR (ObjFldInfo descM n params ty _) fld =
308316
withSubFields (_fSelSet fld) $ \subFld ->
@@ -319,7 +327,7 @@ fieldR (ObjFldInfo descM n params ty _) fld =
319327
-- 4.5.4
320328
inputValueR
321329
:: ( MonadReader r m, Has TypeMap r
322-
, MonadError QErr m)
330+
, MonadError QErr m, MonadReusability m)
323331
=> Field -> InpValInfo -> m J.Object
324332
inputValueR fld (InpValInfo descM n defM ty) =
325333
withSubFields (_fSelSet fld) $ \subFld ->
@@ -348,7 +356,7 @@ enumValueR fld (EnumValInfo descM enumVal isDeprecated) =
348356
-- 4.5.6
349357
directiveR
350358
:: ( MonadReader r m, Has TypeMap r
351-
, MonadError QErr m)
359+
, MonadError QErr m, MonadReusability m)
352360
=> Field -> DirectiveInfo -> m J.Object
353361
directiveR fld (DirectiveInfo descM n args locs) =
354362
withSubFields (_fSelSet fld) $ \subFld ->
@@ -368,7 +376,7 @@ showDirLoc = \case
368376

369377
gtypeR
370378
:: ( MonadReader r m, Has TypeMap r
371-
, MonadError QErr m)
379+
, MonadError QErr m, MonadReusability m)
372380
=> G.GType -> Field -> m J.Object
373381
gtypeR ty fld =
374382
case ty of
@@ -379,7 +387,7 @@ gtypeR ty fld =
379387

380388
schemaR
381389
:: ( MonadReader r m, Has TypeMap r
382-
, MonadError QErr m)
390+
, MonadError QErr m, MonadReusability m)
383391
=> Field -> m J.Object
384392
schemaR fld =
385393
withSubFields (_fSelSet fld) $ \subFld -> do

0 commit comments

Comments
 (0)