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

Entry-level functions for executing based CRUD operations on entity tables.
These are the functions that you will use most often for interacting with
tables.

@since 1.0.0.0
-}
module Orville.PostgreSQL.Execution.EntityOperations
  ( insertEntity
  , insertEntityAndReturnRowCount
  , insertAndReturnEntity
  , insertEntities
  , insertAndReturnEntities
  , insertEntitiesAndReturnRowCount
  , updateEntity
  , updateEntityAndReturnRowCount
  , updateAndReturnEntity
  , updateFields
  , updateFieldsAndReturnEntities
  , updateFieldsAndReturnRowCount
  , deleteEntity
  , deleteEntityAndReturnRowCount
  , deleteAndReturnEntity
  , deleteEntities
  , deleteEntitiesAndReturnRowCount
  , deleteAndReturnEntities
  , findEntitiesBy
  , findFirstEntityBy
  , findEntity
  , findEntities
  )
where

import Control.Exception (Exception, throwIO)
import qualified Control.Monad as Monad
import Control.Monad.IO.Class (MonadIO (liftIO))
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.Maybe (listToMaybe)

import qualified Orville.PostgreSQL.Execution.Delete as Delete
import qualified Orville.PostgreSQL.Execution.Insert as Insert
import qualified Orville.PostgreSQL.Execution.Select as Select
import qualified Orville.PostgreSQL.Execution.SelectOptions as SelectOptions
import qualified Orville.PostgreSQL.Execution.Update as Update
import qualified Orville.PostgreSQL.Expr as Expr
import qualified Orville.PostgreSQL.Internal.RowCountExpectation as RowCountExpectation
import qualified Orville.PostgreSQL.Monad as Monad
import qualified Orville.PostgreSQL.Schema as Schema

{- |
  Inserts an entity into the specified table.

@since 1.0.0.0
-}
insertEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  writeEntity ->
  m ()
insertEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity -> writeEntity -> m ()
insertEntity TableDefinition key writeEntity readEntity
entityTable =
  m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void (m Int -> m ()) -> (writeEntity -> m Int) -> writeEntity -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition key writeEntity readEntity -> writeEntity -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity -> writeEntity -> m Int
insertEntityAndReturnRowCount TableDefinition key writeEntity readEntity
entityTable

{- |
  Inserts an entity into the specified table. Returns the number of rows
  affected by the query.

@since 1.0.0.0
-}
insertEntityAndReturnRowCount ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  writeEntity ->
  m Int
insertEntityAndReturnRowCount :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity -> writeEntity -> m Int
insertEntityAndReturnRowCount TableDefinition key writeEntity readEntity
entityTable writeEntity
entity =
  TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m Int
insertEntitiesAndReturnRowCount TableDefinition key writeEntity readEntity
entityTable (writeEntity
entity writeEntity -> [writeEntity] -> NonEmpty writeEntity
forall a. a -> [a] -> NonEmpty a
:| [])

{- |
  Inserts an entity into the specified table, returning the data inserted into
  the database.

  You can use this function to obtain any column values filled in by the
  database, such as auto-incrementing ids.

@since 1.0.0.0
-}
insertAndReturnEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  writeEntity ->
  m readEntity
insertAndReturnEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> writeEntity -> m readEntity
insertAndReturnEntity TableDefinition key writeEntity readEntity
entityTable writeEntity
entity = do
  [readEntity]
returnedEntities <- TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m [readEntity]
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m [readEntity]
insertAndReturnEntities TableDefinition key writeEntity readEntity
entityTable (writeEntity
entity writeEntity -> [writeEntity] -> NonEmpty writeEntity
forall a. a -> [a] -> NonEmpty a
:| [])

  String -> [readEntity] -> m readEntity
forall (m :: * -> *) a. MonadIO m => String -> [a] -> m a
RowCountExpectation.expectExactlyOneRow
    String
"insertAndReturnEntity RETURNING clause"
    [readEntity]
returnedEntities

