{-# LANGUAGE DefaultSignatures    #-}
{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE GADTs                #-}
{-# LANGUAGE RankNTypes           #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Description: SQL & SqlQuery classes
--
-- Effect class, expressing that a database connection is available or
-- can be acquired, and transactions run.

module Preql.Effect
    ( module Preql.Effect, Transaction
    ) where

import Preql.Effect.Internal
import Preql.Imports
import Preql.Wire

import Control.Exception (throwIO)
import Control.Monad.Trans.Class (MonadTrans(..))
import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
import Control.Monad.Trans.Reader (ReaderT(..), ask, runReaderT)
import Database.PostgreSQL.LibPQ (Connection)
import GHC.TypeNats
import qualified Control.Monad.Trans.RWS.Lazy as L
import qualified Control.Monad.Trans.RWS.Strict as S
import qualified Control.Monad.Trans.State.Lazy as SL
import qualified Control.Monad.Trans.State.Strict as SS

import qualified Preql.Wire.Query as W

-- | An Effect class for running SQL queries.  You can think of this as a context
-- specifying a particular Postgres connection (or connection pool).  A minimal instance
-- defines @withConnection@.
--
-- Override the remaining methods to log errors before rethrowing, or not to rethrow.
class SqlQuery m => SQL (m :: * -> *) where
    -- | Run multiple queries in a transaction.
    runTransaction' :: IsolationLevel -> Transaction a -> m a
    default runTransaction' :: MonadIO m => IsolationLevel -> Transaction a -> m a
    runTransaction' IsolationLevel
level Transaction a
t = (Connection -> m a) -> m a
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection ((Connection -> m a) -> m a) -> (Connection -> m a) -> m a
forall a b. (a -> b) -> a -> b
$ \Connection
conn ->
        IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ (QueryError -> IO a) -> (a -> IO a) -> Either QueryError a -> IO a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either QueryError -> IO a
forall e a. Exception e => e -> IO a
throwIO a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either QueryError a -> IO a) -> IO (Either QueryError a) -> IO a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IsolationLevel
-> Transaction a -> Connection -> IO (Either QueryError a)
forall a.
IsolationLevel
-> Transaction a -> Connection -> IO (Either QueryError a)
runTransactionIO IsolationLevel
level Transaction a
t Connection
conn

    -- | @runTransaction@ covers the most common patterns of
    -- mult-statement transactions.  @withConnection@ is useful when
    -- you want more control, or want to override the defaults that
    -- your instance defines.  For example:
    --      - change the number of retries
    --      - interleave calls to other services with the Postgres transaction
    --      - ensure a prepared statement is shared among successive transactions
    withConnection :: (Connection -> m a) -> m a

    -- | Run a query on the specified 'Connection'
    queryOn :: (ToSql p, FromSql r, KnownNat (Width r)) =>
        Connection -> (Query (Width r), p) -> m (Vector r)
    default queryOn :: (ToSql p, FromSql r, KnownNat (Width r), MonadIO m) =>
        Connection -> (Query (Width r), p) -> m (Vector r)
    queryOn Connection
conn (Query (Width r)
q, p
p) = IO (Vector r) -> m (Vector r)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Vector r) -> m (Vector r)) -> IO (Vector r) -> m (Vector r)
forall a b. (a -> b) -> a -> b
$ (QueryError -> IO (Vector r))
-> (Vector r -> IO (Vector r))
-> Either QueryError (Vector r)
-> IO (Vector r)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either QueryError -> IO (Vector r)
forall e a. Exception e => e -> IO a
throwIO Vector r -> IO (Vector r)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either QueryError (Vector r) -> IO (Vector r))
-> IO (Either QueryError (Vector r)) -> IO (Vector r)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Connection
-> Query (Width r) -> p -> IO (Either QueryError (Vector r))
forall p r.
(ToSql p, FromSql r, KnownNat (Width r)) =>
Connection
-> Query (Width r) -> p -> IO (Either QueryError (Vector r))
W.query Connection
conn Query (Width r)
q p
p

    queryOn_ :: ToSql p => Connection -> (Query 0, p) -> m ()
    default queryOn_ :: (ToSql p, MonadIO m) => Connection -> (Query 0, p) -> m ()
    queryOn_ Connection
