{-# LANGUAGE CPP #-}

-- | Wrappers that apply 'liftSql' to Esqueleto utilities of the same name.
module Database.Persist.Sql.Lifted.Esqueleto
  ( delete
  , deleteCount
  , deleteKey
  , insertSelect
  , insertSelectCount
  , renderQueryDelete
  , renderQueryInsertInto
  , renderQuerySelect
  , renderQueryToText
  , renderQueryUpdate
  , select
  , selectOne
  , update
  , updateCount
  ) where

import Data.Function (($))
import Data.Int (Int64)
import Data.Maybe (Maybe)
import Data.Text (Text)
#if MIN_VERSION_base(4,17,0)
import Data.Type.Equality (type (~))
#endif
import Database.Esqueleto.Experimental
  ( Entity
  , PersistEntity (Key, PersistEntityBackend)
  , PersistValue
  , SqlExpr
  , SqlQuery
  )
import Database.Esqueleto.Experimental qualified as E
import Database.Esqueleto.Internal.Internal (Insertion, Mode, SqlSelect)
import Database.Persist.Sql.Lifted.Core (MonadSqlBackend, SqlBackend, liftSql)
import GHC.Stack (HasCallStack)

-- | Execute an Esqueleto DELETE query
delete :: forall m. (MonadSqlBackend m, HasCallStack) => SqlQuery () -> m ()
delete :: forall (m :: * -> *).
(MonadSqlBackend m, HasCallStack) =>
SqlQuery () -> m ()
delete SqlQuery ()
q = ReaderT SqlBackend m () -> m ()
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m () -> m ())
-> ReaderT SqlBackend m () -> m ()
forall a b. (a -> b) -> a -> b
$ SqlQuery () -> ReaderT SqlBackend m ()
forall (m :: * -> *) backend.
(MonadIO m, SqlBackendCanWrite backend) =>
SqlQuery () -> ReaderT backend m ()
E.delete SqlQuery ()
q

-- | Execute an Esqueleto DELETE query
deleteCount
  :: forall m
   . (MonadSqlBackend m, HasCallStack)
  => SqlQuery ()
  -> m Int64
  -- ^ The number of rows affected
deleteCount :: forall (m :: * -> *).
(MonadSqlBackend m, HasCallStack) =>
SqlQuery () -> m Int64
deleteCount SqlQuery ()
q = ReaderT SqlBackend m Int64 -> m Int64
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m Int64 -> m Int64)
-> ReaderT SqlBackend m Int64 -> m Int64
forall a b. (a -> b) -> a -> b
$ SqlQuery () -> ReaderT SqlBackend m Int64
forall (m :: * -> *) backend.
(MonadIO m, SqlBackendCanWrite backend) =>
SqlQuery () -> ReaderT backend m Int64
E.deleteCount SqlQuery ()
q

-- | Delete a specific record by identifier
--
-- Does nothing if record does not exist.
deleteKey
  :: forall a m
   . ( PersistEntity a
     , PersistEntityBackend a ~ SqlBackend
     , MonadSqlBackend m
     , HasCallStack
     )
  => Key a
  -> m ()
deleteKey :: forall a (m :: * -> *).
(PersistEntity a, PersistEntityBackend a ~ SqlBackend,
 MonadSqlBackend m, HasCallStack) =>
Key a -> m ()
deleteKey Key a
k = ReaderT SqlBackend m () -> m ()
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m () -> m ())
-> ReaderT SqlBackend m () -> m ()
forall a b. (a -> b) -> a -> b
$ Key a -> ReaderT SqlBackend m ()
forall backend val (m :: * -> *).
(PersistStore backend,
 BaseBackend backend ~ PersistEntityBackend val, MonadIO m,
 PersistEntity val) =>
Key val -> ReaderT backend m ()
E.deleteKey Key a
k

