diff --git a/src/PostgREST/DbRequestBuilder.hs b/src/PostgREST/DbRequestBuilder.hs index f87c0685a..dcb05f3bb 100644 --- a/src/PostgREST/DbRequestBuilder.hs +++ b/src/PostgREST/DbRequestBuilder.hs @@ -68,7 +68,7 @@ readRequest maxRows allRels proc apiRequest = buildReadRequest fieldTree = let rootDepth = 0 rootNodeName = if action == ActionRead then rootTableName else sourceCTEName in - foldr (treeEntry rootDepth) (Node (Select [] [rootNodeName] [] [] [] allRange, (rootNodeName, Nothing, Nothing, Nothing, rootDepth)) []) fieldTree + foldr (treeEntry rootDepth) (Node (Select [] rootNodeName [] [] [] [] allRange, (rootNodeName, Nothing, Nothing, Nothing, rootDepth)) []) fieldTree where treeEntry :: Depth -> Tree SelectItem -> ReadRequest -> ReadRequest treeEntry depth (Node fld@((fn, _),_,alias,relationDetail) fldForest) (Node (q, i) rForest) = @@ -76,7 +76,7 @@ readRequest maxRows allRels proc apiRequest = case fldForest of [] -> Node (q {select=fld:select q}, i) rForest _ -> Node (q, i) $ - foldr (treeEntry nxtDepth) (Node (Select [] [fn] [] [] [] allRange, (fn, Nothing, alias, relationDetail, nxtDepth)) []) fldForest:rForest + foldr (treeEntry nxtDepth) (Node (Select [] fn [] [] [] [] allRange, (fn, Nothing, alias, relationDetail, nxtDepth)) []) fldForest:rForest relations :: [Relation] relations = case action of @@ -111,10 +111,10 @@ augumentRequestWithJoin schema allRels request = >>= addJoinConditions schema addRelations :: Schema -> [Relation] -> Maybe ReadRequest -> ReadRequest -> Either ApiRequestError ReadRequest -addRelations schema allRelations parentNode (Node (query, (nodeName, _, alias, relationDetail, depth)) forest) = +addRelations schema allRelations parentNode (Node (query@Select{from=tbl}, (nodeName, _, alias, relationDetail, depth)) forest) = case parentNode of - Just (Node (Select{from=[parentNodeTable]}, _) _) -> - let newFrom r = (\tName -> if tName == nodeName then tableName (relTable r) else tName) <$> from query + Just (Node (Select{from=parentNodeTable}, _) _) -> + let newFrom r = if tbl == nodeName then tableName (relTable r) else tbl newReadNode = (\r -> (query{from=newFrom r}, (nodeName, Just r, alias, Nothing, depth))) <$> rel rel :: Either ApiRequestError Relation rel = note (NoRelationBetween parentNodeTable nodeName) $ @@ -216,7 +216,7 @@ addJoinConditions schema (Node node@(query, nodeProps@(_, relation, _, _, _)) fo Just rel@Relation{relType=Child} -> Node (augmentQuery rel, nodeProps) <$> updatedForest Just rel@Relation{relType=Many, relLinkTable=(Just linkTable)} -> let rq = augmentQuery rel in - Node (rq{from=tableName linkTable:from rq}, nodeProps) <$> updatedForest + Node (rq{implicitJoins=tableName linkTable:implicitJoins rq}, nodeProps) <$> updatedForest _ -> Left UnknownRelation where updatedForest = mapM (addJoinConditions schema) forest diff --git a/src/PostgREST/QueryBuilder.hs b/src/PostgREST/QueryBuilder.hs index 95085af4a..a658abce6 100644 --- a/src/PostgREST/QueryBuilder.hs +++ b/src/PostgREST/QueryBuilder.hs @@ -219,7 +219,7 @@ requestToCountQuery schema (DbRead (Node (Select{where_=logicForest}, (mainTbl, qi = removeSourceCTESchema schema mainTbl requestToQuery :: Schema -> Bool -> DbRequest -> SqlQuery -requestToQuery schema isParent (DbRead (Node (Select colSelects tbls logicForest joinConditions_ ordts range, (nodeName, maybeRelation, _, _, depth)) forest)) = +requestToQuery schema isParent (DbRead (Node (Select colSelects tbl implJoins logicForest joinConditions_ ordts range, (_, maybeRelation, _, _, depth)) forest)) = unwords [ "SELECT " <> intercalate ", " (map (pgFmtSelectItem qi) colSelects ++ selects), "FROM " <> intercalate ", " tables, @@ -230,19 +230,19 @@ requestToQuery schema isParent (DbRead (Node (Select colSelects tbls logicForest ("LIMIT " <> maybe "ALL" show (rangeLimit range) <> " OFFSET " <> show (rangeOffset range)) `emptyOnFalse` (isParent || range == allRange) ] where - mainTbl = maybe nodeName (tableName . relTable) maybeRelation + tbls = tbl:implJoins isSelfJoin = maybe False (\r -> relType r /= Root && relTable r == relFTable r) maybeRelation (qi, tables, joinConds) = let depthAlias name dpth = if dpth /= 0 then name <> "_" <> show dpth else name in -- Root node doesn't get aliased if isSelfJoin then ( - QualifiedIdentifier "" (depthAlias mainTbl depth), + QualifiedIdentifier "" (depthAlias tbl depth), (\t -> fromQi (removeSourceCTESchema schema t) <> " AS " <> pgFmtIdent (depthAlias t depth)) <$> tbls, (\(JoinCondition (qi1, _, c1) (qi2, _, c2)) -> JoinCondition (qi1, Just $ depthAlias (qiName qi1) depth, c1) (qi2, Just $ depthAlias (qiName qi2) (depth - 1), c2)) <$> joinConditions_) else ( - removeSourceCTESchema schema mainTbl, + removeSourceCTESchema schema tbl, fromQi . removeSourceCTESchema schema <$> tbls, joinConditions_) diff --git a/src/PostgREST/Types.hs b/src/PostgREST/Types.hs index 6db26c036..c36c00385 100644 --- a/src/PostgREST/Types.hs +++ b/src/PostgREST/Types.hs @@ -308,7 +308,9 @@ data JoinCondition = JoinCondition (QualifiedIdentifier, Maybe Alias, FieldName) data ReadQuery = Select { select :: [SelectItem] - , from :: [TableName] + , from :: TableName +-- | Only used for many to many joins. Parent and Child joins use explicit joins. + , implicitJoins :: [TableName] , where_ :: [LogicTree] , joinConditions :: [JoinCondition] , order :: [OrderTerm]