fix: aliasing on computed rels

This commit is contained in:
steve-chavez
2022-10-19 19:49:43 -05:00
committed by Steve Chavez
parent c8b39c6cde
commit 7ace8ace49
6 changed files with 56 additions and 15 deletions
+2
View File
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2401, #2444, Fix SIGUSR1 to fully flush connections pool, remove `db-pool-timeout`. - @robx
- #2348, Add `db-pool-acquisition-timeout` configuration option, time in seconds to wait to acquire a connection. - @robx
- #2428, Fix opening an empty transaction on failed resource embedding - @steve-chavez
- #2455, Fix embedding the same table multiple times - @steve-chavez
### Deprecated
+15 -14
View File
@@ -126,23 +126,24 @@ treeRestrictRange maxRows _ request = pure $ nodeRestrictRange maxRows <$> reque
nodeRestrictRange :: Maybe Integer -> ReadPlan -> ReadPlan
nodeRestrictRange m q@ReadPlan{range_=r} = q{range_=restrictRange m r }
-- add relationships to the nodes of the tree by traversing the forest while keeping track of the parentNode
-- add relationships to the nodes of the tree by traversing the forest while keeping track of the parentNode, also adds aliasing
addRels :: Schema -> Action -> RelationshipsMap -> Maybe ReadPlanTree -> ReadPlanTree -> Either ApiRequestError ReadPlanTree
addRels schema action allRels parentNode (Node rPlan@ReadPlan{from=tbl,relName,relHint,depth} forest) =
addRels schema action allRels parentNode (Node rPlan@ReadPlan{relName,relHint,depth} forest) =
case parentNode of
Just (Node ReadPlan{from=parentNodeQi, fromAlias} _) ->
let newFrom r = if qiName tbl == relName then relForeignTable r else tbl
newReadPlan = (\r ->
if not $ relIsSelf r -- add alias if self rel
then rPlan{from=newFrom r, relToParent=Just r, relJoinConds=getJoinConditions Nothing fromAlias r}
else
let selfAlias = Just (qiName (newFrom r) <> "_" <> show depth) in
rPlan{from=newFrom r, relToParent=Just r, fromAlias=selfAlias, relJoinConds=getJoinConditions selfAlias fromAlias r}
) <$> rel
origin = if depth == 1 -- Only on depth 1 we check if the root(depth 0) has an alias so the sourceCTEName alias can be found as a relationship
then fromMaybe (qiName parentNodeQi) fromAlias
else qiName parentNodeQi
rel = findRel schema allRels origin relName relHint
let
newReadPlan = (\r ->
let newAlias = Just (qiName (relForeignTable r) <> "_" <> show depth) in
case r of
Relationship{relCardinality=M2M _} ->
rPlan{from=relForeignTable r, relToParent=Just r, relJoinConds=getJoinConditions Nothing fromAlias r}
_ ->
rPlan{from=relForeignTable r, relToParent=Just r, fromAlias=newAlias, relJoinConds=getJoinConditions newAlias fromAlias r}
) <$> rel
origin = if depth == 1 -- Only on depth 1 we check if the root(depth 0) has an alias so the sourceCTEName alias can be found as a relationship
then fromMaybe (qiName parentNodeQi) fromAlias
else qiName parentNodeQi
rel = findRel schema allRels origin relName relHint
in
Node <$> newReadPlan <*> (updateForest . hush $ Node <$> newReadPlan <*> pure forest)
Nothing -> -- root case
-1
View File
@@ -32,7 +32,6 @@ data ReadPlan = ReadPlan
{ select :: [SelectItem]
, from :: QualifiedIdentifier
, fromAlias :: Maybe Alias
-- ^ A table alias is used in case of self joins
, where_ :: [LogicTree]
, order :: [OrderTerm]
, range_ :: NonnegRange
@@ -107,3 +107,12 @@ spec = describe "computed relationships" $ do
get "/second_1?select=*,first_1(*)"
`shouldRespondWith`
[json|[]|] { matchHeaders = [matchContentTypeJson] }
-- https://github.com/PostgREST/postgrest/issues/2455
it "creates queries with the right aliasing" $ do
get "/fee?select=*,jsbaz(*,janedoe(*))"
`shouldRespondWith`
[json|[]|] { matchHeaders = [matchContentTypeJson] }
get "/fee?select=*,jsbaz(*,johnsmith(*, fee(*)))"
`shouldRespondWith`
[json|[]|] { matchHeaders = [matchContentTypeJson] }
+4
View File
@@ -210,6 +210,10 @@ GRANT ALL ON TABLE
, second
, first_1
, second_1
, fee
, baz
, janedoe
, johnsmith
TO postgrest_test_anonymous;
GRANT INSERT ON TABLE insertonly TO postgrest_test_anonymous;
+26
View File
@@ -2836,3 +2836,29 @@ $$ LANGUAGE sql STABLE ROWS 1;
CREATE FUNCTION test.first_1(test.second_1) RETURNS SETOF test.first_1 AS $$
SELECT * FROM test.first_1 WHERE second_id_1 = $1.id;
$$ LANGUAGE sql STABLE ROWS 1;
create table fee (
fee_id int primary key
);
create table baz (
baz_id int primary key
);
create table janedoe (
janedoe_id int primary key,
baz_id int references baz(baz_id)
);
create table johnsmith (
johnsmith_id int primary key,
fee_id int references fee(fee_id),
baz_id int references baz(baz_id)
);
create or replace function jsbaz(fee) returns setof baz as $$
select b.*
from baz b
join johnsmith js on js.baz_id = b.baz_id
where js.fee_id = $1.fee_id
$$ stable language sql;