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
|
||||
}
|
||||
where
|
||||
relsToMap = map sort . M.fromListWith (++) . map ((\(x,y) -> (x, [y])) . addKey)
|
||||
addKey rel = (relTable rel, rel)
|
||||
relsToMap = map sort . M.fromListWith (++) . map ((\(x, fSch, y) -> ((x, fSch), [y])) . addKey)
|
||||
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.
|
||||
removeInternal :: [Schema] -> DbStructure -> DbStructure
|
||||
@@ -109,7 +109,7 @@ removeInternal schemas dbStruct =
|
||||
DbStructure {
|
||||
dbTables = M.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas) $ dbTables dbStruct
|
||||
, 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.
|
||||
}
|
||||
where
|
||||
|
||||
@@ -13,7 +13,7 @@ import qualified Data.Aeson as JSON
|
||||
import qualified Data.HashMap.Strict as M
|
||||
|
||||
import PostgREST.DbStructure.Identifiers (FieldName,
|
||||
QualifiedIdentifier)
|
||||
QualifiedIdentifier, Schema)
|
||||
|
||||
import Protolude
|
||||
|
||||
@@ -53,4 +53,5 @@ data Junction = Junction
|
||||
isSelfReference :: Relationship -> Bool
|
||||
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
|
||||
Relationship{relCardinality=(M2O _ relColumns)} -> [colName col] == (fst <$> relColumns)
|
||||
_ -> 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)
|
||||
fTbl = qiName . relForeignTable <$> rel
|
||||
fTblCol = (,) <$> fTbl <*> fCol
|
||||
|
||||
@@ -157,47 +157,54 @@ findRel schema allRels origin target hint =
|
||||
rs -> Left $ AmbiguousRelBetween origin target rs
|
||||
where
|
||||
matchFKSingleCol hint_ card = case card of
|
||||
O2M _ cols -> length cols == 1 && hint_ == head (fst <$> cols)
|
||||
M2O _ cols -> length cols == 1 && hint_ == head (fst <$> cols)
|
||||
_ -> False
|
||||
O2M _ [(col, _)] -> hint_ == col
|
||||
M2O _ [(col, _)] -> hint_ == col
|
||||
_ -> False
|
||||
matchFKRefSingleCol hint_ card = case card of
|
||||
O2M _ cols -> length cols == 1 && hint_ == head (snd <$> cols)
|
||||
M2O _ cols -> length cols == 1 && hint_ == head (snd <$> cols)
|
||||
_ -> False
|
||||
O2M _ [(_, fCol)] -> hint_ == fCol
|
||||
M2O _ [(_, fCol)] -> hint_ == fCol
|
||||
_ -> False
|
||||
matchConstraint tar card = case card of
|
||||
O2M cons _ -> tar == Just cons
|
||||
M2O cons _ -> tar == Just cons
|
||||
O2M cons _ -> tar == cons
|
||||
M2O cons _ -> tar == cons
|
||||
_ -> False
|
||||
matchJunction hint_ card = case card of
|
||||
M2M Junction{junTable} -> hint_ == Just (qiName junTable)
|
||||
M2M Junction{junTable} -> hint_ == qiName junTable
|
||||
_ -> False
|
||||
rel = filter (
|
||||
\Relationship{..} ->
|
||||
-- foreign relationship need to be on the exposed schema
|
||||
schema == qiSchema relForeignTable &&
|
||||
(
|
||||
-- /projects?select=clients(*)
|
||||
target == qiName relForeignTable -- clients
|
||||
||
|
||||
-- /projects?select=projects_client_id_fkey(*)
|
||||
matchConstraint (Just target) relCardinality -- projects_client_id_fkey
|
||||
||
|
||||
-- /projects?select=client_id(*)
|
||||
matchFKSingleCol (Just target) relCardinality -- client_id
|
||||
) && (
|
||||
isNothing hint || -- hint is optional
|
||||
case hint of
|
||||
Nothing ->
|
||||
-- /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
|
||||
Just hnt ->
|
||||
(
|
||||
-- /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(*)
|
||||
matchConstraint hint relCardinality || -- projects_client_id_fkey
|
||||
-- /projects?select=clients!client_id(*) or /projects?select=clients!id(*)
|
||||
matchFKSingleCol hnt relCardinality || -- client_id
|
||||
matchFKRefSingleCol hnt relCardinality || -- id
|
||||
|
||||
-- /projects?select=clients!client_id(*) or /projects?select=clients!id(*)
|
||||
matchFKSingleCol hint relCardinality || -- client_id
|
||||
matchFKRefSingleCol hint relCardinality || -- id
|
||||
|
||||
-- /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
|
||||
-- /users?select=tasks!users_tasks(*) many-to-many between users and tasks
|
||||
matchJunction hnt relCardinality -- users_tasks
|
||||
)
|
||||
) $ fromMaybe mempty $ M.lookup (QualifiedIdentifier schema origin, schema) allRels
|
||||
|
||||
-- previousAlias is only used for the case of self joins
|
||||
addJoinConditions :: Maybe Alias -> ReadRequest -> Either ApiRequestError ReadRequest
|
||||
|
||||
@@ -26,7 +26,7 @@ spec =
|
||||
it "accepts application/json" $
|
||||
request methodGet "/"
|
||||
[("Accept", "application/json")] "" `shouldRespondWith`
|
||||
[json| {
|
||||
"qiSchema":"test","qiName":"bars"
|
||||
} |]
|
||||
[json|
|
||||
[{"qiSchema":"test","qiName":"authors_w_entities"},"test"]
|
||||
|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
Reference in New Issue
Block a user