-- | Postgres Translate Returning
--
-- Combinators and helpers for dealing with GraphQL returning statements.
module Hasura.Backends.Postgres.Translate.Returning
  ( MutationCTE (..),
    getMutationCTE,
    checkPermissionRequired,
    mkMutFldExp,
    mkDefaultMutFlds,
    mkCheckErrorExp,
    mkMutationOutputExp,
    checkConstraintIdentifier,
    asCheckErrorExtractor,
  )
where

import Control.Monad.Writer (Writer, runWriter)
import Data.Coerce
import Hasura.Backends.Postgres.SQL.DML qualified as S
import Hasura.Backends.Postgres.SQL.Types
import Hasura.Backends.Postgres.Translate.Select
import Hasura.Backends.Postgres.Translate.Select.Internal.Helpers (customSQLToTopLevelCTEs)
import Hasura.Backends.Postgres.Translate.Types (CustomSQLCTEs)
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.IR.Returning
import Hasura.RQL.IR.Select
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.BackendType
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.NamingCase (NamingCase)
import Hasura.RQL.Types.Schema.Options qualified as Options
import Hasura.Table.Cache

-- | The postgres common table expression (CTE) for mutation queries.
-- This CTE expression is used to generate mutation field output expression,
-- see Note [Mutation output expression].
data MutationCTE
  = -- | A Mutation with check constraint validation (Insert or Update)
    MCCheckConstraint S.TopLevelCTE
  | -- | A Select statement which emits mutated table rows
    MCSelectValues S.Select
  | -- | A Delete statement
    MCDelete S.SQLDelete
  deriving (Int -> MutationCTE -> ShowS
[MutationCTE] -> ShowS
MutationCTE -> String
(Int -> MutationCTE -> ShowS)
-> (MutationCTE -> String)
-> ([MutationCTE] -> ShowS)
-> Show MutationCTE
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MutationCTE -> ShowS
showsPrec :: Int -> MutationCTE -> ShowS
$cshow :: MutationCTE -> String
show :: MutationCTE -> String
$cshowList :: [MutationCTE] -> ShowS
showList :: [MutationCTE] -> ShowS
Show, MutationCTE -> MutationCTE -> Bool
(MutationCTE -> MutationCTE -> Bool)
-> (MutationCTE -> MutationCTE -> Bool) -> Eq MutationCTE
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MutationCTE -> MutationCTE -> Bool
== :: MutationCTE -> MutationCTE -> Bool
$c/= :: MutationCTE -> MutationCTE -> Bool
/= :: MutationCTE -> MutationCTE -> Bool
Eq)

getMutationCTE :: MutationCTE -> S.TopLevelCTE
getMutationCTE :: MutationCTE -> TopLevelCTE
getMutationCTE = \case
  MCCheckConstraint TopLevelCTE
cte -> TopLevelCTE
cte
  MCSelectValues Select
select -> Select -> TopLevelCTE
S.CTESelect Select
select
  MCDelete SQLDelete
delete -> SQLDelete -> TopLevelCTE
S.CTEDelete SQLDelete
delete

checkPermissionRequired :: MutationCTE -> Bool
checkPermissionRequired :: MutationCTE -> Bool
checkPermissionRequired = \case
  MCCheckConstraint TopLevelCTE
_ -> Bool
True
  MCSelectValues Select
_ -> Bool
False
  MCDelete SQLDelete
_ -> Bool
False