-- | Insert a 'E.PersistField' for every selected value
insertSelect
  :: forall a m
   . ( PersistEntity a
     , MonadSqlBackend m
     , HasCallStack
     )
  => SqlQuery (SqlExpr (Insertion a))
  -> m ()
insertSelect :: forall a (m :: * -> *).
(PersistEntity a, MonadSqlBackend m, HasCallStack) =>
SqlQuery (SqlExpr (Insertion a)) -> m ()
insertSelect SqlQuery (SqlExpr (Insertion a))
q = ReaderT SqlBackend m () -> m ()
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m () -> m ())
-> ReaderT SqlBackend m () -> m ()
forall a b. (a -> b) -> a -> b
$ SqlQuery (SqlExpr (Insertion a)) -> ReaderT SqlBackend m ()
forall (m :: * -> *) a backend.
(MonadIO m, PersistEntity a, SqlBackendCanWrite backend) =>
SqlQuery (SqlExpr (Insertion a)) -> ReaderT backend m ()
E.insertSelect SqlQuery (SqlExpr (Insertion a))
q

-- | Insert a 'PersistField' for every selected value, returning the count
insertSelectCount
  :: forall a m
   . ( PersistEntity a
     , MonadSqlBackend m
     , HasCallStack
     )
  => SqlQuery (SqlExpr (Insertion a))
  -> m Int64
  -- ^ The number of inserted rows
insertSelectCount :: forall a (m :: * -> *).
(PersistEntity a, MonadSqlBackend m, HasCallStack) =>
SqlQuery (SqlExpr (Insertion a)) -> m Int64
insertSelectCount SqlQuery (SqlExpr (Insertion a))
q = ReaderT SqlBackend m Int64 -> m Int64
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m Int64 -> m Int64)
-> ReaderT SqlBackend m Int64 -> m Int64
forall a b. (a -> b) -> a -> b
$ SqlQuery (SqlExpr (Insertion a)) -> ReaderT SqlBackend m Int64
forall (m :: * -> *) a backend.
(MonadIO m, PersistEntity a, SqlBackendCanWrite backend) =>
SqlQuery (SqlExpr (Insertion a)) -> ReaderT backend m Int64
E.insertSelectCount SqlQuery (SqlExpr (Insertion a))
q

-- | Renders a 'SqlQuery' to 'Text' along with the list of 'PersistValue's
--   that would be supplied to the database for @?@ placeholders
renderQueryDelete
  :: forall a r m
   . ( SqlSelect a r
     , MonadSqlBackend m
     , HasCallStack
     )
  => SqlQuery a
  -- ^ SQL query to render
  -> m (Text, [PersistValue])
renderQueryDelete :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
SqlQuery a -> m (Text, [PersistValue])
renderQueryDelete SqlQuery a
q = ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m (Text, [PersistValue])
 -> m (Text, [PersistValue]))
-> ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> ReaderT SqlBackend m (Text, [PersistValue])
forall a r backend (m :: * -> *).
(SqlSelect a r, BackendCompatible SqlBackend backend, Monad m) =>
SqlQuery a -> ReaderT backend m (Text, [PersistValue])
E.renderQueryDelete SqlQuery a
q

-- | Renders a 'SqlQuery' to 'Text' along with the list of 'PersistValue's
--   that would be supplied to the database for @?@ placeholders
renderQueryInsertInto
  :: forall a r m
   . ( SqlSelect a r
     , MonadSqlBackend m
     , HasCallStack
     )
  => SqlQuery a
  -- ^ SQL query to render
  -> m (Text, [PersistValue])
renderQueryInsertInto :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
SqlQuery a -> m (Text, [PersistValue])
renderQueryInsertInto SqlQuery a
q = ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m (Text, [PersistValue])
 -> m (Text, [PersistValue]))
-> ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> ReaderT SqlBackend m (Text, [PersistValue])
forall a r backend (m :: * -> *).
(SqlSelect a r, BackendCompatible SqlBackend backend, Monad m) =>
SqlQuery a -> ReaderT backend m (Text, [PersistValue])
E.renderQueryInsertInto SqlQuery a
q

