Skip to content

Commit 3f6be3b

Browse files
committed
Make Selda / Pg effects more consistent
1 parent eb99fe8 commit 3f6be3b

File tree

3 files changed

+137
-116
lines changed

3 files changed

+137
-116
lines changed

src/WebRow/Selda.purs

Lines changed: 137 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,140 @@
11
module WebRow.Selda where
22

33
import Prelude
4-
import Control.Monad.Reader (ask)
5-
import Data.Either (either)
6-
import Data.Maybe (Maybe, maybe)
7-
import Database.PostgreSQL (class FromSQLRow, PGError, Row0(..))
8-
import Database.PostgreSQL as PG
9-
import Effect.Aff (Aff, throwError)
10-
import Effect.Aff.Class (liftAff)
11-
import Selda.PG.Class (class MonadSeldaPG)
12-
13-
pgExecute PG.Connection String Aff (Maybe PGError)
14-
pgExecute conn q = PG.execute conn (PG.Query q) Row0
15-
16-
exec m. MonadSeldaPG m String m Unit
17-
exec q = do
18-
conn ← ask
19-
merr ← liftAff $ pgExecute conn q
20-
maybe (pure unit) throwError merr
21-
22-
queryPG m a. MonadSeldaPG m FromSQLRow a String m (Array a)
23-
queryPG q = do
24-
conn ← ask
25-
(liftAff $ PG.query conn (PG.Query q) Row0)
26-
>>= either throwError pure
4+
import Control.Monad.Except (ExceptT, runExceptT)
5+
import Control.Monad.Reader (ReaderT, runReaderT)
6+
import Data.Either (Either(..))
7+
import Data.Maybe (Maybe(..))
8+
import Data.Symbol (SProxy(..))
9+
import Data.Variant.Internal (FProxy)
10+
import Database.PostgreSQL (Connection, PGError, Query(..), execute) as PG
11+
import Database.PostgreSQL (PGError, Row0(..))
12+
import Database.PostgreSQL (class FromSQLRow, class ToSQLRow, Query, query) as PostgreSQL
13+
import Effect.Aff (Aff)
14+
import Run (Run)
15+
import Run as Run
16+
import Run.Except (EXCEPT, throwAt)
17+
import Run.Reader (READER, askAt)
18+
import Selda (Col, FullQuery, Table)
19+
import Selda.PG.Class (class InsertRecordIntoTableReturning, BackendPGClass)
20+
import Selda.PG.Class (deleteFrom, insert, insert1, insert1_, query, query1, update) as PG.Class
21+
import Selda.Query.Class (class GenericDelete, class GenericInsert, class GenericQuery, class GenericUpdate)
22+
import Type.Row (type (+))
23+
import WebRow.Contrib.Run (AffRow)
24+
25+
type SeldaPG
26+
= ExceptT PG.PGError (ReaderT PG.Connection Aff)
27+
28+
-- | I'm not sure if this represtation is consistent.
29+
-- | I want to allow some inspection but also compile
30+
-- | those actions without coercing.
31+
-- |
32+
-- | * Probably we could split query and keep `FullQuery`.
33+
-- | * We can add `∀ i o. Query i o` to `PgQueryF`.
34+
data SeldaF a
35+
= SeldaF (SeldaPG a)
36+
| PgExecuteF String (Unit a)
37+
| PgQueryF (PG.Connection Aff (Either PGError a))
38+
39+
derive instance functorSeldaFFunctor SeldaF
40+
41+
type SELDA
42+
= FProxy SeldaF
43+
44+
type Selda eff
45+
= ( selda SELDA | eff )
46+
47+
_selda = SProxy SProxy "selda"
48+
49+
type PgError r
50+
= ( pgError EXCEPT PGError | r )
51+
52+
type PgConnection r
53+
= ( pgConnection READER { conn PG.Connection, inTransaction Boolean } | r )
54+
55+
_pgConnection = SProxy SProxy "pgConnection"
56+
57+
_pgError = SProxy SProxy "pgError"
58+
59+
query
60+
eff o i.
61+
GenericQuery BackendPGClass SeldaPG i o
62+
FullQuery BackendPGClass { | i }
63+
Run (Selda + eff) (Array { | o })
64+
query q = do
65+
Run.lift _selda (SeldaF (PG.Class.query q))
66+
67+
query1
68+
eff o i.
69+
GenericQuery BackendPGClass SeldaPG i o
70+
FullQuery BackendPGClass { | i } Run (Selda + eff) { | o }
71+
query1 q = Run.lift _selda (SeldaF (PG.Class.query1 q))
72+
73+
insert
74+
eff r t ret.
75+
InsertRecordIntoTableReturning r t ret
76+
Table t Array { | r } Run (Selda + eff) (Array { | ret })
77+
insert table xs = do
78+
Run.lift _selda (SeldaF (PG.Class.insert table xs))
79+
80+
insert1_
81+
eff t r.
82+
GenericInsert BackendPGClass SeldaPG t r
83+
Table t { | r } Run (Selda + eff) Unit
84+
insert1_ table r = Run.lift _selda (SeldaF (PG.Class.insert1_ table r))
85+
86+
insert1
87+
eff r t ret.
88+
InsertRecordIntoTableReturning r t ret
89+
Table t { | r } Run (Selda + eff) { | ret }
90+
insert1 table r = Run.lift _selda (SeldaF (PG.Class.insert1 table r))
91+
92+
deleteFrom
93+
eff t r.
94+
GenericDelete BackendPGClass SeldaPG t r
95+
Table t ({ | r } Col BackendPGClass Boolean) Run (Selda + eff) Unit
96+
deleteFrom table r = Run.lift _selda (SeldaF (PG.Class.deleteFrom table r))
97+
98+
update
99+
eff t r.
100+
GenericUpdate BackendPGClass SeldaPG t r
101+
Table t ({ | r } Col BackendPGClass Boolean) ({ | r } { | r }) Run (Selda + eff) Unit
102+
update table cond set = Run.lift _selda (SeldaF (PG.Class.update table cond set))
103+
104+
pgExecute eff. String Run (Selda + eff) Unit
105+
pgExecute q = Run.lift _selda (PgExecuteF q identity)
106+
107+
pgQuery
108+
eff i o.
109+
PostgreSQL.ToSQLRow i
110+
PostgreSQL.FromSQLRow o
111+
PostgreSQL.Query i o
112+
i
113+
Run (Selda + eff) (Array o)
114+
pgQuery q i = Run.lift _selda (PgQueryF (\conn → PostgreSQL.query conn q i))
115+
116+
run
117+
eff.
118+
Run (AffRow + PgConnection + PgError + Selda + eff)
119+
~> Run (AffRow + PgConnection + PgError + eff)
120+
run = Run.run (Run.on _selda handleSelda Run.send)
121+
where
122+
handleSelda a. SeldaF a Run (AffRow + PgConnection + PgError + eff) a
123+
handleSelda action = do
124+
{ conn, inTransaction } ← askAt _pgConnection
125+
case action of
126+
SeldaF q → do
127+
Run.liftAff (runReaderT (runExceptT q) conn)
128+
>>= case _ of
129+
Right next → pure next
130+
Left err → throwAt _pgError err
131+
PgExecuteF q next → do
132+
(Run.liftAff $ PG.execute conn (PG.Query q) Row0)
133+
>>= case _ of
134+
Just err → throwAt _pgError err
135+
Nothing → pure (next unit)
136+
PgQueryF q → do
137+
(Run.liftAff (q conn))
138+
>>= case _ of
139+
Left err → throwAt _pgError err
140+
Right next → pure next

src/WebRow/Selda/Class.purs

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/WebRow/Selda/Effect.purs

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)