{- |
  Inserts a non-empty list of entities into the specified table.

@since 1.0.0.0
-}
insertEntities ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  NonEmpty writeEntity ->
  m ()
insertEntities :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m ()
insertEntities TableDefinition key writeEntity readEntity
tableDef =
  m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void (m Int -> m ())
-> (NonEmpty writeEntity -> m Int) -> NonEmpty writeEntity -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m Int
insertEntitiesAndReturnRowCount TableDefinition key writeEntity readEntity
tableDef

{- |
  Inserts a non-empty list of entities into the specified table. Returns the
  number of rows affected by the query.

@since 1.0.0.0
-}
insertEntitiesAndReturnRowCount ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  NonEmpty writeEntity ->
  m Int
insertEntitiesAndReturnRowCount :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m Int
insertEntitiesAndReturnRowCount TableDefinition key writeEntity readEntity
tableDef =
  Insert readEntity NoReturningClause -> m Int
forall (m :: * -> *) readEntity.
MonadOrville m =>
Insert readEntity NoReturningClause -> m Int
Insert.executeInsert (Insert readEntity NoReturningClause -> m Int)
-> (NonEmpty writeEntity -> Insert readEntity NoReturningClause)
-> NonEmpty writeEntity
-> m Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> Insert readEntity NoReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> Insert readEntity NoReturningClause
Insert.insertToTable TableDefinition key writeEntity readEntity
tableDef

{- |
  Inserts a non-empty list of entities into the specified table, returning the data that
  was inserted into the database.

  You can use this function to obtain any column values filled in by the
  database, such as auto-incrementing ids.

@since 1.0.0.0
-}
insertAndReturnEntities ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  NonEmpty writeEntity ->
  m [readEntity]
insertAndReturnEntities :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> m [readEntity]
insertAndReturnEntities TableDefinition key writeEntity readEntity
tableDef =
  Insert readEntity ReturningClause -> m [readEntity]
forall (m :: * -> *) readEntity.
MonadOrville m =>
Insert readEntity ReturningClause -> m [readEntity]
Insert.executeInsertReturnEntities (Insert readEntity ReturningClause -> m [readEntity])
-> (NonEmpty writeEntity -> Insert readEntity ReturningClause)
-> NonEmpty writeEntity
-> m [readEntity]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> Insert readEntity ReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> NonEmpty writeEntity -> Insert readEntity ReturningClause
Insert.insertToTableReturning TableDefinition key writeEntity readEntity
tableDef

{- |
  Updates the row with the given key with the data given by @writeEntity@.

@since 1.0.0.0
-}
updateEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  writeEntity ->
  m ()
updateEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> m ()
updateEntity TableDefinition (HasKey key) writeEntity readEntity
tableDef key
key =
  m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void (m Int -> m ()) -> (writeEntity -> m Int) -> writeEntity -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> m Int
updateEntityAndReturnRowCount TableDefinition (HasKey key) writeEntity readEntity
tableDef key
key

{- |
  Updates the row with the given key with the data given by @writeEntity@.
  Returns the number of rows affected by the query.

@since 1.0.0.0
-}
updateEntityAndReturnRowCount ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  writeEntity ->
  m Int
updateEntityAndReturnRowCount :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> m Int
updateEntityAndReturnRowCount TableDefinition (HasKey key) writeEntity readEntity
tableDef key
key writeEntity
writeEntity =
  case TableDefinition (HasKey key) writeEntity readEntity
-> key
-> writeEntity
-> Maybe (Update readEntity NoReturningClause)
forall key writeEntity readEntity.
TableDefinition (HasKey key) writeEntity readEntity
-> key
-> writeEntity
-> Maybe (Update readEntity NoReturningClause)
Update.updateToTable TableDefinition (HasKey key) writeEntity readEntity
tableDef key
key writeEntity
writeEntity of
    Maybe (Update readEntity NoReturningClause)