-- | Renders a 'SqlQuery' to 'Text' along with the list of 'PersistValue's
--   that would be supplied to the database for @?@ placeholders
renderQuerySelect
  :: forall a r m
   . ( SqlSelect a r
     , MonadSqlBackend m
     , HasCallStack
     )
  => SqlQuery a
  -- ^ SQL query to render
  -> m (Text, [PersistValue])
renderQuerySelect :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
SqlQuery a -> m (Text, [PersistValue])
renderQuerySelect SqlQuery a
q = ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m (Text, [PersistValue])
 -> m (Text, [PersistValue]))
-> ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> ReaderT SqlBackend m (Text, [PersistValue])
forall a r backend (m :: * -> *).
(SqlSelect a r, BackendCompatible SqlBackend backend, Monad m) =>
SqlQuery a -> ReaderT backend m (Text, [PersistValue])
E.renderQuerySelect SqlQuery a
q

-- | Renders a 'SqlQuery' to 'Text' along with the list of 'PersistValue's
--   that would be supplied to the database for @?@ placeholders
renderQueryToText
  :: forall a r m
   . ( SqlSelect a r
     , MonadSqlBackend m
     , HasCallStack
     )
  => Mode
  -- ^ Whether to render as an SELECT, DELETE, etc.
  --   You must ensure that the Mode you pass to this function corresponds
  --   with the actual SqlQuery. If you pass a query that uses incompatible
  --   features (like an INSERT statement with a SELECT mode) then you'll
  --   get a weird result.
  -> SqlQuery a
  -- ^ SQL query to render
  -> m (Text, [PersistValue])
renderQueryToText :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
Mode -> SqlQuery a -> m (Text, [PersistValue])
renderQueryToText Mode
m SqlQuery a
q = ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m (Text, [PersistValue])
 -> m (Text, [PersistValue]))
-> ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall a b. (a -> b) -> a -> b
$ Mode -> SqlQuery a -> ReaderT SqlBackend m (Text, [PersistValue])
forall a r backend (m :: * -> *).
(SqlSelect a r, BackendCompatible SqlBackend backend, Monad m) =>
Mode -> SqlQuery a -> ReaderT backend m (Text, [PersistValue])
E.renderQueryToText Mode
m SqlQuery a
q

-- | Renders a 'SqlQuery' to 'Text' along with the list of 'PersistValue's
--   that would be supplied to the database for @?@ placeholders
renderQueryUpdate
  :: forall a r m
   . ( SqlSelect a r
     , MonadSqlBackend m
     , HasCallStack
     )
  => SqlQuery a
  -- ^ SQL query to render
  -> m (Text, [PersistValue])
renderQueryUpdate :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
SqlQuery a -> m (Text, [PersistValue])
renderQueryUpdate SqlQuery a
q = ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m (Text, [PersistValue])
 -> m (Text, [PersistValue]))
-> ReaderT SqlBackend m (Text, [PersistValue])
-> m (Text, [PersistValue])
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> ReaderT SqlBackend m (Text, [PersistValue])
forall a r backend (m :: * -> *).
(SqlSelect a r, BackendCompatible SqlBackend backend, Monad m) =>
SqlQuery a -> ReaderT backend m (Text, [PersistValue])
E.renderQueryUpdate SqlQuery a
q

-- | Execute an Esqueleto SELECT query
select
  :: forall a r m
   . (SqlSelect a r, MonadSqlBackend m, HasCallStack)
  => SqlQuery a
  -> m [r]
  -- ^ A list of rows
select :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
SqlQuery a -> m [r]
select SqlQuery a
q = ReaderT SqlBackend m [r] -> m [r]
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m [r] -> m [r])
-> ReaderT SqlBackend m [r] -> m [r]
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> ReaderT SqlBackend m [r]
forall a r (m :: * -> *) backend.
(SqlSelect a r, MonadIO m, SqlBackendCanRead backend) =>
SqlQuery a -> ReaderT backend m [r]
E.select SqlQuery a
q

