{-# LANGUAGE GeneralizedNewtypeDeriving #-}

{- |
Copyright : Flipstone Technology Partners 2023
License   : MIT
Stability : Stable

@since 1.0.0.0
-}
module Orville.PostgreSQL.Expr.Transaction
  ( BeginTransactionExpr
  , beginTransaction
  , TransactionMode
  , readWrite
  , readOnly
  , deferrable
  , notDeferrable
  , isolationLevel
  , IsolationLevel
  , serializable
  , repeatableRead
  , readCommitted
  , readUncommitted
  , CommitExpr
  , commit
  , RollbackExpr
  , rollback
  , rollbackTo
  , SavepointExpr
  , savepoint
  , ReleaseSavepointExpr
  , releaseSavepoint
  )
where

import Data.Maybe (maybeToList)

import qualified Orville.PostgreSQL.Expr.Name as Name
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql

{- |
Type to represent the name of a begin transaction statement. E.G.

> BEGIN TRANSACTION

'BeginTransactionExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype BeginTransactionExpr
  = BeginTransactionExpr RawSql.RawSql
  deriving (RawSql -> BeginTransactionExpr
BeginTransactionExpr -> RawSql
(BeginTransactionExpr -> RawSql)
-> (RawSql -> BeginTransactionExpr)
-> SqlExpression BeginTransactionExpr
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: BeginTransactionExpr -> RawSql
toRawSql :: BeginTransactionExpr -> RawSql
$cunsafeFromRawSql :: RawSql -> BeginTransactionExpr
unsafeFromRawSql :: RawSql -> BeginTransactionExpr
RawSql.SqlExpression)

{- |
  Constructs a 'BeginTransactionExpr' that will begin a transaction using
  the specified mode, if any.

  @since 1.0.0.0
-}
beginTransaction :: Maybe TransactionMode -> BeginTransactionExpr
beginTransaction :: Maybe TransactionMode -> BeginTransactionExpr
beginTransaction Maybe TransactionMode
maybeTransactionMode =
  RawSql -> BeginTransactionExpr
BeginTransactionExpr (RawSql -> BeginTransactionExpr) -> RawSql -> BeginTransactionExpr
forall a b. (a -> b) -> a -> b
$
    RawSql -> [RawSql] -> RawSql
forall sql (f :: * -> *).
(SqlExpression sql, Foldable f) =>
RawSql -> f sql -> RawSql
RawSql.intercalate RawSql
RawSql.space ([RawSql] -> RawSql) -> [RawSql] -> RawSql
forall a b. (a -> b) -> a -> b
$
      ( String -> RawSql
RawSql.fromString String
"BEGIN TRANSACTION"
          RawSql -> [RawSql] -> [RawSql]
forall a. a -> [a] -> [a]
: Maybe RawSql -> [RawSql]
forall a. Maybe a -> [a]
maybeToList (TransactionMode -> RawSql
forall a. SqlExpression a => a -> RawSql
RawSql.toRawSql (TransactionMode -> RawSql)
-> Maybe TransactionMode -> Maybe RawSql
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe TransactionMode
maybeTransactionMode)
      )

{- |
Type to represent the transaction mode. E.G.

> ISOLATION LEVEL SERIALIZABLE

'TransactionMode' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype TransactionMode
  = TransactionMode RawSql.RawSql
  deriving (RawSql -> TransactionMode
TransactionMode -> RawSql
(TransactionMode -> RawSql)
-> (RawSql -> TransactionMode) -> SqlExpression TransactionMode
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: TransactionMode -> RawSql
toRawSql :: TransactionMode -> RawSql
$cunsafeFromRawSql :: RawSql -> TransactionMode
unsafeFromRawSql :: RawSql -> TransactionMode
RawSql.SqlExpression)

{- |
  The @READ WRITE@ transaction mode.

  @since 1.0.0.0
-}
readWrite :: TransactionMode
readWrite :: TransactionMode
readWrite =
  RawSql -> TransactionMode
TransactionMode (String -> RawSql
RawSql.fromString String
"READ WRITE")

{- |
  The @READ ONLY@ transaction mode.

  @since 1.0.0.0
-}
readOnly :: TransactionMode
readOnly :: TransactionMode
readOnly =
  RawSql -> TransactionMode
TransactionMode (String -> RawSql
RawSql.fromString String
"READ ONLY")

{- |
  The @DEFERRABLE@ transaction mode.

  @since 1.0.0.0
-}
deferrable :: TransactionMode
deferrable :: TransactionMode
deferrable =
  RawSql -> TransactionMode
TransactionMode (String -> RawSql
RawSql.fromString String
"DEFERRABLE")

{- |
  The @NOT DEFERRABLE@ transaction mode.

  @since 1.0.0.0
-}
notDeferrable :: TransactionMode
notDeferrable :: TransactionMode
notDeferrable =
  RawSql -> TransactionMode
TransactionMode (String -> RawSql
RawSql.fromString String
"NOT DEFERRABLE")

{- |
  An @ISOLATION LEVEL@ transaction mode with the given 'IsolationLevel'.

  @since 1.0.0.0
-}
isolationLevel :: IsolationLevel -> TransactionMode
isolationLevel :: IsolationLevel -> TransactionMode
isolationLevel IsolationLevel
level =
  RawSql -> TransactionMode
TransactionMode (RawSql -> TransactionMode) -> RawSql -> TransactionMode
forall a b. (a -> b) -> a -> b
$
    (String -> RawSql
RawSql.fromString String
"ISOLATION LEVEL " RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> IsolationLevel -> RawSql
forall a. SqlExpression a => a -> RawSql
RawSql.toRawSql IsolationLevel
level)

{- |
Type to represent the transaction isolation level. E.G.

> SERIALIZABLE

'IsolationLevel' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype IsolationLevel
  = IsolationLevel RawSql.RawSql
  deriving (RawSql -> IsolationLevel
IsolationLevel -> RawSql
(IsolationLevel -> RawSql)
-> (RawSql -> IsolationLevel) -> SqlExpression IsolationLevel
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: IsolationLevel -> RawSql
toRawSql :: IsolationLevel -> RawSql
$cunsafeFromRawSql :: RawSql -> IsolationLevel
unsafeFromRawSql :: RawSql -> IsolationLevel
RawSql.SqlExpression)

{- |
  The @SERIALIZABLE@ isolation level.

  @since 1.0.0.0
-}
serializable :: IsolationLevel
serializable :: IsolationLevel
serializable =
  RawSql -> IsolationLevel
IsolationLevel (String -> RawSql
RawSql.fromString String
"SERIALIZABLE")

{- |
  The @REPEATABLE READ@ isolation level.

  @since 1.0.0.0
-}
repeatableRead :: IsolationLevel
repeatableRead :: IsolationLevel
repeatableRead =
  RawSql -> IsolationLevel
IsolationLevel (String -> RawSql
RawSql.fromString String
"REPEATABLE READ")

{- |
  The @READ COMMITTED@ isolation level.

  @since 1.0.0.0
-}
readCommitted :: IsolationLevel
readCommitted :: IsolationLevel
readCommitted =
  RawSql -> IsolationLevel
IsolationLevel (String -> RawSql
RawSql.fromString String
"READ COMMITTED")

{- |
  The @READ UNCOMMITTED@ isolation level.

  @since 1.0.0.0
-}
readUncommitted :: IsolationLevel
readUncommitted :: IsolationLevel
readUncommitted =
  RawSql -> IsolationLevel
IsolationLevel (String -> RawSql
RawSql.fromString String
"READ UNCOMMITTED")

{- |
Type to represent the transaction commit statement. E.G.

> COMMIT

'CommitExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype CommitExpr
  = CommitExpr RawSql.RawSql
  deriving (RawSql -> CommitExpr
CommitExpr -> RawSql
(CommitExpr -> RawSql)
-> (RawSql -> CommitExpr) -> SqlExpression CommitExpr
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: CommitExpr -> RawSql
toRawSql :: CommitExpr -> RawSql
$cunsafeFromRawSql :: RawSql -> CommitExpr
unsafeFromRawSql :: RawSql -> CommitExpr
RawSql.SqlExpression)

{- |
  A @COMMIT@ transaction statement.

  @since 1.0.0.0
-}
commit :: CommitExpr
commit :: CommitExpr
commit =
  RawSql -> CommitExpr
CommitExpr (String -> RawSql
RawSql.fromString String
"COMMIT")

{- |
Type to represent the transaction rollback statement. E.G.

> ROLLBACK

'RollbackExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype RollbackExpr
  = RollbackExpr RawSql.RawSql
  deriving (RawSql -> RollbackExpr
RollbackExpr -> RawSql
(RollbackExpr -> RawSql)
-> (RawSql -> RollbackExpr) -> SqlExpression RollbackExpr
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: RollbackExpr -> RawSql
toRawSql :: RollbackExpr -> RawSql
$cunsafeFromRawSql :: RawSql -> RollbackExpr
unsafeFromRawSql :: RawSql -> RollbackExpr
RawSql.SqlExpression)

{- |
  A @ROLLBACK@ transaction statement.

  @since 1.0.0.0
-}
rollback :: RollbackExpr
rollback :: RollbackExpr
rollback =
  RawSql -> RollbackExpr
RollbackExpr (String -> RawSql
RawSql.fromString String
"ROLLBACK")

{- |
  A @ROLLBACK TO@ transaction statement that will rollback to the specified
  savepoint.

  @since 1.0.0.0
-}
rollbackTo :: Name.SavepointName -> RollbackExpr
rollbackTo :: SavepointName -> RollbackExpr
rollbackTo SavepointName
savepointName =
  RawSql -> RollbackExpr
RollbackExpr (RawSql -> RollbackExpr) -> RawSql -> RollbackExpr
forall a b. (a -> b) -> a -> b
$
    String -> RawSql
RawSql.fromString String
"ROLLBACK TO SAVEPOINT " RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> SavepointName -> RawSql
forall a. SqlExpression a => a -> RawSql
RawSql.toRawSql SavepointName
savepointName

{- |
Type to represent the transaction savepoint statement. E.G.

> SAVEPOINT foo

'SavepointExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype SavepointExpr
  = SavepointExpr RawSql.RawSql
  deriving (RawSql -> SavepointExpr
SavepointExpr -> RawSql
(SavepointExpr -> RawSql)
-> (RawSql -> SavepointExpr) -> SqlExpression SavepointExpr
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: SavepointExpr -> RawSql
toRawSql :: SavepointExpr -> RawSql
$cunsafeFromRawSql :: RawSql -> SavepointExpr
unsafeFromRawSql :: RawSql -> SavepointExpr
RawSql.SqlExpression)

{- |
  A @SAVEPOINT@ statement that will create a savepoint with the given name.

  @since 1.0.0.0
-}
savepoint :: Name.SavepointName -> SavepointExpr
savepoint :: SavepointName -> SavepointExpr
savepoint SavepointName
savepointName =
  RawSql -> SavepointExpr
SavepointExpr (RawSql -> SavepointExpr) -> RawSql -> SavepointExpr
forall a b. (a -> b) -> a -> b
$
    String -> RawSql
RawSql.fromString String
"SAVEPOINT " RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> SavepointName -> RawSql
forall a. SqlExpression a => a -> RawSql
RawSql.toRawSql SavepointName
savepointName

{- |
Type to represent the transaction release savepoint statement. E.G.

> RELEASE SAVEPOINT foo

'ReleaseSavepointExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype ReleaseSavepointExpr
  = ReleaseSavepontExpr RawSql.RawSql
  deriving (RawSql -> ReleaseSavepointExpr
ReleaseSavepointExpr -> RawSql
(ReleaseSavepointExpr -> RawSql)
-> (RawSql -> ReleaseSavepointExpr)
-> SqlExpression ReleaseSavepointExpr
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: ReleaseSavepointExpr -> RawSql
toRawSql :: ReleaseSavepointExpr -> RawSql
$cunsafeFromRawSql :: RawSql -> ReleaseSavepointExpr
unsafeFromRawSql :: RawSql -> ReleaseSavepointExpr
RawSql.SqlExpression)

{- |
  A @RELEASE SAVEPOINT@ statement that will release the specified savepoint.

  @since 1.0.0.0
-}
releaseSavepoint :: Name.SavepointName -> ReleaseSavepointExpr
releaseSavepoint :: SavepointName -> ReleaseSavepointExpr
releaseSavepoint SavepointName
savepointName =
  RawSql -> ReleaseSavepointExpr
ReleaseSavepontExpr (RawSql -> ReleaseSavepointExpr) -> RawSql -> ReleaseSavepointExpr
forall a b. (a -> b) -> a -> b
$
    String -> RawSql
RawSql.fromString String
"RELEASE SAVEPOINT " RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> SavepointName -> RawSql
forall a. SqlExpression a => a -> RawSql
RawSql.toRawSql SavepointName
savepointName