server/nada: add unit tests for Postgres insert SQL generation

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5543
GitOrigin-RevId: 55646f653926559f1847aa692d3522627a463d25
This commit is contained in:
Evie Ciobanu 2022-08-18 13:42:57 +03:00 committed by hasura-bot
parent 56f2501ab9
commit 1e48af2d03
4 changed files with 160 additions and 0 deletions

View File

@ -1040,6 +1040,7 @@ test-suite graphql-engine-tests
Hasura.Backends.Postgres.SQL.Select.RenameIdentifiersSpec
Hasura.Backends.Postgres.SQL.ValueSpec
Hasura.Backends.Postgres.Translate.DeleteSpec
Hasura.Backends.Postgres.Translate.InsertSpec
Hasura.Backends.Postgres.Translate.UpdateSpec
Hasura.EventingSpec
Hasura.Generator.Common
@ -1073,11 +1074,13 @@ test-suite graphql-engine-tests
Network.HTTP.Client.TransformableSpec
Test.Aeson.Utils
Test.Backend.Postgres.Delete
Test.Backend.Postgres.Insert
Test.Backend.Postgres.Misc
Test.Backend.Postgres.Update
Test.Parser.Delete
Test.Parser.Expectation
Test.Parser.Field
Test.Parser.Insert
Test.Parser.Internal
Test.Parser.Monad
Test.QuickCheck.Extended

View File

