refactor: Combine relConstraint and relJunction in relLink

This commit is contained in:
Wolfgang Walther
2021-01-03 17:54:28 +01:00
committed by Wolfgang Walther
parent d173b7d8d6
commit 522308217a
4 changed files with 68 additions and 72 deletions
+20 -26
View File
@@ -10,6 +10,7 @@ A query tree is built in case of resource embedding. By inferring the relationsh
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
module PostgREST.DbRequestBuilder (
readRequest
@@ -135,13 +136,13 @@ findRel schema allRels origin target hint =
-- In a self reference we get two relationships with the same foreign key and relTable/relFtable but with different cardinalities(m2o/o2m)
-- We output the O2M rel, the M2O rel can be obtained by using the origin column as an embed hint.
let [rel0, rel1] = take 2 rs in
if length rs == 2 && relConstraint rel0 == relConstraint rel1 && relTable rel0 == relTable rel1 && relFTable rel0 == relFTable rel1
if length rs == 2 && relLink rel0 == relLink rel1 && relTable rel0 == relTable rel1 && relFTable rel0 == relFTable rel1
then note (NoRelBetween origin target) (find (\r -> relType r == O2M) rs)
else Left $ AmbiguousRelBetween origin target rs
where
matchFKSingleCol hint_ cols = length cols == 1 && hint_ == (colName <$> head cols)
rel = filter (
\Relation{relTable, relColumns, relConstraint, relFTable, relFColumns, relType, relJunction} ->
\Relation{..} ->
-- Both relationship ends need to be on the exposed schema
schema == tableSchema relTable && schema == tableSchema relFTable &&
(
@@ -152,7 +153,7 @@ findRel schema allRels origin target hint =
-- /projects?select=projects_client_id_fkey(*)
(
origin == tableName relTable && -- projects
Just target == relConstraint -- projects_client_id_fkey
Constraint target == relLink -- projects_client_id_fkey
) ||
-- /projects?select=client_id(*)
(
@@ -163,7 +164,10 @@ findRel schema allRels origin target hint =
isNothing hint || -- hint is optional
-- /projects?select=clients!projects_client_id_fkey(*)
hint == relConstraint || -- projects_client_id_fkey
(
relType /= M2M &&
hint == Just (constName relLink) -- projects_client_id_fkey
) ||
-- /projects?select=clients!client_id(*) or /projects?select=clients!id(*)
matchFKSingleCol hint relColumns || -- client_id
@@ -171,8 +175,8 @@ findRel schema allRels origin target hint =
-- /users?select=tasks!users_tasks(*)
(
relType == M2M && -- many-to-many between users and tasks
hint == (tableName . junTable <$> relJunction) -- users_tasks
relType == M2M && -- many-to-many between users and tasks
hint == Just (tableName $ junTable relLink) -- users_tasks
)
)
) allRels
@@ -181,15 +185,10 @@ findRel schema allRels origin target hint =
addJoinConditions :: Maybe Alias -> ReadRequest -> Either ApiRequestError ReadRequest
addJoinConditions previousAlias (Node node@(query@Select{from=tbl}, nodeProps@(_, rel, _, _, depth)) forest) =
case rel of
Just r@Relation{relType=O2M} -> Node (augmentQuery r, nodeProps) <$> updatedForest
Just r@Relation{relType=M2O} -> Node (augmentQuery r, nodeProps) <$> updatedForest
Just r@Relation{relType=M2M, relJunction=junction} ->
case junction of
Just Junction{junTable} ->
let rq = augmentQuery r in
Node (rq{implicitJoins=tableQi junTable:implicitJoins rq}, nodeProps) <$> updatedForest
Nothing ->
Left UnknownRelation
Just r@Relation{relType=M2M, relLink=Junction{junTable}} ->
let rq = augmentQuery r in
Node (rq{implicitJoins=tableQi junTable:implicitJoins rq}, nodeProps) <$> updatedForest
Just r -> Node (augmentQuery r, nodeProps) <$> updatedForest
Nothing -> Node node <$> updatedForest
where
newAlias = case isSelfReference <$> rel of
@@ -206,17 +205,12 @@ addJoinConditions previousAlias (Node node@(query@Select{from=tbl}, nodeProps@(_
-- previousAlias and newAlias are used in the case of self joins
getJoinConditions :: Maybe Alias -> Maybe Alias -> Relation -> [JoinCondition]
getJoinConditions previousAlias newAlias (Relation Table{tableSchema=tSchema, tableName=tN} cols _ Table{tableName=ftN} fCols typ jun) =
case typ of
O2M ->
zipWith (toJoinCondition tN ftN) cols fCols
M2O ->
zipWith (toJoinCondition tN ftN) cols fCols
M2M -> case jun of
Just (Junction jt _ jc1 _ jc2) ->
let jtn = tableName jt in
zipWith (toJoinCondition tN jtn) cols jc1 ++ zipWith (toJoinCondition ftN jtn) fCols jc2
Nothing -> []
getJoinConditions previousAlias newAlias (Relation Table{tableSchema=tSchema, tableName=tN} cols Table{tableName=ftN} fCols _ lnk) =
case lnk of
Junction Table{tableName=jtn} _ jc1 _ jc2 ->
zipWith (toJoinCondition tN jtn) cols jc1 ++ zipWith (toJoinCondition ftN jtn) fCols jc2
Constraint _ ->
zipWith (toJoinCondition tN ftN) cols fCols
where
toJoinCondition :: Text -> Text -> Column -> Column -> JoinCondition
toJoinCondition tb ftb c fc =