Nothing ->
      IO Int -> m Int
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int -> m Int)
-> (TableDefinition (HasKey key) writeEntity readEntity -> IO Int)
-> TableDefinition (HasKey key) writeEntity readEntity
-> m Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EmptyUpdateError -> IO Int
forall e a. Exception e => e -> IO a
throwIO (EmptyUpdateError -> IO Int)
-> (TableDefinition (HasKey key) writeEntity readEntity
    -> EmptyUpdateError)
-> TableDefinition (HasKey key) writeEntity readEntity
-> IO Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableIdentifier -> EmptyUpdateError
EmptyUpdateError (TableIdentifier -> EmptyUpdateError)
-> (TableDefinition (HasKey key) writeEntity readEntity
    -> TableIdentifier)
-> TableDefinition (HasKey key) writeEntity readEntity
-> EmptyUpdateError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition (HasKey key) writeEntity readEntity
-> TableIdentifier
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity -> TableIdentifier
Schema.tableIdentifier (TableDefinition (HasKey key) writeEntity readEntity -> m Int)
-> TableDefinition (HasKey key) writeEntity readEntity -> m Int
forall a b. (a -> b) -> a -> b
$ TableDefinition (HasKey key) writeEntity readEntity
tableDef
    Just Update readEntity NoReturningClause
update ->
      Update readEntity NoReturningClause -> m Int
forall (m :: * -> *) readEntity returningClause.
MonadOrville m =>
Update readEntity returningClause -> m Int
Update.executeUpdate Update readEntity NoReturningClause
update

{- |
  Updates the row with the given key with the data given by @writeEntity@,
  returning the updated row from the database. If no row matches the given key,
  'Nothing' will be returned.

  You can use this function to obtain any column values computed by the database
  during the update, including columns with triggers attached to them.

@since 1.0.0.0
-}
updateAndReturnEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  writeEntity ->
  m (Maybe readEntity)
updateAndReturnEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> m (Maybe readEntity)
updateAndReturnEntity TableDefinition (HasKey key) writeEntity readEntity
tableDef key
key writeEntity
writeEntity =
  case TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> Maybe (Update readEntity ReturningClause)
forall key writeEntity readEntity.
TableDefinition (HasKey key) writeEntity readEntity
-> key -> writeEntity -> Maybe (Update readEntity ReturningClause)
Update.updateToTableReturning TableDefinition (HasKey key) writeEntity readEntity
tableDef key
key writeEntity
writeEntity of
    Maybe (Update readEntity ReturningClause)
Nothing ->
      IO (Maybe readEntity) -> m (Maybe readEntity)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe readEntity) -> m (Maybe readEntity))
-> (TableDefinition (HasKey key) writeEntity readEntity
    -> IO (Maybe readEntity))
-> TableDefinition (HasKey key) writeEntity readEntity
-> m (Maybe readEntity)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EmptyUpdateError -> IO (Maybe readEntity)
forall e a. Exception e => e -> IO a
throwIO (EmptyUpdateError -> IO (Maybe readEntity))
-> (TableDefinition (HasKey key) writeEntity readEntity
    -> EmptyUpdateError)
-> TableDefinition (HasKey key) writeEntity readEntity
-> IO (Maybe readEntity)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableIdentifier -> EmptyUpdateError
EmptyUpdateError (TableIdentifier -> EmptyUpdateError)
-> (TableDefinition (HasKey key) writeEntity readEntity
    -> TableIdentifier)
-> TableDefinition (HasKey key) writeEntity readEntity
-> EmptyUpdateError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition (HasKey key) writeEntity readEntity
-> TableIdentifier
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity -> TableIdentifier
Schema.tableIdentifier (TableDefinition (HasKey key) writeEntity readEntity
 -> m (Maybe readEntity))
-> TableDefinition (HasKey key) writeEntity readEntity
-> m (Maybe readEntity)
forall a b. (a -> b) -> a -> b
$ TableDefinition (HasKey key) writeEntity readEntity
tableDef
    Just Update readEntity ReturningClause
update -> do
      [readEntity]
returnedEntities <- Update readEntity ReturningClause -> m [readEntity]
forall (m :: * -> *) readEntity.
MonadOrville m =>
Update readEntity ReturningClause -> m [readEntity]
Update.executeUpdateReturnEntities Update readEntity ReturningClause
update
      String -> [readEntity] -> m (Maybe readEntity)
