graphql-engine/server/src-test/Hasura/Backends/Postgres/NativeQueries/NativeQueriesSpec.hs
Tom Harding 7e334e08a4 Import HashMap, not HM, Map, M...
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8947
GitOrigin-RevId: 18e52c928e1df535579e2077b4af6c2ce92bdcef
2023-04-26 15:43:44 +00:00

135 lines
5.2 KiB
Haskell

{-# HLINT ignore "avoid Language.GraphQL.Draft.Syntax.unsafeMkName" #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
module Hasura.Backends.Postgres.NativeQueries.NativeQueriesSpec (spec) where
import Data.Bifunctor
import Data.Either
import Data.HashMap.Strict qualified as HashMap
import Hasura.Backends.Postgres.Instances.NativeQueries
import Hasura.Backends.Postgres.SQL.Types
import Hasura.Base.Error
import Hasura.LogicalModel.Metadata
import Hasura.NativeQuery.Metadata
import Hasura.Prelude hiding (first)
import Language.GraphQL.Draft.Syntax qualified as G
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
spec :: Spec
spec = do
describe "Parses raw query into InterpolatedQuery" do
it "Parses SQL with no parameters in it" $ do
let rawSQL = "SELECT * FROM dogs"
parseInterpolatedQuery rawSQL `shouldBe` Right (InterpolatedQuery [IIText "SELECT * FROM dogs"])
it "Parses only a variable" $ do
let rawSQL = "{{dogs}}"
parseInterpolatedQuery rawSQL `shouldBe` Right (InterpolatedQuery [IIVariable (NativeQueryArgumentName "dogs")])
it "Parses SQL with one parameter in it" $ do
let rawSQL = "SELECT * FROM dogs WHERE name = {{name}}"
parseInterpolatedQuery rawSQL
`shouldBe` Right
( InterpolatedQuery
[ IIText "SELECT * FROM dogs WHERE name = ",
IIVariable (NativeQueryArgumentName "name")
]
)
it "Parses SQL with one parameter in the middle of the string" $ do
let rawSQL = "SELECT * FROM dogs WHERE {{name}} = name"
parseInterpolatedQuery rawSQL
`shouldBe` Right
( InterpolatedQuery
[ IIText "SELECT * FROM dogs WHERE ",
IIVariable (NativeQueryArgumentName "name"),
IIText " = name"
]
)
it "Parses SQL with one parameter and a loose { hanging around" $ do
let rawSQL = "SELECT * FROM dogs WHERE {{name}} = '{doggy friend}'"
parseInterpolatedQuery rawSQL
`shouldBe` Right
( InterpolatedQuery
[ IIText "SELECT * FROM dogs WHERE ",
IIVariable (NativeQueryArgumentName "name"),
IIText " = '{doggy friend}'"
]
)
it "What should happen for unclosed variable" $ do
let rawSQL = "SELECT * FROM dogs WHERE {{name"
parseInterpolatedQuery rawSQL `shouldBe` Left "Found '{{' without a matching closing '}}'"
describe "Validation" do
let lmm =
LogicalModelMetadata
{ _lmmName = LogicalModelName (G.unsafeMkName "logical_model_name"),
_lmmFields = mempty,
_lmmDescription = Nothing,
_lmmSelectPermissions = mempty
}
nqm =
NativeQueryMetadata
{ _nqmRootFieldName = NativeQueryName (G.unsafeMkName "root_field_name"),
_nqmCode = InterpolatedQuery mempty,
_nqmReturns = LogicalModelName (G.unsafeMkName "logical_model_name"),
_nqmArguments = mempty,
_nqmArrayRelationships = mempty,
_nqmDescription = mempty
}
it "Rejects undeclared variables" do
let Right code = parseInterpolatedQuery "SELECT {{hey}}"
let actual :: Either QErr Text = fmap snd $ runExcept $ nativeQueryToPreparedStatement lmm nqm {_nqmCode = code}
(first showQErr actual) `shouldSatisfy` isLeft
let Left err = actual
qeCode err `shouldBe` ValidationFailed
it "Handles multiple occurences of variables " do
let Right code = parseInterpolatedQuery "SELECT {{hey}}, {{hey}}"
let actual :: Either QErr Text =
fmap snd $
runExcept $
nativeQueryToPreparedStatement
lmm
nqm
{ _nqmCode = code,
_nqmArguments =
HashMap.fromList
[ (NativeQueryArgumentName "hey", NullableScalarType PGVarchar False Nothing)
]
}
(first showQErr actual) `shouldSatisfy` isRight
let Right rendered = actual
rendered
`shouldBe` "PREPARE _logimo_vali_(varchar) AS WITH _cte_logimo_vali_ AS (\nSELECT $1, $1\n)\nSELECT \nFROM _cte_logimo_vali_"
it "Handles multiple variables " do
let Right code = parseInterpolatedQuery "SELECT {{hey}}, {{ho}}"
let actual :: Either QErr Text =
fmap snd $
runExcept $
nativeQueryToPreparedStatement
lmm
nqm
{ _nqmCode = code,
_nqmArguments =
HashMap.fromList
[ (NativeQueryArgumentName "hey", NullableScalarType PGVarchar False Nothing),
(NativeQueryArgumentName "ho", NullableScalarType PGInteger False Nothing)
]
}
(first showQErr actual) `shouldSatisfy` isRight
let Right rendered = actual
rendered
`shouldBe` "PREPARE _logimo_vali_(varchar, integer) AS WITH _cte_logimo_vali_ AS (\nSELECT $1, $2\n)\nSELECT \nFROM _cte_logimo_vali_"