generated from srid/haskell-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Session.hs
92 lines (78 loc) · 3.2 KB
/
Session.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Hasql.Api.Eff.Session (
Session,
SessionEffects,
toEff,
sql,
statement,
QueryError (..),
ResultError (..),
CommandError (..),
runWithHandler,
runWithConnection,
run,
) where
import Control.Monad.Error.Class (MonadError (..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Reader.Class (MonadReader (..))
import Data.ByteString (ByteString)
import Effectful (Eff, IOE, inject, (:>))
import Effectful.Dispatch.Dynamic (send)
import Effectful.Reader.Static (runReader)
import qualified Effectful.Reader.Static as E
import Hasql.Api.Eff
import Hasql.Api.Eff.Throws
import qualified Hasql.Api.Eff.Throws as T
import Hasql.Api.Eff.WithResource (WithConnection, withConnection)
import qualified Hasql.Connection as S
import Hasql.Session (CommandError (..), QueryError (..), ResultError (..))
import qualified Hasql.Statement as S
type SessionEffects es = (SqlEff ByteString S.Statement :> es, Throws QueryError :> es, E.Reader S.Connection :> es, IOE :> es)
newtype Session a = Session (forall es. (SessionEffects es) => Eff es a)
instance Functor Session where
fmap f (Session eff) = Session (fmap f eff)
{-# INLINEABLE fmap #-}
instance Applicative Session where
pure a = Session (pure a)
{-# INLINEABLE pure #-}
(Session f) <*> (Session eff) = Session (f <*> eff)
{-# INLINEABLE (<*>) #-}
instance Monad Session where
(Session eff) >>= f =
Session $
eff >>= \a -> let (Session effb) = f a in effb
{-# INLINEABLE (>>=) #-}
instance MonadError QueryError Session where
throwError e = Session $ T.throwError e
{-# INLINEABLE throwError #-}
catchError :: forall a. Session a -> (QueryError -> Session a) -> Session a
catchError (Session eff) handler = Session $ T.catchError eff $ const $ toEff . handler
{-# INLINEABLE catchError #-}
instance MonadReader S.Connection Session where
ask = Session E.ask
{-# INLINEABLE ask #-}
local f (Session eff) = Session $ E.local f eff
{-# INLINEABLE local #-}
instance MonadIO Session where
liftIO ioa = Session $ liftIO ioa
{-# INLINEABLE liftIO #-}
{-# INLINEABLE sql #-}
sql :: ByteString -> Session ()
sql q = Session (send @(SqlEff ByteString S.Statement) $ SqlCommand q)
{-# INLINEABLE statement #-}
statement :: forall parameters result. parameters -> S.Statement parameters result -> Session result
statement params stmt = Session (send @(SqlEff ByteString S.Statement) $ SqlStatement params stmt)
{-# INLINEABLE runWithHandler #-}
runWithHandler :: SessionEffects es => (Eff es a -> result) -> Session a -> result
runWithHandler h (Session eff) = h eff
{-# INLINEABLE runWithConnection #-}
runWithConnection :: forall es a. (Throws QueryError :> es, SqlEff ByteString S.Statement :> es, IOE :> es, WithConnection (Eff es) :> es) => Session a -> Eff es a
runWithConnection session = withConnection (run @es session)
{-# INLINEABLE run #-}
run :: (Throws QueryError :> es, SqlEff ByteString S.Statement :> es, IOE :> es) => Session a -> S.Connection -> Eff es a
run session connection = runWithHandler (runReader connection) session
{-# INLINE toEff #-}
toEff :: SessionEffects es => Session a -> Eff es a
toEff (Session eff) = eff