diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index 62a07253c..0948514b6 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -107,7 +107,7 @@ initReadRequest qi@QualifiedIdentifier{..} = foldr (treeEntry rootDepth) $ Node defReadPlan{from=qi, relName=qiName, depth=rootDepth} [] where rootDepth = 0 - defReadPlan = ReadPlan [] (QualifiedIdentifier mempty mempty) Nothing [] [] allRange mempty Nothing [] Nothing Nothing Nothing rootDepth + defReadPlan = ReadPlan [] (QualifiedIdentifier mempty mempty) Nothing [] [] allRange mempty Nothing [] Nothing mempty Nothing Nothing rootDepth treeEntry :: Depth -> Tree SelectItem -> ReadPlanTree -> ReadPlanTree treeEntry depth (Node fld@((fldName, _),_,alias, hint, joinType) fldForest) (Node q rForest) = let nxtDepth = succ depth in @@ -128,17 +128,18 @@ treeRestrictRange maxRows _ request = pure $ nodeRestrictRange maxRows <$> reque -- 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{relName,relHint,depth} forest) = +addRels schema action allRels parentNode (Node rPlan@ReadPlan{relName,relHint,relAlias,depth} forest) = case parentNode of Just (Node ReadPlan{from=parentNodeQi, fromAlias} _) -> let newReadPlan = (\r -> - let newAlias = Just (qiName (relForeignTable r) <> "_" <> show depth) in + let newAlias = Just (qiName (relForeignTable r) <> "_" <> show depth) + aggAlias = qiName (relTable r) <> "_" <> fromMaybe relName relAlias <> "_" <> 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, relAggAlias=aggAlias, relJoinConds=getJoinConditions Nothing fromAlias r} _ -> - rPlan{from=relForeignTable r, relToParent=Just r, fromAlias=newAlias, relJoinConds=getJoinConditions newAlias fromAlias r} + rPlan{from=relForeignTable r, relToParent=Just r, relAggAlias=aggAlias, 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 diff --git a/src/PostgREST/Plan/ReadPlan.hs b/src/PostgREST/Plan/ReadPlan.hs index cc23f7a6a..6ac789dab 100644 --- a/src/PostgREST/Plan/ReadPlan.hs +++ b/src/PostgREST/Plan/ReadPlan.hs @@ -39,6 +39,7 @@ data ReadPlan = ReadPlan , relToParent :: Maybe Relationship , relJoinConds :: [JoinCondition] , relAlias :: Maybe Alias + , relAggAlias :: Alias , relHint :: Maybe Hint , relJoinType :: Maybe JoinType , depth :: Depth diff --git a/src/PostgREST/Query/QueryBuilder.hs b/src/PostgREST/Query/QueryBuilder.hs index 388840572..91e54ceff 100644 --- a/src/PostgREST/Query/QueryBuilder.hs +++ b/src/PostgREST/Query/QueryBuilder.hs @@ -56,11 +56,11 @@ readPlanToQuery (Node ReadPlan{select,from=mainQi,fromAlias,where_=logicForest,o getSelectsJoins :: ReadPlanTree -> ([SQL.Snippet], [SQL.Snippet]) -> ([SQL.Snippet], [SQL.Snippet]) getSelectsJoins (Node ReadPlan{relToParent=Nothing} _) _ = ([], []) -getSelectsJoins rr@(Node ReadPlan{relName, relToParent=Just rel, relAlias, relJoinType=joinType, depth} _) (selects,joins) = +getSelectsJoins rr@(Node ReadPlan{relName, relToParent=Just rel, relAggAlias, relAlias, relJoinType=joinType} _) (selects,joins) = let subquery = readPlanToQuery rr - aliasOrName = fromMaybe relName relAlias - localTableName = pgFmtIdent $ qiName (relTable rel) <> "_" <> aliasOrName <> "_" <> show depth + aliasOrName = pgFmtIdent $ fromMaybe relName relAlias + aggAlias = pgFmtIdent relAggAlias correlatedSubquery sub al cond = (if joinType == Just JTInner then "INNER" else "LEFT") <> " JOIN LATERAL ( " <> sub <> " ) AS " <> SQL.sql al <> " ON " <> cond isToOne = case rel of @@ -70,14 +70,14 @@ getSelectsJoins rr@(Node ReadPlan{relName, relToParent=Just rel, relAlias, relJo _ -> False (sel, joi) = if isToOne then - ( SQL.sql ("row_to_json(" <> localTableName <> ".*) AS " <> pgFmtIdent aliasOrName) - , correlatedSubquery subquery localTableName "TRUE") + ( SQL.sql ("row_to_json(" <> aggAlias <> ".*) AS " <> aliasOrName) + , correlatedSubquery subquery aggAlias "TRUE") else - ( SQL.sql $ "COALESCE( " <> localTableName <> "." <> localTableName <> ", '[]') AS " <> pgFmtIdent aliasOrName + ( SQL.sql $ "COALESCE( " <> aggAlias <> "." <> aggAlias <> ", '[]') AS " <> aliasOrName , correlatedSubquery ( - "SELECT json_agg(" <> SQL.sql localTableName <> ") AS " <> SQL.sql localTableName <> - "FROM (" <> subquery <> " ) AS " <> SQL.sql localTableName - ) localTableName $ if joinType == Just JTInner then SQL.sql localTableName <> " IS NOT NULL" else "TRUE") + "SELECT json_agg(" <> SQL.sql aggAlias <> ") AS " <> SQL.sql aggAlias <> + "FROM (" <> subquery <> " ) AS " <> SQL.sql aggAlias + ) aggAlias $ if joinType == Just JTInner then SQL.sql aggAlias <> " IS NOT NULL" else "TRUE") in (sel:selects, joi:joins)