conn (Query 0
q, p
p) = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ (QueryError -> IO ())
-> (() -> IO ()) -> Either QueryError () -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either QueryError -> IO ()
forall e a. Exception e => e -> IO a
throwIO () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either QueryError () -> IO ())
-> IO (Either QueryError ()) -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Connection -> Query 0 -> p -> IO (Either QueryError ())
forall p (n :: Nat).
ToSql p =>
Connection -> Query n -> p -> IO (Either QueryError ())
W.query_ Connection
conn Query 0
q p
p

-- | Run a Transaction with full Serializable isolation.
runTransaction :: SQL m => Transaction a -> m a
runTransaction :: Transaction a -> m a
runTransaction = IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
Serializable

-- | SqlQuery is separate from 'SQL' so that nested 'Transaction's are
-- statically prevented.  @query@ can be used directly within any
-- 'SQL' monad (running a single-statement transaction), or within a
-- 'Transaction'.
--
-- Users should not need to define instances, as every @SQL@ instance
-- implies a @SqlQuery@ instance.
class Monad m => SqlQuery (m :: * -> *) where
    -- | Run a parameterized query that returns data.  The tuple argument is typically provided by
    -- one of the Quasiquoters: 'Preql.sql' or 'Preql.select'
    query :: (ToSql p, FromSql r, KnownNat (Width r)) => (Query (Width r), p) -> m (Vector r)

    -- | Run a parameterized query that does not return data.
    query_ :: ToSql p => (Query 0, p) -> m ()

-- | Most larger applications will define an instance; this one is suitable to test out the library.
-- A safer version would use @MVar Connection@ to ensure only one thread using it.
instance SQL (ReaderT Connection IO) where
    withConnection :: (Connection -> ReaderT Connection IO a) -> ReaderT Connection IO a
withConnection = (ReaderT Connection IO Connection
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask ReaderT Connection IO Connection
-> (Connection -> ReaderT Connection IO a)
-> ReaderT Connection IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=)

instance {-# OVERLAPPABLE #-} (Monad m, SQL m) => SqlQuery m where
    query :: (Query (Width r), p) -> m (Vector r)
query (Query (Width r), p)
qp = (Connection -> m (Vector r)) -> m (Vector r)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp)
    query_ :: (Query 0, p) -> m ()
query_ (Query 0, p)
q = (Connection -> m ()) -> m ()
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q)

-- * Transactions

-- | Run the provided 'Transaction'.  If it fails with a 'QueryError', roll back.
runTransactionIO :: IsolationLevel -> Transaction a -> Connection -> IO (Either QueryError a)
runTransactionIO :: IsolationLevel
-> Transaction a -> Connection -> IO (Either QueryError a)
runTransactionIO IsolationLevel
level (Transaction ExceptT QueryError (ReaderT Connection IO) a
m) Connection
conn = do
    (QueryError -> IO ())
-> (() -> IO ()) -> Either QueryError () -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either QueryError -> IO ()
forall e a. Exception e => e -> IO a
throwIO () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either QueryError () -> IO ())
-> IO (Either QueryError ()) -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Connection -> IsolationLevel -> IO (Either QueryError ())
W.begin Connection
conn IsolationLevel
level
    Either QueryError a
e_a <- ReaderT Connection IO (Either QueryError a)
-> Connection -> IO (Either QueryError a)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (ExceptT QueryError (ReaderT Connection IO) a
-> ReaderT Connection IO (Either QueryError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT QueryError (ReaderT Connection IO) a
m) Connection
conn
    IO (Either QueryError ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Either QueryError ()) -> IO ())
