git.iko.soy/rowtype-yoga/purescript-yoga-postgres
on main help sign in
Add parameterized LIMIT/OFFSET, UNION/INTERSECT/EXCEPT, WHERE feature tests
commitbb5dcf55c01b8ac702d58e163ea7711844ce1e22 authorMark <mark.eibes@gmail.com> dateFri 13 Feb 2026, 22:30 (8 months ago) parent5550cd6
11 files changed+63−58
compile-fail-tests/DoubleLimit.purs+1−1 compile-fail-tests/DoubleOffset.purs+1−1 compile-fail-tests/LimitBeforeSelect.purs+1−1 compile-fail-tests/LimitOnInsert.purs+1−1 compile-fail-tests/LimitParamDuplicateName.purs+1−1 compile-fail-tests/OffsetBeforeSelect.purs+1−1 compile-fail-tests/OrderByAfterLimit.purs+1−1 compile-fail-tests/SelectAfterLimit.purs+1−1 compile-fail-tests/WhereAfterLimit.purs+1−1 src/Yoga/Postgres/Schema.purs+35−30 test/Schema.purs+19−19
compile-fail-tests/DoubleLimit.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # selectAll # limit 10 # limit 5
20+bad = from usersTable # selectAll # limit @"10" # limit @"5"
compile-fail-tests/DoubleOffset.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # selectAll # offset 10 # offset 5
20+bad = from usersTable # selectAll # offset @"10" # offset @"5"
compile-fail-tests/LimitBeforeSelect.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # limit 10
20+bad = from usersTable # limit @"10"
compile-fail-tests/LimitOnInsert.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # insert { name: "A", email: "a@b.com" } # limit 10
20+bad = from usersTable # insert { name: "A", email: "a@b.com" } # limit @"10"
compile-fail-tests/LimitParamDuplicateName.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # selectAll # where_ @"age > $n" # limitParam @"n"
20+bad = from usersTable # selectAll # where_ @"age > $n" # limit @"$n"
compile-fail-tests/OffsetBeforeSelect.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # offset 5
20+bad = from usersTable # offset @"5"
compile-fail-tests/OrderByAfterLimit.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # selectAll # limit 10 # orderBy @"name"
20+bad = from usersTable # selectAll # limit @"10" # orderBy @"name"
compile-fail-tests/SelectAfterLimit.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # selectAll # limit 10 # select @"name"
20+bad = from usersTable # selectAll # limit @"10" # select @"name"
compile-fail-tests/WhereAfterLimit.purs+1−1
@@ -17,4 +17,4 @@ type UsersTable = Table "users"
1717usersTable :: Proxy UsersTable
1818usersTable = Proxy
1919
20−bad = from usersTable # selectAll # limit 10 # where_ @"id = $id"
20+bad = from usersTable # selectAll # limit @"10" # where_ @"id = $id"
src/Yoga/Postgres/Schema.purs+35−30
@@ -1828,49 +1828,54 @@ having
18281828 -> Q tables result params' stage'
18291829having (Q q) = Q (q { sql = q.sql <> " HAVING " <> reflectSymbol (Proxy :: Proxy cond) })
18301830
1831−limit
1832− :: forall tables result params stage stage'
1833− . HasClause "select" stage
1834− => Row.Lacks "limit" stage
1835− => Row.Cons "limit" Unit stage stage'
1836− => Int
1837− -> Q tables result params stage
1838− -> Q tables result params stage'
1839−limit n (Q q) = Q (q { sql = q.sql <> " LIMIT " <> show n })
1831+class IsLimitParam :: Symbol -> Symbol -> Boolean -> Constraint
1832+class IsLimitParam head tail isParam | head tail -> isParam
18401833
1841−limitParam
1842− :: forall @name tables result params params' stage stage'
1843− . IsSymbol name
1844− => Row.Lacks name params
1845− => Row.Cons name Int params params'
1834+instance IsLimitParam "$" tail True
1835+else instance IsLimitParam head tail False
1836+
1837+class ParseLimitOffsetParams :: Boolean -> Symbol -> Row Type -> Row Type -> Constraint
1838+class ParseLimitOffsetParams isParam name params params' | isParam name params -> params'
1839+
1840+instance
1841+ ( Row.Lacks name params
1842+ , Row.Cons name Int params params'
1843+ ) =>
1844+ ParseLimitOffsetParams True name params params'
1845+
1846+instance ParseLimitOffsetParams False name params params
1847+
1848+class ParseLimitOffset :: Symbol -> Row Type -> Row Type -> Constraint
1849+class ParseLimitOffset sym params params' | sym params -> params'
1850+
1851+instance
1852+ ( Symbol.Cons head tail sym
1853+ , IsLimitParam head tail isParam
1854+ , ParseLimitOffsetParams isParam tail params params'
1855+ ) =>
1856+ ParseLimitOffset sym params params'
1857+
1858+limit
1859+ :: forall @sym tables result params params' stage stage'
1860+ . ParseLimitOffset sym params params'
1861+ => IsSymbol sym
18461862 => HasClause "select" stage
18471863 => Row.Lacks "limit" stage
18481864 => Row.Cons "limit" Unit stage stage'
18491865 => Q tables result params stage
18501866 -> Q tables result params' stage'
1851−limitParam (Q q) = Q (q { sql = q.sql <> " LIMIT $" <> reflectSymbol (Proxy :: Proxy name) })
1867+limit (Q q) = Q (q { sql = q.sql <> " LIMIT " <> reflectSymbol (Proxy :: Proxy sym) })
18521868
18531869offset
1854− :: forall tables result params stage stage'
1855− . HasClause "select" stage
1856− => Row.Lacks "offset" stage
1857− => Row.Cons "offset" Unit stage stage'
1858− => Int
1859− -> Q tables result params stage
1860− -> Q tables result params stage'
1861−offset n (Q q) = Q (q { sql = q.sql <> " OFFSET " <> show n })
1862−
1863−offsetParam
1864− :: forall @name tables result params params' stage stage'
1865− . IsSymbol name
1866− => Row.Lacks name params
1867− => Row.Cons name Int params params'
1870+ :: forall @sym tables result params params' stage stage'
1871+ . ParseLimitOffset sym params params'
1872+ => IsSymbol sym
18681873 => HasClause "select" stage
18691874 => Row.Lacks "offset" stage
18701875 => Row.Cons "offset" Unit stage stage'
18711876 => Q tables result params stage
18721877 -> Q tables result params' stage'
1873−offsetParam (Q q) = Q (q { sql = q.sql <> " OFFSET $" <> reflectSymbol (Proxy :: Proxy name) })
1878+offset (Q q) = Q (q { sql = q.sql <> " OFFSET " <> reflectSymbol (Proxy :: Proxy sym) })
18741879
18751880-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18761881-- INSERT builder
test/Schema.purs+19−19
@@ -270,7 +270,7 @@ typedOrderByDesc = from usersTable # selectAll # orderBy @"name DESC, age ASC"
270270
271271typedLimitOffset
272272 :: Q _ (age :: Maybe Int, email :: String, id :: Int, name :: String) () _
273−typedLimitOffset = from usersTable # selectAll # orderBy @"name" # limit 10 # offset 5
273+typedLimitOffset = from usersTable # selectAll # orderBy @"name" # limit @"10" # offset @"5"
274274
275275typedInArray
276276 :: Q _ (age :: Maybe Int, email :: String, id :: Int, name :: String) (id :: Array Int) _
@@ -381,8 +381,8 @@ typedJoinLimitOffset = from usersTable
381381 # innerJoin @"users.id = posts.user_id" postsTable
382382 # select @"users.name, posts.title"
383383 # orderBy @"users.name"
384− # limit 10
385− # offset 5
384+ # limit @"10"
385+ # offset @"5"
386386
387387typedUnqualifiedSelect
388388 :: Q _ (title :: String, name :: String) () _
@@ -463,7 +463,7 @@ typedFullAggregate = from usersTable
463463 # groupBy @"name"
464464 # having @"COUNT(*) > $min"
465465 # orderBy @"name"
466− # limit 10
466+ # limit @"10"
467467
468468-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
469469-- Table aliases
@@ -536,18 +536,18 @@ typedNtile = from usersTable
536536
537537typedLimitParam
538538 :: Q _ (name :: String) (n :: Int) _
539−typedLimitParam = from usersTable # select @"name" # limitParam @"n"
539+typedLimitParam = from usersTable # select @"name" # limit @"$n"
540540
541541typedOffsetParam
542542 :: Q _ (name :: String) (n :: Int) _
543−typedOffsetParam = from usersTable # select @"name" # offsetParam @"n"
543+typedOffsetParam = from usersTable # select @"name" # offset @"$n"
544544
545545typedLimitParamWithWhere
546546 :: Q _ (name :: String) (age :: Int, n :: Int) _
547547typedLimitParamWithWhere = from usersTable
548548 # select @"name"
549549 # where_ @"age > $age"
550− # limitParam @"n"
550+ # limit @"$n"
551551
552552-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
553553-- UNION / INTERSECT / EXCEPT
@@ -575,7 +575,7 @@ typedUnionOrderByLimit =
575575 (from usersTable # select @"name")
576576 `union` (from usersTable # select @"name")
577577 # orderBy @"name"
578− # limit 10
578+ # limit @"10"
579579
580580typedIntersect
581581 :: Q _ (name :: String) () _
@@ -946,7 +946,7 @@ integrationSpec conn = do
946946 rows <- from usersTable
947947 # selectAll
948948 # orderBy @"name"
949− # limit 1
949+ # limit @"1"
950950 # runQuery conn {}
951951 Array.length rows `shouldEqual` 1
952952
@@ -954,8 +954,8 @@ integrationSpec conn = do
954954 rows <- from usersTable
955955 # select @"name"
956956 # orderBy @"name ASC"
957− # limit 1
958− # offset 1
957+ # limit @"1"
958+ # offset @"1"
959959 # runQuery conn {}
960960 Array.length rows `shouldEqual` 1
961961 allRows <- from usersTable
@@ -1018,7 +1018,7 @@ integrationSpec conn = do
10181018 # innerJoin @"users.id = posts.user_id" postsTable
10191019 # select @"users.name, posts.title"
10201020 # orderBy @"users.name ASC"
1021− # limit 1
1021+ # limit @"1"
10221022 # runQuery conn {}
10231023 Array.length rows `shouldEqual` 1
10241024 (map _.name rows) `shouldEqual` [ "Alice" ]
@@ -1055,14 +1055,14 @@ integrationSpec conn = do
10551055 describe "Parameterized LIMIT/OFFSET execution" do
10561056 it "parameterized LIMIT restricts rows" do
10571057 rows <- from usersTable # select @"name" # orderBy @"name"
1058− # limitParam @"n"
1058+ # limit @"$n"
10591059 # runQuery conn { n: 1 }
10601060 Array.length rows `shouldEqual` 1
10611061
10621062 it "parameterized OFFSET skips rows" do
10631063 rows <- from usersTable # select @"name" # orderBy @"name"
1064− # limitParam @"n"
1065− # offsetParam @"off"
1064+ # limit @"$n"
1065+ # offset @"$off"
10661066 # runQuery conn { n: 1, off: 1 }
10671067 Array.length rows `shouldEqual` 1
10681068
@@ -1070,7 +1070,7 @@ integrationSpec conn = do
10701070 rows <- from usersTable # select @"name"
10711071 # where_ @"age > $age"
10721072 # orderBy @"name"
1073− # limitParam @"n"
1073+ # limit @"$n"
10741074 # runQuery conn { age: 0, n: 1 }
10751075 Array.length rows `shouldEqual` 1
10761076
@@ -1113,10 +1113,10 @@ integrationSpec conn = do
11131113
11141114 it "UNION with ORDER BY and LIMIT" do
11151115 rows <-
1116− (from usersTable # select @"name")
1117− `union` (from usersTable # select @"name")
1116+ from usersTable # select @"name"
1117+ # union (from usersTable # select @"name")
11181118 # orderBy @"name"
1119− # limit 1
1119+ # limit @"1"
11201120 # runQuery conn {}
11211121 Array.length rows `shouldEqual` 1
11221122 (map _.name rows) `shouldEqual` [ "Alice" ]