forall (m :: * -> *) a. MonadIO m => String -> [a] -> m (Maybe a)
RowCountExpectation.expectAtMostOneRow
        String
"updateAndReturnEntity RETURNING clause"
        [readEntity]
returnedEntities

{- |
  Applies the given 'Expr.SetClause's to the rows in the table that match the
  given where condition. The easiest way to construct a 'Expr.SetClause' is
  via the 'Orville.Postgresql.setField' function (also exported as @.:=@).

@since 1.0.0.0
-}
updateFields ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  NonEmpty Expr.SetClause ->
  Maybe Expr.BooleanExpr ->
  m ()
updateFields :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause -> Maybe BooleanExpr -> m ()
updateFields TableDefinition (HasKey key) writeEntity readEntity
tableDef NonEmpty SetClause
setClauses =
  m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void (m Int -> m ())
-> (Maybe BooleanExpr -> m Int) -> Maybe BooleanExpr -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause -> Maybe BooleanExpr -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause -> Maybe BooleanExpr -> m Int
updateFieldsAndReturnRowCount TableDefinition (HasKey key) writeEntity readEntity
tableDef NonEmpty SetClause
setClauses

{- |
  Applies the given 'Expr.SetClause's to the rows in the table that match the
  given where condition. The easiest way to construct a 'Expr.SetClause' is
  via the 'Orville.Postgresql.setField' function (also exported as @.:=@).
  Returns the number of rows affected by the query.

@since 1.0.0.0
-}
updateFieldsAndReturnRowCount ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  NonEmpty Expr.SetClause ->
  Maybe Expr.BooleanExpr ->
  m Int
updateFieldsAndReturnRowCount :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause -> Maybe BooleanExpr -> m Int
updateFieldsAndReturnRowCount TableDefinition (HasKey key) writeEntity readEntity
tableDef NonEmpty SetClause
setClauses Maybe BooleanExpr
mbWhereCondition =
  Update readEntity NoReturningClause -> m Int
forall (m :: * -> *) readEntity returningClause.
MonadOrville m =>
Update readEntity returningClause -> m Int
Update.executeUpdate (Update readEntity NoReturningClause -> m Int)
-> Update readEntity NoReturningClause -> m Int
forall a b. (a -> b) -> a -> b
$
    TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause
-> Maybe BooleanExpr
-> Update readEntity NoReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> NonEmpty SetClause
-> Maybe BooleanExpr
-> Update readEntity NoReturningClause
Update.updateToTableFields TableDefinition (HasKey key) writeEntity readEntity
tableDef NonEmpty SetClause
setClauses Maybe BooleanExpr
mbWhereCondition

{- |
  Like 'updateFields', but uses a @RETURNING@ clause to return the updated
  version of any rows that were affected by the update.

@since 1.0.0.0
-}
updateFieldsAndReturnEntities ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  NonEmpty Expr.SetClause ->
  Maybe Expr.BooleanExpr ->
  m [readEntity]
updateFieldsAndReturnEntities :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause -> Maybe BooleanExpr -> m [readEntity]
updateFieldsAndReturnEntities TableDefinition (HasKey key) writeEntity readEntity
tableDef NonEmpty SetClause
setClauses Maybe BooleanExpr
mbWhereCondition =
  Update readEntity ReturningClause -> m [readEntity]
forall (m :: * -> *) readEntity.
MonadOrville m =>
Update readEntity ReturningClause -> m [readEntity]
Update.executeUpdateReturnEntities (Update readEntity ReturningClause -> m [readEntity])
-> Update readEntity ReturningClause -> m [readEntity]
forall a b. (a -> b) -> a -> b
$
    TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty SetClause
-> Maybe BooleanExpr
-> Update readEntity ReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> NonEmpty SetClause
-> Maybe BooleanExpr
-> Update readEntity ReturningClause
Update.updateToTableFieldsReturning TableDefinition (HasKey key) writeEntity readEntity
tableDef NonEmpty SetClause
setClauses Maybe BooleanExpr
mbWhereCondition

