mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-16 18:42:30 +03:00
d43a30e8fc
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5686 GitOrigin-RevId: 85b39ad569180929e5620c45bf9a98ef6ee99d42
83 lines
2.8 KiB
Haskell
83 lines
2.8 KiB
Haskell
{-# LANGUAGE QuasiQuotes #-}
|
|
{-# LANGUAGE TemplateHaskellQuotes #-}
|
|
|
|
-- | QuasiQuoter for parsing GraphQL fields in tests. See 'field' for details.
|
|
module Test.Parser.Field
|
|
( field,
|
|
inputfields,
|
|
)
|
|
where
|
|
|
|
import Control.Monad.Trans.Except
|
|
import Data.Attoparsec.Text qualified as Parser
|
|
import Data.Text qualified as T
|
|
import Hasura.Base.Error (showQErr)
|
|
import Hasura.GraphQL.Execute.Inline (inlineField, runInlineM)
|
|
import Hasura.GraphQL.Parser.Variable
|
|
import Hasura.Prelude
|
|
import Language.GraphQL.Draft.Parser qualified as GraphQL
|
|
import Language.GraphQL.Draft.Syntax qualified as GraphQL
|
|
import Language.Haskell.TH.Lib (ExpQ)
|
|
import Language.Haskell.TH.Quote
|
|
import Language.Haskell.TH.Syntax qualified as TH
|
|
|
|
-- | Quasi-Quoter for GraphQL fields.
|
|
-- Example usage:
|
|
-- > [GQL.field|
|
|
-- > update_artist(
|
|
-- > where: { name: { _eq: "old name"}},
|
|
-- > _set: { name: "new name" }
|
|
-- > ) {
|
|
-- > affected_rows
|
|
-- > }
|
|
-- > |],
|
|
field :: QuasiQuoter
|
|
field =
|
|
QuasiQuoter
|
|
{ quoteExp = fieldExp,
|
|
quotePat = \_ -> fail "invalid",
|
|
quoteType = \_ -> fail "invalid",
|
|
quoteDec = \_ -> fail "invalid"
|
|
}
|
|
where
|
|
fieldExp :: String -> ExpQ
|
|
fieldExp input = do
|
|
either fail TH.lift $
|
|
runExcept $ do
|
|
parsed <- hoistEither $ Parser.parseOnly (Parser.skipSpace *> GraphQL.field @GraphQL.Name) . T.pack $ input
|
|
fixField parsed
|
|
|
|
-- A parsed field can contain both fragments and variables.
|
|
-- We support neither yet.
|
|
fixField :: GraphQL.Field GraphQL.FragmentSpread GraphQL.Name -> Except String (GraphQL.Field GraphQL.NoFragments Variable)
|
|
fixField f = do
|
|
x <- except $ mapLeft (T.unpack . showQErr) $ runInlineM mempty . inlineField $ f
|
|
traverse (throwE . ("Variables are not supported in tests yet: " ++) . show) x
|
|
|
|
-- | Quasi-Quoter for GraphQL input fields.
|
|
-- Example usage:
|
|
-- > [GQL.inputfields|
|
|
-- > where: { name: { _eq: "old name"}},
|
|
-- > _set: { name: "new name" }
|
|
-- > |],
|
|
--
|
|
-- Note that because the graphql parser library does not expose a parser for
|
|
-- input fields directly we instead wrap the input text in dummy field syntax,
|
|
-- delegate to the 'field' quasi-quoter, and extract the inputfields from there.
|
|
inputfields :: QuasiQuoter
|
|
inputfields =
|
|
QuasiQuoter
|
|
{ quoteExp = inputfieldExp,
|
|
quotePat = \_ -> fail "invalid",
|
|
quoteType = \_ -> fail "invalid",
|
|
quoteDec = \_ -> fail "invalid"
|
|
}
|
|
where
|
|
inputfieldExp :: String -> ExpQ
|
|
inputfieldExp input = do
|
|
applied <- TH.AppE <$> [e|fmap GraphQLValue . GraphQL._fArguments|] <*> quoteExp field ("field(" ++ input ++ ")")
|
|
-- For some reason the type is 'InputValue v' for some rigid 'v' if we
|
|
-- don't add this type annotation.
|
|
annotated <- TH.SigE applied <$> [t|HashMap GraphQL.Name (InputValue Variable)|]
|
|
return annotated
|