git.iko.soy/rowtype-yoga/purescript-yoga-postgres-om
on main help sign in
checkpoint
commit92cc5900b3c6dda239f3ae8746aa7329f0c4120c authorMark <mark.eibes@gmail.com> dateMon 2 Mar 2026, 21:23 (7 months ago) parentfae203a
4 files changed+542−413
.psc-ide-port+1−1 test/Test/ClientOm.purs+387−411 test/Test/Main.purs+4−1 test/Test/SchemaQ.purs+150
.psc-ide-port+1−1
@@ -1 +1 @@
1−15503
1+15396
test/Test/ClientOm.purs+387−411
@@ -1,6 +1,6 @@
11module Test.ClientOm where
22
3−import Prelude
3+import Prelude hiding (join)
44
55import Control.Monad.Error.Class (throwError)
66import Data.Array as Array
@@ -15,9 +15,8 @@ import Type.Function (type (#))
1515import Type.Proxy (Proxy(..))
1616import Yoga.Om as Om
1717import Yoga.Postgres as PG
18−import Yoga.Postgres.ClientOm as C
18+import Yoga.Postgres.ClientOm hiding (run, runOne, runExec)
1919import Yoga.Postgres.Schema (Table, PrimaryKey, AutoIncrement, Unique, Default, DefaultExpr, ForeignKey, References, PGUUID)
20−import Yoga.Postgres.Schema as Schema
2120
2221-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2322-- Test schemas
@@ -69,20 +68,19 @@ type CommentsTable = Table "test_om_comments"
6968commentsTable :: Proxy CommentsTable
7069commentsTable = Proxy
7170
72−
73−
7471-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7572-- Helpers
7673-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7774
7875testConnection :: Aff PG.Connection
79−testConnection = PG.postgres
80− { host: PG.PostgresHost "localhost"
81− , port: PG.PostgresPort 5433
82− , database: PG.PostgresDatabase "test_playground"
83− , username: PG.PostgresUsername "postgres"
84− , password: PG.PostgresPassword "postgres"
85− } # liftEffect
76+testConnection =
77+ PG.postgres
78+ { host: PG.PostgresHost "localhost"
79+ , port: PG.PostgresPort 5433
80+ , database: PG.PostgresDatabase "test_playground"
81+ , username: PG.PostgresUsername "postgres"
82+ , password: PG.PostgresPassword "postgres"
83+ } # liftEffect
8684
8785run
8886 :: forall a
@@ -227,653 +225,631 @@ spec = describe "ClientOm" do
227225
228226 describe "findBy" do
229227 it "returns rows matching a column value" $ withUsersTable \conn -> do
230− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
231− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "admin" } usersTable) conn
232− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
233− admins <- run (C.findBy @"role" "admin" usersTable) conn
228+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
229+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "admin" }
230+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "user" }
231+ admins <- conn # run do usersTable # findBy @"role" "admin"
234232 Array.length admins `shouldEqual` 2
235233
236234 describe "findOneBy" do
237235 it "returns Just for matching row, Nothing for missing" $ withUsersTable \conn -> do
238− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
239− found <- run (C.findOneBy @"email" "a@t.com" usersTable) conn
236+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
237+ found <- conn # run do usersTable # findOneBy @"email" "a@t.com"
240238 user <- shouldBeJust found
241239 user.name `shouldEqual` "Alice"
242− missing <- run (C.findOneBy @"email" "nobody@t.com" usersTable) conn
240+ missing <- conn # run do usersTable # findOneBy @"email" "nobody@t.com"
243241 isNothing missing `shouldEqual` true
244242
245243 describe "findAllWhere" do
246244 it "returns rows matching multiple column conditions" $ withUsersTable \conn -> do
247− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
248− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "admin" } usersTable) conn
249− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
250− alices <- run (C.findAllWhere { name: "Alice", role: "admin" } usersTable) conn
245+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
246+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "admin" }
247+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "user" }
248+ alices <- conn # run do usersTable # findAllWhere { name: "Alice", role: "admin" }
251249 Array.length alices `shouldEqual` 1
252250 alice <- shouldBeJust (Array.head alices)
253251 alice.email `shouldEqual` "a@t.com"
254252
255253 describe "findOneWhere" do
256254 it "returns Just/Nothing for multi-column conditions" $ withUsersTable \conn -> do
257− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
258− found <- run (C.findOneWhere { name: "Alice", role: "admin" } usersTable) conn
255+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
256+ found <- conn # run do usersTable # findOneWhere { name: "Alice", role: "admin" }
259257 user <- shouldBeJust found
260258 user.email `shouldEqual` "a@t.com"
261− missing <- run (C.findOneWhere { name: "Alice", role: "user" } usersTable) conn
259+ missing <- conn # run do usersTable # findOneWhere { name: "Alice", role: "user" }
262260 isNothing missing `shouldEqual` true
263261
264262 describe "count" do
265263 it "counts all rows in a table" $ withUsersTable \conn -> do
266− n0 <- runNoErr (C.count usersTable) conn
264+ n0 <- conn # runNoErr do usersTable # count
267265 n0 `shouldEqual` 0
268− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
269− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
270− n2 <- runNoErr (C.count usersTable) conn
266+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
267+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
268+ n2 <- conn # runNoErr do usersTable # count
271269 n2 `shouldEqual` 2
272270
273271 describe "countWhere" do
274272 it "counts rows matching conditions" $ withUsersTable \conn -> do
275− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
276− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
277− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "admin" } usersTable) conn
278− n <- runNoErr (C.countWhere { role: "admin" } usersTable) conn
273+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
274+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
275+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "admin" }
276+ n <- conn # runNoErr do usersTable # countWhere { role: "admin" }
279277 n `shouldEqual` 2
280278
281279 describe "exists" do
282280 it "checks existence by primary key" $ withUsersTable \conn -> do
283− created <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
281+ created <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
284282 user <- shouldBeJust created
285− yes <- runNoErr (C.exists user.id usersTable) conn
283+ yes <- conn # runNoErr do usersTable # exists user.id
286284 yes `shouldEqual` true
287− no <- runNoErr (C.exists 99999 usersTable) conn
285+ no <- conn # runNoErr do usersTable # exists 99999
288286 no `shouldEqual` false
289287
290288 describe "existsWhere" do
291289 it "checks existence by multiple conditions" $ withUsersTable \conn -> do
292− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
293− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
294− yes <- runNoErr (C.existsWhere { name: "Alice", role: "admin" } usersTable) conn
290+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
291+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
292+ yes <- conn # runNoErr do usersTable # existsWhere { name: "Alice", role: "admin" }
295293 yes `shouldEqual` true
296− no <- runNoErr (C.existsWhere { name: "Alice", role: "user" } usersTable) conn
294+ no <- conn # runNoErr do usersTable # existsWhere { name: "Alice", role: "user" }
297295 no `shouldEqual` false
298296
299297 describe "createMany" do
300298 it "bulk inserts records and handles empty arrays" $ withUsersTable \conn -> do
301299 let noUsers = [] :: Array { name :: String, email :: String, role :: String }
302− empty <- run (C.createMany noUsers usersTable) conn
300+ empty <- conn # run do usersTable # createMany noUsers
303301 Array.length empty `shouldEqual` 0
304− users <- run (C.createMany
305− [ { name: "Alice", email: "a@t.com", role: "admin" }
306− , { name: "Bob", email: "b@t.com", role: "user" }
307− , { name: "Carol", email: "c@t.com", role: "user" }
308− ] usersTable) conn
302+ users <- conn # run do
303+ usersTable # createMany
304+ [ { name: "Alice", email: "a@t.com", role: "admin" }
305+ , { name: "Bob", email: "b@t.com", role: "user" }
306+ , { name: "Carol", email: "c@t.com", role: "user" }
307+ ]
309308 Array.length users `shouldEqual` 3
310− n <- runNoErr (C.count usersTable) conn
309+ n <- conn # runNoErr do usersTable # count
311310 n `shouldEqual` 3
312311
313312 describe "upsert" do
314313 it "inserts or updates on primary key conflict" $ withSettingsTable \conn -> do
315− inserted <- run (C.upsert { key: "theme", value: "dark" } settingsTable) conn
314+ inserted <- conn # run do settingsTable # upsert { key: "theme", value: "dark" }
316315 r1 <- shouldBeJust inserted
317316 r1.value `shouldEqual` "dark"
318− updated <- run (C.upsert { key: "theme", value: "light" } settingsTable) conn
317+ updated <- conn # run do settingsTable # upsert { key: "theme", value: "light" }
319318 r2 <- shouldBeJust updated
320319 r2.value `shouldEqual` "light"
321− n <- runNoErr (C.count settingsTable) conn
320+ n <- conn # runNoErr do settingsTable # count
322321 n `shouldEqual` 1
323322
324323 describe "deleteAll" do
325324 it "deletes all rows and returns count" $ withUsersTable \conn -> do
326− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
327− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
328− deleted <- runNoErr (C.deleteAll usersTable) conn
325+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
326+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
327+ deleted <- conn # runNoErr do usersTable # deleteAll
329328 deleted `shouldEqual` 2
330− n <- runNoErr (C.count usersTable) conn
329+ n <- conn # runNoErr do usersTable # count
331330 n `shouldEqual` 0
332331
333332 describe "deleteWhere" do
334333 it "deletes rows matching conditions and returns count" $ withUsersTable \conn -> do
335− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
336− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
337− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
338− deleted <- runNoErr (C.deleteWhere { role: "user" } usersTable) conn
334+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
335+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
336+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "user" }
337+ deleted <- conn # runNoErr do usersTable # deleteWhere { role: "user" }
339338 deleted `shouldEqual` 2
340− remaining <- runNoErr (C.count usersTable) conn
339+ remaining <- conn # runNoErr do usersTable # count
341340 remaining `shouldEqual` 1
342341
343342 describe "updateWhere" do
344343 it "updates rows matching conditions and returns updated rows" $ withUsersTable \conn -> do
345− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
346− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
347− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
348− updated <- run (C.updateWhere { role: "user" } { role: "member" } usersTable) conn
344+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
345+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
346+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "user" }
347+ updated <- conn # run do usersTable # updateWhere { role: "user" } { role: "member" }
349348 Array.length updated `shouldEqual` 2
350− members <- run (C.findBy @"role" "member" usersTable) conn
349+ members <- conn # run do usersTable # findBy @"role" "member"
351350 Array.length members `shouldEqual` 2
352351
353352 describe "createIfNotExists" do
354353 it "inserts new row or returns Nothing on conflict" $ withSettingsTable \conn -> do
355− inserted <- run (C.createIfNotExists { key: "theme", value: "dark" } settingsTable) conn
354+ inserted <- conn # run do settingsTable # createIfNotExists { key: "theme", value: "dark" }
356355 r1 <- shouldBeJust inserted
357356 r1.value `shouldEqual` "dark"
358− skipped <- run (C.createIfNotExists { key: "theme", value: "light" } settingsTable) conn
357+ skipped <- conn # run do settingsTable # createIfNotExists { key: "theme", value: "light" }
359358 isNothing skipped `shouldEqual` true
360− found <- run (C.findOneBy @"key" "theme" settingsTable) conn
359+ found <- conn # run do settingsTable # findOneBy @"key" "theme"
361360 existing <- shouldBeJust found
362361 existing.value `shouldEqual` "dark"
363362
364363 describe "upsertMany" do
365364 it "bulk upserts with ON CONFLICT DO UPDATE" $ withSettingsTable \conn -> do
366− _ <- run (C.upsertMany
367− [ { key: "theme", value: "dark" }
368− , { key: "lang", value: "en" }
369− ] settingsTable) conn
370− n1 <- runNoErr (C.count settingsTable) conn
365+ _ <- conn # run do
366+ settingsTable # upsertMany
367+ [ { key: "theme", value: "dark" }
368+ , { key: "lang", value: "en" }
369+ ]
370+ n1 <- conn # runNoErr do settingsTable # count
371371 n1 `shouldEqual` 2
372− updated <- run (C.upsertMany
373− [ { key: "theme", value: "light" }
374− , { key: "lang", value: "de" }
375− , { key: "tz", value: "UTC" }
376− ] settingsTable) conn
372+ updated <- conn # run do
373+ settingsTable # upsertMany
374+ [ { key: "theme", value: "light" }
375+ , { key: "lang", value: "de" }
376+ , { key: "tz", value: "UTC" }
377+ ]
377378 Array.length updated `shouldEqual` 3
378− n2 <- runNoErr (C.count settingsTable) conn
379+ n2 <- conn # runNoErr do settingsTable # count
379380 n2 `shouldEqual` 3
380− found <- run (C.findOneBy @"key" "theme" settingsTable) conn
381+ found <- conn # run do settingsTable # findOneBy @"key" "theme"
381382 setting <- shouldBeJust found
382383 setting.value `shouldEqual` "light"
383384
384385 describe "findByIdIn" do
385386 it "finds rows by array of primary keys" $ withUsersTable \conn -> do
386− created1 <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
387+ created1 <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
387388 u1 <- shouldBeJust created1
388− created2 <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
389+ created2 <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
389390 u2 <- shouldBeJust created2
390− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
391− found <- run (C.findByIdIn [ u1.id, u2.id ] usersTable) conn
391+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "user" }
392+ found <- conn # run do usersTable # findByIdIn [ u1.id, u2.id ]
392393 Array.length found `shouldEqual` 2
393− empty <- run (C.findByIdIn ([] :: Array Int) usersTable) conn
394+ empty <- conn # run do usersTable # findByIdIn ([] :: Array Int)
394395 Array.length empty `shouldEqual` 0
395396
396397 describe "cursor pagination" do
397398 it "findFirst returns first page with hasMore" $ withUsersTable \conn -> do
398− _ <- run (C.createMany
399− [ { name: "Alice", email: "a@t.com", role: "admin" }
400− , { name: "Bob", email: "b@t.com", role: "user" }
401− , { name: "Carol", email: "c@t.com", role: "user" }
402− , { name: "Dave", email: "d@t.com", role: "user" }
403− , { name: "Eve", email: "e@t.com", role: "admin" }
404− ] usersTable) conn
405− page1 <- run (C.findFirst @"id" 2 usersTable) conn
399+ _ <- conn # run do
400+ usersTable # createMany
401+ [ { name: "Alice", email: "a@t.com", role: "admin" }
402+ , { name: "Bob", email: "b@t.com", role: "user" }
403+ , { name: "Carol", email: "c@t.com", role: "user" }
404+ , { name: "Dave", email: "d@t.com", role: "user" }
405+ , { name: "Eve", email: "e@t.com", role: "admin" }
406+ ]
407+ page1 <- conn # run do usersTable # findFirst @"id" 2
406408 Array.length page1.items `shouldEqual` 2
407409 page1.hasMore `shouldEqual` true
408410
409411 it "findAfter paginates forward through all pages" $ withUsersTable \conn -> do
410− _ <- run (C.createMany
411− [ { name: "Alice", email: "a@t.com", role: "admin" }
412− , { name: "Bob", email: "b@t.com", role: "user" }
413− , { name: "Carol", email: "c@t.com", role: "user" }
414− , { name: "Dave", email: "d@t.com", role: "user" }
415− , { name: "Eve", email: "e@t.com", role: "admin" }
416− ] usersTable) conn
417− page1 <- run (C.findFirst @"id" 2 usersTable) conn
418− let lastId = case Array.last page1.items of
419− Just u -> u.id
420− Nothing -> 0
421− page2 <- run (C.findAfter @"id" lastId 2 usersTable) conn
412+ _ <- conn # run do
413+ usersTable # createMany
414+ [ { name: "Alice", email: "a@t.com", role: "admin" }
415+ , { name: "Bob", email: "b@t.com", role: "user" }
416+ , { name: "Carol", email: "c@t.com", role: "user" }
417+ , { name: "Dave", email: "d@t.com", role: "user" }
418+ , { name: "Eve", email: "e@t.com", role: "admin" }
419+ ]
420+ page1 <- conn # run do usersTable # findFirst @"id" 2
421+ let
422+ lastId = case Array.last page1.items of
423+ Just u -> u.id
424+ Nothing -> 0
425+ page2 <- conn # run do usersTable # findAfter @"id" lastId 2
422426 Array.length page2.items `shouldEqual` 2
423427 page2.hasMore `shouldEqual` true
424− let lastId2 = case Array.last page2.items of
425− Just u -> u.id
426− Nothing -> 0
427− page3 <- run (C.findAfter @"id" lastId2 2 usersTable) conn
428+ let
429+ lastId2 = case Array.last page2.items of
430+ Just u -> u.id
431+ Nothing -> 0
432+ page3 <- conn # run do usersTable # findAfter @"id" lastId2 2
428433 Array.length page3.items `shouldEqual` 1
429434 page3.hasMore `shouldEqual` false
430435
431436 it "findBefore paginates backward" $ withUsersTable \conn -> do
432− _ <- run (C.createMany
433− [ { name: "Alice", email: "a@t.com", role: "admin" }
434− , { name: "Bob", email: "b@t.com", role: "user" }
435− , { name: "Carol", email: "c@t.com", role: "user" }
436− , { name: "Dave", email: "d@t.com", role: "user" }
437− , { name: "Eve", email: "e@t.com", role: "admin" }
438− ] usersTable) conn
439− all <- run (C.findAll usersTable) conn
440− let lastUser = case Array.last all of
441− Just u -> u
442− Nothing -> { id: 0, name: "", email: "", active: true, role: "" }
443− page <- run (C.findBefore @"id" lastUser.id 2 usersTable) conn
437+ _ <- conn # run do
438+ usersTable # createMany
439+ [ { name: "Alice", email: "a@t.com", role: "admin" }
440+ , { name: "Bob", email: "b@t.com", role: "user" }
441+ , { name: "Carol", email: "c@t.com", role: "user" }
442+ , { name: "Dave", email: "d@t.com", role: "user" }
443+ , { name: "Eve", email: "e@t.com", role: "admin" }
444+ ]
445+ all <- conn # run do usersTable # findAll
446+ let
447+ lastUser = case Array.last all of
448+ Just u -> u
449+ Nothing -> { id: 0, name: "", email: "", active: true, role: "" }
450+ page <- conn # run do usersTable # findBefore @"id" lastUser.id 2
444451 Array.length page.items `shouldEqual` 2
445452 page.hasMore `shouldEqual` true
446453
447454 it "findAfterWhere paginates with conditions" $ withUsersTable \conn -> do
448− _ <- run (C.createMany
449− [ { name: "Alice", email: "a@t.com", role: "admin" }
450− , { name: "Bob", email: "b@t.com", role: "user" }
451− , { name: "Carol", email: "c@t.com", role: "user" }
452− , { name: "Dave", email: "d@t.com", role: "user" }
453− , { name: "Eve", email: "e@t.com", role: "admin" }
454− ] usersTable) conn
455− page1 <- run (C.findFirstWhere @"id" { role: "user" } 2 usersTable) conn
455+ _ <- conn # run do
456+ usersTable # createMany
457+ [ { name: "Alice", email: "a@t.com", role: "admin" }
458+ , { name: "Bob", email: "b@t.com", role: "user" }
459+ , { name: "Carol", email: "c@t.com", role: "user" }
460+ , { name: "Dave", email: "d@t.com", role: "user" }
461+ , { name: "Eve", email: "e@t.com", role: "admin" }
462+ ]
463+ page1 <- conn # run do usersTable # findFirstWhere @"id" { role: "user" } 2
456464 Array.length page1.items `shouldEqual` 2
457465 page1.hasMore `shouldEqual` true
458− let lastId = case Array.last page1.items of
459− Just u -> u.id
460− Nothing -> 0
461− page2 <- run (C.findAfterWhere @"id" { role: "user" } lastId 2 usersTable) conn
466+ let
467+ lastId = case Array.last page1.items of
468+ Just u -> u.id
469+ Nothing -> 0
470+ page2 <- conn # run do usersTable # findAfterWhere @"id" { role: "user" } lastId 2
462471 Array.length page2.items `shouldEqual` 1
463472 page2.hasMore `shouldEqual` false
464473
465474 describe "newtypes" do
466475 it "PGUUID round-trip: create, findById, findBy, findOneBy, exists" $ withUuidTable \conn -> do
467− created <- run (C.create { label: "first" } uuidTable) conn
476+ created <- conn # run do uuidTable # create { label: "first" }
468477 row <- shouldBeJust created
469478 row.label `shouldEqual` "first"
470− found <- run (C.findById row.id uuidTable) conn
479+ found <- conn # run do uuidTable # findById row.id
471480 r2 <- shouldBeJust found
472481 r2.label `shouldEqual` "first"
473− byCol <- run (C.findBy @"label" "first" uuidTable) conn
482+ byCol <- conn # run do uuidTable # findBy @"label" "first"
474483 Array.length byCol `shouldEqual` 1
475− byId <- run (C.findOneBy @"id" row.id uuidTable) conn
484+ byId <- conn # run do uuidTable # findOneBy @"id" row.id
476485 r3 <- shouldBeJust byId
477486 r3.label `shouldEqual` "first"
478− yes <- runNoErr (C.exists row.id uuidTable) conn
487+ yes <- conn # runNoErr do uuidTable # exists row.id
479488 yes `shouldEqual` true
480489
481490 describe "WHERE operators" do
482491 it "gt, gte, lt, lte filter by comparison" $ withUsersTable \conn -> do
483− _ <- run (C.createMany
484− [ { name: "Alice", email: "a@t.com", role: "admin" }
485− , { name: "Bob", email: "b@t.com", role: "user" }
486− , { name: "Carol", email: "c@t.com", role: "user" }
487− ] usersTable) conn
488− all <- run (C.findAll usersTable) conn
489− let id1 = case Array.head all of
490− Just u -> u.id
491− Nothing -> 0
492− gtRows <- run (C.findAllWhere { id: C.gt id1 } usersTable) conn
492+ _ <- conn # run do
493+ usersTable # createMany
494+ [ { name: "Alice", email: "a@t.com", role: "admin" }
495+ , { name: "Bob", email: "b@t.com", role: "user" }
496+ , { name: "Carol", email: "c@t.com", role: "user" }
497+ ]
498+ all <- conn # run do usersTable # findAll
499+ let
500+ id1 = case Array.head all of
501+ Just u -> u.id
502+ Nothing -> 0
503+ gtRows <- conn # run do usersTable # findAllWhere { id: gt id1 }
493504 Array.length gtRows `shouldEqual` 2
494− gteRows <- run (C.findAllWhere { id: C.gte id1 } usersTable) conn
505+ gteRows <- conn # run do usersTable # findAllWhere { id: gte id1 }
495506 Array.length gteRows `shouldEqual` 3
496− ltRows <- run (C.findAllWhere { id: C.lt (id1 + 3) } usersTable) conn
507+ ltRows <- conn # run do usersTable # findAllWhere { id: lt (id1 + 3) }
497508 Array.length ltRows `shouldEqual` 3
498− lteRows <- run (C.findAllWhere { id: C.lte id1 } usersTable) conn
509+ lteRows <- conn # run do usersTable # findAllWhere { id: lte id1 }
499510 Array.length lteRows `shouldEqual` 1
500511
501512 it "ne filters out matching rows" $ withUsersTable \conn -> do
502− _ <- run (C.createMany
503− [ { name: "Alice", email: "a@t.com", role: "admin" }
504− , { name: "Bob", email: "b@t.com", role: "user" }
505− , { name: "Carol", email: "c@t.com", role: "user" }
506− ] usersTable) conn
507− rows <- run (C.findAllWhere { role: C.ne "admin" } usersTable) conn
513+ _ <- conn # run do
514+ usersTable # createMany
515+ [ { name: "Alice", email: "a@t.com", role: "admin" }
516+ , { name: "Bob", email: "b@t.com", role: "user" }
517+ , { name: "Carol", email: "c@t.com", role: "user" }
518+ ]
519+ rows <- conn # run do usersTable # findAllWhere { role: ne "admin" }
508520 Array.length rows `shouldEqual` 2
509521
510522 it "like_ and ilike match patterns" $ withUsersTable \conn -> do
511− _ <- run (C.createMany
512− [ { name: "Alice", email: "a@t.com", role: "admin" }
513− , { name: "Bob", email: "b@t.com", role: "user" }
514− , { name: "Carol", email: "c@t.com", role: "user" }
515− ] usersTable) conn
516− likeRows <- run (C.findAllWhere { name: C.like_ "A%" } usersTable) conn
523+ _ <- conn # run do
524+ usersTable # createMany
525+ [ { name: "Alice", email: "a@t.com", role: "admin" }
526+ , { name: "Bob", email: "b@t.com", role: "user" }
527+ , { name: "Carol", email: "c@t.com", role: "user" }
528+ ]
529+ likeRows <- conn # run do usersTable # findAllWhere { name: like_ "A%" }
517530 Array.length likeRows `shouldEqual` 1
518− ilikeRows <- run (C.findAllWhere { name: C.ilike "a%" } usersTable) conn
531+ ilikeRows <- conn # run do usersTable # findAllWhere { name: ilike "a%" }
519532 Array.length ilikeRows `shouldEqual` 1
520533
521534 it "inArray matches values in list" $ withUsersTable \conn -> do
522− _ <- run (C.createMany
523− [ { name: "Alice", email: "a@t.com", role: "admin" }
524− , { name: "Bob", email: "b@t.com", role: "user" }
525− , { name: "Carol", email: "c@t.com", role: "mod" }
526− ] usersTable) conn
527− rows <- run (C.findAllWhere { role: C.inArray ["admin", "mod"] } usersTable) conn
535+ _ <- conn # run do
536+ usersTable # createMany
537+ [ { name: "Alice", email: "a@t.com", role: "admin" }
538+ , { name: "Bob", email: "b@t.com", role: "user" }
539+ , { name: "Carol", email: "c@t.com", role: "mod" }
540+ ]
541+ rows <- conn # run do usersTable # findAllWhere { role: inArray [ "admin", "mod" ] }
528542 Array.length rows `shouldEqual` 2
529543
530544 it "or_ combines conditions" $ withUsersTable \conn -> do
531− _ <- run (C.createMany
532− [ { name: "Alice", email: "a@t.com", role: "admin" }
533− , { name: "Bob", email: "b@t.com", role: "user" }
534− , { name: "Carol", email: "c@t.com", role: "mod" }
535− ] usersTable) conn
536− rows <- run (C.findAllWhere { role: C.or_ (C.eq_ "admin") (C.eq_ "mod") } usersTable) conn
545+ _ <- conn # run do
546+ usersTable # createMany
547+ [ { name: "Alice", email: "a@t.com", role: "admin" }
548+ , { name: "Bob", email: "b@t.com", role: "user" }
549+ , { name: "Carol", email: "c@t.com", role: "mod" }
550+ ]
551+ rows <- conn # run do usersTable # findAllWhere { role: or_ (eq_ "admin") (eq_ "mod") }
537552 Array.length rows `shouldEqual` 2
538553
539554 it "not_ negates conditions" $ withUsersTable \conn -> do
540− _ <- run (C.createMany
541− [ { name: "Alice", email: "a@t.com", role: "admin" }
542− , { name: "Bob", email: "b@t.com", role: "user" }
543− , { name: "Carol", email: "c@t.com", role: "user" }
544− ] usersTable) conn
545− rows <- run (C.findAllWhere { role: C.not_ (C.eq_ "admin") } usersTable) conn
555+ _ <- conn # run do
556+ usersTable # createMany
557+ [ { name: "Alice", email: "a@t.com", role: "admin" }
558+ , { name: "Bob", email: "b@t.com", role: "user" }
559+ , { name: "Carol", email: "c@t.com", role: "user" }
560+ ]
561+ rows <- conn # run do usersTable # findAllWhere { role: not_ (eq_ "admin") }
546562 Array.length rows `shouldEqual` 2
547563
548564 it "operators compose with countWhere and deleteWhere" $ withUsersTable \conn -> do
549− _ <- run (C.createMany
550− [ { name: "Alice", email: "a@t.com", role: "admin" }
551− , { name: "Bob", email: "b@t.com", role: "user" }
552− , { name: "Carol", email: "c@t.com", role: "user" }
553− ] usersTable) conn
554− n <- runNoErr (C.countWhere { role: C.ne "admin" } usersTable) conn
565+ _ <- conn # run do
566+ usersTable # createMany
567+ [ { name: "Alice", email: "a@t.com", role: "admin" }
568+ , { name: "Bob", email: "b@t.com", role: "user" }
569+ , { name: "Carol", email: "c@t.com", role: "user" }
570+ ]
571+ n <- conn # runNoErr do usersTable # countWhere { role: ne "admin" }
555572 n `shouldEqual` 2
556− deleted <- runNoErr (C.deleteWhere { role: C.ne "admin" } usersTable) conn
573+ deleted <- conn # runNoErr do usersTable # deleteWhere { role: ne "admin" }
557574 deleted `shouldEqual` 2
558575
559576 describe "ordering" do
560577 it "findOrdered sorts results" $ withUsersTable \conn -> do
561− _ <- run (C.createMany
562− [ { name: "Carol", email: "c@t.com", role: "user" }
563− , { name: "Alice", email: "a@t.com", role: "admin" }
564− , { name: "Bob", email: "b@t.com", role: "user" }
565− ] usersTable) conn
566− asc <- run (C.findOrdered @"name" C.Asc usersTable) conn
567− (map _.name asc) `shouldEqual` ["Alice", "Bob", "Carol"]
568− desc <- run (C.findOrdered @"name" C.Desc usersTable) conn
569− (map _.name desc) `shouldEqual` ["Carol", "Bob", "Alice"]
578+ _ <- conn # run do
579+ usersTable # createMany
580+ [ { name: "Carol", email: "c@t.com", role: "user" }
581+ , { name: "Alice", email: "a@t.com", role: "admin" }
582+ , { name: "Bob", email: "b@t.com", role: "user" }
583+ ]
584+ asc <- conn # run do usersTable # findOrdered @"name" Asc
585+ (map _.name asc) `shouldEqual` [ "Alice", "Bob", "Carol" ]
586+ desc <- conn # run do usersTable # findOrdered @"name" Desc
587+ (map _.name desc) `shouldEqual` [ "Carol", "Bob", "Alice" ]
570588
571589 it "findWhereOrdered filters and sorts" $ withUsersTable \conn -> do
572− _ <- run (C.createMany
573− [ { name: "Carol", email: "c@t.com", role: "user" }
574− , { name: "Alice", email: "a@t.com", role: "admin" }
575− , { name: "Bob", email: "b@t.com", role: "user" }
576− ] usersTable) conn
577− rows <- run (C.findWhereOrdered @"name" { role: "user" } C.Asc usersTable) conn
578− (map _.name rows) `shouldEqual` ["Bob", "Carol"]
590+ _ <- conn # run do
591+ usersTable # createMany
592+ [ { name: "Carol", email: "c@t.com", role: "user" }
593+ , { name: "Alice", email: "a@t.com", role: "admin" }
594+ , { name: "Bob", email: "b@t.com", role: "user" }
595+ ]
596+ rows <- conn # run do usersTable # findWhereOrdered @"name" { role: "user" } Asc
597+ (map _.name rows) `shouldEqual` [ "Bob", "Carol" ]
579598
580599 it "findWhereLimited paginates with offset" $ withUsersTable \conn -> do
581− _ <- run (C.createMany
582− [ { name: "Alice", email: "a@t.com", role: "user" }
583− , { name: "Bob", email: "b@t.com", role: "user" }
584− , { name: "Carol", email: "c@t.com", role: "user" }
585− , { name: "Dave", email: "d@t.com", role: "user" }
586− ] usersTable) conn
587− page1 <- run (C.findWhereLimited @"name" { role: "user" } C.Asc { limit: 2, offset: 0 } usersTable) conn
588− (map _.name page1) `shouldEqual` ["Alice", "Bob"]
589− page2 <- run (C.findWhereLimited @"name" { role: "user" } C.Asc { limit: 2, offset: 2 } usersTable) conn
590− (map _.name page2) `shouldEqual` ["Carol", "Dave"]
600+ _ <- conn # run do
601+ usersTable # createMany
602+ [ { name: "Alice", email: "a@t.com", role: "user" }
603+ , { name: "Bob", email: "b@t.com", role: "user" }
604+ , { name: "Carol", email: "c@t.com", role: "user" }
605+ , { name: "Dave", email: "d@t.com", role: "user" }
606+ ]
607+ page1 <- conn # run do usersTable # findWhereLimited @"name" { role: "user" } Asc { limit: 2, offset: 0 }
608+ (map _.name page1) `shouldEqual` [ "Alice", "Bob" ]
609+ page2 <- conn # run do usersTable # findWhereLimited @"name" { role: "user" } Asc { limit: 2, offset: 2 }
610+ (map _.name page2) `shouldEqual` [ "Carol", "Dave" ]
591611
592612 describe "aggregations" do
593613 it "sumOf sums a numeric column" $ withUsersTable \conn -> do
594− _ <- run (C.createMany
595− [ { name: "Alice", email: "a@t.com", role: "admin" }
596− , { name: "Bob", email: "b@t.com", role: "user" }
597− , { name: "Carol", email: "c@t.com", role: "user" }
598− ] usersTable) conn
599− total <- runNoErr (C.sumOf @"id" usersTable) conn
614+ _ <- conn # run do
615+ usersTable # createMany
616+ [ { name: "Alice", email: "a@t.com", role: "admin" }
617+ , { name: "Bob", email: "b@t.com", role: "user" }
618+ , { name: "Carol", email: "c@t.com", role: "user" }
619+ ]
620+ total <- conn # runNoErr do usersTable # sumOf @"id"
600621 (total > 0.0) `shouldEqual` true
601− emptySum <- runNoErr (C.sumOfWhere @"id" { role: "nobody" } usersTable) conn
622+ emptySum <- conn # runNoErr do usersTable # sumOfWhere @"id" { role: "nobody" }
602623 emptySum `shouldEqual` 0.0
603624
604625 it "avgOf averages a numeric column" $ withUsersTable \conn -> do
605− _ <- run (C.createMany
606− [ { name: "Alice", email: "a@t.com", role: "admin" }
607− , { name: "Bob", email: "b@t.com", role: "user" }
608− ] usersTable) conn
609− avg <- runNoErr (C.avgOf @"id" usersTable) conn
626+ _ <- conn # run do
627+ usersTable # createMany
628+ [ { name: "Alice", email: "a@t.com", role: "admin" }
629+ , { name: "Bob", email: "b@t.com", role: "user" }
630+ ]
631+ avg <- conn # runNoErr do usersTable # avgOf @"id"
610632 isNothing avg `shouldEqual` false
611− emptyAvg <- runNoErr (C.avgOfWhere @"id" { role: "nobody" } usersTable) conn
633+ emptyAvg <- conn # runNoErr do usersTable # avgOfWhere @"id" { role: "nobody" }
612634 isNothing emptyAvg `shouldEqual` true
613635
614636 it "minOf and maxOf find extremes" $ withUsersTable \conn -> do
615− _ <- run (C.createMany
616− [ { name: "Alice", email: "a@t.com", role: "admin" }
617− , { name: "Bob", email: "b@t.com", role: "user" }
618− , { name: "Carol", email: "c@t.com", role: "user" }
619− ] usersTable) conn
620− minName <- run (C.minOf @"name" usersTable) conn
637+ _ <- conn # run do
638+ usersTable # createMany
639+ [ { name: "Alice", email: "a@t.com", role: "admin" }
640+ , { name: "Bob", email: "b@t.com", role: "user" }
641+ , { name: "Carol", email: "c@t.com", role: "user" }
642+ ]
643+ minName <- conn # run do usersTable # minOf @"name"
621644 minName `shouldEqual` (Just "Alice")
622− maxName <- run (C.maxOf @"name" usersTable) conn
645+ maxName <- conn # run do usersTable # maxOf @"name"
623646 maxName `shouldEqual` (Just "Carol")
624− noMin <- run (C.minOfWhere @"name" { role: "nobody" } usersTable) conn
647+ noMin <- conn # run do usersTable # minOfWhere @"name" { role: "nobody" }
625648 isNothing noMin `shouldEqual` true
626649
627650 describe "distinct" do
628651 it "findDistinct returns unique column values" $ withUsersTable \conn -> do
629− _ <- run (C.createMany
630− [ { name: "Alice", email: "a@t.com", role: "admin" }
631− , { name: "Bob", email: "b@t.com", role: "user" }
632− , { name: "Carol", email: "c@t.com", role: "user" }
633− ] usersTable) conn
634− roles <- run (C.findDistinct @"role" usersTable) conn
635− Array.sort roles `shouldEqual` ["admin", "user"]
652+ _ <- conn # run do
653+ usersTable # createMany
654+ [ { name: "Alice", email: "a@t.com", role: "admin" }
655+ , { name: "Bob", email: "b@t.com", role: "user" }
656+ , { name: "Carol", email: "c@t.com", role: "user" }
657+ ]
658+ roles <- conn # run do usersTable # findDistinct @"role"
659+ Array.sort roles `shouldEqual` [ "admin", "user" ]
636660
637661 it "findDistinctWhere with conditions" $ withUsersTable \conn -> do
638− _ <- run (C.createMany
639− [ { name: "Alice", email: "a@t.com", role: "admin" }
640− , { name: "Bob", email: "b@t.com", role: "user" }
641− , { name: "Carol", email: "c@t.com", role: "user" }
642− ] usersTable) conn
643− roles <- run (C.findDistinctWhere @"role" { active: true } usersTable) conn
644− Array.sort roles `shouldEqual` ["admin", "user"]
662+ _ <- conn # run do
663+ usersTable # createMany
664+ [ { name: "Alice", email: "a@t.com", role: "admin" }
665+ , { name: "Bob", email: "b@t.com", role: "user" }
666+ , { name: "Carol", email: "c@t.com", role: "user" }
667+ ]
668+ roles <- conn # run do usersTable # findDistinctWhere @"role" { active: true }
669+ Array.sort roles `shouldEqual` [ "admin", "user" ]
645670
646671 describe "deleteWhereReturning" do
647672 it "returns deleted rows" $ withUsersTable \conn -> do
648− _ <- run (C.createMany
649− [ { name: "Alice", email: "a@t.com", role: "admin" }
650− , { name: "Bob", email: "b@t.com", role: "user" }
651− , { name: "Carol", email: "c@t.com", role: "user" }
652− ] usersTable) conn
653− deleted <- run (C.deleteWhereReturning { role: "user" } usersTable) conn
673+ _ <- conn # run do
674+ usersTable # createMany
675+ [ { name: "Alice", email: "a@t.com", role: "admin" }
676+ , { name: "Bob", email: "b@t.com", role: "user" }
677+ , { name: "Carol", email: "c@t.com", role: "user" }
678+ ]
679+ deleted <- conn # run do usersTable # deleteWhereReturning { role: "user" }
654680 Array.length deleted `shouldEqual` 2
655− Array.sort (map _.name deleted) `shouldEqual` ["Bob", "Carol"]
656− remaining <- runNoErr (C.count usersTable) conn
681+ Array.sort (map _.name deleted) `shouldEqual` [ "Bob", "Carol" ]
682+ remaining <- conn # runNoErr do usersTable # count
657683 remaining `shouldEqual` 1
658684
659685 describe "withTransaction" do
660686 it "commits on success" $ withUsersTable \conn -> do
661− _ <- run (C.withTransaction do
662− _ <- C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable
663− _ <- C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable
664− pure unit
665− ) conn
666− n <- runNoErr (C.count usersTable) conn
687+ conn # run do
688+ withTransaction do
689+ _ <- usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
690+ _ <- usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
691+ pure unit
692+ n <- conn # runNoErr do usersTable # count
667693 n `shouldEqual` 2
694+
668695 describe "partial select" do
669696 it "selectFrom picks specific columns" $ withUsersTable \conn -> do
670− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
671− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
672− rows <- run (C.selectFrom @"name, email" usersTable) conn
697+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
698+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
699+ rows <- conn # run do usersTable # selectFrom @"name, email"
673700 Array.length rows `shouldEqual` 2
674− let first = case Array.head rows of
675− Just r -> r
676− Nothing -> { name: "", email: "" }
701+ let
702+ first = case Array.head rows of
703+ Just r -> r
704+ Nothing -> { name: "", email: "" }
677705 first.name `shouldEqual` "Alice"
678706 first.email `shouldEqual` "a@t.com"
679707
680708 it "selectOneFrom returns Maybe with picked columns" $ withUsersTable \conn -> do
681− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
682− found <- run (C.selectOneFrom @"name, role" usersTable) conn
709+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
710+ found <- conn # run do usersTable # selectOneFrom @"name, role"
683711 r <- shouldBeJust found
684712 r.name `shouldEqual` "Alice"
685713 r.role `shouldEqual` "admin"
686714
687715 it "selectFromWhere filters and picks columns" $ withUsersTable \conn -> do
688− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
689− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
690− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
691− rows <- run (C.selectFromWhere @"name" { role: "user" } usersTable) conn
716+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
717+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
718+ _ <- conn # run do usersTable # create { name: "Carol", email: "c@t.com", role: "user" }
719+ rows <- conn # run do usersTable # selectFromWhere @"name" { role: "user" }
692720 Array.length rows `shouldEqual` 2
693− Array.sort (map _.name rows) `shouldEqual` ["Bob", "Carol"]
721+ Array.sort (map _.name rows) `shouldEqual` [ "Bob", "Carol" ]
694722
695723 it "selectFromWhere works with operators" $ withUsersTable \conn -> do
696− _ <- run (C.createMany
697− [ { name: "Alice", email: "a@t.com", role: "admin" }
698− , { name: "Bob", email: "b@t.com", role: "user" }
699− , { name: "Carol", email: "c@t.com", role: "mod" }
700− ] usersTable) conn
701− rows <- run (C.selectFromWhere @"name" { role: C.ne "admin" } usersTable) conn
724+ _ <- conn # run do
725+ usersTable # createMany
726+ [ { name: "Alice", email: "a@t.com", role: "admin" }
727+ , { name: "Bob", email: "b@t.com", role: "user" }
728+ , { name: "Carol", email: "c@t.com", role: "mod" }
729+ ]
730+ rows <- conn # run do usersTable # selectFromWhere @"name" { role: ne "admin" }
702731 Array.length rows `shouldEqual` 2
703732
704733 it "selectOneFromWhere returns Maybe with conditions" $ withUsersTable \conn -> do
705− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
706− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
707− found <- run (C.selectOneFromWhere @"email" { name: "Bob" } usersTable) conn
734+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
735+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
736+ found <- conn # run do usersTable # selectOneFromWhere @"email" { name: "Bob" }
708737 r <- shouldBeJust found
709738 r.email `shouldEqual` "b@t.com"
710− missing <- run (C.selectOneFromWhere @"email" { name: "Nobody" } usersTable) conn
739+ missing <- conn # run do usersTable # selectOneFromWhere @"email" { name: "Nobody" }
711740 isNothing missing `shouldEqual` true
712741
713− describe "query builder (Q)" do
714− it "select with where" $ withUsersTable \conn -> do
715− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
716− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
717− rows <- run (C.run { role: "admin" } (Schema.from usersTable # Schema.select @"name, email" # Schema.where_ @"role = $role")) conn
718− Array.length rows `shouldEqual` 1
719− let r = case Array.head rows of
720− Just x -> x
721− Nothing -> { name: "", email: "" }
722− r.name `shouldEqual` "Alice"
723−
724− it "order by and limit" $ withUsersTable \conn -> do
725− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
726− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
727− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
728− rows <- run (C.run {} (Schema.from usersTable # Schema.select @"name" # Schema.orderBy @"name" # Schema.limit @"2")) conn
729− Array.length rows `shouldEqual` 2
730− (map _.name rows) `shouldEqual` ["Alice", "Bob"]
731−
732− it "group by" $ withUsersTable \conn -> do
733− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
734− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
735− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "user" } usersTable) conn
736− rows <- run (C.run {} (Schema.from usersTable # Schema.select @"role" # Schema.groupBy @"role" # Schema.orderBy @"role")) conn
737− (map _.role rows) `shouldEqual` ["admin", "user"]
738−
739− it "between in where" $ withUsersTable \conn -> do
740− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
741− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
742− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "mod" } usersTable) conn
743− rows <- run (C.run { lo: 2, hi: 3 } (Schema.from usersTable # Schema.select @"name" # Schema.where_ @"id BETWEEN $lo AND $hi" # Schema.orderBy @"id")) conn
744− (map _.name rows) `shouldEqual` ["Bob", "Carol"]
745−
746− it "insert with returning" $ withUsersTable \conn -> do
747− row <- run (C.runOne {} (Schema.from usersTable # Schema.insert { name: "Alice", email: "a@t.com", role: "admin" } # Schema.returning @"id, name")) conn
748− r <- shouldBeJust row
749− r.name `shouldEqual` "Alice"
750− (r.id > 0) `shouldEqual` true
751−
752− it "delete with returning" $ withUsersTable \conn -> do
753− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
754− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
755− rows <- run (C.run { role: "admin" } (Schema.from usersTable # Schema.delete # Schema.where_ @"role = $role" # Schema.returningAll)) conn
756− Array.length rows `shouldEqual` 1
757− let r = case Array.head rows of
758− Just x -> x
759− Nothing -> { id: 0, name: "", email: "", active: false, role: "" }
760− r.name `shouldEqual` "Alice"
761−
762− it "union" $ withUsersTable \conn -> do
763− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
764− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
765− _ <- run (C.create { name: "Carol", email: "c@t.com", role: "mod" } usersTable) conn
766− rows <- run (C.run { a: "admin", b: "mod" }
767− ( (Schema.from usersTable # Schema.select @"name" # Schema.where_ @"role = $a")
768− `Schema.union`
769− (Schema.from usersTable # Schema.select @"name" # Schema.where_ @"role = $b")
770− )) conn
771− Array.sort (map _.name rows) `shouldEqual` ["Alice", "Carol"]
772−
773742 describe "joins (ORMy)" do
774743 it "findWith joins child to parent" $ withPostsTable \conn -> do
775− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
776− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
777− _ <- run (C.create { title: "First Post", body: "Hello", user_id: 1 } postsTable) conn
778− _ <- run (C.create { title: "Second Post", body: "World", user_id: 1 } postsTable) conn
779− _ <- run (C.create { title: "Bob's Post", body: "Hi", user_id: 2 } postsTable) conn
780− rows <- run (C.findWith postsTable usersTable) conn
744+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
745+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
746+ _ <- conn # run do postsTable # create { title: "First Post", body: "Hello", user_id: 1 }
747+ _ <- conn # run do postsTable # create { title: "Second Post", body: "World", user_id: 1 }
748+ _ <- conn # run do postsTable # create { title: "Bob's Post", body: "Hi", user_id: 2 }
749+ rows <- conn # run do findWith postsTable usersTable
781750 Array.length rows `shouldEqual` 3
782− let r = case Array.head rows of
783− Just x -> x
784− Nothing -> { test_om_posts: { id: 0, title: "", body: "", user_id: 0 }, test_om_users: { id: 0, name: "", email: "", active: false, role: "" } }
751+ let
752+ r = case Array.head rows of
753+ Just x -> x
754+ Nothing -> { test_om_posts: { id: 0, title: "", body: "", user_id: 0 }, test_om_users: { id: 0, name: "", email: "", active: false, role: "" } }
785755 r.test_om_posts.title `shouldEqual` "First Post"
786756 r.test_om_users.name `shouldEqual` "Alice"
787757
788758 it "findByIdWith joins by primary key" $ withPostsTable \conn -> do
789− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
790− _ <- run (C.create { title: "My Post", body: "Content", user_id: 1 } postsTable) conn
791− found <- run (C.findByIdWith 1 postsTable usersTable) conn
759+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
760+ _ <- conn # run do postsTable # create { title: "My Post", body: "Content", user_id: 1 }
761+ found <- conn # run do findByIdWith 1 postsTable usersTable
792762 r <- shouldBeJust found
793763 r.test_om_posts.title `shouldEqual` "My Post"
794764 r.test_om_users.name `shouldEqual` "Alice"
795765
796766 it "findWithWhere joins with conditions" $ withPostsTable \conn -> do
797− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
798− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
799− _ <- run (C.create { title: "Post A", body: "A", user_id: 1 } postsTable) conn
800− _ <- run (C.create { title: "Post B", body: "B", user_id: 2 } postsTable) conn
801− rows <- run (C.findWithWhere { user_id: 1 } postsTable usersTable) conn
767+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
768+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
769+ _ <- conn # run do postsTable # create { title: "Post A", body: "A", user_id: 1 }
770+ _ <- conn # run do postsTable # create { title: "Post B", body: "B", user_id: 2 }
771+ rows <- conn # run do findWithWhere { user_id: 1 } postsTable usersTable
802772 Array.length rows `shouldEqual` 1
803− let r = case Array.head rows of
804− Just x -> x
805− Nothing -> { test_om_posts: { id: 0, title: "", body: "", user_id: 0 }, test_om_users: { id: 0, name: "", email: "", active: false, role: "" } }
773+ let
774+ r = case Array.head rows of
775+ Just x -> x
776+ Nothing -> { test_om_posts: { id: 0, title: "", body: "", user_id: 0 }, test_om_users: { id: 0, name: "", email: "", active: false, role: "" } }
806777 r.test_om_posts.title `shouldEqual` "Post A"
807778
808779 it "findIncluding nests children under parent" $ withPostsTable \conn -> do
809− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
810− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
811− _ <- run (C.create { title: "Post 1", body: "A", user_id: 1 } postsTable) conn
812− _ <- run (C.create { title: "Post 2", body: "B", user_id: 1 } postsTable) conn
813− rows <- run (C.findIncluding @"posts" usersTable postsTable) conn
780+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
781+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
782+ _ <- conn # run do postsTable # create { title: "Post 1", body: "A", user_id: 1 }
783+ _ <- conn # run do postsTable # create { title: "Post 2", body: "B", user_id: 1 }
784+ rows <- conn # run do findIncluding @"posts" usersTable postsTable
814785 Array.length rows `shouldEqual` 2
815− let alice = case Array.head rows of
816− Just x -> x
817− Nothing -> { id: 0, name: "", email: "", active: false, role: "", posts: [] }
786+ let
787+ alice = case Array.head rows of
788+ Just x -> x
789+ Nothing -> { id: 0, name: "", email: "", active: false, role: "", posts: [] }
818790 alice.name `shouldEqual` "Alice"
819791 Array.length alice.posts `shouldEqual` 2
820792
821793 it "findByIdIncluding nests children for one parent" $ withPostsTable \conn -> do
822− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
823− _ <- run (C.create { title: "Post 1", body: "A", user_id: 1 } postsTable) conn
824− _ <- run (C.create { title: "Post 2", body: "B", user_id: 1 } postsTable) conn
825− found <- run (C.findByIdIncluding @"posts" 1 usersTable postsTable) conn
794+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
795+ _ <- conn # run do postsTable # create { title: "Post 1", body: "A", user_id: 1 }
796+ _ <- conn # run do postsTable # create { title: "Post 2", body: "B", user_id: 1 }
797+ found <- conn # run do findByIdIncluding @"posts" 1 usersTable postsTable
826798 r <- shouldBeJust found
827799 r.name `shouldEqual` "Alice"
828800 Array.length r.posts `shouldEqual` 2
829801
830802 it "findIncludingWhere nests children with conditions" $ withPostsTable \conn -> do
831− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
832− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
833− _ <- run (C.create { title: "Post 1", body: "A", user_id: 1 } postsTable) conn
834− _ <- run (C.create { title: "Post 2", body: "B", user_id: 2 } postsTable) conn
835− rows <- run (C.findIncludingWhere @"posts" { role: "admin" } usersTable postsTable) conn
803+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
804+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
805+ _ <- conn # run do postsTable # create { title: "Post 1", body: "A", user_id: 1 }
806+ _ <- conn # run do postsTable # create { title: "Post 2", body: "B", user_id: 2 }
807+ rows <- conn # run do findIncludingWhere @"posts" { role: "admin" } usersTable postsTable
836808 Array.length rows `shouldEqual` 1
837− let r = case Array.head rows of
838− Just x -> x
839− Nothing -> { id: 0, name: "", email: "", active: false, role: "", posts: [] }
809+ let
810+ r = case Array.head rows of
811+ Just x -> x
812+ Nothing -> { id: 0, name: "", email: "", active: false, role: "", posts: [] }
840813 r.name `shouldEqual` "Alice"
841814 Array.length r.posts `shouldEqual` 1
842815
843816 describe "join combinator" do
844− it "findJoined works on plain table" $ withUsersTable \conn -> do
845− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
846− rows <- run (C.findAll usersTable) conn
817+ it "findAll on plain table" $ withUsersTable \conn -> do
818+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
819+ rows <- conn # run do usersTable # findAll
847820 Array.length rows `shouldEqual` 1
848− let r = case Array.head rows of
849− Just x -> x
850− Nothing -> { id: 0, name: "", email: "", active: false, role: "" }
821+ let
822+ r = case Array.head rows of
823+ Just x -> x
824+ Nothing -> { id: 0, name: "", email: "", active: false, role: "" }
851825 r.name `shouldEqual` "Alice"
852826
853− it "usersTable # join postsTable # findJoined" $ withPostsTable \conn -> do
854− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
855− _ <- run (C.create { name: "Bob", email: "b@t.com", role: "user" } usersTable) conn
856− _ <- run (C.create { title: "Post 1", body: "A", user_id: 1 } postsTable) conn
857− _ <- run (C.create { title: "Post 2", body: "B", user_id: 1 } postsTable) conn
858− _ <- run (C.create { title: "Post 3", body: "C", user_id: 2 } postsTable) conn
859− rows <- run (C.findAll (usersTable # C.join postsTable)) conn
827+ it "usersTable # join postsTable # findAll" $ withPostsTable \conn -> do
828+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
829+ _ <- conn # run do usersTable # create { name: "Bob", email: "b@t.com", role: "user" }
830+ _ <- conn # run do postsTable # create { title: "Post 1", body: "A", user_id: 1 }
831+ _ <- conn # run do postsTable # create { title: "Post 2", body: "B", user_id: 1 }
832+ _ <- conn # run do postsTable # create { title: "Post 3", body: "C", user_id: 2 }
833+ rows <- conn # run do (usersTable # join postsTable) # findAll
860834 Array.length rows `shouldEqual` 2
861− let alice = case Array.head rows of
862− Just x -> x
863− Nothing -> { id: 0, name: "", email: "", active: false, role: "", test_om_posts: [] }
835+ let
836+ alice = case Array.head rows of
837+ Just x -> x
838+ Nothing -> { id: 0, name: "", email: "", active: false, role: "", test_om_posts: [] }
864839 alice.name `shouldEqual` "Alice"
865840 Array.length alice.test_om_posts `shouldEqual` 2
866841
867842 it "usersTable # join postsTable # join commentsTable" $ withPostsAndCommentsTable \conn -> do
868− _ <- run (C.create { name: "Alice", email: "a@t.com", role: "admin" } usersTable) conn
869− _ <- run (C.create { title: "Post 1", body: "A", user_id: 1 } postsTable) conn
870− _ <- run (C.create { title: "Post 2", body: "B", user_id: 1 } postsTable) conn
871− _ <- run (C.create { text: "Nice!", user_id: 1 } commentsTable) conn
872− rows <- run (C.findAll (usersTable # C.join postsTable # C.join commentsTable)) conn
843+ _ <- conn # run do usersTable # create { name: "Alice", email: "a@t.com", role: "admin" }
844+ _ <- conn # run do postsTable # create { title: "Post 1", body: "A", user_id: 1 }
845+ _ <- conn # run do postsTable # create { title: "Post 2", body: "B", user_id: 1 }
846+ _ <- conn # run do commentsTable # create { text: "Nice!", user_id: 1 }
847+ rows <- conn # run do (usersTable # join postsTable # join commentsTable) # findAll
873848 Array.length rows `shouldEqual` 1
874− let r = case Array.head rows of
875− Just x -> x
876− Nothing -> { id: 0, name: "", email: "", active: false, role: "", test_om_posts: [], test_om_comments: [] }
849+ let
850+ r = case Array.head rows of
851+ Just x -> x
852+ Nothing -> { id: 0, name: "", email: "", active: false, role: "", test_om_posts: [], test_om_comments: [] }
877853 r.name `shouldEqual` "Alice"
878854 Array.length r.test_om_posts `shouldEqual` 2
879855 Array.length r.test_om_comments `shouldEqual` 1
test/Test/Main.purs+4−1
@@ -7,6 +7,9 @@ import Effect.Aff (launchAff_)
77import Test.Spec.Reporter (consoleReporter)
88import Test.Spec.Runner (runSpec)
99import Test.ClientOm as ClientOm
10+import Test.SchemaQ as SchemaQ
1011
1112main :: Effect Unit
12−main = launchAff_ $ runSpec [ consoleReporter ] ClientOm.spec
13+main = launchAff_ $ runSpec [ consoleReporter ] do
14+ ClientOm.spec
15+ SchemaQ.spec
test/Test/SchemaQ.pursnew file+150
@@ -0,0 +1,150 @@
1+module Test.SchemaQ where
2+
3+import Prelude
4+
5+import Control.Monad.Error.Class (throwError)
6+import Data.Array as Array
7+import Data.Maybe (Maybe(..))
8+import Effect.Aff (Aff)
9+import Effect.Class (liftEffect)
10+import Effect.Exception (error)
11+import Foreign (MultipleErrors)
12+import Test.Spec (Spec, describe, it)
13+import Test.Spec.Assertions (shouldEqual)
14+import Type.Proxy (Proxy(..))
15+import Yoga.Om as Om
16+import Yoga.Postgres as PG
17+import Yoga.Postgres.ClientOm (run, runOne, create) as Q
18+import Yoga.Postgres.Schema (Table, PrimaryKey, AutoIncrement, Unique, Default, from, select, where_, orderBy, limit, groupBy, insert, delete, returning, returningAll, union)
19+
20+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
21+-- Test schema
22+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
23+
24+type UsersTable = Table "test_om_users"
25+ ( id :: PrimaryKey (AutoIncrement Int)
26+ , name :: String
27+ , email :: Unique String
28+ , active :: Default "true" Boolean
29+ , role :: String
30+ )
31+
32+usersTable :: Proxy UsersTable
33+usersTable = Proxy
34+
35+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
36+-- Helpers
37+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
38+
39+testConnection :: Aff PG.Connection
40+testConnection =
41+ PG.postgres
42+ { host: PG.PostgresHost "localhost"
43+ , port: PG.PostgresPort 5433
44+ , database: PG.PostgresDatabase "test_playground"
45+ , username: PG.PostgresUsername "postgres"
46+ , password: PG.PostgresPassword "postgres"
47+ } # liftEffect
48+
49+exec
50+ :: forall a
51+ . Om.Om { postgresConnection :: PG.Connection } (parseError :: MultipleErrors) a
52+ -> PG.Connection
53+ -> Aff a
54+exec om conn = Om.runOm { postgresConnection: conn }
55+ { exception: \e -> throwError e
56+ , parseError: \errs -> throwError (error ("Parse error: " <> show errs))
57+ }
58+ om
59+
60+shouldBeJust :: forall a. Maybe a -> Aff a
61+shouldBeJust (Just a) = pure a
62+shouldBeJust Nothing = throwError $ error "Expected Just but got Nothing"
63+
64+withUsersTable :: (PG.Connection -> Aff Unit) -> Aff Unit
65+withUsersTable test = do
66+ conn <- testConnection
67+ _ <- PG.executeSimple createDDL conn
68+ test conn
69+ _ <- PG.executeSimple dropDDL conn
70+ PG.end conn
71+ where
72+ dropDDL = PG.SQL "DROP TABLE IF EXISTS test_om_users CASCADE"
73+ createDDL = PG.SQL
74+ """DROP TABLE IF EXISTS test_om_users CASCADE;
75+ CREATE TABLE test_om_users (
76+ id SERIAL PRIMARY KEY,
77+ name TEXT NOT NULL,
78+ email TEXT UNIQUE NOT NULL,
79+ active BOOLEAN DEFAULT true NOT NULL,
80+ role TEXT NOT NULL
81+ )"""
82+
83+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
84+-- Spec
85+-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
86+
87+spec :: Spec Unit
88+spec = describe "Schema Q" do
89+
90+ it "select with where" $ withUsersTable \conn -> do
91+ _ <- conn # exec do usersTable # Q.create { name: "Alice", email: "a@t.com", role: "admin" }
92+ _ <- conn # exec do usersTable # Q.create { name: "Bob", email: "b@t.com", role: "user" }
93+ rows <- conn # exec do Q.run { role: "admin" } (from usersTable # select @"name, email" # where_ @"role = $role")
94+ Array.length rows `shouldEqual` 1
95+ let
96+ r = case Array.head rows of
97+ Just x -> x
98+ Nothing -> { name: "", email: "" }
99+ r.name `shouldEqual` "Alice"
100+
101+ it "order by and limit" $ withUsersTable \conn -> do
102+ _ <- conn # exec do usersTable # Q.create { name: "Alice", email: "a@t.com", role: "admin" }
103+ _ <- conn # exec do usersTable # Q.create { name: "Bob", email: "b@t.com", role: "user" }
104+ _ <- conn # exec do usersTable # Q.create { name: "Carol", email: "c@t.com", role: "user" }
105+ rows <- conn # exec do Q.run {} (from usersTable # select @"name" # orderBy @"name" # limit @"2")
106+ Array.length rows `shouldEqual` 2
107+ (map _.name rows) `shouldEqual` [ "Alice", "Bob" ]
108+
109+ it "group by" $ withUsersTable \conn -> do
110+ _ <- conn # exec do usersTable # Q.create { name: "Alice", email: "a@t.com", role: "admin" }
111+ _ <- conn # exec do usersTable # Q.create { name: "Bob", email: "b@t.com", role: "user" }
112+ _ <- conn # exec do usersTable # Q.create { name: "Carol", email: "c@t.com", role: "user" }
113+ rows <- conn # exec do Q.run {} (from usersTable # select @"role" # groupBy @"role" # orderBy @"role")
114+ (map _.role rows) `shouldEqual` [ "admin", "user" ]
115+
116+ it "between in where" $ withUsersTable \conn -> do
117+ _ <- conn # exec do usersTable # Q.create { name: "Alice", email: "a@t.com", role: "admin" }
118+ _ <- conn # exec do usersTable # Q.create { name: "Bob", email: "b@t.com", role: "user" }
119+ _ <- conn # exec do usersTable # Q.create { name: "Carol", email: "c@t.com", role: "mod" }
120+ rows <- conn # exec do Q.run { lo: 2, hi: 3 } (from usersTable # select @"name" # where_ @"id BETWEEN $lo AND $hi" # orderBy @"id")
121+ (map _.name rows) `shouldEqual` [ "Bob", "Carol" ]
122+
123+ it "insert with returning" $ withUsersTable \conn -> do
124+ row <- conn # exec do Q.runOne {} (from usersTable # insert { name: "Alice", email: "a@t.com", role: "admin" } # returning @"id, name")
125+ r <- shouldBeJust row
126+ r.name `shouldEqual` "Alice"
127+ (r.id > 0) `shouldEqual` true
128+
129+ it "delete with returning" $ withUsersTable \conn -> do
130+ _ <- conn # exec do usersTable # Q.create { name: "Alice", email: "a@t.com", role: "admin" }
131+ _ <- conn # exec do usersTable # Q.create { name: "Bob", email: "b@t.com", role: "user" }
132+ rows <- conn # exec do Q.run { role: "admin" } (from usersTable # delete # where_ @"role = $role" # returningAll)
133+ Array.length rows `shouldEqual` 1
134+ let
135+ r = case Array.head rows of
136+ Just x -> x
137+ Nothing -> { id: 0, name: "", email: "", active: false, role: "" }
138+ r.name `shouldEqual` "Alice"
139+
140+ it "union" $ withUsersTable \conn -> do
141+ _ <- conn # exec do usersTable # Q.create { name: "Alice", email: "a@t.com", role: "admin" }
142+ _ <- conn # exec do usersTable # Q.create { name: "Bob", email: "b@t.com", role: "user" }
143+ _ <- conn # exec do usersTable # Q.create { name: "Carol", email: "c@t.com", role: "mod" }
144+ rows <- conn # exec do
145+ Q.run { a: "admin", b: "mod" }
146+ ( (from usersTable # select @"name" # where_ @"role = $a")
147+ `union`
148+ (from usersTable # select @"name" # where_ @"role = $b")
149+ )
150+ Array.sort (map _.name rows) `shouldEqual` [ "Alice", "Carol" ]