Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
haskell-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
195
Issues
195
List
Board
Labels
Milestones
Merge Requests
12
Merge Requests
12
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
haskell-gargantext
Commits
b14c2506
Commit
b14c2506
authored
Apr 28, 2025
by
Alfredo Di Napoli
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add PGUpdateReturning facility
parent
489968f6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
45 additions
and
16 deletions
+45
-16
Transactional.hs
src/Gargantext/Database/Transactional.hs
+30
-12
Transactions.hs
test/Test/Database/Transactions.hs
+15
-4
No files found.
src/Gargantext/Database/Transactional.hs
View file @
b14c2506
...
@@ -15,6 +15,7 @@ module Gargantext.Database.Transactional (
...
@@ -15,6 +15,7 @@ module Gargantext.Database.Transactional (
-- * Smart constructors
-- * Smart constructors
,
mkPGQuery
,
mkPGQuery
,
mkPGUpdate
,
mkPGUpdate
,
mkPGUpdateReturning
,
mkOpaQuery
,
mkOpaQuery
,
mkOpaUpdate
,
mkOpaUpdate
,
mkOpaInsert
,
mkOpaInsert
...
@@ -35,6 +36,7 @@ import Database.PostgreSQL.Simple.Transaction qualified as PG
...
@@ -35,6 +36,7 @@ import Database.PostgreSQL.Simple.Transaction qualified as PG
import
Gargantext.Database.Prelude
import
Gargantext.Database.Prelude
import
Opaleye
import
Opaleye
import
Prelude
import
Prelude
import
qualified
Control.Exception.Safe
as
Safe
data
DBOperation
=
DBRead
|
DBWrite
data
DBOperation
=
DBRead
|
DBWrite
...
@@ -48,6 +50,10 @@ data DBTransactionOp err (r :: DBOperation) next where
...
@@ -48,6 +50,10 @@ data DBTransactionOp err (r :: DBOperation) next where
-- | A Postgres /write/, returning the number of affected rows. It can be used only in
-- | A Postgres /write/, returning the number of affected rows. It can be used only in
-- 'DBWrite' transactions.
-- 'DBWrite' transactions.
PGUpdate
::
PG
.
ToRow
a
=>
PG
.
Query
->
a
->
(
Int
->
next
)
->
DBTransactionOp
err
DBWrite
next
PGUpdate
::
PG
.
ToRow
a
=>
PG
.
Query
->
a
->
(
Int
->
next
)
->
DBTransactionOp
err
DBWrite
next
-- | Unlike a 'PGUpdate' that returns the list of affected rows, this can be used
-- to write updates that returns a value via the \"RETURNING\" directive. It's the programmer's
-- responsibility to ensure that the SQL fragment contains it.
PGUpdateReturning
::
(
PG
.
ToRow
q
,
PG
.
FromRow
a
)
=>
PG
.
Query
->
q
->
(
a
->
next
)
->
DBTransactionOp
err
DBWrite
next
-- | An Opaleye /read/, returning a list of results. The 'r' in the result is polymorphic
-- | An Opaleye /read/, returning a list of results. The 'r' in the result is polymorphic
-- so that reads can be embedded in updates transactions.
-- so that reads can be embedded in updates transactions.
OpaQuery
::
Default
FromFields
fields
a
=>
Select
fields
->
([
a
]
->
next
)
->
DBTransactionOp
err
r
next
OpaQuery
::
Default
FromFields
fields
a
=>
Select
fields
->
([
a
]
->
next
)
->
DBTransactionOp
err
r
next
...
@@ -74,12 +80,13 @@ type DBTxCmd err a = forall m env. (IsCmd env err m, HasConnectionPool env) => m
...
@@ -74,12 +80,13 @@ type DBTxCmd err a = forall m env. (IsCmd env err m, HasConnectionPool env) => m
instance
Functor
(
DBTransactionOp
err
r
)
where
instance
Functor
(
DBTransactionOp
err
r
)
where
fmap
f
=
\
case
fmap
f
=
\
case
PGQuery
q
params
cont
->
PGQuery
q
params
(
f
.
cont
)
PGQuery
q
params
cont
->
PGQuery
q
params
(
f
.
cont
)
PGUpdate
q
a
cont
->
PGUpdate
q
a
(
f
.
cont
)
PGUpdate
q
a
cont
->
PGUpdate
q
a
(
f
.
cont
)
OpaQuery
sel
cont
->
OpaQuery
sel
(
f
.
cont
)
PGUpdateReturning
q
a
cont
->
PGUpdateReturning
q
a
(
f
.
cont
)
OpaInsert
ins
cont
->
OpaInsert
ins
(
f
.
cont
)
OpaQuery
sel
cont
->
OpaQuery
sel
(
f
.
cont
)
OpaUpdate
upd
cont
->
OpaUpdate
upd
(
f
.
cont
)
OpaInsert
ins
cont
->
OpaInsert
ins
(
f
.
cont
)
DBFail
err
->
DBFail
err
OpaUpdate
upd
cont
->
OpaUpdate
upd
(
f
.
cont
)
DBFail
err
->
DBFail
err
-- | Generalised version of 'withResource' to work over any unlifted monad.
-- | Generalised version of 'withResource' to work over any unlifted monad.
-- For some reason 'resource-pool' removed this from version 0.3.0.0 onwards.
-- For some reason 'resource-pool' removed this from version 0.3.0.0 onwards.
...
@@ -125,12 +132,20 @@ runDBQuery (DBTx m) = do
...
@@ -125,12 +132,20 @@ runDBQuery (DBTx m) = do
-- 'DBCmd'.
-- 'DBCmd'.
evalOp
::
PG
.
Connection
->
DBTransactionOp
err
r
a
->
DBTxCmd
err
a
evalOp
::
PG
.
Connection
->
DBTransactionOp
err
r
a
->
DBTxCmd
err
a
evalOp
conn
=
\
case
evalOp
conn
=
\
case
PGQuery
qr
q
cc
->
cc
<$>
liftBase
(
PG
.
query
conn
qr
q
)
PGQuery
qr
q
cc
->
cc
<$>
liftBase
(
PG
.
query
conn
qr
q
)
PGUpdate
qr
a
cc
->
cc
<$>
liftBase
(
fromIntegral
<$>
PG
.
execute
conn
qr
a
)
PGUpdate
qr
a
cc
->
cc
<$>
liftBase
(
fromIntegral
<$>
PG
.
execute
conn
qr
a
)
OpaQuery
sel
cc
->
cc
<$>
liftBase
(
runSelect
conn
sel
)
PGUpdateReturning
qr
a
cc
->
cc
<$>
liftBase
(
queryOne
conn
qr
a
)
OpaInsert
ins
cc
->
cc
<$>
liftBase
(
runInsert
conn
ins
)
OpaQuery
sel
cc
->
cc
<$>
liftBase
(
runSelect
conn
sel
)
OpaUpdate
upd
cc
->
cc
<$>
liftBase
(
runUpdate
conn
upd
)
OpaInsert
ins
cc
->
cc
<$>
liftBase
(
runInsert
conn
ins
)
DBFail
err
->
throwError
err
OpaUpdate
upd
cc
->
cc
<$>
liftBase
(
runUpdate
conn
upd
)
DBFail
err
->
throwError
err
queryOne
::
(
PG
.
ToRow
q
,
PG
.
FromRow
r
)
=>
PG
.
Connection
->
PG
.
Query
->
q
->
IO
r
queryOne
conn
q
v
=
do
rs
<-
PG
.
query
conn
q
v
case
rs
of
[
x
]
->
pure
x
_
->
Safe
.
throwIO
$
userError
"queryOne: more than one result returned. Have you used the 'RETURNING' directive?"
--
--
-- Smart constructors
-- Smart constructors
...
@@ -148,6 +163,9 @@ mkPGQuery q a = DBTx $ liftF (PGQuery q a id)
...
@@ -148,6 +163,9 @@ mkPGQuery q a = DBTx $ liftF (PGQuery q a id)
mkPGUpdate
::
PG
.
ToRow
a
=>
PG
.
Query
->
a
->
DBUpdate
err
Int
mkPGUpdate
::
PG
.
ToRow
a
=>
PG
.
Query
->
a
->
DBUpdate
err
Int
mkPGUpdate
q
a
=
DBTx
$
liftF
(
PGUpdate
q
a
id
)
mkPGUpdate
q
a
=
DBTx
$
liftF
(
PGUpdate
q
a
id
)
mkPGUpdateReturning
::
(
PG
.
ToRow
q
,
PG
.
FromRow
a
)
=>
PG
.
Query
->
q
->
DBUpdate
err
a
mkPGUpdateReturning
q
a
=
DBTx
$
liftF
(
PGUpdateReturning
q
a
id
)
mkOpaQuery
::
Default
FromFields
fields
a
mkOpaQuery
::
Default
FromFields
fields
a
=>
Select
fields
=>
Select
fields
->
DBQuery
err
x
[
a
]
->
DBQuery
err
x
[
a
]
...
...
test/Test/Database/Transactions.hs
View file @
b14c2506
...
@@ -140,6 +140,10 @@ getCounterById (CounterId cid) = do
...
@@ -140,6 +140,10 @@ getCounterById (CounterId cid) = do
[
c
]
->
pure
c
[
c
]
->
pure
c
rst
->
dbFail
$
Prelude
.
userError
(
"getCounterId returned more than one result: "
<>
show
rst
)
rst
->
dbFail
$
Prelude
.
userError
(
"getCounterId returned more than one result: "
<>
show
rst
)
insertCounter
::
DBUpdate
IOException
Counter
insertCounter
=
do
mkPGUpdateReturning
[
sql
|
INSERT INTO public.ggtx_test_counter_table(counter_value) VALUES(0) RETURNING id, counter_value
|]
()
--
--
-- MAIN TESTS
-- MAIN TESTS
--
--
...
@@ -147,10 +151,17 @@ getCounterById (CounterId cid) = do
...
@@ -147,10 +151,17 @@ getCounterById (CounterId cid) = do
tests
::
Spec
tests
::
Spec
tests
=
parallel
$
around
withTestCounterDB
$
tests
=
parallel
$
around
withTestCounterDB
$
describe
"Database Transactions"
$
do
describe
"Database Transactions"
$
do
describe
"Pure Queries"
$
do
describe
"Pure PG Queries"
$
do
it
"Simple query works"
simpleQueryWorks
it
"Simple query works"
simplePGQueryWorks
describe
"Pure PG Inserts"
$
do
it
"Simple insert works"
simplePGInsertWorks
simpleQueryWorks
::
DBHandle
->
Assertion
simple
PG
QueryWorks
::
DBHandle
->
Assertion
simpleQueryWorks
env
=
flip
runReaderT
env
$
runTestMonad
$
do
simple
PG
QueryWorks
env
=
flip
runReaderT
env
$
runTestMonad
$
do
x
<-
runDBQuery
$
getCounterById
(
CounterId
1
)
x
<-
runDBQuery
$
getCounterById
(
CounterId
1
)
liftIO
$
counterValue
x
`
shouldBe
`
42
liftIO
$
counterValue
x
`
shouldBe
`
42
simplePGInsertWorks
::
DBHandle
->
Assertion
simplePGInsertWorks
env
=
flip
runReaderT
env
$
runTestMonad
$
do
x
<-
runDBTx
$
insertCounter
liftIO
$
x
`
shouldBe
`
(
Counter
(
CounterId
2
)
0
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment