fix: embedding computed with normal relationship
This commit is contained in:
committed by
Steve Chavez
parent
5d126bf0a3
commit
45e7aac218
@@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- #2283, Fix infinite recursion when loading schema cache with self-referencing view - @wolfgangwalther
|
- #2283, Fix infinite recursion when loading schema cache with self-referencing view - @wolfgangwalther
|
||||||
- #2343, Return status code 200 for PATCH requests which don't affect any rows - @wolfgangwalther
|
- #2343, Return status code 200 for PATCH requests which don't affect any rows - @wolfgangwalther
|
||||||
- #2481, Treat computed relationships not marked SETOF as M2O/O2O relationship - @wolfgangwalther
|
- #2481, Treat computed relationships not marked SETOF as M2O/O2O relationship - @wolfgangwalther
|
||||||
|
- #2534, Fix embedding a computed relationship with a normal relationship - @steve-chavez
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -126,23 +126,26 @@ treeRestrictRange maxRows _ request = pure $ nodeRestrictRange maxRows <$> reque
|
|||||||
nodeRestrictRange :: Maybe Integer -> ReadPlan -> ReadPlan
|
nodeRestrictRange :: Maybe Integer -> ReadPlan -> ReadPlan
|
||||||
nodeRestrictRange m q@ReadPlan{range_=r} = q{range_=restrictRange m r }
|
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, also adds aliasing
|
-- add relationships to the nodes of the tree by traversing the forest while keeping track of the parentNode(https://stackoverflow.com/questions/22721064/get-the-parent-of-a-node-in-data-tree-haskell#comment34627048_22721064)
|
||||||
|
-- also adds aliasing
|
||||||
addRels :: Schema -> Action -> RelationshipsMap -> Maybe ReadPlanTree -> ReadPlanTree -> Either ApiRequestError ReadPlanTree
|
addRels :: Schema -> Action -> RelationshipsMap -> Maybe ReadPlanTree -> ReadPlanTree -> Either ApiRequestError ReadPlanTree
|
||||||
addRels schema action allRels parentNode (Node rPlan@ReadPlan{relName,relHint,relAlias,depth} forest) =
|
addRels schema action allRels parentNode (Node rPlan@ReadPlan{relName,relHint,relAlias,depth} forest) =
|
||||||
case parentNode of
|
case parentNode of
|
||||||
Just (Node ReadPlan{from=parentNodeQi, fromAlias} _) ->
|
Just (Node ReadPlan{from=parentNodeQi, fromAlias=parentAlias} _) ->
|
||||||
let
|
let
|
||||||
newReadPlan = (\r ->
|
newReadPlan = (\r ->
|
||||||
let newAlias = Just (qiName (relForeignTable r) <> "_" <> show depth)
|
let newAlias = Just (qiName (relForeignTable r) <> "_" <> show depth)
|
||||||
aggAlias = qiName (relTable r) <> "_" <> fromMaybe relName relAlias <> "_" <> show depth in
|
aggAlias = qiName (relTable r) <> "_" <> fromMaybe relName relAlias <> "_" <> show depth in
|
||||||
case r of
|
case r of
|
||||||
Relationship{relCardinality=M2M _} ->
|
Relationship{relCardinality=M2M _} -> -- m2m does internal implicit joins that don't need aliasing
|
||||||
rPlan{from=relForeignTable r, relToParent=Just r, relAggAlias=aggAlias, relJoinConds=getJoinConditions Nothing fromAlias r}
|
rPlan{from=relForeignTable r, relToParent=Just r, relAggAlias=aggAlias, relJoinConds=getJoinConditions Nothing parentAlias r}
|
||||||
|
ComputedRelationship{} ->
|
||||||
|
rPlan{from=relForeignTable r, relToParent=Just r{relTable=maybe (relTable r) (QualifiedIdentifier mempty) parentAlias}, relAggAlias=aggAlias, fromAlias=newAlias}
|
||||||
_ ->
|
_ ->
|
||||||
rPlan{from=relForeignTable r, relToParent=Just r, relAggAlias=aggAlias, fromAlias=newAlias, relJoinConds=getJoinConditions newAlias fromAlias r}
|
rPlan{from=relForeignTable r, relToParent=Just r, relAggAlias=aggAlias, fromAlias=newAlias, relJoinConds=getJoinConditions newAlias parentAlias r}
|
||||||
) <$> rel
|
) <$> 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
|
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
|
then fromMaybe (qiName parentNodeQi) parentAlias
|
||||||
else qiName parentNodeQi
|
else qiName parentNodeQi
|
||||||
rel = findRel schema allRels origin relName relHint
|
rel = findRel schema allRels origin relName relHint
|
||||||
in
|
in
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ data ReadPlan = ReadPlan
|
|||||||
, relHint :: Maybe Hint
|
, relHint :: Maybe Hint
|
||||||
, relJoinType :: Maybe JoinType
|
, relJoinType :: Maybe JoinType
|
||||||
, depth :: Depth
|
, depth :: Depth
|
||||||
-- depth is used bc when a self join occurs we
|
-- ^ used for aliasing
|
||||||
-- need to differentiate the parent from the child tables by having an alias like
|
|
||||||
-- "table_depth". See http://github.com/PostgREST/postgrest/issues/987.
|
|
||||||
}
|
}
|
||||||
deriving (Eq)
|
deriving (Eq)
|
||||||
|
|
||||||
|
|||||||
@@ -136,3 +136,18 @@ spec = describe "computed relationships" $ do
|
|||||||
get "/fee?select=*,jsbaz(*,johnsmith(*, fee(*)))"
|
get "/fee?select=*,jsbaz(*,johnsmith(*, fee(*)))"
|
||||||
`shouldRespondWith`
|
`shouldRespondWith`
|
||||||
[json|[]|] { matchHeaders = [matchContentTypeJson] }
|
[json|[]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
|
it "creates queries with the right aliasing when following a normal embed" $ do
|
||||||
|
get "/projects?select=name,clients(name,computed_projects(name))&limit=1"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|
|
||||||
|
[{"name":"Windows 7","clients":{"name":"Microsoft","computed_projects":{"name":"Windows 7"}}}]
|
||||||
|
|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
get "/clients?select=name,projects(name,computed_clients(name))&limit=1"
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[
|
||||||
|
{"name":"Microsoft","projects":[
|
||||||
|
{"name":"Windows 7","computed_clients":{"name":"Microsoft"}},
|
||||||
|
{"name":"Windows 10","computed_clients":{"name":"Microsoft"}}
|
||||||
|
]}
|
||||||
|
]|] { matchHeaders = [matchContentTypeJson] }
|
||||||
|
|||||||
Vendored
+8
@@ -2910,3 +2910,11 @@ create trigger ins instead of insert on with_multiple_pks
|
|||||||
-- issue https://github.com/PostgREST/postgrest/issues/2283
|
-- issue https://github.com/PostgREST/postgrest/issues/2283
|
||||||
create view self_recursive_view as table projects;
|
create view self_recursive_view as table projects;
|
||||||
create or replace view self_recursive_view as table self_recursive_view;
|
create or replace view self_recursive_view as table self_recursive_view;
|
||||||
|
|
||||||
|
CREATE FUNCTION test.computed_clients(test.projects) RETURNS SETOF test.clients ROWS 1 AS $$
|
||||||
|
SELECT * FROM test.clients WHERE id = $1.client_id;
|
||||||
|
$$ LANGUAGE sql STABLE;
|
||||||
|
|
||||||
|
CREATE FUNCTION test.computed_projects(test.clients) RETURNS SETOF test.projects ROWS 1 AS $$
|
||||||
|
SELECT * FROM test.projects WHERE client_id = $1.id;
|
||||||
|
$$ LANGUAGE sql STABLE;
|
||||||
|
|||||||
Reference in New Issue
Block a user