refactor: remove parent embed workaround(in #647)
This workaround is no more necessary since the addition of #978. * Also add a test for proving parent embeds offset is consistent with other types of embeds.
This commit is contained in:
committed by
Steve Chávez
parent
f2b126f147
commit
337f821e00
@@ -335,22 +335,22 @@ app dbStructure proc cols conf apiRequest =
|
|||||||
topLevelRange = iTopLevelRange apiRequest
|
topLevelRange = iTopLevelRange apiRequest
|
||||||
returnsScalar = maybe False procReturnsScalar proc
|
returnsScalar = maybe False procReturnsScalar proc
|
||||||
|
|
||||||
selectQuery = readRequestToQuery False
|
|
||||||
readSqlParts s t =
|
readSqlParts s t =
|
||||||
let
|
let
|
||||||
readReq = readRequest s t maxRows (dbRelations dbStructure) apiRequest
|
readReq = readRequest s t maxRows (dbRelations dbStructure) apiRequest
|
||||||
in
|
in
|
||||||
(,,) <$>
|
(,,) <$>
|
||||||
(selectQuery <$> readReq) <*>
|
(readRequestToQuery <$> readReq) <*>
|
||||||
(readRequestToCountQuery <$> readReq) <*>
|
(readRequestToCountQuery <$> readReq) <*>
|
||||||
(binaryField contentType rawContentTypes returnsScalar =<< readReq)
|
(binaryField contentType rawContentTypes returnsScalar =<< readReq)
|
||||||
|
|
||||||
mutateSqlParts s t =
|
mutateSqlParts s t =
|
||||||
let
|
let
|
||||||
readReq = readRequest s t maxRows (dbRelations dbStructure) apiRequest
|
readReq = readRequest s t maxRows (dbRelations dbStructure) apiRequest
|
||||||
mutReq = mutateRequest s t apiRequest cols (tablePKCols dbStructure s t) =<< readReq
|
mutReq = mutateRequest s t apiRequest cols (tablePKCols dbStructure s t) =<< readReq
|
||||||
in
|
in
|
||||||
(,) <$>
|
(,) <$>
|
||||||
(selectQuery <$> readReq) <*>
|
(readRequestToQuery <$> readReq) <*>
|
||||||
(mutateRequestToQuery <$> mutReq)
|
(mutateRequestToQuery <$> mutReq)
|
||||||
|
|
||||||
responseContentTypeOrError :: [ContentType] -> [ContentType] -> Action -> Target -> Either Response ContentType
|
responseContentTypeOrError :: [ContentType] -> [ContentType] -> Action -> Target -> Either Response ContentType
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ import PostgREST.Types
|
|||||||
import Protolude hiding (cast, intercalate,
|
import Protolude hiding (cast, intercalate,
|
||||||
replace)
|
replace)
|
||||||
|
|
||||||
readRequestToQuery :: Bool -> ReadRequest -> SqlQuery
|
readRequestToQuery :: ReadRequest -> SqlQuery
|
||||||
readRequestToQuery isParent (Node (Select colSelects mainQi tblAlias implJoins logicForest joinConditions_ ordts range, _) forest) =
|
readRequestToQuery (Node (Select colSelects mainQi tblAlias implJoins logicForest joinConditions_ ordts range, _) forest) =
|
||||||
unwords [
|
unwords [
|
||||||
"SELECT " <> intercalate ", " (map (pgFmtSelectItem qi) colSelects ++ selects),
|
"SELECT " <> intercalate ", " (map (pgFmtSelectItem qi) colSelects ++ selects),
|
||||||
"FROM " <> intercalate ", " (tabl : implJs),
|
"FROM " <> intercalate ", " (tabl : implJs),
|
||||||
@@ -43,42 +43,39 @@ readRequestToQuery isParent (Node (Select colSelects mainQi tblAlias implJoins l
|
|||||||
("WHERE " <> intercalate " AND " (map (pgFmtLogicTree qi) logicForest ++ map pgFmtJoinCondition joinConditions_))
|
("WHERE " <> intercalate " AND " (map (pgFmtLogicTree qi) logicForest ++ map pgFmtJoinCondition joinConditions_))
|
||||||
`emptyOnFalse` (null logicForest && null joinConditions_),
|
`emptyOnFalse` (null logicForest && null joinConditions_),
|
||||||
("ORDER BY " <> intercalate ", " (map (pgFmtOrderTerm qi) ordts)) `emptyOnFalse` null ordts,
|
("ORDER BY " <> intercalate ", " (map (pgFmtOrderTerm qi) ordts)) `emptyOnFalse` null ordts,
|
||||||
("LIMIT " <> maybe "ALL" show (rangeLimit range) <> " OFFSET " <> show (rangeOffset range)) `emptyOnFalse` (isParent || range == allRange) ]
|
("LIMIT " <> maybe "ALL" show (rangeLimit range) <> " OFFSET " <> show (rangeOffset range)) `emptyOnFalse` (range == allRange)
|
||||||
|
]
|
||||||
where
|
where
|
||||||
implJs = fromQi <$> implJoins
|
implJs = fromQi <$> implJoins
|
||||||
tabl = fromQi mainQi <> maybe mempty (\a -> " AS " <> pgFmtIdent a) tblAlias
|
tabl = fromQi mainQi <> maybe mempty (\a -> " AS " <> pgFmtIdent a) tblAlias
|
||||||
qi = maybe mainQi (QualifiedIdentifier mempty) tblAlias
|
qi = maybe mainQi (QualifiedIdentifier mempty) tblAlias
|
||||||
|
(joins, selects) = foldr getJoinsSelects ([],[]) forest
|
||||||
|
|
||||||
(joins, selects) = foldr getQueryParts ([],[]) forest
|
getJoinsSelects :: ReadRequest -> ([SqlFragment], [SqlFragment]) -> ([SqlFragment], [SqlFragment])
|
||||||
|
getJoinsSelects rr@(Node (_, (name, Just Relation{relType=relTyp,relTable=Table{tableName=table}}, alias, _, _)) _) (j,s) =
|
||||||
getQueryParts :: Tree ReadNode -> ([SqlFragment], [SqlFragment]) -> ([SqlFragment], [SqlFragment])
|
let subquery = readRequestToQuery rr in
|
||||||
getQueryParts (Node n@(_, (name, Just Relation{relType=Child,relTable=Table{tableName=table}}, alias, _, _)) forst) (j,s) = (j,sel:s)
|
case relTyp of
|
||||||
where
|
Child ->
|
||||||
sel = "COALESCE(("
|
let sel = "COALESCE(("
|
||||||
<> "SELECT json_agg(" <> pgFmtIdent table <> ".*) "
|
<> "SELECT json_agg(" <> pgFmtIdent table <> ".*) "
|
||||||
<> "FROM (" <> subquery <> ") " <> pgFmtIdent table
|
<> "FROM (" <> subquery <> ") " <> pgFmtIdent table
|
||||||
<> "), '[]') AS " <> pgFmtIdent (fromMaybe name alias)
|
<> "), '[]') AS " <> pgFmtIdent (fromMaybe name alias) in
|
||||||
where subquery = readRequestToQuery False (Node n forst)
|
(j, sel:s)
|
||||||
getQueryParts (Node n@(_, (name, Just Relation{relType=Parent,relTable=Table{tableName=table}}, alias, _, _)) forst) (j,s) = (joi:j,sel:s)
|
Parent ->
|
||||||
where
|
let aliasOrName = fromMaybe name alias
|
||||||
aliasOrName = fromMaybe name alias
|
localTableName = pgFmtIdent $ table <> "_" <> aliasOrName
|
||||||
localTableName = pgFmtIdent $ table <> "_" <> aliasOrName
|
sel = "row_to_json(" <> localTableName <> ".*) AS " <> pgFmtIdent aliasOrName
|
||||||
sel = "row_to_json(" <> localTableName <> ".*) AS " <> pgFmtIdent aliasOrName
|
joi = " LEFT JOIN LATERAL( " <> subquery <> " ) AS " <> localTableName <> " ON TRUE " in
|
||||||
joi = " LEFT JOIN LATERAL( " <> subquery <> " ) AS " <> localTableName <> " ON TRUE "
|
(joi:j,sel:s)
|
||||||
where subquery = readRequestToQuery True (Node n forst)
|
Many ->
|
||||||
getQueryParts (Node n@(_, (name, Just Relation{relType=Many,relTable=Table{tableName=table}}, alias, _, _)) forst) (j,s) = (j,sel:s)
|
let sel = "COALESCE (("
|
||||||
where
|
<> "SELECT json_agg(" <> pgFmtIdent table <> ".*) "
|
||||||
sel = "COALESCE (("
|
<> "FROM (" <> subquery <> ") " <> pgFmtIdent table
|
||||||
<> "SELECT json_agg(" <> pgFmtIdent table <> ".*) "
|
<> "), '[]') AS " <> pgFmtIdent (fromMaybe name alias) in
|
||||||
<> "FROM (" <> subquery <> ") " <> pgFmtIdent table
|
(j,sel:s)
|
||||||
<> "), '[]') AS " <> pgFmtIdent (fromMaybe name alias)
|
--readRequestToQuery is called only after addJoinConditions which ensures the only posible relations are Child Parent Many
|
||||||
where subquery = readRequestToQuery False (Node n forst)
|
Root -> witness
|
||||||
--the following is just to remove the warning
|
getJoinsSelects _ _ = witness
|
||||||
--getQueryParts is not total but readRequestToQuery is called only after addJoinConditions which ensures the only
|
|
||||||
--posible relations are Child Parent Many
|
|
||||||
getQueryParts _ _ = witness
|
|
||||||
|
|
||||||
|
|
||||||
mutateRequestToQuery :: MutateRequest -> SqlQuery
|
mutateRequestToQuery :: MutateRequest -> SqlQuery
|
||||||
mutateRequestToQuery (Insert mainQi iCols onConflct putConditions returnings) =
|
mutateRequestToQuery (Insert mainQi iCols onConflct putConditions returnings) =
|
||||||
|
|||||||
@@ -36,13 +36,20 @@ spec =
|
|||||||
, matchHeaders = ["Content-Range" <:> "0-1/*"]
|
, matchHeaders = ["Content-Range" <:> "0-1/*"]
|
||||||
}
|
}
|
||||||
|
|
||||||
it "is not applied to parent embeds" $
|
it "succeeds in getting parent embeds despite the limit, see #647" $
|
||||||
get "/tasks?select=id,project(id)&id=gt.5"
|
get "/tasks?select=id,project(id)&id=gt.5"
|
||||||
`shouldRespondWith` [json|[{"id":6,"project":{"id":3}},{"id":7,"project":{"id":4}}]|]
|
`shouldRespondWith` [json|[{"id":6,"project":{"id":3}},{"id":7,"project":{"id":4}}]|]
|
||||||
{ matchStatus = 200
|
{ matchStatus = 200
|
||||||
, matchHeaders = ["Content-Range" <:> "0-1/*"]
|
, matchHeaders = ["Content-Range" <:> "0-1/*"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it "can offset the parent embed, being consistent with the other embed types" $
|
||||||
|
get "/tasks?select=id,project:projects(id)&id=gt.5&project.offset=1"
|
||||||
|
`shouldRespondWith` [json|[{"id":6,"project":null}, {"id":7,"project":null}]|]
|
||||||
|
{ matchStatus = 200
|
||||||
|
, matchHeaders = ["Content-Range" <:> "0-1/*"]
|
||||||
|
}
|
||||||
|
|
||||||
context "count=estimated" $ do
|
context "count=estimated" $ do
|
||||||
it "uses the query planner guess when query rows > maxRows" $
|
it "uses the query planner guess when query rows > maxRows" $
|
||||||
request methodHead "/getallprojects_view" [("Prefer", "count=estimated")] ""
|
request methodHead "/getallprojects_view" [("Prefer", "count=estimated")] ""
|
||||||
|
|||||||
Reference in New Issue
Block a user