Skip to content

Commit 8bc34e1

Browse files
plcplchasura-bot
authored andcommitted
refactor(tests): Remove use of unsafeCoerce
PR-URL: hasura/graphql-engine-mono#5682 GitOrigin-RevId: 78ac1482977f427148e7675e45ff9c515db02b68
1 parent bf91655 commit 8bc34e1

File tree

2 files changed

+61
-22
lines changed

2 files changed

+61
-22
lines changed

server/src-lib/Hasura/GraphQL/Execute/Inline.hs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@
3434
-- performed by "Hasura.GraphQL.Execute.Resolve", but for fragment definitions
3535
-- rather than variables.
3636
module Hasura.GraphQL.Execute.Inline
37-
( inlineSelectionSet,
37+
( InlineMT,
38+
InlineM,
39+
inlineSelectionSet,
40+
inlineField,
41+
runInlineMT,
42+
runInlineM,
3843
)
3944
where
4045

@@ -74,6 +79,34 @@ type MonadInline m =
7479
MonadState InlineState m
7580
)
7681

82+
type InlineMT m a = MonadError QErr m => (StateT InlineState (ReaderT InlineEnv m)) a
83+
84+
type InlineM a = InlineMT (Except QErr) a
85+
86+
{-# INLINE runInlineMT #-}
87+
runInlineMT ::
88+
forall m a.
89+
(MonadError QErr m) =>
90+
HashMap Name FragmentDefinition ->
91+
InlineMT m a ->
92+
m a
93+
runInlineMT uniqueFragmentDefinitions =
94+
flip
95+
runReaderT
96+
InlineEnv
97+
{ _ieFragmentDefinitions = uniqueFragmentDefinitions,
98+
_ieFragmentStack = []
99+
}
100+
. flip evalStateT InlineState {_isFragmentCache = mempty}
101+
102+
{-# INLINE runInlineM #-}
103+
runInlineM ::
104+
forall a.
105+
HashMap Name FragmentDefinition ->
106+
InlineM a ->
107+
Either QErr a
108+
runInlineM fragments = runExcept . runInlineMT fragments
109+
77110
-- | Inlines all fragment spreads in a 'SelectionSet'; see the module
78111
-- documentation for "Hasura.GraphQL.Execute.Inline" for details.
79112
inlineSelectionSet ::
@@ -106,6 +139,8 @@ inlineSelectionSet fragmentDefinitions selectionSet = do
106139
Set.toList $
107140
Set.difference definedFragmentNames usedFragmentNames
108141
)
142+
-- The below code is a manual inlining of 'runInlineMT', as appearently the
143+
-- inlining optimization does not trigger, even with the INLINE pragma.
109144
traverse inlineSelection selectionSet
110145
& flip evalStateT InlineState {_isFragmentCache = mempty}
111146
& flip
@@ -128,18 +163,21 @@ inlineSelection ::
128163
MonadInline m =>
129164
Selection FragmentSpread Name ->
130165
m (Selection NoFragments Name)
131-
inlineSelection (SelectionField field@Field {_fSelectionSet}) =
132-
withPathK "selectionSet" $
133-
withPathK (unName $ _fName field) $ do
134-
selectionSet <- traverse inlineSelection _fSelectionSet
135-
pure $! SelectionField field {_fSelectionSet = selectionSet}
166+
inlineSelection (SelectionField field) =
167+
withPathK "selectionSet" $ SelectionField <$> inlineField field
136168
inlineSelection (SelectionFragmentSpread spread) =
137169
withPathK "selectionSet" $
138170
SelectionInlineFragment <$> inlineFragmentSpread spread
139171
inlineSelection (SelectionInlineFragment fragment@InlineFragment {_ifSelectionSet}) = do
140172
selectionSet <- traverse inlineSelection _ifSelectionSet
141173
pure $! SelectionInlineFragment fragment {_ifSelectionSet = selectionSet}
142174

175+
{-# INLINE inlineField #-}
176+
inlineField :: MonadInline m => Field FragmentSpread Name -> m (Field NoFragments Name)
177+
inlineField field@(Field {_fSelectionSet}) = withPathK (unName $ _fName field) $ do
178+
selectionSet <- traverse inlineSelection _fSelectionSet
179+
pure $! field {_fSelectionSet = selectionSet}
180+
143181
inlineFragmentSpread ::
144182
MonadInline m =>
145183
FragmentSpread Name ->

server/src-test/Test/Parser/Field.hs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
-- | QuasiQuoter for parsing GraphQL fields in tests. See 'field' for details.
22
module Test.Parser.Field (field) where
33

4+
import Control.Monad.Trans.Except
45
import Data.Attoparsec.Text qualified as Parser
56
import Data.Text qualified as T
7+
import Hasura.Base.Error (showQErr)
8+
import Hasura.GraphQL.Execute.Inline (inlineField, runInlineM)
69
import Hasura.GraphQL.Parser.Variable
710
import Hasura.Prelude
811
import Language.GraphQL.Draft.Parser qualified as GraphQL
912
import Language.GraphQL.Draft.Syntax qualified as GraphQL
1013
import Language.Haskell.TH.Lib (ExpQ)
1114
import Language.Haskell.TH.Quote
1215
import Language.Haskell.TH.Syntax qualified as TH
13-
import Unsafe.Coerce (unsafeCoerce)
1416

15-
-- | Warning: we are currently using unsafe coercions to convert the field. This
16-
-- seems to work for now, but beware.
17-
--
17+
-- | Quasi-Quoter for GraphQL fields.
1818
-- Example usage:
1919
-- > [GQL.field|
2020
-- > update_artist(
@@ -27,21 +27,22 @@ import Unsafe.Coerce (unsafeCoerce)
2727
field :: QuasiQuoter
2828
field =
2929
QuasiQuoter
30-
{ quoteExp = evalFieldGQL,
30+
{ quoteExp = fieldExp,
3131
quotePat = \_ -> fail "invalid",
3232
quoteType = \_ -> fail "invalid",
3333
quoteDec = \_ -> fail "invalid"
3434
}
35-
36-
evalFieldGQL :: String -> ExpQ
37-
evalFieldGQL = either fail TH.lift . go
3835
where
39-
-- Note: @skipSpace@ is used here to allow trailing whitespace in the QQ.
40-
go :: String -> Either String (GraphQL.Field GraphQL.NoFragments Variable)
41-
go =
42-
fmap fixField
43-
. Parser.parseOnly (Parser.skipSpace *> GraphQL.field @GraphQL.Name)
44-
. T.pack
36+
fieldExp :: String -> ExpQ
37+
fieldExp input = do
38+
either fail TH.lift $
39+
runExcept $ do
40+
parsed <- hoistEither $ Parser.parseOnly (Parser.skipSpace *> GraphQL.field @GraphQL.Name) . T.pack $ input
41+
fixField parsed
4542

46-
fixField :: GraphQL.Field GraphQL.FragmentSpread GraphQL.Name -> GraphQL.Field GraphQL.NoFragments Variable
47-
fixField = unsafeCoerce
43+
-- A parsed field can contain both fragments and variables.
44+
-- We support neither yet.
45+
fixField :: GraphQL.Field GraphQL.FragmentSpread GraphQL.Name -> Except String (GraphQL.Field GraphQL.NoFragments Variable)
46+
fixField f = do
47+
x <- except $ mapLeft (T.unpack . showQErr) $ runInlineM mempty . inlineField $ f
48+
traverse (throwE . ("Variables are not supported in tests yet: " ++) . show) x

0 commit comments

Comments
 (0)