-> IO (Either QueryError ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ case Either QueryError a
e_a of
        Left QueryError
_  -> Connection -> IO (Either QueryError ())
W.rollback Connection
conn
        Right a
_ -> Connection -> IO (Either QueryError ())
W.commit Connection
conn
    Either QueryError a -> IO (Either QueryError a)
forall (m :: * -> *) a. Monad m => a -> m a
return Either QueryError a
e_a

instance SqlQuery Transaction where
    query :: (Query (Width r), p) -> Transaction (Vector r)
query (Query (Width r)
q, p
p) = ExceptT QueryError (ReaderT Connection IO) (Vector r)
-> Transaction (Vector r)
forall a.
ExceptT QueryError (ReaderT Connection IO) a -> Transaction a
Transaction (ReaderT Connection IO (Either QueryError (Vector r))
-> ExceptT QueryError (ReaderT Connection IO) (Vector r)
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT ((Connection -> IO (Either QueryError (Vector r)))
-> ReaderT Connection IO (Either QueryError (Vector r))
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (\Connection
conn -> Connection
-> Query (Width r) -> p -> IO (Either QueryError (Vector r))
forall p r.
(ToSql p, FromSql r, KnownNat (Width r)) =>
Connection
-> Query (Width r) -> p -> IO (Either QueryError (Vector r))
W.query Connection
conn Query (Width r)
q p
p)))
    query_ :: (Query 0, p) -> Transaction ()
query_ (Query 0
q, p
p) = ExceptT QueryError (ReaderT Connection IO) () -> Transaction ()
forall a.
ExceptT QueryError (ReaderT Connection IO) a -> Transaction a
Transaction (ReaderT Connection IO (Either QueryError ())
-> ExceptT QueryError (ReaderT Connection IO) ()
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT ((Connection -> IO (Either QueryError ()))
-> ReaderT Connection IO (Either QueryError ())
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (\Connection
conn -> Connection -> Query 0 -> p -> IO (Either QueryError ())
forall p (n :: Nat).
ToSql p =>
Connection -> Query n -> p -> IO (Either QueryError ())
W.query_ Connection
conn Query 0
q p
p)))

-- Transformer instances
-- These are all the same, except for the @withConnection@ definitions.

instance SQL m => SQL (ExceptT e m) where
    withConnection :: (Connection -> ExceptT e m a) -> ExceptT e m a
withConnection Connection -> ExceptT e m a
f = m (Either e a) -> ExceptT e m a
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT ((Connection -> m (Either e a)) -> m (Either e a)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (ExceptT e m a -> m (Either e a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT e m a -> m (Either e a))
-> (Connection -> ExceptT e m a) -> Connection -> m (Either e a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Connection -> ExceptT e m a
f))
    runTransaction' :: IsolationLevel -> Transaction a -> ExceptT e m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> ExceptT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ExceptT e m a) -> m a -> ExceptT e m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> ExceptT e m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> ExceptT e m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> ExceptT e m (Vector r))
-> m (Vector r) -> ExceptT e m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> ExceptT e m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> ExceptT e m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ExceptT e m ()) -> m () -> ExceptT e m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q

instance {-# OVERLAPPABLE #-} SQL m => SQL (ReaderT r m) where
    withConnection :: (Connection -> ReaderT r m a) -> ReaderT r m a
withConnection Connection -> ReaderT r m a
f = (r -> m a) -> ReaderT r m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (\r
r -> (Connection -> m a) -> m a
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> ReaderT r m a -> r -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (Connection -> ReaderT r m a
f Connection
conn) r
r))
    runTransaction' :: IsolationLevel -> Transaction a -> ReaderT r m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> ReaderT r m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ReaderT r m a) -> m a -> ReaderT r m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> ReaderT r m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> ReaderT r m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> ReaderT r m (Vector r))
-> m (Vector r) -> ReaderT r m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> ReaderT r m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> ReaderT r m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT r m ()) -> m () -> ReaderT r m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q

instance SQL m => SQL (MaybeT m) where
    withConnection :: (Connection -> MaybeT m a) -> MaybeT m a
withConnection Connection -> MaybeT m a
f = m (Maybe a) -> MaybeT m a
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT ((Connection -> m (Maybe a)) -> m (Maybe a)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (MaybeT m a -> m (Maybe a)
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (MaybeT m a -> m (Maybe a))
-> (Connection -> MaybeT m a) -> Connection -> m (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Connection -> MaybeT m a
f))
    runTransaction' :: IsolationLevel -> Transaction a -> MaybeT m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> MaybeT m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> MaybeT m a) -> m a -> MaybeT m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> MaybeT m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> MaybeT m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> MaybeT m (Vector r))
-> m (Vector r) -> MaybeT m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> MaybeT m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> MaybeT m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> MaybeT m ()) -> m () -> MaybeT m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q

instance SQL m => SQL (SL.StateT s m) where
    withConnection :: (Connection -> StateT s m a) -> StateT s m a
withConnection Connection -> StateT s m a
f = (s -> m (a, s)) -> StateT s m a
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
SL.StateT (\s
s -> (Connection -> m (a, s)) -> m (a, s)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
SL.runStateT (Connection -> StateT s m a
f Connection
conn) s
s))
    runTransaction' :: IsolationLevel -> Transaction a -> StateT s m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> StateT s m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> StateT s m a) -> m a -> StateT s m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> StateT s m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> StateT s m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> StateT s m (Vector r))
-> m (Vector r) -> StateT s m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> StateT s m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> StateT s m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> StateT s m ()) -> m () -> StateT s m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q

