orville-postgresql-1.1.0.0: src/Orville/PostgreSQL/Expr/Trigger.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{- |
Copyright : Flipstone Technology Partners 2024
License : MIT
Stability : Stable
@since 1.1.0.0
-}
module Orville.PostgreSQL.Expr.Trigger
( DropTriggerExpr
, dropTrigger
, CreateTriggerExpr
, createTrigger
, TriggerTiming
, triggerBefore
, triggerAfter
, triggerInsteadOf
, TriggerEvent
, triggerOnInsert
, triggerOnUpdate
, triggerOnUpdateOf
, triggerOnDelete
, triggerOnTruncate
, TriggerFireScope
, triggerForEachRow
, triggerForEachStatement
) where
import qualified Data.List.NonEmpty as NEL
import Data.Maybe (catMaybes)
import Orville.PostgreSQL.Expr.IfExists (IfExists)
import Orville.PostgreSQL.Expr.Name (ColumnName, FunctionName, QualifiedOrUnqualified, TableName, TriggerName)
import Orville.PostgreSQL.Expr.OrReplace (OrReplace)
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
{- | Type to represent a SQL "DROP TRIGGER" statement. E.G.
> DROP TRIGGER my_trigger ON my_table
'DropTriggerExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype DropTriggerExpr
= DropTriggerExpr RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | Constructs a SQL @DROP TRIGGER@ statement from the trigger name and table name
@since 1.1.0.0
-}
dropTrigger ::
Maybe IfExists ->
TriggerName ->
QualifiedOrUnqualified TableName ->
DropTriggerExpr
dropTrigger maybeIfExists name tableName =
DropTriggerExpr $
RawSql.intercalate
RawSql.space
( catMaybes
[ Just (RawSql.fromString "DROP TRIGGER")
, fmap RawSql.toRawSql maybeIfExists
, Just (RawSql.toRawSql name)
, Just (RawSql.fromString "ON")
, Just (RawSql.toRawSql tableName)
]
)
{- | Type to represent a SQL "CREATE TRIGGER" statement. E.G.
> CREATE TRIGGER my_trigger BEFORE UPDATE ON my_table EXECUTE PROCEDURE my_trigger_function
'CreateTriggerExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype CreateTriggerExpr
= CreateTriggerExpr RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | Constructs a SQL @CREATE TRIGGER@ statement from the trigger name and its defining
attributes.
Note: Orville does not currently support creating triggers with arguments.
Note: Before PostgreSQL 14, there is no @CREATE OR REPLACE TRIGGER@ syntax in
PsotgreSQL. If you're using a version of PostgreSQL prior to 14 then you must
specify 'Nothing' for the 'OrReplace' property.
@since 1.1.0.0
-}
createTrigger ::
Maybe OrReplace ->
TriggerName ->
TriggerTiming ->
NEL.NonEmpty TriggerEvent ->
QualifiedOrUnqualified TableName ->
TriggerFireScope ->
QualifiedOrUnqualified FunctionName ->
CreateTriggerExpr
createTrigger maybeOrReplace name timing events tableName fireScope functionName =
CreateTriggerExpr $
RawSql.intercalate
RawSql.space
( catMaybes
[ Just $ RawSql.fromString "CREATE"
, RawSql.toRawSql <$> maybeOrReplace
, Just $ RawSql.fromString "TRIGGER"
, Just $ RawSql.toRawSql name
, Just $ RawSql.toRawSql timing
, Just $ RawSql.intercalate (RawSql.fromString " OR ") events
, Just $ RawSql.fromString "ON"
, Just $ RawSql.toRawSql tableName
, Just $ RawSql.toRawSql fireScope
, Just $ RawSql.fromString "EXECUTE FUNCTION"
, Just $ RawSql.toRawSql functionName
, Just $ RawSql.fromString "()" -- we don't currently support arguments
]
)
{- | Type to represent the time at which a trigger will fire in releation to the
event that caused it. E.G. the @BEFORE@ in
> CREATE TRIGGER my_trigger BEFORE UPDATE ON my_table FOR EACH ROW EXECUTE PROCEDURE my_trigger_function
'TriggerTiming' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype TriggerTiming
= TriggerTiming RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | The @BEFORE@ 'TriggerTiming'.
@since 1.1.0.0
-}
triggerBefore :: TriggerTiming
triggerBefore =
TriggerTiming (RawSql.fromString "BEFORE")
{- | The @AFTER@ 'TriggerTiming'.
@since 1.1.0.0
-}
triggerAfter :: TriggerTiming
triggerAfter =
TriggerTiming (RawSql.fromString "AFTER")
{- | The @INSTEAD OF@ 'TriggerTiming'.
@since 1.1.0.0
-}
triggerInsteadOf :: TriggerTiming
triggerInsteadOf =
TriggerTiming (RawSql.fromString "INSTEAD OF")
{- | Type to represent the an event that will cause a trigger to fire in a SQL "CREATE
TRIGGER" statement. E.G. the @UPDATE@ in
> CREATE TRIGGER my_trigger BEFORE UPDATE ON my_table FOR EACH ROW EXECUTE PROCEDURE my_trigger_function
'TriggerEvent' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype TriggerEvent
= TriggerEvent RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | The @INSERT@ 'TriggerEvent'
@since 1.1.0.0
-}
triggerOnInsert :: TriggerEvent
triggerOnInsert =
TriggerEvent (RawSql.fromString "INSERT")
{- | The @UPDATE@ 'TriggerEvent'
@since 1.1.0.0
-}
triggerOnUpdate :: TriggerEvent
triggerOnUpdate =
TriggerEvent (RawSql.fromString "UPDATE")
{- | The @UPDATE OF@ 'TriggerEvent'. This causes the trigger only to fire when on of
the specified columns is mentioned of affected by an update.
@since 1.1.0.0
-}
triggerOnUpdateOf :: NEL.NonEmpty ColumnName -> TriggerEvent
triggerOnUpdateOf columnNames =
TriggerEvent $
RawSql.fromString "UPDATE OF"
<> RawSql.intercalate RawSql.comma (fmap RawSql.toRawSql columnNames)
{- | The @DELETE@ 'TriggerEvent'
@since 1.1.0.0
-}
triggerOnDelete :: TriggerEvent
triggerOnDelete =
TriggerEvent (RawSql.fromString "DELETE")
{- | The @TRUNCATE@ 'TriggerEvent'
@since 1.1.0.0
-}
triggerOnTruncate :: TriggerEvent
triggerOnTruncate =
TriggerEvent (RawSql.fromString "TRUNCATE")
{- | Type to represent the part of a SQL "CREATE TRIGGER" statement that indicates whether
the trigger will be fired once for each row or once for each statement. E.G. the
@FOR EACH ROW@ in
> CREATE TRIGGER my_trigger BEFORE UPDATE ON my_table FOR EACH ROW EXECUTE PROCEDURE my_trigger_function
'TriggerFireScope' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype TriggerFireScope
= TriggerFireScope RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | The @FOR EACH ROW@ 'TriggerFireScope'
@since 1.1.0.0
-}
triggerForEachRow :: TriggerFireScope
triggerForEachRow =
TriggerFireScope (RawSql.fromString "FOR EACH ROW")
{- | The @FOR EACH STATEMENT@ 'TriggerFireScope'
@since 1.1.0.0
-}
triggerForEachStatement :: TriggerFireScope
triggerForEachStatement =
TriggerFireScope (RawSql.fromString "FOR EACH STATEMENT")