{- |
  Deletes the row with the given key.

@since 1.0.0.0
-}
deleteEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  m ()
deleteEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity -> key -> m ()
deleteEntity TableDefinition (HasKey key) writeEntity readEntity
entityTable =
  m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void (m Int -> m ()) -> (key -> m Int) -> key -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition (HasKey key) writeEntity readEntity -> key -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity -> key -> m Int
deleteEntityAndReturnRowCount TableDefinition (HasKey key) writeEntity readEntity
entityTable

{- |
  Deletes the row with the given key. Returns the number of rows affected
  by the query.

@since 1.0.0.0
-}
deleteEntityAndReturnRowCount ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  m Int
deleteEntityAndReturnRowCount :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity -> key -> m Int
deleteEntityAndReturnRowCount TableDefinition (HasKey key) writeEntity readEntity
entityTable key
key =
  let
    primaryKeyCondition :: BooleanExpr
primaryKeyCondition =
      PrimaryKey key -> key -> BooleanExpr
forall key. PrimaryKey key -> key -> BooleanExpr
Schema.primaryKeyEquals
        (TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
forall key writeEntity readEntity.
TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
Schema.tablePrimaryKey TableDefinition (HasKey key) writeEntity readEntity
entityTable)
        key
key
  in
    Delete readEntity NoReturningClause -> m Int
forall (m :: * -> *) readEntity.
MonadOrville m =>
Delete readEntity NoReturningClause -> m Int
Delete.executeDelete (Delete readEntity NoReturningClause -> m Int)
-> Delete readEntity NoReturningClause -> m Int
forall a b. (a -> b) -> a -> b
$
      TableDefinition (HasKey key) writeEntity readEntity
-> Maybe BooleanExpr -> Delete readEntity NoReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> Delete readEntity NoReturningClause
Delete.deleteFromTable TableDefinition (HasKey key) writeEntity readEntity
entityTable (BooleanExpr -> Maybe BooleanExpr
forall a. a -> Maybe a
Just BooleanExpr
primaryKeyCondition)

{- |
  Deletes the row with the given key, returning the row that was deleted.
  If no row matches the given key, 'Nothing' is returned.

@since 1.0.0.0
-}
deleteAndReturnEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  m (Maybe readEntity)
deleteAndReturnEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> key -> m (Maybe readEntity)
deleteAndReturnEntity TableDefinition (HasKey key) writeEntity readEntity
entityTable key
key = do
  let
    primaryKeyCondition :: BooleanExpr
primaryKeyCondition =
      PrimaryKey key -> key -> BooleanExpr
forall key. PrimaryKey key -> key -> BooleanExpr
Schema.primaryKeyEquals
        (TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
forall key writeEntity readEntity.
TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
Schema.tablePrimaryKey TableDefinition (HasKey key) writeEntity readEntity
entityTable)
        key
key

  [readEntity]
returnedEntities <- TableDefinition (HasKey key) writeEntity readEntity
-> Maybe BooleanExpr -> m [readEntity]
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> m [readEntity]
deleteAndReturnEntities TableDefinition (HasKey key) writeEntity readEntity
entityTable (BooleanExpr -> Maybe BooleanExpr
forall a. a -> Maybe a
Just BooleanExpr
primaryKeyCondition)

  String -> [readEntity] -> m (Maybe readEntity)
forall (m :: * -> *) a. MonadIO m => String -> [a] -> m (Maybe a)
RowCountExpectation.expectAtMostOneRow
    String
"deleteAndReturnEntity RETURNING clause"
    [readEntity]
returnedEntities

{- |
  Deletes all rows in the given table that match the where condition.

@since 1.0.0.0
-}
deleteEntities ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  Maybe Expr.BooleanExpr ->
  m ()
deleteEntities :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> m ()
deleteEntities TableDefinition key writeEntity readEntity
entityTable =
  m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void (m Int -> m ())