-- | Execute an Esqueleto SELECT query, getting only the first row
selectOne
  :: forall a r m
   . (SqlSelect a r, MonadSqlBackend m, HasCallStack)
  => SqlQuery a
  -> m (Maybe r)
  -- ^ The first row, or 'Nothing' if no rows are selected
selectOne :: forall a r (m :: * -> *).
(SqlSelect a r, MonadSqlBackend m, HasCallStack) =>
SqlQuery a -> m (Maybe r)
selectOne SqlQuery a
q = ReaderT SqlBackend m (Maybe r) -> m (Maybe r)
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m (Maybe r) -> m (Maybe r))
-> ReaderT SqlBackend m (Maybe r) -> m (Maybe r)
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> ReaderT SqlBackend m (Maybe r)
forall a r (m :: * -> *) backend.
(SqlSelect a r, MonadIO m, SqlBackendCanRead backend) =>
SqlQuery a -> ReaderT backend m (Maybe r)
E.selectOne SqlQuery a
q

-- | Execute an Esqueleto UPDATE query
update
  :: forall a m
   . ( PersistEntity a
     , PersistEntityBackend a ~ SqlBackend
     , MonadSqlBackend m
     , HasCallStack
     )
  => (SqlExpr (Entity a) -> SqlQuery ())
  -> m ()
update :: forall a (m :: * -> *).
(PersistEntity a, PersistEntityBackend a ~ SqlBackend,
 MonadSqlBackend m, HasCallStack) =>
(SqlExpr (Entity a) -> SqlQuery ()) -> m ()
update SqlExpr (Entity a) -> SqlQuery ()
q = ReaderT SqlBackend m () -> m ()
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m () -> m ())
-> ReaderT SqlBackend m () -> m ()
forall a b. (a -> b) -> a -> b
$ (SqlExpr (Entity a) -> SqlQuery ()) -> ReaderT SqlBackend m ()
forall (m :: * -> *) val backend.
(MonadIO m, PersistEntity val,
 BackendCompatible SqlBackend (PersistEntityBackend val),
 SqlBackendCanWrite backend) =>
(SqlExpr (Entity val) -> SqlQuery ()) -> ReaderT backend m ()
E.update SqlExpr (Entity a) -> SqlQuery ()
q

-- | Execute an Esqueleto UPDATE query, returning the count
updateCount
  :: forall a m
   . ( PersistEntity a
     , PersistEntityBackend a ~ SqlBackend
     , MonadSqlBackend m
     , HasCallStack
     )
  => (SqlExpr (Entity a) -> SqlQuery ())
  -> m Int64
  -- ^ The number of inserted rows
updateCount :: forall a (m :: * -> *).
(PersistEntity a, PersistEntityBackend a ~ SqlBackend,
 MonadSqlBackend m, HasCallStack) =>
(SqlExpr (Entity a) -> SqlQuery ()) -> m Int64
updateCount SqlExpr (Entity a) -> SqlQuery ()
q = ReaderT SqlBackend m Int64 -> m Int64
forall (m :: * -> *) a.
(MonadSqlBackend m, HasCallStack) =>
ReaderT SqlBackend m a -> m a
liftSql (ReaderT SqlBackend m Int64 -> m Int64)
-> ReaderT SqlBackend m Int64 -> m Int64
forall a b. (a -> b) -> a -> b
$ (SqlExpr (Entity a) -> SqlQuery ()) -> ReaderT SqlBackend m Int64
forall (m :: * -> *) val backend.
(MonadIO m, PersistEntity val,
 BackendCompatible SqlBackend (PersistEntityBackend val),
 SqlBackendCanWrite backend) =>
(SqlExpr (Entity val) -> SqlQuery ()) -> ReaderT backend m Int64
E.updateCount SqlExpr (Entity a) -> SqlQuery ()
q