perf: RelationshipsMap with foreign schema as key

This commit is contained in:
steve-chavez
2022-05-09 21:31:19 -05:00
committed by Steve Chavez
parent d88b16e5ab
commit c60380b5fc
5 changed files with 49 additions and 41 deletions
+3 -3
View File
@@ -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
+3 -2
View File
@@ -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]
+1 -1
View File
@@ -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
+39 -32
View File
@@ -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
+3 -3
View File
@@ -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] }