-> (Maybe BooleanExpr -> m Int) -> Maybe BooleanExpr -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> m Int
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> m Int
deleteEntitiesAndReturnRowCount TableDefinition key writeEntity readEntity
entityTable

{- |
  Deletes all rows in the given table that match the where condition. Returns
  the number of rows affected by the query.

@since 1.0.0.0
-}
deleteEntitiesAndReturnRowCount ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  Maybe Expr.BooleanExpr ->
  m Int
deleteEntitiesAndReturnRowCount :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> m Int
deleteEntitiesAndReturnRowCount TableDefinition key writeEntity readEntity
entityTable Maybe BooleanExpr
whereCondition =
  Delete readEntity NoReturningClause -> m Int
forall (m :: * -> *) readEntity.
MonadOrville m =>
Delete readEntity NoReturningClause -> m Int
Delete.executeDelete (Delete readEntity NoReturningClause -> m Int)
-> Delete readEntity NoReturningClause -> m Int
forall a b. (a -> b) -> a -> b
$
    TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> Delete readEntity NoReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> Delete readEntity NoReturningClause
Delete.deleteFromTable TableDefinition key writeEntity readEntity
entityTable Maybe BooleanExpr
whereCondition

{- |
  Deletes all rows in the given table that match the where condition, returning
  the rows that were deleted.

@since 1.0.0.0
-}
deleteAndReturnEntities ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  Maybe Expr.BooleanExpr ->
  m [readEntity]
deleteAndReturnEntities :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> m [readEntity]
deleteAndReturnEntities TableDefinition key writeEntity readEntity
entityTable Maybe BooleanExpr
whereCondition =
  Delete readEntity ReturningClause -> m [readEntity]
forall (m :: * -> *) readEntity.
MonadOrville m =>
Delete readEntity ReturningClause -> m [readEntity]
Delete.executeDeleteReturnEntities (Delete readEntity ReturningClause -> m [readEntity])
-> Delete readEntity ReturningClause -> m [readEntity]
forall a b. (a -> b) -> a -> b
$
    TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> Delete readEntity ReturningClause
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> Maybe BooleanExpr -> Delete readEntity ReturningClause
Delete.deleteFromTableReturning TableDefinition key writeEntity readEntity
entityTable Maybe BooleanExpr
whereCondition

{- |
  Finds all the entities in the given table according to the specified
  'SelectOptions.SelectOptions', which may include where conditions to
  match, ordering specifications, etc.

@since 1.0.0.0
-}
findEntitiesBy ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  SelectOptions.SelectOptions ->
  m [readEntity]
findEntitiesBy :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> SelectOptions -> m [readEntity]
findEntitiesBy TableDefinition key writeEntity readEntity
entityTable SelectOptions
selectOptions =
  Select readEntity -> m [readEntity]
forall (m :: * -> *) row. MonadOrville m => Select row -> m [row]
Select.executeSelect (Select readEntity -> m [readEntity])
-> Select readEntity -> m [readEntity]
forall a b. (a -> b) -> a -> b
$
    TableDefinition key writeEntity readEntity
-> SelectOptions -> Select readEntity
forall key writeEntity readEntity.
TableDefinition key writeEntity readEntity
-> SelectOptions -> Select readEntity
Select.selectTable TableDefinition key writeEntity readEntity
entityTable SelectOptions
selectOptions

{- |
  Like 'findEntitiesBy', but adds a 'LIMIT 1' to the query and then returns
  the first item from the list. Usually when you use this you will want to
  provide an order by clause in the 'SelectOptions.SelectOptions' because the
  database will not guarantee ordering.

@since 1.0.0.0
-}
findFirstEntityBy ::
  Monad.MonadOrville m =>
  Schema.TableDefinition key writeEntity readEntity ->
  SelectOptions.SelectOptions ->
  m (Maybe readEntity)
findFirstEntityBy :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> SelectOptions -> m (Maybe readEntity)
findFirstEntityBy TableDefinition key writeEntity readEntity
entityTable SelectOptions
selectOptions =
  [readEntity] -> Maybe readEntity