@ -0,0 +1,37 @@
{-# LANGUAGE QuasiQuotes #-}
module Hasura.Backends.Postgres.Translate.InsertSpec
( spec,
)
where
import Database.PG.Query.Pool qualified as QQ
import Hasura.RQL.IR.Returning (MutFldG (..), MutationOutputG (..))
import Test.Backend.Postgres.Insert qualified as Test
import Test.Backend.Postgres.Misc qualified as P
import Test.Hspec
import Test.Parser.Expectation as Expect
-- | TODO: add tests for OnConflict. Start with no longer passing 'Nothing' to
-- /iqp1Conflict/ in 'Test.Parser.Insert.mkInsertQuery'.
spec :: Spec
spec =
describe "Postgres.Translate.InsertSpec" do
Test.runTest
Test.TestBuilder
{ name = "insert record",
table = Expect.mkTable "test",
insertColumns = [P.nameColumn],
values = [[P.textNew], [P.textOther]],
columns = [P.idColumn, P.nameColumn],
mutationOutput = MOutMultirowFields [("affected_rows", MCount)],
expectedSQL =
[QQ.sql|
INSERT INTO "public"."test"
("name")
VALUES
(('new name')::text),
(('other')::text)
RETURNING *, ('true')::boolean AS "check__constraint"
|]
}

View File

@ -0,0 +1,59 @@
-- | Test Backend Postgres Insert
--
-- Helpers to build 'Hasura.RQL.IR.Insert.InsertQueryP1' and test the results
-- of running 'Hasura.Backends.Postgres.Translate.Insert.mkInsertCTE' as raw
-- SQL.
--
-- See 'Hasura.Backends.Postgres.Translate.InserSpec.spec' for usage examples.
module Test.Backend.Postgres.Insert
( TestBuilder (..),
runTest,
)
where
import Hasura.Backends.Postgres.SQL.Types (QualifiedTable)
import Hasura.Backends.Postgres.Translate.Insert qualified as Insert
import Hasura.Prelude
import Hasura.RQL.IR.Returning (MutationOutputG (..))
import Hasura.RQL.IR.Value (UnpreparedValue (..))
import Hasura.RQL.Types.Column (ColumnInfo)
import Hasura.SQL.Backend (PostgresKind (Vanilla))
import Hasura.SQL.Types (toSQLTxt)
import Test.Backend.Postgres.Misc (PG)
import Test.Hspec
import Test.Parser.Insert qualified as Expect
import Test.SIString qualified as SI
-- | Describes a /mkInsertCTE/ test.
data TestBuilder = TestBuilder
{ -- | test name
name :: String,
-- | table details
table :: QualifiedTable,
-- | columns used in the insert statement
insertColumns :: [ColumnInfo PG],
-- | rows of values to be inserted
values :: [[UnpreparedValue PG]],
-- | table columns
columns :: [ColumnInfo PG],
-- | expected output fields
mutationOutput :: MutationOutputG PG Void (UnpreparedValue PG),
-- | expected SQL
expectedSQL :: Text
}
-- | Runs a test for insert queries.
runTest :: TestBuilder -> Spec
runTest TestBuilder {..} =
it name do
let ins =
Expect.mkInsertQuery
Expect.InsertQueryBuilder
{ iqbTable = table,
iqbInsertColumns = insertColumns,
iqbValues = values,
iqbOutput = mutationOutput,
iqbAllColumns = columns
}
(SI.fromText . toSQLTxt . Insert.mkInsertCTE @'Vanilla $ ins)
`shouldBe` SI.fromText expectedSQL

View File

@ -0,0 +1,61 @@
module Test.Parser.Insert
( InsertQueryBuilder (..),
mkInsertQuery,
)
where
import Hasura.Backends.Postgres.SQL.DML qualified as S
import Hasura.Backends.Postgres.SQL.Types (PGScalarType, QualifiedTable)
import Hasura.Backends.Postgres.SQL.Value (txtEncoder, withScalarTypeAnn)
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp (GBoolExp (..))
import Hasura.RQL.IR.Insert (InsertQueryP1 (..))
import Hasura.RQL.IR.Returning (MutationOutputG (..))
import Hasura.RQL.IR.Value (UnpreparedValue (..))
import Hasura.RQL.Types.Column (ColumnInfo (..), ColumnType (..), ColumnValue (..))
import Hasura.RQL.Types.Instances ()
import Hasura.SQL.Backend (BackendType (Postgres), PostgresKind (Vanilla))
type PG = 'Postgres 'Vanilla
type Output = MutationOutputG PG Void (UnpreparedValue PG)
-- | Internal use only. The intended use is through
-- 'Test.Backend.Postgres.Insert.runTest'.
--
-- Build an 'InsertQueryP1', to be used with 'mkInsertQuery'.
data InsertQueryBuilder = InsertQueryBuilder
{ -- | the main table for the update
iqbTable :: QualifiedTable,
-- | the columns used in the insert statement
iqbInsertColumns :: [ColumnInfo PG],
-- | the rows of values to be inserted
iqbValues :: [[UnpreparedValue PG]],
-- | the 'Output' clause, e.g., selection set, affected_rows, etc.
iqbOutput :: Output,
-- | the table columns (all of them)
iqbAllColumns :: [ColumnInfo PG]
}
mkInsertQuery :: InsertQueryBuilder -> InsertQueryP1 PG
mkInsertQuery InsertQueryBuilder {..} =
InsertQueryP1
{ iqp1Table = iqbTable,
iqp1Cols = ciColumn <$> iqbInsertColumns,
iqp1Tuples = fmap unpreparedValueToSQLExp <$> iqbValues,
iqp1Conflict = Nothing,
iqp1CheckCond = (BoolAnd [], Nothing),
iqp1Output = unpreparedValueToSQLExp <$> iqbOutput,
iqp1AllCols = iqbAllColumns
}
unpreparedValueToSQLExp :: UnpreparedValue PG -> S.SQLExp
unpreparedValueToSQLExp = \case
UVLiteral sqlExp -> sqlExp
UVParameter _varInfo cval -> withScalarTypeAnn (go $ cvType cval) (txtEncoder $ cvValue cval)
_ -> error "unexpected value"
where
go :: ColumnType PG -> PGScalarType
go = \case
ColumnScalar t -> t
ColumnEnumReference _ -> error "unexpected enum in translating column type"