From f7fa7174112ed8a360a1c791bcf44a0b479c23c7 Mon Sep 17 00:00:00 2001 From: Laurence Isla Date: Mon, 2 Jun 2025 11:53:36 -0500 Subject: [PATCH] fix: regression that makes order by with nulls order not work alongside limits --- CHANGELOG.md | 4 ++++ src/PostgREST/Query/QueryBuilder.hs | 4 ++-- test/spec/Feature/Query/RangeSpec.hs | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19da47cc4..f9c46ccce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). + The exposed schemas are now listed in the `hint` instead of the `message` field. - Improve error details of `PGRST301` error by @taimoorzaeem in #4051 +### Fixed + +- Fix regression that makes `ORDER BY` with nulls-order not work alongside limits by @laurenceisla in #4109 + ## [13.0.1] - 2025-06-01 ### Fixed diff --git a/src/PostgREST/Query/QueryBuilder.hs b/src/PostgREST/Query/QueryBuilder.hs index 3f7e43244..2e07cc321 100644 --- a/src/PostgREST/Query/QueryBuilder.hs +++ b/src/PostgREST/Query/QueryBuilder.hs @@ -53,8 +53,8 @@ readPlanToQuery node@(Node ReadPlan{select,from=mainQi,fromAlias,where_=logicFor (if null logicForest && null relJoinConds then mempty else " WHERE " <> intercalateSnippet " AND " (map (pgFmtLogicTree qi) logicForest ++ map pgFmtJoinCondition relJoinConds)) <> " " <> - groupF qi select relSelect <> - orderF qi order <> + groupF qi select relSelect <> " " <> + orderF qi order <> " " <> limitOffsetF readRange where fromFrag = fromF relToParent mainQi fromAlias diff --git a/test/spec/Feature/Query/RangeSpec.hs b/test/spec/Feature/Query/RangeSpec.hs index 3086be605..5c2541877 100644 --- a/test/spec/Feature/Query/RangeSpec.hs +++ b/test/spec/Feature/Query/RangeSpec.hs @@ -223,6 +223,14 @@ spec = do , "Content-Range" <:> "2-4/*" ] } + it "works alongside order by with nulls order" $ + get "/clients?select=id,projects(id,tasks(id))&order=id.asc.nullslast&limit=1&projects.order=id.asc.nullsfirst&projects.limit=2" + `shouldRespondWith` + [json|[{"id":1,"projects":[{"id": 1, "tasks": [{"id": 1}, {"id": 2}]}, {"id": 2, "tasks": [{"id": 3}, {"id": 4}]}]}]|] + { matchStatus = 200 + , matchHeaders = ["Content-Range" <:> "0-0/*"] + } + context "succeeds if offset equals 0 as a no-op" $ do it "no items" $ do get "/items?offset=0&id=eq.0"