instance SQL m => SQL (SS.StateT s m) where
    withConnection :: (Connection -> StateT s m a) -> StateT s m a
withConnection Connection -> StateT s m a
f = (s -> m (a, s)) -> StateT s m a
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
SS.StateT (\s
s -> (Connection -> m (a, s)) -> m (a, s)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
SS.runStateT (Connection -> StateT s m a
f Connection
conn) s
s))
    runTransaction' :: IsolationLevel -> Transaction a -> StateT s m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> StateT s m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> StateT s m a) -> m a -> StateT s m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> StateT s m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> StateT s m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> StateT s m (Vector r))
-> m (Vector r) -> StateT s m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> StateT s m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> StateT s m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> StateT s m ()) -> m () -> StateT s m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q

instance (Monoid w, SQL m) => SQL (S.RWST r w s m) where
    withConnection :: (Connection -> RWST r w s m a) -> RWST r w s m a
withConnection Connection -> RWST r w s m a
f = (r -> s -> m (a, s, w)) -> RWST r w s m a
forall r w s (m :: * -> *) a.
(r -> s -> m (a, s, w)) -> RWST r w s m a
S.RWST (\r
r s
s  -> (Connection -> m (a, s, w)) -> m (a, s, w)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> RWST r w s m a -> r -> s -> m (a, s, w)
forall r w s (m :: * -> *) a.
RWST r w s m a -> r -> s -> m (a, s, w)
S.runRWST (Connection -> RWST r w s m a
f Connection
conn) r
r s
s))
    runTransaction' :: IsolationLevel -> Transaction a -> RWST r w s m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> RWST r w s m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> RWST r w s m a) -> m a -> RWST r w s m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> RWST r w s m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> RWST r w s m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> RWST r w s m (Vector r))
-> m (Vector r) -> RWST r w s m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> RWST r w s m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> RWST r w s m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> RWST r w s m ()) -> m () -> RWST r w s m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q

instance (Monoid w, SQL m) => SQL (L.RWST r w s m) where
    withConnection :: (Connection -> RWST r w s m a) -> RWST r w s m a
withConnection Connection -> RWST r w s m a
f = (r -> s -> m (a, s, w)) -> RWST r w s m a
forall r w s (m :: * -> *) a.
(r -> s -> m (a, s, w)) -> RWST r w s m a
L.RWST (\r
r s
s  -> (Connection -> m (a, s, w)) -> m (a, s, w)
forall (m :: * -> *) a. SQL m => (Connection -> m a) -> m a
withConnection (\Connection
conn -> RWST r w s m a -> r -> s -> m (a, s, w)
forall r w s (m :: * -> *) a.
RWST r w s m a -> r -> s -> m (a, s, w)
L.runRWST (Connection -> RWST r w s m a
f Connection
conn) r
r s
s))
    runTransaction' :: IsolationLevel -> Transaction a -> RWST r w s m a
runTransaction' IsolationLevel
level Transaction a
t = m a -> RWST r w s m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> RWST r w s m a) -> m a -> RWST r w s m a
forall a b. (a -> b) -> a -> b
$ IsolationLevel -> Transaction a -> m a
forall (m :: * -> *) a.
SQL m =>
IsolationLevel -> Transaction a -> m a
runTransaction' IsolationLevel
level Transaction a
t
    queryOn :: Connection -> (Query (Width r), p) -> RWST r w s m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp = m (Vector r) -> RWST r w s m (Vector r)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Vector r) -> RWST r w s m (Vector r))
-> m (Vector r) -> RWST r w s m (Vector r)
forall a b. (a -> b) -> a -> b
$ Connection -> (Query (Width r), p) -> m (Vector r)
forall (m :: * -> *) p r.
(SQL m, ToSql p, FromSql r, KnownNat (Width r)) =>
Connection -> (Query (Width r), p) -> m (Vector r)
queryOn Connection
conn (Query (Width r), p)
qp
    queryOn_ :: Connection -> (Query 0, p) -> RWST r w s m ()
queryOn_ Connection
conn (Query 0, p)
q = m () -> RWST r w s m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> RWST r w s m ()) -> m () -> RWST r w s m ()
forall a b. (a -> b) -> a -> b
$ Connection -> (Query 0, p) -> m ()
forall (m :: * -> *) p.
(SQL m, ToSql p) =>
Connection -> (Query 0, p) -> m ()
queryOn_ Connection
conn (Query 0, p)
q