refactor: remove Table from Relationship
Just having the QualifiedIdentifier gets us closer to having Relationship as a Table attribute since it avoids a cyclic dependency * remove unnecessary findTable * modify RootSpec test
This commit is contained in:
committed by
Steve Chavez
parent
cdcc175abf
commit
7f1507b9fb
@@ -63,8 +63,7 @@ import PostgREST.Config (AppConfig (..),
|
|||||||
import PostgREST.Config.PgVersion (PgVersion (..))
|
import PostgREST.Config.PgVersion (PgVersion (..))
|
||||||
import PostgREST.ContentType (ContentType (..))
|
import PostgREST.ContentType (ContentType (..))
|
||||||
import PostgREST.DbStructure (DbStructure (..),
|
import PostgREST.DbStructure (DbStructure (..),
|
||||||
findIfView, findTable,
|
findIfView, tablePKCols)
|
||||||
tablePKCols)
|
|
||||||
import PostgREST.DbStructure.Identifiers (FieldName,
|
import PostgREST.DbStructure.Identifiers (FieldName,
|
||||||
QualifiedIdentifier (..),
|
QualifiedIdentifier (..),
|
||||||
Schema)
|
Schema)
|
||||||
@@ -417,7 +416,7 @@ handleDelete identifier context@(RequestContext _ ctxDbStructure ApiRequest{..}
|
|||||||
|
|
||||||
handleInfo :: Monad m => QualifiedIdentifier -> RequestContext -> Handler m Wai.Response
|
handleInfo :: Monad m => QualifiedIdentifier -> RequestContext -> Handler m Wai.Response
|
||||||
handleInfo identifier RequestContext{..} =
|
handleInfo identifier RequestContext{..} =
|
||||||
case findTable identifier $ dbTables ctxDbStructure of
|
case M.lookup identifier $ dbTables ctxDbStructure of
|
||||||
Just table ->
|
Just table ->
|
||||||
return $ Wai.responseLBS HTTP.status200 [allOrigins, allowH table] mempty
|
return $ Wai.responseLBS HTTP.status200 [allOrigins, allowH table] mempty
|
||||||
Nothing ->
|
Nothing ->
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ module PostgREST.DbStructure
|
|||||||
, accessibleTables
|
, accessibleTables
|
||||||
, accessibleProcs
|
, accessibleProcs
|
||||||
, findIfView
|
, findIfView
|
||||||
, findTable
|
|
||||||
, schemaDescription
|
, schemaDescription
|
||||||
, tableCols
|
, tableCols
|
||||||
, tablePKCols
|
, tablePKCols
|
||||||
@@ -57,7 +56,8 @@ import PostgREST.DbStructure.Relationship (Cardinality (..),
|
|||||||
Junction (..),
|
Junction (..),
|
||||||
PrimaryKey (..),
|
PrimaryKey (..),
|
||||||
Relationship (..))
|
Relationship (..))
|
||||||
import PostgREST.DbStructure.Table (Column (..), Table (..), TablesMap)
|
import PostgREST.DbStructure.Table (Column (..), Table (..),
|
||||||
|
TablesMap)
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
import Protolude.Unsafe (unsafeHead)
|
import Protolude.Unsafe (unsafeHead)
|
||||||
@@ -80,11 +80,8 @@ tableCols dbs tSchema tName = filter (\Column{colTable=Table{tableSchema=s, tabl
|
|||||||
tablePKCols :: DbStructure -> Schema -> TableName -> [Text]
|
tablePKCols :: DbStructure -> Schema -> TableName -> [Text]
|
||||||
tablePKCols dbs tSchema tName = pkName <$> filter (\pk -> tSchema == (tableSchema . pkTable) pk && tName == (tableName . pkTable) pk) (dbPrimaryKeys dbs)
|
tablePKCols dbs tSchema tName = pkName <$> filter (\pk -> tSchema == (tableSchema . pkTable) pk && tName == (tableName . pkTable) pk) (dbPrimaryKeys dbs)
|
||||||
|
|
||||||
findTable :: QualifiedIdentifier -> TablesMap -> Maybe Table
|
|
||||||
findTable identifier tbls = M.lookup identifier tbls
|
|
||||||
|
|
||||||
findIfView :: QualifiedIdentifier -> TablesMap -> Bool
|
findIfView :: QualifiedIdentifier -> TablesMap -> Bool
|
||||||
findIfView identifier tbls = maybe False tableIsView $ findTable identifier tbls
|
findIfView identifier tbls = maybe False tableIsView $ M.lookup identifier tbls
|
||||||
|
|
||||||
-- | The source table column a view column refers to
|
-- | The source table column a view column refers to
|
||||||
type SourceColumn = (Column, ViewColumn)
|
type SourceColumn = (Column, ViewColumn)
|
||||||
@@ -100,7 +97,7 @@ queryDbStructure schemas extraSearchPath prepared = do
|
|||||||
tabs <- SQL.statement mempty $ allTables pgVer prepared
|
tabs <- SQL.statement mempty $ allTables pgVer prepared
|
||||||
cols <- SQL.statement schemas $ allColumns tabs prepared
|
cols <- SQL.statement schemas $ allColumns tabs prepared
|
||||||
srcCols <- SQL.statement (schemas, extraSearchPath) $ pfkSourceColumns cols prepared
|
srcCols <- SQL.statement (schemas, extraSearchPath) $ pfkSourceColumns cols prepared
|
||||||
m2oRels <- SQL.statement mempty $ allM2ORels tabs cols prepared
|
m2oRels <- SQL.statement mempty $ allM2ORels cols prepared
|
||||||
keys <- SQL.statement mempty $ allPrimaryKeys tabs prepared
|
keys <- SQL.statement mempty $ allPrimaryKeys tabs prepared
|
||||||
procs <- SQL.statement schemas $ allProcs pgVer prepared
|
procs <- SQL.statement schemas $ allProcs pgVer prepared
|
||||||
|
|
||||||
@@ -121,15 +118,15 @@ 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
|
||||||
, dbColumns = filter (\x -> tableSchema (colTable x) `elem` schemas) (dbColumns dbStruct)
|
, dbColumns = filter (\x -> tableSchema (colTable x) `elem` schemas) (dbColumns dbStruct)
|
||||||
, dbRelationships = filter (\x -> tableSchema (relTable x) `elem` schemas &&
|
, dbRelationships = filter (\x -> qiSchema (relTable x) `elem` schemas &&
|
||||||
tableSchema (relForeignTable x) `elem` schemas &&
|
qiSchema (relForeignTable x) `elem` schemas &&
|
||||||
not (hasInternalJunction x)) $ dbRelationships dbStruct
|
not (hasInternalJunction x)) $ dbRelationships dbStruct
|
||||||
, dbPrimaryKeys = filter (\x -> tableSchema (pkTable x) `elem` schemas) $ dbPrimaryKeys dbStruct
|
, dbPrimaryKeys = filter (\x -> tableSchema (pkTable x) `elem` schemas) $ dbPrimaryKeys 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
|
||||||
hasInternalJunction rel = case relCardinality rel of
|
hasInternalJunction rel = case relCardinality rel of
|
||||||
M2M Junction{junTable} -> tableSchema junTable `notElem` schemas
|
M2M Junction{junTable} -> qiSchema junTable `notElem` schemas
|
||||||
_ -> False
|
_ -> False
|
||||||
|
|
||||||
decodeTables :: HD.Result TablesMap
|
decodeTables :: HD.Result TablesMap
|
||||||
@@ -160,9 +157,9 @@ decodeColumns tables =
|
|||||||
<*> nullableColumn HD.text
|
<*> nullableColumn HD.text
|
||||||
<*> nullableColumn HD.text
|
<*> nullableColumn HD.text
|
||||||
|
|
||||||
decodeRels :: TablesMap -> [Column] -> HD.Result [Relationship]
|
decodeRels :: [Column] -> HD.Result [Relationship]
|
||||||
decodeRels tables cols =
|
decodeRels cols =
|
||||||
mapMaybe (relFromRow tables cols) <$> HD.rowList relRow
|
mapMaybe (relFromRow cols) <$> HD.rowList relRow
|
||||||
where
|
where
|
||||||
relRow = (,,,,,,)
|
relRow = (,,,,,,)
|
||||||
<$> column HD.text
|
<$> column HD.text
|
||||||
@@ -378,8 +375,8 @@ addViewM2ORels allSrcCols = concatMap (\rel@Relationship{..} -> rel :
|
|||||||
filter (\(c, _) -> c `elem` relCols) allSrcCols
|
filter (\(c, _) -> c `elem` relCols) allSrcCols
|
||||||
relSrcCols = srcColsGroupedByView relColumns
|
relSrcCols = srcColsGroupedByView relColumns
|
||||||
relFSrcCols = srcColsGroupedByView relForeignColumns
|
relFSrcCols = srcColsGroupedByView relForeignColumns
|
||||||
getView :: [SourceColumn] -> Table
|
getView :: [SourceColumn] -> QualifiedIdentifier
|
||||||
getView = colTable . snd . unsafeHead
|
getView = (\t -> QualifiedIdentifier (tableSchema t) (tableName t)) . colTable . snd . unsafeHead
|
||||||
srcCols `allSrcColsOf` cols = S.fromList (fst <$> srcCols) == S.fromList cols
|
srcCols `allSrcColsOf` cols = S.fromList (fst <$> srcCols) == S.fromList cols
|
||||||
-- Relationship is dependent on the order of relColumns and relFColumns to get the join conditions right in the generated query.
|
-- Relationship is dependent on the order of relColumns and relFColumns to get the join conditions right in the generated query.
|
||||||
-- So we need to change the order of the SourceColumns to match the relColumns
|
-- So we need to change the order of the SourceColumns to match the relColumns
|
||||||
@@ -612,13 +609,13 @@ columnFromRow :: TablesMap ->
|
|||||||
columnFromRow tabs (s, t, n, desc, nul, typ, l, d, e) = buildColumn <$> table
|
columnFromRow tabs (s, t, n, desc, nul, typ, l, d, e) = buildColumn <$> table
|
||||||
where
|
where
|
||||||
buildColumn tbl = Column tbl n desc nul typ l d (parseEnum e)
|
buildColumn tbl = Column tbl n desc nul typ l d (parseEnum e)
|
||||||
table = findTable (QualifiedIdentifier s t) tabs
|
table = M.lookup (QualifiedIdentifier s t) tabs
|
||||||
parseEnum :: Maybe Text -> [Text]
|
parseEnum :: Maybe Text -> [Text]
|
||||||
parseEnum = maybe [] (split (==','))
|
parseEnum = maybe [] (split (==','))
|
||||||
|
|
||||||
allM2ORels :: TablesMap -> [Column] -> Bool -> SQL.Statement () [Relationship]
|
allM2ORels :: [Column] -> Bool -> SQL.Statement () [Relationship]
|
||||||
allM2ORels tabs cols =
|
allM2ORels allCols =
|
||||||
SQL.Statement sql HE.noParams (decodeRels tabs cols)
|
SQL.Statement sql HE.noParams (decodeRels allCols)
|
||||||
where
|
where
|
||||||
sql = [q|
|
sql = [q|
|
||||||
SELECT ns1.nspname AS table_schema,
|
SELECT ns1.nspname AS table_schema,
|
||||||
@@ -643,13 +640,11 @@ allM2ORels tabs cols =
|
|||||||
WHERE confrelid != 0
|
WHERE confrelid != 0
|
||||||
ORDER BY (conrelid, column_info.nums) |]
|
ORDER BY (conrelid, column_info.nums) |]
|
||||||
|
|
||||||
relFromRow :: TablesMap -> [Column] -> (Text, Text, Text, [Text], Text, Text, [Text]) -> Maybe Relationship
|
relFromRow :: [Column] -> (Text, Text, Text, [Text], Text, Text, [Text]) -> Maybe Relationship
|
||||||
relFromRow allTabs allCols (rs, rt, cn, rcs, frs, frt, frcs) =
|
relFromRow allCols (rs, rt, cn, rcs, frs, frt, frcs) =
|
||||||
Relationship <$> table <*> cols <*> tableF <*> colsF <*> pure (M2O cn)
|
Relationship (QualifiedIdentifier rs rt) <$> cols <*> pure (QualifiedIdentifier frs frt) <*> colsF <*> pure (M2O cn)
|
||||||
where
|
where
|
||||||
findCol s t c = find (\col -> tableSchema (colTable col) == s && tableName (colTable col) == t && colName col == c) allCols
|
findCol s t c = find (\col -> tableSchema (colTable col) == s && tableName (colTable col) == t && colName col == c) allCols
|
||||||
table = findTable (QualifiedIdentifier rs rt) allTabs
|
|
||||||
tableF = findTable (QualifiedIdentifier frs frt) allTabs
|
|
||||||
cols = mapM (findCol rs rt) rcs
|
cols = mapM (findCol rs rt) rcs
|
||||||
colsF = mapM (findCol frs frt) frcs
|
colsF = mapM (findCol frs frt) frcs
|
||||||
|
|
||||||
@@ -731,7 +726,7 @@ allPrimaryKeys tabs =
|
|||||||
|
|
||||||
pkFromRow :: TablesMap -> (Schema, Text, Text) -> Maybe PrimaryKey
|
pkFromRow :: TablesMap -> (Schema, Text, Text) -> Maybe PrimaryKey
|
||||||
pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n
|
pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n
|
||||||
where table = findTable (QualifiedIdentifier s t) tabs
|
where table = M.lookup (QualifiedIdentifier s t) tabs
|
||||||
|
|
||||||
-- returns all the primary and foreign key columns which are referenced in views
|
-- returns all the primary and foreign key columns which are referenced in views
|
||||||
pfkSourceColumns :: [Column] -> Bool -> SQL.Statement ([Schema], [Schema]) [SourceColumn]
|
pfkSourceColumns :: [Column] -> Bool -> SQL.Statement ([Schema], [Schema]) [SourceColumn]
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ module PostgREST.DbStructure.Relationship
|
|||||||
|
|
||||||
import qualified Data.Aeson as JSON
|
import qualified Data.Aeson as JSON
|
||||||
|
|
||||||
import PostgREST.DbStructure.Table (Column (..), Table (..))
|
import PostgREST.DbStructure.Identifiers (QualifiedIdentifier)
|
||||||
|
import PostgREST.DbStructure.Table (Column (..), Table)
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
@@ -23,9 +24,9 @@ import Protolude
|
|||||||
--
|
--
|
||||||
-- TODO merge relColumns and relForeignColumns to a tuple or Data.Bimap
|
-- TODO merge relColumns and relForeignColumns to a tuple or Data.Bimap
|
||||||
data Relationship = Relationship
|
data Relationship = Relationship
|
||||||
{ relTable :: Table
|
{ relTable :: QualifiedIdentifier
|
||||||
, relColumns :: [Column]
|
, relColumns :: [Column]
|
||||||
, relForeignTable :: Table
|
, relForeignTable :: QualifiedIdentifier
|
||||||
, relForeignColumns :: [Column]
|
, relForeignColumns :: [Column]
|
||||||
, relCardinality :: Cardinality
|
, relCardinality :: Cardinality
|
||||||
}
|
}
|
||||||
@@ -44,7 +45,7 @@ type FKConstraint = Text
|
|||||||
|
|
||||||
-- | Junction table on an M2M relationship
|
-- | Junction table on an M2M relationship
|
||||||
data Junction = Junction
|
data Junction = Junction
|
||||||
{ junTable :: Table
|
{ junTable :: QualifiedIdentifier
|
||||||
, junConstraint1 :: FKConstraint
|
, junConstraint1 :: FKConstraint
|
||||||
, junColumns1 :: [Column]
|
, junColumns1 :: [Column]
|
||||||
, junConstraint2 :: FKConstraint
|
, junConstraint2 :: FKConstraint
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
module PostgREST.DbStructure.Table
|
module PostgREST.DbStructure.Table
|
||||||
( Column(..)
|
( Column(..)
|
||||||
, Table(..)
|
, Table(..)
|
||||||
, tableQi
|
|
||||||
, TablesMap
|
, TablesMap
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@@ -34,9 +33,6 @@ data Table = Table
|
|||||||
instance Eq Table where
|
instance Eq Table where
|
||||||
Table{tableSchema=s1,tableName=n1} == Table{tableSchema=s2,tableName=n2} = s1 == s2 && n1 == n2
|
Table{tableSchema=s1,tableName=n1} == Table{tableSchema=s2,tableName=n2} = s1 == s2 && n1 == n2
|
||||||
|
|
||||||
tableQi :: Table -> QualifiedIdentifier
|
|
||||||
tableQi Table{tableSchema=s, tableName=n} = QualifiedIdentifier s n
|
|
||||||
|
|
||||||
data Column = Column
|
data Column = Column
|
||||||
{ colTable :: Table
|
{ colTable :: Table
|
||||||
, colName :: FieldName
|
, colName :: FieldName
|
||||||
|
|||||||
@@ -34,12 +34,13 @@ import qualified PostgREST.ContentType as ContentType
|
|||||||
import PostgREST.Request.Types (ApiRequestError (..),
|
import PostgREST.Request.Types (ApiRequestError (..),
|
||||||
QPError (..))
|
QPError (..))
|
||||||
|
|
||||||
|
import PostgREST.DbStructure.Identifiers (QualifiedIdentifier (..))
|
||||||
import PostgREST.DbStructure.Proc (ProcDescription (..),
|
import PostgREST.DbStructure.Proc (ProcDescription (..),
|
||||||
ProcParam (..))
|
ProcParam (..))
|
||||||
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
||||||
Junction (..),
|
Junction (..),
|
||||||
Relationship (..))
|
Relationship (..))
|
||||||
import PostgREST.DbStructure.Table (Column (..), Table (..))
|
import PostgREST.DbStructure.Table (Column (..))
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
@@ -153,28 +154,28 @@ compressedRel Relationship{..} =
|
|||||||
fmtEls els = "(" <> T.intercalate ", " els <> ")"
|
fmtEls els = "(" <> T.intercalate ", " els <> ")"
|
||||||
in
|
in
|
||||||
JSON.object $
|
JSON.object $
|
||||||
("embedding" .= (tableName relTable <> " with " <> tableName relForeignTable :: Text))
|
("embedding" .= (qiName relTable <> " with " <> qiName relForeignTable :: Text))
|
||||||
: case relCardinality of
|
: case relCardinality of
|
||||||
M2M Junction{..} -> [
|
M2M Junction{..} -> [
|
||||||
"cardinality" .= ("many-to-many" :: Text)
|
"cardinality" .= ("many-to-many" :: Text)
|
||||||
, "relationship" .= (tableName junTable <> " using " <> junConstraint1 <> fmtEls (colName <$> junColumns1) <> " and " <> junConstraint2 <> fmtEls (colName <$> junColumns2))
|
, "relationship" .= (qiName junTable <> " using " <> junConstraint1 <> fmtEls (colName <$> junColumns1) <> " and " <> junConstraint2 <> fmtEls (colName <$> junColumns2))
|
||||||
]
|
]
|
||||||
M2O cons -> [
|
M2O cons -> [
|
||||||
"cardinality" .= ("many-to-one" :: Text)
|
"cardinality" .= ("many-to-one" :: Text)
|
||||||
, "relationship" .= (cons <> " using " <> tableName relTable <> fmtEls (colName <$> relColumns) <> " and " <> tableName relForeignTable <> fmtEls (colName <$> relForeignColumns))
|
, "relationship" .= (cons <> " using " <> qiName relTable <> fmtEls (colName <$> relColumns) <> " and " <> qiName relForeignTable <> fmtEls (colName <$> relForeignColumns))
|
||||||
]
|
]
|
||||||
O2M cons -> [
|
O2M cons -> [
|
||||||
"cardinality" .= ("one-to-many" :: Text)
|
"cardinality" .= ("one-to-many" :: Text)
|
||||||
, "relationship" .= (cons <> " using " <> tableName relTable <> fmtEls (colName <$> relColumns) <> " and " <> tableName relForeignTable <> fmtEls (colName <$> relForeignColumns))
|
, "relationship" .= (cons <> " using " <> qiName relTable <> fmtEls (colName <$> relColumns) <> " and " <> qiName relForeignTable <> fmtEls (colName <$> relForeignColumns))
|
||||||
]
|
]
|
||||||
|
|
||||||
relHint :: [Relationship] -> Text
|
relHint :: [Relationship] -> Text
|
||||||
relHint rels = T.intercalate ", " (hintList <$> rels)
|
relHint rels = T.intercalate ", " (hintList <$> rels)
|
||||||
where
|
where
|
||||||
hintList Relationship{..} =
|
hintList Relationship{..} =
|
||||||
let buildHint rel = "'" <> tableName relForeignTable <> "!" <> rel <> "'" in
|
let buildHint rel = "'" <> qiName relForeignTable <> "!" <> rel <> "'" in
|
||||||
case relCardinality of
|
case relCardinality of
|
||||||
M2M Junction{..} -> buildHint (tableName junTable)
|
M2M Junction{..} -> buildHint (qiName junTable)
|
||||||
M2O cons -> buildHint cons
|
M2O cons -> buildHint cons
|
||||||
O2M cons -> buildHint cons
|
O2M cons -> buildHint cons
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ import PostgREST.Config (AppConfig (..), Proxy (..),
|
|||||||
isMalformedProxyUri, toURI)
|
isMalformedProxyUri, toURI)
|
||||||
import PostgREST.DbStructure (DbStructure (..),
|
import PostgREST.DbStructure (DbStructure (..),
|
||||||
tableCols, tablePKCols)
|
tableCols, tablePKCols)
|
||||||
|
import PostgREST.DbStructure.Identifiers (QualifiedIdentifier (..))
|
||||||
import PostgREST.DbStructure.Proc (ProcDescription (..),
|
import PostgREST.DbStructure.Proc (ProcDescription (..),
|
||||||
ProcParam (..))
|
ProcParam (..))
|
||||||
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
||||||
PrimaryKey (..),
|
PrimaryKey (..),
|
||||||
Relationship (..))
|
Relationship (..))
|
||||||
import PostgREST.DbStructure.Table (Column (..), Table (..), TablesMap)
|
import PostgREST.DbStructure.Table (Column (..), Table (..),
|
||||||
|
TablesMap)
|
||||||
import PostgREST.Version (docsVersion, prettyVersion)
|
import PostgREST.Version (docsVersion, prettyVersion)
|
||||||
|
|
||||||
import PostgREST.ContentType
|
import PostgREST.ContentType
|
||||||
@@ -103,7 +105,7 @@ makeProperty rels pks c = (colName c, Inline s)
|
|||||||
_ -> False
|
_ -> False
|
||||||
) rels
|
) rels
|
||||||
fCol = colName <$> (headMay . relForeignColumns =<< rel)
|
fCol = colName <$> (headMay . relForeignColumns =<< rel)
|
||||||
fTbl = tableName . relForeignTable <$> rel
|
fTbl = qiName . relForeignTable <$> rel
|
||||||
fTblCol = (,) <$> fTbl <*> fCol
|
fTblCol = (,) <$> fTbl <*> fCol
|
||||||
in
|
in
|
||||||
(\(a, b) -> T.intercalate "" ["This is a Foreign Key to `", a, ".", b, "`.<fk table='", a, "' column='", b, "'/>"]) <$> fTblCol
|
(\(a, b) -> T.intercalate "" ["This is a Foreign Key to `", a, ".", b, "`.<fk table='", a, "' column='", b, "'/>"]) <$> fTblCol
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import PostgREST.DbStructure.Identifiers (QualifiedIdentifier (..))
|
|||||||
import PostgREST.DbStructure.Proc (ProcParam (..))
|
import PostgREST.DbStructure.Proc (ProcParam (..))
|
||||||
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
||||||
Relationship (..))
|
Relationship (..))
|
||||||
import PostgREST.DbStructure.Table (Table (..))
|
|
||||||
import PostgREST.Request.Preferences (PreferResolution (..))
|
import PostgREST.Request.Preferences (PreferResolution (..))
|
||||||
|
|
||||||
import PostgREST.Query.SqlFragment
|
import PostgREST.Query.SqlFragment
|
||||||
@@ -51,7 +50,7 @@ readRequestToQuery (Node (Select colSelects mainQi tblAlias implJoins logicFores
|
|||||||
(joins, selects) = foldr getJoinsSelects ([],[]) forest
|
(joins, selects) = foldr getJoinsSelects ([],[]) forest
|
||||||
|
|
||||||
getJoinsSelects :: ReadRequest -> ([SQL.Snippet], [SQL.Snippet]) -> ([SQL.Snippet], [SQL.Snippet])
|
getJoinsSelects :: ReadRequest -> ([SQL.Snippet], [SQL.Snippet]) -> ([SQL.Snippet], [SQL.Snippet])
|
||||||
getJoinsSelects rr@(Node (_, (name, Just Relationship{relCardinality=card,relTable=Table{tableName=table}}, alias, _, joinType, _)) _) (joins,selects) =
|
getJoinsSelects rr@(Node (_, (name, Just Relationship{relCardinality=card,relTable=QualifiedIdentifier{qiName=table}}, alias, _, joinType, _)) _) (joins,selects) =
|
||||||
let subquery = readRequestToQuery rr in
|
let subquery = readRequestToQuery rr in
|
||||||
case card of
|
case card of
|
||||||
M2O _ ->
|
M2O _ ->
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ import PostgREST.DbStructure.Proc (ProcDescription (..),
|
|||||||
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
import PostgREST.DbStructure.Relationship (Cardinality (..),
|
||||||
Junction (..),
|
Junction (..),
|
||||||
Relationship (..))
|
Relationship (..))
|
||||||
import PostgREST.DbStructure.Table (Column (..), Table (..),
|
import PostgREST.DbStructure.Table (Column (..))
|
||||||
tableQi)
|
|
||||||
import PostgREST.Error (Error (..))
|
import PostgREST.Error (Error (..))
|
||||||
import PostgREST.Query.SqlFragment (sourceCTEName)
|
import PostgREST.Query.SqlFragment (sourceCTEName)
|
||||||
import PostgREST.RangeQuery (NonnegRange, allRange,
|
import PostgREST.RangeQuery (NonnegRange, allRange,
|
||||||
@@ -88,7 +87,7 @@ rootWithRels schema rootTableName allRels action = case action of
|
|||||||
-- findRel can find relationships with sourceCTEName.
|
-- findRel can find relationships with sourceCTEName.
|
||||||
toSourceRel :: Relationship -> Maybe Relationship
|
toSourceRel :: Relationship -> Maybe Relationship
|
||||||
toSourceRel r@Relationship{relTable=t}
|
toSourceRel r@Relationship{relTable=t}
|
||||||
| rootTableName == tableName t = Just $ r {relTable=t {tableName=_sourceCTEName}}
|
| rootTableName == qiName t = Just $ r {relTable=t {qiName=_sourceCTEName}}
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
-- Build the initial tree with a Depth attribute so when a self join occurs we
|
-- Build the initial tree with a Depth attribute so when a self join occurs we
|
||||||
@@ -131,7 +130,7 @@ addRels :: Schema -> [Relationship] -> Maybe ReadRequest -> ReadRequest -> Eithe
|
|||||||
addRels schema allRels parentNode (Node (query@Select{from=tbl}, (nodeName, _, alias, hint, joinType, depth)) forest) =
|
addRels schema allRels parentNode (Node (query@Select{from=tbl}, (nodeName, _, alias, hint, joinType, depth)) forest) =
|
||||||
case parentNode of
|
case parentNode of
|
||||||
Just (Node (Select{from=parentNodeQi}, _) _) ->
|
Just (Node (Select{from=parentNodeQi}, _) _) ->
|
||||||
let newFrom r = if qiName tbl == nodeName then tableQi (relForeignTable r) else tbl
|
let newFrom r = if qiName tbl == nodeName then relForeignTable r else tbl
|
||||||
newReadNode = (\r -> (query{from=newFrom r}, (nodeName, Just r, alias, hint, joinType, depth))) <$> rel
|
newReadNode = (\r -> (query{from=newFrom r}, (nodeName, Just r, alias, hint, joinType, depth))) <$> rel
|
||||||
rel = findRel schema allRels (qiName parentNodeQi) nodeName hint
|
rel = findRel schema allRels (qiName parentNodeQi) nodeName hint
|
||||||
in
|
in
|
||||||
@@ -175,25 +174,25 @@ findRel schema allRels origin target hint =
|
|||||||
M2O cons -> tar == Just cons
|
M2O cons -> tar == Just cons
|
||||||
_ -> False
|
_ -> False
|
||||||
matchJunction hint_ card = case card of
|
matchJunction hint_ card = case card of
|
||||||
M2M Junction{junTable} -> hint_ == Just (tableName junTable)
|
M2M Junction{junTable} -> hint_ == Just (qiName junTable)
|
||||||
_ -> False
|
_ -> False
|
||||||
rel = filter (
|
rel = filter (
|
||||||
\Relationship{..} ->
|
\Relationship{..} ->
|
||||||
-- Both relationship ends need to be on the exposed schema
|
-- Both relationship ends need to be on the exposed schema
|
||||||
schema == tableSchema relTable && schema == tableSchema relForeignTable &&
|
schema == qiSchema relTable && schema == qiSchema relForeignTable &&
|
||||||
(
|
(
|
||||||
-- /projects?select=clients(*)
|
-- /projects?select=clients(*)
|
||||||
origin == tableName relTable && -- projects
|
origin == qiName relTable && -- projects
|
||||||
target == tableName relForeignTable || -- clients
|
target == qiName relForeignTable || -- clients
|
||||||
|
|
||||||
-- /projects?select=projects_client_id_fkey(*)
|
-- /projects?select=projects_client_id_fkey(*)
|
||||||
(
|
(
|
||||||
origin == tableName relTable && -- projects
|
origin == qiName relTable && -- projects
|
||||||
matchConstraint (Just target) relCardinality -- projects_client_id_fkey
|
matchConstraint (Just target) relCardinality -- projects_client_id_fkey
|
||||||
) ||
|
) ||
|
||||||
-- /projects?select=client_id(*)
|
-- /projects?select=client_id(*)
|
||||||
(
|
(
|
||||||
origin == tableName relTable && -- projects
|
origin == qiName relTable && -- projects
|
||||||
matchFKSingleCol (Just target) relColumns -- client_id
|
matchFKSingleCol (Just target) relColumns -- client_id
|
||||||
)
|
)
|
||||||
) && (
|
) && (
|
||||||
@@ -217,7 +216,7 @@ addJoinConditions previousAlias (Node node@(query@Select{from=tbl}, nodeProps@(_
|
|||||||
case rel of
|
case rel of
|
||||||
Just r@Relationship{relCardinality=M2M Junction{junTable}} ->
|
Just r@Relationship{relCardinality=M2M Junction{junTable}} ->
|
||||||
let rq = augmentQuery r in
|
let rq = augmentQuery r in
|
||||||
Node (rq{implicitJoins=tableQi junTable:implicitJoins rq}, nodeProps) <$> updatedForest
|
Node (rq{implicitJoins=junTable:implicitJoins rq}, nodeProps) <$> updatedForest
|
||||||
Just r -> Node (augmentQuery r, nodeProps) <$> updatedForest
|
Just r -> Node (augmentQuery r, nodeProps) <$> updatedForest
|
||||||
Nothing -> Node node <$> updatedForest
|
Nothing -> Node node <$> updatedForest
|
||||||
where
|
where
|
||||||
@@ -235,9 +234,9 @@ addJoinConditions previousAlias (Node node@(query@Select{from=tbl}, nodeProps@(_
|
|||||||
|
|
||||||
-- previousAlias and newAlias are used in the case of self joins
|
-- previousAlias and newAlias are used in the case of self joins
|
||||||
getJoinConditions :: Maybe Alias -> Maybe Alias -> Relationship -> [JoinCondition]
|
getJoinConditions :: Maybe Alias -> Maybe Alias -> Relationship -> [JoinCondition]
|
||||||
getJoinConditions previousAlias newAlias (Relationship Table{tableSchema=tSchema, tableName=tN} cols Table{tableName=ftN} fCols card) =
|
getJoinConditions previousAlias newAlias (Relationship QualifiedIdentifier{qiSchema=tSchema, qiName=tN} cols QualifiedIdentifier{qiName=ftN} fCols card) =
|
||||||
case card of
|
case card of
|
||||||
M2M (Junction Table{tableName=jtn} _ jc1 _ jc2) ->
|
M2M (Junction QualifiedIdentifier{qiName=jtn} _ jc1 _ jc2) ->
|
||||||
zipWith (toJoinCondition tN jtn) cols jc1 ++ zipWith (toJoinCondition ftN jtn) fCols jc2
|
zipWith (toJoinCondition tN jtn) cols jc1 ++ zipWith (toJoinCondition ftN jtn) fCols jc2
|
||||||
_ ->
|
_ ->
|
||||||
zipWith (toJoinCondition tN ftN) cols fCols
|
zipWith (toJoinCondition tN ftN) cols fCols
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ spec =
|
|||||||
request methodGet "/"
|
request methodGet "/"
|
||||||
[("Accept", "application/json")] "" `shouldRespondWith`
|
[("Accept", "application/json")] "" `shouldRespondWith`
|
||||||
[json| {
|
[json| {
|
||||||
"tableName": "orders_view", "tableSchema": "test",
|
"qiSchema":"test","qiName":"orders_view"
|
||||||
"tableDeletable": true, "tableUpdatable": true,
|
|
||||||
"tableIsView":true, "tableInsertable": true,
|
|
||||||
"tableDescription": null
|
|
||||||
} |]
|
} |]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|||||||
Reference in New Issue
Block a user