forall a. [a] -> Maybe a
listToMaybe
    ([readEntity] -> Maybe readEntity)
-> m [readEntity] -> m (Maybe readEntity)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TableDefinition key writeEntity readEntity
-> SelectOptions -> m [readEntity]
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> SelectOptions -> m [readEntity]
findEntitiesBy TableDefinition key writeEntity readEntity
entityTable (Int -> SelectOptions
SelectOptions.limit Int
1 SelectOptions -> SelectOptions -> SelectOptions
forall a. Semigroup a => a -> a -> a
<> SelectOptions
selectOptions)

{- |
  Finds a single entity by the table's primary key value.

@since 1.0.0.0
-}
findEntity ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  key ->
  m (Maybe readEntity)
findEntity :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> key -> m (Maybe readEntity)
findEntity TableDefinition (HasKey key) writeEntity readEntity
entityTable key
key =
  let
    primaryKeyCondition :: BooleanExpr
primaryKeyCondition =
      PrimaryKey key -> key -> BooleanExpr
forall key. PrimaryKey key -> key -> BooleanExpr
Schema.primaryKeyEquals
        (TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
forall key writeEntity readEntity.
TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
Schema.tablePrimaryKey TableDefinition (HasKey key) writeEntity readEntity
entityTable)
        key
key
  in
    TableDefinition (HasKey key) writeEntity readEntity
-> SelectOptions -> m (Maybe readEntity)
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> SelectOptions -> m (Maybe readEntity)
findFirstEntityBy TableDefinition (HasKey key) writeEntity readEntity
entityTable (BooleanExpr -> SelectOptions
SelectOptions.where_ BooleanExpr
primaryKeyCondition)

{- |
  Finds multiple entities by the table's primary key.

@since 1.0.0.0
-}
findEntities ::
  Monad.MonadOrville m =>
  Schema.TableDefinition (Schema.HasKey key) writeEntity readEntity ->
  NonEmpty key ->
  m [readEntity]
findEntities :: forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition (HasKey key) writeEntity readEntity
-> NonEmpty key -> m [readEntity]
findEntities TableDefinition (HasKey key) writeEntity readEntity
entityTable NonEmpty key
keys =
  let
    primaryKeyCondition :: BooleanExpr
primaryKeyCondition =
      PrimaryKey key -> NonEmpty key -> BooleanExpr
forall key. PrimaryKey key -> NonEmpty key -> BooleanExpr
Schema.primaryKeyIn
        (TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
forall key writeEntity readEntity.
TableDefinition (HasKey key) writeEntity readEntity
-> PrimaryKey key
Schema.tablePrimaryKey TableDefinition (HasKey key) writeEntity readEntity
entityTable)
        NonEmpty key
keys
  in
    TableDefinition (HasKey key) writeEntity readEntity
-> SelectOptions -> m [readEntity]
forall (m :: * -> *) key writeEntity readEntity.
MonadOrville m =>
TableDefinition key writeEntity readEntity
-> SelectOptions -> m [readEntity]
findEntitiesBy TableDefinition (HasKey key) writeEntity readEntity
entityTable (BooleanExpr -> SelectOptions
SelectOptions.where_ BooleanExpr
primaryKeyCondition)

{- |
  Thrown by 'updateFields' and 'updateFieldsAndReturnEntities' if the
  'Schema.TableDefinition' they are given has no columns to update.

@since 1.0.0.0
-}
newtype EmptyUpdateError
  = EmptyUpdateError Schema.TableIdentifier

-- | @since 1.0.0.0
instance Show EmptyUpdateError where
  show :: EmptyUpdateError -> String
show (EmptyUpdateError TableIdentifier
tableId) =
    String
"EmptyUdateError: "
      String -> ShowS
forall a. Semigroup a => a -> a -> a
<> TableIdentifier -> String
Schema.tableIdToString TableIdentifier
tableId
      String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" has no columns to update."

-- | @since 1.0.0.0
instance Exception EmptyUpdateError