perf: RelationshipsMap with foreign schema as key
This commit is contained in:
committed by
Steve Chavez
parent
d88b16e5ab
commit
c60380b5fc
@@ -100,8 +100,8 @@ queryDbStructure schemas extraSearchPath prepared = do
|
|||||||
, dbProcs = procs
|
, dbProcs = procs
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
relsToMap = map sort . M.fromListWith (++) . map ((\(x,y) -> (x, [y])) . addKey)
|
relsToMap = map sort . M.fromListWith (++) . map ((\(x, fSch, y) -> ((x, fSch), [y])) . addKey)
|
||||||
addKey rel = (relTable rel, rel)
|
addKey rel = (relTable rel, qiSchema $ relForeignTable rel, rel)
|
||||||
|
|
||||||
-- | Remove db objects that belong to an internal schema(not exposed through the API) from the DbStructure.
|
-- | Remove db objects that belong to an internal schema(not exposed through the API) from the DbStructure.
|
||||||
removeInternal :: [Schema] -> DbStructure -> DbStructure
|
removeInternal :: [Schema] -> DbStructure -> DbStructure
|
||||||
@@ -109,7 +109,7 @@ removeInternal schemas dbStruct =
|
|||||||
DbStructure {
|
DbStructure {
|
||||||
dbTables = M.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas) $ dbTables dbStruct
|
dbTables = M.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas) $ dbTables dbStruct
|
||||||
, dbRelationships = filter (\r -> qiSchema (relForeignTable r) `elem` schemas && not (hasInternalJunction r)) <$>
|
, dbRelationships = filter (\r -> qiSchema (relForeignTable r) `elem` schemas && not (hasInternalJunction r)) <$>
|
||||||
M.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas ) (dbRelationships dbStruct)
|
M.filterWithKey (\(QualifiedIdentifier sch _, _) _ -> sch `elem` schemas ) (dbRelationships dbStruct)
|
||||||
, dbProcs = dbProcs dbStruct -- procs are only obtained from the exposed schemas, no need to filter them.
|
, dbProcs = dbProcs dbStruct -- procs are only obtained from the exposed schemas, no need to filter them.
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import qualified Data.Aeson as JSON
|
|||||||
import qualified Data.HashMap.Strict as M
|
import qualified Data.HashMap.Strict as M
|
||||||
|
|
||||||
import PostgREST.DbStructure.Identifiers (FieldName,
|
import PostgREST.DbStructure.Identifiers (FieldName,
|
||||||
QualifiedIdentifier)
|
QualifiedIdentifier, Schema)
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
@@ -53,4 +53,5 @@ data Junction = Junction
|
|||||||
isSelfReference :: Relationship -> Bool
|
isSelfReference :: Relationship -> Bool
|
||||||
isSelfReference r = relTable r == relForeignTable r
|
isSelfReference r = relTable r == relForeignTable r
|
||||||
|
|
||||||
type RelationshipsMap = M.HashMap QualifiedIdentifier [Relationship]
|
-- | Key based on the source table and the foreign table schema
|
||||||
|
type RelationshipsMap = M.HashMap (QualifiedIdentifier, Schema) [Relationship]
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ makeProperty tbl rels col = (colName col, Inline s)
|
|||||||
rel = find (\case
|
rel = find (\case
|
||||||
Relationship{relCardinality=(M2O _ relColumns)} -> [colName col] == (fst <$> relColumns)
|
Relationship{relCardinality=(M2O _ relColumns)} -> [colName col] == (fst <$> relColumns)
|
||||||
_ -> False
|
_ -> False
|
||||||
) $ fromMaybe mempty $ M.lookup (QualifiedIdentifier (tableSchema tbl) (tableName tbl)) rels
|
) $ fromMaybe mempty $ M.lookup (QualifiedIdentifier (tableSchema tbl) (tableName tbl), tableSchema tbl) rels
|
||||||
fCol = (headMay . (\r -> snd <$> relColumns (relCardinality r)) =<< rel)
|
fCol = (headMay . (\r -> snd <$> relColumns (relCardinality r)) =<< rel)
|
||||||
fTbl = qiName . relForeignTable <$> rel
|
fTbl = qiName . relForeignTable <$> rel
|
||||||
fTblCol = (,) <$> fTbl <*> fCol
|
fTblCol = (,) <$> fTbl <*> fCol
|
||||||
|
|||||||
@@ -157,47 +157,54 @@ findRel schema allRels origin target hint =
|
|||||||
rs -> Left $ AmbiguousRelBetween origin target rs
|
rs -> Left $ AmbiguousRelBetween origin target rs
|
||||||
where
|
where
|
||||||
matchFKSingleCol hint_ card = case card of
|
matchFKSingleCol hint_ card = case card of
|
||||||
O2M _ cols -> length cols == 1 && hint_ == head (fst <$> cols)
|
O2M _ [(col, _)] -> hint_ == col
|
||||||
M2O _ cols -> length cols == 1 && hint_ == head (fst <$> cols)
|
M2O _ [(col, _)] -> hint_ == col
|
||||||
_ -> False
|
_ -> False
|
||||||
matchFKRefSingleCol hint_ card = case card of
|
matchFKRefSingleCol hint_ card = case card of
|
||||||
O2M _ cols -> length cols == 1 && hint_ == head (snd <$> cols)
|
O2M _ [(_, fCol)] -> hint_ == fCol
|
||||||
M2O _ cols -> length cols == 1 && hint_ == head (snd <$> cols)
|
M2O _ [(_, fCol)] -> hint_ == fCol
|
||||||
_ -> False
|
_ -> False
|
||||||
matchConstraint tar card = case card of
|
matchConstraint tar card = case card of
|
||||||
O2M cons _ -> tar == Just cons
|
O2M cons _ -> tar == cons
|
||||||
M2O cons _ -> tar == Just cons
|
M2O cons _ -> tar == cons
|
||||||
_ -> False
|
_ -> False
|
||||||
matchJunction hint_ card = case card of
|
matchJunction hint_ card = case card of
|
||||||
M2M Junction{junTable} -> hint_ == Just (qiName junTable)
|
M2M Junction{junTable} -> hint_ == qiName junTable
|
||||||
_ -> False
|
_ -> False
|
||||||
rel = filter (
|
rel = filter (
|
||||||
\Relationship{..} ->
|
\Relationship{..} ->
|
||||||
-- foreign relationship need to be on the exposed schema
|
case hint of
|
||||||
schema == qiSchema relForeignTable &&
|
Nothing ->
|
||||||
(
|
-- /projects?select=clients(*)
|
||||||
-- /projects?select=clients(*)
|
target == qiName relForeignTable -- clients
|
||||||
target == qiName relForeignTable -- clients
|
||
|
||||||
||
|
-- /projects?select=projects_client_id_fkey(*)
|
||||||
-- /projects?select=projects_client_id_fkey(*)
|
matchConstraint target relCardinality -- projects_client_id_fkey
|
||||||
matchConstraint (Just target) relCardinality -- projects_client_id_fkey
|
||
|
||||||
||
|
-- /projects?select=client_id(*)
|
||||||
-- /projects?select=client_id(*)
|
matchFKSingleCol target relCardinality -- client_id
|
||||||
matchFKSingleCol (Just target) relCardinality -- client_id
|
Just hnt ->
|
||||||
) && (
|
(
|
||||||
isNothing hint || -- hint is optional
|
-- /projects?select=clients(*)
|
||||||
|
target == qiName relForeignTable -- clients
|
||||||
|
||
|
||||||
|
-- /projects?select=projects_client_id_fkey(*)
|
||||||
|
matchConstraint target relCardinality -- projects_client_id_fkey
|
||||||
|
||
|
||||||
|
-- /projects?select=client_id(*)
|
||||||
|
matchFKSingleCol target relCardinality -- client_id
|
||||||
|
) && (
|
||||||
|
-- /projects?select=clients!projects_client_id_fkey(*)
|
||||||
|
matchConstraint hnt relCardinality || -- projects_client_id_fkey
|
||||||
|
|
||||||
-- /projects?select=clients!projects_client_id_fkey(*)
|
-- /projects?select=clients!client_id(*) or /projects?select=clients!id(*)
|
||||||
matchConstraint hint relCardinality || -- projects_client_id_fkey
|
matchFKSingleCol hnt relCardinality || -- client_id
|
||||||
|
matchFKRefSingleCol hnt relCardinality || -- id
|
||||||
|
|
||||||
-- /projects?select=clients!client_id(*) or /projects?select=clients!id(*)
|
-- /users?select=tasks!users_tasks(*) many-to-many between users and tasks
|
||||||
matchFKSingleCol hint relCardinality || -- client_id
|
matchJunction hnt relCardinality -- users_tasks
|
||||||
matchFKRefSingleCol hint relCardinality || -- id
|
)
|
||||||
|
) $ fromMaybe mempty $ M.lookup (QualifiedIdentifier schema origin, schema) allRels
|
||||||
-- /users?select=tasks!users_tasks(*) many-to-many between users and tasks
|
|
||||||
matchJunction hint relCardinality -- users_tasks
|
|
||||||
)
|
|
||||||
) $ fromMaybe mempty $ M.lookup (QualifiedIdentifier schema origin) allRels
|
|
||||||
|
|
||||||
-- previousAlias is only used for the case of self joins
|
-- previousAlias is only used for the case of self joins
|
||||||
addJoinConditions :: Maybe Alias -> ReadRequest -> Either ApiRequestError ReadRequest
|
addJoinConditions :: Maybe Alias -> ReadRequest -> Either ApiRequestError ReadRequest
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ spec =
|
|||||||
it "accepts application/json" $
|
it "accepts application/json" $
|
||||||
request methodGet "/"
|
request methodGet "/"
|
||||||
[("Accept", "application/json")] "" `shouldRespondWith`
|
[("Accept", "application/json")] "" `shouldRespondWith`
|
||||||
[json| {
|
[json|
|
||||||
"qiSchema":"test","qiName":"bars"
|
[{"qiSchema":"test","qiName":"authors_w_entities"},"test"]
|
||||||
} |]
|
|]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|||||||
Reference in New Issue
Block a user