Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ All notable changes to this project will be documented in this file. From versio
- Shutdown should wait for in flight requests by @mkleczek in #4702
- Fix login with uppercase and mixed case role names by @taimoorzaeem in #4678
- Remove automatic transaction retries on `40001 (serialization_failure)` errors to prevent replication lag by @laurenceisla in #3673
- Fix unexpected results when embedding and filtering the same table more than once by @laurenceisla in #4075

### Changed

Expand All @@ -29,6 +30,8 @@ All notable changes to this project will be documented in this file. From versio
+ Now fails at startup. Prior to this, it failed with `PGRST205` on requests related to these schemas.
- Build a static executable for aarch64-linux by @wolfgangwalther in #4193
- Build the minimal docker image for aarch64-linux by @wolfgangwalther in #4193
- The name of an embedded table can no longer be used in filters if it has an alias by @laurenceisla in #4075
+ e.g. `?select=alias:table(*)&table.id=eq.1` is not possible anymore, use `?select=alias:table(*)&alias.id=eq.1` instead.

## [14.10] - 2026-04-16

Expand Down
2 changes: 1 addition & 1 deletion src/PostgREST/Plan.hs
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ updateNode f (targetNodeName:remainingPath, a) (Right (Node rootNode forest)) =
updateNode f (remainingPath, a) (Right target)
where
findNode :: Maybe ReadPlanTree
findNode = find (\(Node ReadPlan{relName, relAlias} _) -> relName == targetNodeName || relAlias == Just targetNodeName) forest
findNode = find (\(Node ReadPlan{relName, relAlias} _) -> fromMaybe relName relAlias == targetNodeName) forest

mutatePlan :: Mutation -> QualifiedIdentifier -> ApiRequest -> SchemaCache -> ReadPlanTree -> Either Error MutatePlan
mutatePlan mutation qi ApiRequest{iPreferences=Preferences{..}, ..} SchemaCache{dbTables, dbRepresentations} readReq =
Expand Down
12 changes: 11 additions & 1 deletion test/spec/Feature/Query/QuerySpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,16 @@ spec = do
{ "id":4,"children":[]}
]|] { matchHeaders = [matchContentTypeJson] }

it "works when embedding the same table more than once" $
get "/places?select=name,visits(id,start_time,visit_type),work_visits:visits(id,start_time,visit_type)&id=eq.1&visits.visit_type=neq.work&visits.start_time=gt.20250101+00:00&work_visits.visit_type=eq.work&work_visits.start_time=gt.20250101+00:00" `shouldRespondWith`
[json|[
{
"name":"Lake",
"visits":[{"id": 1, "start_time": "2025-01-01T10:00:00", "visit_type": "vacation"}, {"id": 2, "start_time": "2025-01-01T15:00:00", "visit_type": "vacation"}],
"work_visits":[{"id": 3, "start_time": "2025-01-01T20:00:00", "visit_type": "work"}]
}
]|] { matchHeaders = [matchContentTypeJson] }

describe "ordering response" $ do
it "by a column asc" $
get "/items?id=lte.2&order=id.asc"
Expand Down Expand Up @@ -1152,7 +1162,7 @@ spec = do
{ matchHeaders = [matchContentTypeJson] }

it "ordering embeded entities with alias" $
get "/projects?id=eq.1&select=id, name, the_tasks:tasks(id, name)&tasks.order=name.asc" `shouldRespondWith`
get "/projects?id=eq.1&select=id, name, the_tasks:tasks(id, name)&the_tasks.order=name.asc" `shouldRespondWith`
Comment thread
laurenceisla marked this conversation as resolved.
[json|[{"id":1,"name":"Windows 7","the_tasks":[{"id":2,"name":"Code w7"},{"id":1,"name":"Design w7"}]}]|]
{ matchHeaders = [matchContentTypeJson] }

Expand Down
13 changes: 13 additions & 0 deletions test/spec/fixtures/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -970,3 +970,16 @@ VALUES (1, 'stratosphere', 1),
(2, 'ants from up above',2),
(3, 'vespertine',3),
(4, 'contemporary movement', 1);

TRUNCATE TABLE places CASCADE;
INSERT INTO places (name)
VALUES ('Lake'), ('Mountain'), ('Beach');

TRUNCATE TABLE visits CASCADE;
INSERT INTO visits (place_id, start_time, end_time, visit_type)
VALUES (1, '2025-01-01 10:00','2025-01-01 11:00', 'vacation'),
(1, '2025-01-01 15:00','2025-01-01 16:00', 'vacation'),
(1, '2025-01-01 20:00', '2025-01-01 21:00', 'work'),
(2, '2024-11-01 09:00','2024-11-01 10:00', 'vacation'),
(3, '2024-12-02 13:00','2024-12-02 14:00', 'vacation'),
(1, '2023-01-02 20:00','2023-01-01 21:00', 'work');
15 changes: 15 additions & 0 deletions test/spec/fixtures/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3855,3 +3855,18 @@ $_$ language sql;
create or replace function test.get_tiobe_pls() returns setof test.tiobe_pls as $$
select * from test.tiobe_pls;
$$ language sql;

create type visit_type as enum ('vacation', 'work');

create table places (
id int primary key generated always as identity,
name text not null
);

create table visits (
id int primary key generated always as identity,
place_id int not null references places(id),
start_time timestamp,
end_time timestamp,
visit_type visit_type
);
Loading