pgColsToSelFlds ::
  forall pgKind.
  (Backend ('Postgres pgKind)) =>
  [ColumnInfo ('Postgres pgKind)] ->
  [(FieldName, AnnField ('Postgres pgKind))]
pgColsToSelFlds :: forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
[ColumnInfo ('Postgres pgKind)]
-> [(FieldName, AnnField ('Postgres pgKind))]
pgColsToSelFlds [ColumnInfo ('Postgres pgKind)]
cols =
  ((ColumnInfo ('Postgres pgKind)
  -> (FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp))
 -> [ColumnInfo ('Postgres pgKind)]
 -> [(FieldName, AnnField ('Postgres pgKind))])
-> [ColumnInfo ('Postgres pgKind)]
-> (ColumnInfo ('Postgres pgKind)
    -> (FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp))
-> [(FieldName, AnnField ('Postgres pgKind))]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (ColumnInfo ('Postgres pgKind)
 -> (FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp))
-> [ColumnInfo ('Postgres pgKind)]
-> [(FieldName, AnnField ('Postgres pgKind))]
(ColumnInfo ('Postgres pgKind)
 -> (FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp))
-> [ColumnInfo ('Postgres pgKind)]
-> [(FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp)]
forall a b. (a -> b) -> [a] -> [b]
map [ColumnInfo ('Postgres pgKind)]
cols
    ((ColumnInfo ('Postgres pgKind)
  -> (FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp))
 -> [(FieldName, AnnField ('Postgres pgKind))])
-> (ColumnInfo ('Postgres pgKind)
    -> (FieldName, AnnFieldG ('Postgres pgKind) Void SQLExp))
-> [(FieldName, AnnField ('Postgres pgKind))]
forall a b. (a -> b) -> a -> b
$ \ColumnInfo ('Postgres pgKind)
pgColInfo ->
      ( forall (b :: BackendType). Backend b => Column b -> FieldName
fromCol @('Postgres pgKind) (Column ('Postgres pgKind) -> FieldName)
-> Column ('Postgres pgKind) -> FieldName
forall a b. (a -> b) -> a -> b
$ ColumnInfo ('Postgres pgKind) -> Column ('Postgres pgKind)
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo ('Postgres pgKind)
pgColInfo,
        Column ('Postgres pgKind)
-> ColumnType ('Postgres pgKind)
-> AnnRedactionExp ('Postgres pgKind) SQLExp
-> Maybe (ScalarSelectionArguments ('Postgres pgKind))
-> AnnFieldG ('Postgres pgKind) Void SQLExp
forall (backend :: BackendType) v r.
Column backend
-> ColumnType backend
-> AnnRedactionExp backend v
-> Maybe (ScalarSelectionArguments backend)
-> AnnFieldG backend r v
mkAnnColumnField (ColumnInfo ('Postgres pgKind) -> Column ('Postgres pgKind)
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo ('Postgres pgKind)
pgColInfo) (ColumnInfo ('Postgres pgKind) -> ColumnType ('Postgres pgKind)
forall (b :: BackendType). ColumnInfo b -> ColumnType b
ciType ColumnInfo ('Postgres pgKind)
pgColInfo) AnnRedactionExp ('Postgres pgKind) SQLExp
forall (b :: BackendType) v. AnnRedactionExp b v
NoRedaction Maybe (ScalarSelectionArguments ('Postgres pgKind))
Maybe ColumnOp
forall a. Maybe a
Nothing
        --  ^^ Nothing because mutations aren't supported
        --  with inherited role
      )

mkDefaultMutFlds ::
  (Backend ('Postgres pgKind)) =>
  Maybe [ColumnInfo ('Postgres pgKind)] ->
  MutationOutput ('Postgres pgKind)
mkDefaultMutFlds :: forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
Maybe [ColumnInfo ('Postgres pgKind)]
-> MutationOutput ('Postgres pgKind)
mkDefaultMutFlds =
  MutFldsG ('Postgres pgKind) Void SQLExp
-> MutationOutputG ('Postgres pgKind) Void SQLExp
forall (b :: BackendType) r v.
MutFldsG b r v -> MutationOutputG b r v
MOutMultirowFields (MutFldsG ('Postgres pgKind) Void SQLExp
 -> MutationOutputG ('Postgres pgKind) Void SQLExp)
-> (Maybe [ColumnInfo ('Postgres pgKind)]
    -> MutFldsG ('Postgres pgKind) Void SQLExp)
-> Maybe [ColumnInfo ('Postgres pgKind)]
-> MutationOutputG ('Postgres pgKind) Void SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
    Maybe [ColumnInfo ('Postgres pgKind)]
Nothing -> MutFldsG ('Postgres pgKind) Void SQLExp
forall {b :: BackendType} {r} {v}. [(FieldName, MutFldG b r v)]
mutFlds
    Just [ColumnInfo ('Postgres pgKind)]
cols -> (FieldName
"returning", AnnFieldsG ('Postgres pgKind) Void SQLExp
-> MutFldG ('Postgres pgKind) Void SQLExp
forall (b :: BackendType) r v. AnnFieldsG b r v -> MutFldG b r v
MRet (AnnFieldsG ('Postgres pgKind) Void SQLExp
 -> MutFldG ('Postgres pgKind) Void SQLExp)
-> AnnFieldsG ('Postgres pgKind) Void SQLExp
-> MutFldG ('Postgres pgKind) Void SQLExp
forall a b. (a -> b) -> a -> b
$ [ColumnInfo ('Postgres pgKind)]
-> [(FieldName, AnnField ('Postgres pgKind))]
forall (pgKind :: PostgresKind).
Backend ('Postgres pgKind) =>
[ColumnInfo ('Postgres pgKind)]
-> [(FieldName, AnnField ('Postgres pgKind))]
pgColsToSelFlds [ColumnInfo ('Postgres pgKind)]
cols) (FieldName, MutFldG ('Postgres pgKind) Void SQLExp)
-> MutFldsG ('Postgres pgKind) Void SQLExp
-> MutFldsG ('Postgres pgKind) Void SQLExp
forall a. a -> [a] -> [a]
: MutFldsG ('Postgres pgKind) Void SQLExp
forall {b :: BackendType} {r} {v}. [(FieldName, MutFldG b r v)]
mutFlds
  where
    mutFlds :: [(FieldName, MutFldG b r v)]
mutFlds = [(FieldName
"affected_rows", MutFldG b r v
forall (b :: BackendType) r v. MutFldG b r v
MCount)]

mkMutFldExp ::
  ( Backend ('Postgres pgKind),
    PostgresAnnotatedFieldJSON pgKind,
    MonadWriter CustomSQLCTEs m
  ) =>
  TableIdentifier ->
  Maybe Int ->
  Options.StringifyNumbers ->
  Maybe NamingCase ->
  MutFld ('Postgres pgKind) ->
  m S.SQLExp
mkMutFldExp :: forall (pgKind :: PostgresKind) (m :: * -> *).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind,
 MonadWriter CustomSQLCTEs m) =>
TableIdentifier
-> Maybe Int
-> StringifyNumbers
-> Maybe NamingCase
-> MutFld ('Postgres pgKind)
-> m SQLExp
mkMutFldExp TableIdentifier
cteAlias Maybe Int
preCalAffRows StringifyNumbers
strfyNum Maybe NamingCase
tCase = \case
  MutFld ('Postgres pgKind)
MCount ->
    let countExp :: SQLExp
countExp =
          Select -> SQLExp
S.SESelect
            (Select -> SQLExp) -> Select -> SQLExp
forall a b. (a -> b) -> a -> b
$ Select
S.mkSelect
              { selExtr :: [Extractor]
S.selExtr = [SQLExp -> Maybe ColumnAlias -> Extractor
S.Extractor SQLExp
S.countStar Maybe ColumnAlias
forall a. Maybe a
Nothing],
                selFrom :: Maybe FromExp
S.selFrom = FromExp -> Maybe FromExp
forall a. a -> Maybe a
Just (FromExp -> Maybe FromExp) -> FromExp -> Maybe FromExp
forall a b. (a -> b) -> a -> b
$ [FromItem] -> FromExp
S.FromExp ([FromItem] -> FromExp) -> [FromItem] -> FromExp
forall a b. (a -> b) -> a -> b
$ FromItem -> [FromItem]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FromItem -> [FromItem]) -> FromItem -> [FromItem]
forall a b. (a -> b) -> a -> b
$ TableIdentifier -> FromItem
S.FIIdentifier TableIdentifier
cteAlias
              }
     in SQLExp -> m SQLExp
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SQLExp -> m SQLExp) -> SQLExp -> m SQLExp
forall a b. (a -> b) -> a -> b
$ SQLExp -> (Int -> SQLExp) -> Maybe Int -> SQLExp
forall b a. b -> (a -> b) -> Maybe a -> b
maybe SQLExp
countExp (Text -> SQLExp
S.SEUnsafe (Text -> SQLExp) -> (Int -> Text) -> Int -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text
forall a. Show a => a -> Text
tshow) Maybe Int
preCalAffRows
  MExp Text
t -> SQLExp -> m SQLExp
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SQLExp -> m SQLExp) -> SQLExp -> m SQLExp
forall a b. (a -> b) -> a -> b
$ Text -> SQLExp
S.SELit Text
t
  MRet AnnFieldsG
  ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind))
selFlds ->
    let tabFrom :: SelectFromG ('Postgres pgKind) SQLExp
tabFrom = FIIdentifier -> SelectFromG ('Postgres pgKind) SQLExp
forall (b :: BackendType) v. FIIdentifier -> SelectFromG b v
FromIdentifier (FIIdentifier -> SelectFromG ('Postgres pgKind) SQLExp)
-> FIIdentifier -> SelectFromG ('Postgres pgKind) SQLExp
forall a b. (a -> b) -> a -> b
$ TableIdentifier -> FIIdentifier
toFIIdentifier TableIdentifier
cteAlias
        tabPerm :: TablePermG b v
tabPerm = AnnBoolExp b v -> Maybe Int -> TablePermG b v
forall (b :: BackendType) v.
AnnBoolExp b v -> Maybe Int -> TablePermG b v
TablePerm AnnBoolExp b v
forall (backend :: BackendType) scalar. AnnBoolExp backend scalar
annBoolExpTrue Maybe Int
forall a. Maybe a
Nothing
     in Select -> SQLExp
S.SESelect
          (Select -> SQLExp) -> m Select -> m SQLExp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JsonAggSelect -> AnnSimpleSelect ('Postgres pgKind) -> m Select
forall (pgKind :: PostgresKind) (m :: * -> *).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind,
 MonadWriter CustomSQLCTEs m) =>
JsonAggSelect -> AnnSimpleSelect ('Postgres pgKind) -> m Select
mkSQLSelect
            JsonAggSelect
JASMultipleRows
            ( Fields (AnnFieldG ('Postgres pgKind) Void SQLExp)
-> SelectFromG ('Postgres pgKind) SQLExp
-> TablePermG ('Postgres pgKind) SQLExp
-> SelectArgsG ('Postgres pgKind) SQLExp
-> StringifyNumbers
-> Maybe NamingCase
-> AnnSelectG
     ('Postgres pgKind) (AnnFieldG ('Postgres pgKind) Void) SQLExp
forall (b :: BackendType) (f :: * -> *) v.
Fields (f v)
-> SelectFromG b v
-> TablePermG b v
-> SelectArgsG b v
-> StringifyNumbers
-> Maybe NamingCase
-> AnnSelectG b f v
AnnSelectG AnnFieldsG
  ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind))
Fields (AnnFieldG ('Postgres pgKind) Void SQLExp)
selFlds SelectFromG ('Postgres pgKind) SQLExp
tabFrom TablePermG ('Postgres pgKind) SQLExp
forall {b :: BackendType} {v}. TablePermG b v
tabPerm SelectArgsG ('Postgres pgKind) SQLExp
forall (backend :: BackendType) v. SelectArgsG backend v
noSelectArgs StringifyNumbers
strfyNum Maybe NamingCase
tCase
            )

toFIIdentifier :: TableIdentifier -> FIIdentifier
toFIIdentifier :: TableIdentifier -> FIIdentifier
toFIIdentifier = Text -> FIIdentifier
forall a b. Coercible a b => a -> b
coerce (Text -> FIIdentifier)
-> (TableIdentifier -> Text) -> TableIdentifier -> FIIdentifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableIdentifier -> Text
unTableIdentifier
{-# INLINE toFIIdentifier #-}

{- Note [Mutation output expression]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An example output expression for INSERT mutation:

WITH "mra__<table-name>" AS (
  INSERT INTO <table-name> (<insert-column>[..])
  VALUES
    (<insert-value-row>[..])
    ON CONFLICT ON CONSTRAINT "<table-constraint-name>" DO NOTHING RETURNING *,
    -- An extra column expression which performs the 'CHECK' validation
    (<CHECK Condition>) AS "check__constraint"
),
"aca__<table-name>" AS (
  -- Only extract columns from mutated rows. Columns sorted by ordinal position so that
  -- resulted rows can be casted to table type.
  SELECT (<table-column>[..])
  FROM
    "mra__<table-name>"
)
<SELECT statement to generate mutation response using 'aca__<table-name>' as FROM
 and bool_and("check__constraint") from "mra__<table-name>">
-}

-- | Generate mutation output expression with given mutation CTE statement.
-- See Note [Mutation output expression].
mkMutationOutputExp ::
  ( Backend ('Postgres pgKind),
    PostgresAnnotatedFieldJSON pgKind
  ) =>
  QualifiedTable ->
  [ColumnInfo ('Postgres pgKind)] ->
  Maybe Int ->
  MutationCTE ->
  MutationOutput ('Postgres pgKind) ->
  Options.StringifyNumbers ->
  Maybe NamingCase ->
  S.SelectWith
mkMutationOutputExp :: forall (pgKind :: PostgresKind).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind) =>
QualifiedTable
-> [ColumnInfo ('Postgres pgKind)]
-> Maybe Int
-> MutationCTE
-> MutationOutput ('Postgres pgKind)
-> StringifyNumbers
-> Maybe NamingCase
-> SelectWith
mkMutationOutputExp QualifiedTable
qt [ColumnInfo ('Postgres pgKind)]
allCols Maybe Int
preCalAffRows MutationCTE
cte MutationOutput ('Postgres pgKind)
mutOutput StringifyNumbers
strfyNum Maybe NamingCase
tCase =
  let (Select
sel, CustomSQLCTEs
customSQLCTEs) = Writer CustomSQLCTEs Select -> (Select, CustomSQLCTEs)
forall w a. Writer w a -> (a, w)
runWriter Writer CustomSQLCTEs Select
writerSelect
   in [(TableAlias, TopLevelCTE)] -> Select -> SelectWith
forall statement.
[(TableAlias, statement)] -> Select -> SelectWithG statement
S.SelectWith
        ( [ (TableAlias
mutationResultAlias, MutationCTE -> TopLevelCTE
getMutationCTE MutationCTE
cte),
            (TableAlias
allColumnsAlias, TopLevelCTE
allColumnsSelect)
          ]
            [(TableAlias, TopLevelCTE)]
-> [(TableAlias, TopLevelCTE)] -> [(TableAlias, TopLevelCTE)]
forall a. Semigroup a => a -> a -> a
<> CustomSQLCTEs -> [(TableAlias, TopLevelCTE)]
customSQLToTopLevelCTEs CustomSQLCTEs
customSQLCTEs
        )
        Select
sel
  where
    mutationResultAlias :: TableAlias
mutationResultAlias = Text -> TableAlias
S.mkTableAlias (Text -> TableAlias) -> Text -> TableAlias
forall a b. (a -> b) -> a -> b
$ Text
"mra__" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> QualifiedTable -> Text
forall a. ToTxt a => QualifiedObject a -> Text
snakeCaseQualifiedObject QualifiedTable
qt
    mutationResultIdentifier :: TableIdentifier
mutationResultIdentifier = TableAlias -> TableIdentifier
S.tableAliasToIdentifier TableAlias
mutationResultAlias
    allColumnsAlias :: TableAlias
allColumnsAlias = Text -> TableAlias
S.mkTableAlias (Text -> TableAlias) -> Text -> TableAlias
forall a b. (a -> b) -> a -> b
$ Text
"aca__" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> QualifiedTable -> Text
forall a. ToTxt a => QualifiedObject a -> Text
snakeCaseQualifiedObject QualifiedTable
qt
    allColumnsIdentifier :: TableIdentifier
allColumnsIdentifier = TableAlias -> TableIdentifier
S.tableAliasToIdentifier TableAlias
allColumnsAlias
    allColumnsSelect :: TopLevelCTE
allColumnsSelect =
      Select -> TopLevelCTE
S.CTESelect
        (Select -> TopLevelCTE) -> Select -> TopLevelCTE
forall a b. (a -> b) -> a -> b
$ Select
S.mkSelect
          { selExtr :: [Extractor]
S.selExtr = (ColumnInfo ('Postgres pgKind) -> Extractor)
-> [ColumnInfo ('Postgres pgKind)] -> [Extractor]
forall a b. (a -> b) -> [a] -> [b]
map (PGCol -> Extractor
forall a. IsIdentifier a => a -> Extractor
S.mkExtr (PGCol -> Extractor)
-> (ColumnInfo ('Postgres pgKind) -> PGCol)
-> ColumnInfo ('Postgres pgKind)
-> Extractor
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ColumnInfo ('Postgres pgKind) -> Column ('Postgres pgKind)
ColumnInfo ('Postgres pgKind) -> PGCol
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn) ([ColumnInfo ('Postgres pgKind)] -> [ColumnInfo ('Postgres pgKind)]
forall (backend :: BackendType).
[ColumnInfo backend] -> [ColumnInfo backend]
sortCols [ColumnInfo ('Postgres pgKind)]
allCols),
            selFrom :: Maybe FromExp
S.selFrom = FromExp -> Maybe FromExp
forall a. a -> Maybe a
Just (FromExp -> Maybe FromExp) -> FromExp -> Maybe FromExp
forall a b. (a -> b) -> a -> b
$ TableIdentifier -> FromExp
S.mkIdenFromExp TableIdentifier
mutationResultIdentifier
          }

    writerSelect :: Writer CustomSQLCTEs Select
writerSelect =
      ( \SQLExp
extrExp ->
          Select
S.mkSelect
            { selExtr :: [Extractor]
S.selExtr =
                SQLExp -> Maybe ColumnAlias -> Extractor
S.Extractor SQLExp
extrExp Maybe ColumnAlias
forall a. Maybe a
Nothing
                  Extractor -> [Extractor] -> [Extractor]
forall a. a -> [a] -> [a]
: [Extractor] -> [Extractor] -> Bool -> [Extractor]
forall a. a -> a -> Bool -> a
bool [] [SQLExp -> Maybe ColumnAlias -> Extractor
S.Extractor SQLExp
checkErrorExp Maybe ColumnAlias
forall a. Maybe a
Nothing] (MutationCTE -> Bool
checkPermissionRequired MutationCTE
cte)
            }
      )
        (SQLExp -> Select)
-> WriterT CustomSQLCTEs Identity SQLExp
-> Writer CustomSQLCTEs Select
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> WriterT CustomSQLCTEs Identity SQLExp
writerExtrExp
      where
        checkErrorExp :: SQLExp
checkErrorExp = TableIdentifier -> SQLExp
mkCheckErrorExp TableIdentifier
mutationResultIdentifier

        writerExtrExp :: Writer CustomSQLCTEs S.SQLExp
        writerExtrExp :: WriterT CustomSQLCTEs Identity SQLExp
writerExtrExp = case MutationOutput ('Postgres pgKind)
mutOutput of
          MOutMultirowFields MutFldsG ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind))
mutFlds ->
            let jsonBuildObjArgs :: WriterT CustomSQLCTEs Identity [SQLExp]
jsonBuildObjArgs =
                  [[SQLExp]] -> [SQLExp]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                    ([[SQLExp]] -> [SQLExp])
-> WriterT CustomSQLCTEs Identity [[SQLExp]]
-> WriterT CustomSQLCTEs Identity [SQLExp]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((FieldName, MutFldG ('Postgres pgKind) Void SQLExp)
 -> WriterT CustomSQLCTEs Identity [SQLExp])
-> [(FieldName, MutFldG ('Postgres pgKind) Void SQLExp)]
-> WriterT CustomSQLCTEs Identity [[SQLExp]]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse
                      ( \(FieldName Text
k, MutFldG ('Postgres pgKind) Void SQLExp
mutFld) -> do
                          SQLExp
mutFldExp <- TableIdentifier
-> Maybe Int
-> StringifyNumbers
-> Maybe NamingCase
-> MutFld ('Postgres pgKind)
-> WriterT CustomSQLCTEs Identity SQLExp
forall (pgKind :: PostgresKind) (m :: * -> *).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind,
 MonadWriter CustomSQLCTEs m) =>
TableIdentifier
-> Maybe Int
-> StringifyNumbers
-> Maybe NamingCase
-> MutFld ('Postgres pgKind)
-> m SQLExp
mkMutFldExp TableIdentifier
allColumnsIdentifier Maybe Int
preCalAffRows StringifyNumbers
strfyNum Maybe NamingCase
tCase MutFld ('Postgres pgKind)
MutFldG ('Postgres pgKind) Void SQLExp
mutFld
                          [SQLExp] -> WriterT CustomSQLCTEs Identity [SQLExp]
forall a. a -> WriterT CustomSQLCTEs Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Text -> SQLExp
S.SELit Text
k, SQLExp
mutFldExp]
                      )
                      MutFldsG ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind))
[(FieldName, MutFldG ('Postgres pgKind) Void SQLExp)]
mutFlds
             in Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"json_build_object" ([SQLExp] -> Maybe OrderByExp -> SQLExp)
-> WriterT CustomSQLCTEs Identity [SQLExp]
-> WriterT CustomSQLCTEs Identity (Maybe OrderByExp -> SQLExp)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> WriterT CustomSQLCTEs Identity [SQLExp]
jsonBuildObjArgs WriterT CustomSQLCTEs Identity (Maybe OrderByExp -> SQLExp)
-> WriterT CustomSQLCTEs Identity (Maybe OrderByExp)
-> WriterT CustomSQLCTEs Identity SQLExp
forall a b.
WriterT CustomSQLCTEs Identity (a -> b)
-> WriterT CustomSQLCTEs Identity a
-> WriterT CustomSQLCTEs Identity b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe OrderByExp
-> WriterT CustomSQLCTEs Identity (Maybe OrderByExp)
forall a. a -> WriterT CustomSQLCTEs Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe OrderByExp
forall a. Maybe a
Nothing
          MOutSinglerowObject AnnFieldsG
  ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind))
annFlds ->
            let tabFrom :: SelectFromG ('Postgres pgKind) SQLExp
tabFrom = FIIdentifier -> SelectFromG ('Postgres pgKind) SQLExp
forall (b :: BackendType) v. FIIdentifier -> SelectFromG b v
FromIdentifier (FIIdentifier -> SelectFromG ('Postgres pgKind) SQLExp)
-> FIIdentifier -> SelectFromG ('Postgres pgKind) SQLExp
forall a b. (a -> b) -> a -> b
$ TableIdentifier -> FIIdentifier
toFIIdentifier TableIdentifier
allColumnsIdentifier
                tabPerm :: TablePermG b v
tabPerm = AnnBoolExp b v -> Maybe Int -> TablePermG b v
forall (b :: BackendType) v.
AnnBoolExp b v -> Maybe Int -> TablePermG b v
TablePerm AnnBoolExp b v
forall (backend :: BackendType) scalar. AnnBoolExp backend scalar
annBoolExpTrue Maybe Int
forall a. Maybe a
Nothing
             in Select -> SQLExp
S.SESelect
                  (Select -> SQLExp)
-> Writer CustomSQLCTEs Select
-> WriterT CustomSQLCTEs Identity SQLExp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JsonAggSelect
-> AnnSimpleSelect ('Postgres pgKind)
-> Writer CustomSQLCTEs Select
forall (pgKind :: PostgresKind) (m :: * -> *).
(Backend ('Postgres pgKind), PostgresAnnotatedFieldJSON pgKind,
 MonadWriter CustomSQLCTEs m) =>
JsonAggSelect -> AnnSimpleSelect ('Postgres pgKind) -> m Select
mkSQLSelect
                    JsonAggSelect
JASSingleObject
                    ( Fields (AnnFieldG ('Postgres pgKind) Void SQLExp)
-> SelectFromG ('Postgres pgKind) SQLExp
-> TablePermG ('Postgres pgKind) SQLExp
-> SelectArgsG ('Postgres pgKind) SQLExp
-> StringifyNumbers
-> Maybe NamingCase
-> AnnSelectG
     ('Postgres pgKind) (AnnFieldG ('Postgres pgKind) Void) SQLExp
forall (b :: BackendType) (f :: * -> *) v.
Fields (f v)
-> SelectFromG b v
-> TablePermG b v
-> SelectArgsG b v
-> StringifyNumbers
-> Maybe NamingCase
-> AnnSelectG b f v
AnnSelectG AnnFieldsG
  ('Postgres pgKind) Void (SQLExpression ('Postgres pgKind))
Fields (AnnFieldG ('Postgres pgKind) Void SQLExp)
annFlds SelectFromG ('Postgres pgKind) SQLExp
tabFrom TablePermG ('Postgres pgKind) SQLExp
forall {b :: BackendType} {v}. TablePermG b v
tabPerm SelectArgsG ('Postgres pgKind) SQLExp
forall (backend :: BackendType) v. SelectArgsG backend v
noSelectArgs StringifyNumbers
strfyNum Maybe NamingCase
tCase
                    )

mkCheckErrorExp :: TableIdentifier -> S.SQLExp
mkCheckErrorExp :: TableIdentifier -> SQLExp
mkCheckErrorExp TableIdentifier
alias =
  let boolAndCheckConstraint :: SQLExp
boolAndCheckConstraint =
        SQLExp -> SQLExp -> SQLExp
S.handleIfNull (BoolExp -> SQLExp
S.SEBool (BoolExp -> SQLExp) -> BoolExp -> SQLExp
forall a b. (a -> b) -> a -> b
$ Bool -> BoolExp
S.BELit Bool
True)
          (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall a b. (a -> b) -> a -> b
$ Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"bool_and" [Identifier -> SQLExp
S.SEIdentifier Identifier
checkConstraintIdentifier] Maybe OrderByExp
forall a. Maybe a
Nothing
   in Select -> SQLExp
S.SESelect
        (Select -> SQLExp) -> Select -> SQLExp
forall a b. (a -> b) -> a -> b
$ Select
S.mkSelect
          { selExtr :: [Extractor]
S.selExtr = [SQLExp -> Maybe ColumnAlias -> Extractor
S.Extractor SQLExp
boolAndCheckConstraint Maybe ColumnAlias
forall a. Maybe a
Nothing],
            selFrom :: Maybe FromExp
S.selFrom = FromExp -> Maybe FromExp
forall a. a -> Maybe a
Just (FromExp -> Maybe FromExp) -> FromExp -> Maybe FromExp
forall a b. (a -> b) -> a -> b
$ TableIdentifier -> FromExp
S.mkIdenFromExp TableIdentifier
alias
          }

checkConstraintIdentifier :: Identifier
checkConstraintIdentifier :: Identifier
checkConstraintIdentifier = Text -> Identifier
Identifier Text
"check__constraint"

asCheckErrorExtractor :: S.SQLExp -> S.Extractor
asCheckErrorExtractor :: SQLExp -> Extractor
asCheckErrorExtractor SQLExp
s =
  SQLExp -> Maybe ColumnAlias -> Extractor
S.Extractor SQLExp
s (Maybe ColumnAlias -> Extractor) -> Maybe ColumnAlias -> Extractor
forall a b. (a -> b) -> a -> b
$ ColumnAlias -> Maybe ColumnAlias
forall a. a -> Maybe a
Just (ColumnAlias -> Maybe ColumnAlias)
-> ColumnAlias -> Maybe ColumnAlias
forall a b. (a -> b) -> a -> b
$ Identifier -> ColumnAlias
forall a. IsIdentifier a => a -> ColumnAlias
S.toColumnAlias Identifier
checkConstraintIdentifier