server: allow fragments to use variables (fix hasura/graphql-engine#6303) (#225)

GitOrigin-RevId: a60b6816212b749836d5d88f296e229e581ab452
This commit is contained in:
Auke Booij 2020-12-22 11:41:39 +01:00 committed by hasura-bot
parent 4ff84756ca
commit 4bbd2fd4dc
5 changed files with 41 additions and 16 deletions

View File

@ -72,6 +72,7 @@ and be accessible according to the permissions that were configured for the role
(Add entries here in the order of: server, console, cli, docs, others)
- server: fix a regression where variables in fragments weren't accepted (fix #6303)
- server: output stack traces when encountering conflicting GraphQL types in the schema
- server: add `--websocket-compression` command-line flag for enabling websocket compression (fix #3292)
- server: some mutations that cannot be performed will no longer be in the schema (for instance, `delete_by_pk` mutations won't be shown to users that do not have select permissions on all primary keys) (#4111)

View File

@ -48,7 +48,7 @@ source-repository-package
source-repository-package
type: git
location: https://github.com/hasura/graphql-parser-hs.git
tag: f2e51dbde21ad1c596f659144128d80b69254e98
tag: f3a20ab6201669bd683d5a0c8580410af264c7d0
source-repository-package
type: git

View File

@ -61,8 +61,8 @@ data InlineEnv = InlineEnv
}
-- | Internal bookkeeping used during inlining.
newtype InlineState var = InlineState
{ _isFragmentCache :: HashMap Name (InlineFragment NoFragments var)
newtype InlineState = InlineState
{ _isFragmentCache :: HashMap Name (InlineFragment NoFragments Name)
-- ^ A cache of fragment definitions weve already inlined, so we dont need
-- to inline them again.
}
@ -70,10 +70,10 @@ newtype InlineState var = InlineState
$(makeLensesFor [("_ieFragmentStack", "ieFragmentStack")] ''InlineEnv)
$(makeLenses ''InlineState)
type MonadInline var m =
type MonadInline m =
( MonadError QErr m
, MonadReader InlineEnv m
, MonadState (InlineState var) m
, MonadState InlineState m
)
-- | Inlines all fragment spreads in a 'SelectionSet'; see the module
@ -81,8 +81,8 @@ type MonadInline var m =
inlineSelectionSet
:: (MonadError QErr m, Foldable t)
=> t FragmentDefinition
-> SelectionSet FragmentSpread var
-> m (SelectionSet NoFragments var)
-> SelectionSet FragmentSpread Name
-> m (SelectionSet NoFragments Name)
inlineSelectionSet fragmentDefinitions selectionSet = do
let fragmentDefinitionMap = Map.groupOnNE _fdName fragmentDefinitions
uniqueFragmentDefinitions <- flip Map.traverseWithKey fragmentDefinitionMap
@ -109,19 +109,19 @@ inlineSelectionSet fragmentDefinitions selectionSet = do
{ _ieFragmentDefinitions = uniqueFragmentDefinitions
, _ieFragmentStack = [] }
where
fragmentsInSelectionSet :: SelectionSet FragmentSpread var -> [Name]
fragmentsInSelectionSet :: SelectionSet FragmentSpread Name -> [Name]
fragmentsInSelectionSet selectionSet' = concatMap getFragFromSelection selectionSet'
getFragFromSelection :: Selection FragmentSpread var -> [Name]
getFragFromSelection :: Selection FragmentSpread Name -> [Name]
getFragFromSelection = \case
SelectionField fld -> fragmentsInSelectionSet $ _fSelectionSet fld
SelectionFragmentSpread fragmentSpread -> [_fsName fragmentSpread]
SelectionInlineFragment inlineFragment -> fragmentsInSelectionSet $ _ifSelectionSet inlineFragment
inlineSelection
:: MonadInline var m
=> Selection FragmentSpread var
-> m (Selection NoFragments var)
:: MonadInline m
=> Selection FragmentSpread Name
-> m (Selection NoFragments Name)
inlineSelection (SelectionField field@Field{ _fSelectionSet }) =
withPathK "selectionSet" $ withPathK (unName $ _fName field) $ do
selectionSet <- traverse inlineSelection _fSelectionSet
@ -134,9 +134,9 @@ inlineSelection (SelectionInlineFragment fragment@InlineFragment{ _ifSelectionSe
pure $! SelectionInlineFragment fragment{ _ifSelectionSet = selectionSet }
inlineFragmentSpread
:: MonadInline var m
=> FragmentSpread var
-> m (InlineFragment NoFragments var)
:: MonadInline m
=> FragmentSpread Name
-> m (InlineFragment NoFragments Name)
inlineFragmentSpread FragmentSpread{ _fsName, _fsDirectives } = do
InlineEnv{ _ieFragmentDefinitions, _ieFragmentStack } <- ask
InlineState{ _isFragmentCache } <- get
@ -158,7 +158,7 @@ inlineFragmentSpread FragmentSpread{ _fsName, _fsDirectives } = do
<- Map.lookup _fsName _ieFragmentDefinitions -> withPathK (unName _fsName) $ do
selectionSet <- locally ieFragmentStack (_fsName :) $
traverse inlineSelection (fmap absurd <$> _fdSelectionSet)
traverse inlineSelection _fdSelectionSet
let fragment = InlineFragment
{ _ifTypeCondition = Just _fdTypeCondition

View File

@ -0,0 +1,21 @@
description: select query on author with id = 1, passed through a fragment with variables
url: /v1/graphql
status: 200
response:
data:
author_by_pk:
id: 2
name: Author 2
query:
variables:
authorId: 2
query: |
fragment MyFragment on query_root {
author_by_pk(id: $authorId){
id
name
}
}
query ($authorId : Int!) {
...MyFragment
}

View File

@ -100,6 +100,9 @@ class TestGraphQLQueryFragments:
def test_select_query_fragment_cycles(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/select_query_fragment_cycles.yaml', transport)
def test_select_query_fragment_with_variable(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/select_query_fragment_with_variable.yaml', transport)
@classmethod
def dir(cls):
return 'queries/graphql_query/basic'