diff --git a/postgrest.cabal b/postgrest.cabal index ea93096bd..1ee117302 100644 --- a/postgrest.cabal +++ b/postgrest.cabal @@ -45,7 +45,7 @@ library PostgREST.DbStructure.Identifiers PostgREST.DbStructure.PgVersion PostgREST.DbStructure.Proc - PostgREST.DbStructure.Relation + PostgREST.DbStructure.Relationship PostgREST.DbStructure.Table PostgREST.Error PostgREST.GucHeader diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index 81dd85023..001c5dcbb 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -518,7 +518,7 @@ readRequest :: Monad m => QualifiedIdentifier -> RequestContext -> Handler m Rea readRequest QualifiedIdentifier{..} (RequestContext AppConfig{..} dbStructure apiRequest _) = liftEither $ ReqBuilder.readRequest qiSchema qiName configDbMaxRows - (dbRelations dbStructure) + (dbRelationships dbStructure) apiRequest contentTypeHeaders :: RequestContext -> [HTTP.Header] diff --git a/src/PostgREST/DbStructure.hs b/src/PostgREST/DbStructure.hs index 6c10d36e8..4a6f7b56a 100644 --- a/src/PostgREST/DbStructure.hs +++ b/src/PostgREST/DbStructure.hs @@ -43,19 +43,19 @@ import Data.Set as S (fromList) import Data.Text (split) import Text.InterpolatedString.Perl6 (q) -import PostgREST.DbStructure.Identifiers (QualifiedIdentifier (..), - Schema, TableName) -import PostgREST.DbStructure.PgVersion (PgVersion (..)) -import PostgREST.DbStructure.Proc (PgArg (..), PgType (..), - ProcDescription (..), - ProcVolatility (..), - ProcsMap, RetType (..)) -import PostgREST.DbStructure.Relation (Cardinality (..), - ForeignKey (..), - Junction (..), - PrimaryKey (..), - Relation (..)) -import PostgREST.DbStructure.Table (Column (..), Table (..)) +import PostgREST.DbStructure.Identifiers (QualifiedIdentifier (..), + Schema, TableName) +import PostgREST.DbStructure.PgVersion (PgVersion (..)) +import PostgREST.DbStructure.Proc (PgArg (..), PgType (..), + ProcDescription (..), + ProcVolatility (..), + ProcsMap, RetType (..)) +import PostgREST.DbStructure.Relationship (Cardinality (..), + ForeignKey (..), + Junction (..), + PrimaryKey (..), + Relationship (..)) +import PostgREST.DbStructure.Table (Column (..), Table (..)) import Protolude hiding (toS) import Protolude.Conv (toS) @@ -63,12 +63,12 @@ import Protolude.Unsafe (unsafeHead) data DbStructure = DbStructure - { dbTables :: [Table] - , dbColumns :: [Column] - , dbRelations :: [Relation] - , dbPrimaryKeys :: [PrimaryKey] - , dbProcs :: ProcsMap - , pgVersion :: PgVersion + { dbTables :: [Table] + , dbColumns :: [Column] + , dbRelationships :: [Relationship] + , dbPrimaryKeys :: [PrimaryKey] + , dbProcs :: ProcsMap + , pgVersion :: PgVersion } deriving (Generic, JSON.ToJSON) @@ -104,7 +104,7 @@ getDbStructure schemas extraSearchPath pgVer prepared = do return DbStructure { dbTables = tabs , dbColumns = cols' - , dbRelations = rels + , dbRelationships = rels , dbPrimaryKeys = keys' , dbProcs = procs , pgVersion = pgVer @@ -135,7 +135,7 @@ decodeColumns tables = <*> nullableColumn HD.text <*> nullableColumn HD.text -decodeRels :: [Table] -> [Column] -> HD.Result [Relation] +decodeRels :: [Table] -> [Column] -> HD.Result [Relationship] decodeRels tables cols = mapMaybe (relFromRow tables cols) <$> HD.rowList relRow where @@ -341,28 +341,28 @@ accessibleTables = ) order by relname |] -addForeignKeys :: [Relation] -> [Column] -> [Column] +addForeignKeys :: [Relationship] -> [Column] -> [Column] addForeignKeys rels = map addFk where addFk col = col { colFK = fk col } fk col = find (lookupFn col) rels >>= relToFk col - lookupFn :: Column -> Relation -> Bool + lookupFn :: Column -> Relationship -> Bool lookupFn c rel = case rel of - Relation{relColumns=cs, relCardinality=M2O _} -> c `elem` cs - _ -> False - relToFk col Relation{relColumns=cols, relForeignColumns=colsF} = do + Relationship{relColumns=cs, relCardinality=M2O _} -> c `elem` cs + _ -> False + relToFk col Relationship{relColumns=cols, relForeignColumns=colsF} = do pos <- L.elemIndex col cols colF <- atMay colsF pos return $ ForeignKey colF {- -Adds Views M2O Relations based on SourceColumns found, the logic is as follows: +Adds Views M2O Relationships based on SourceColumns found, the logic is as follows: -Having a Relation{relTable=t1, relColumns=[c1], relFTable=t2, relFColumns=[c2], relCardinality=M2O} represented by: +Having a Relationship{relTable=t1, relColumns=[c1], relFTable=t2, relFColumns=[c2], relCardinality=M2O} represented by: t1.c1------t2.c2 -When only having a t1_view.c1 source column, we need to add a View-Table M2O Relation +When only having a t1_view.c1 source column, we need to add a View-Table M2O Relationship t1.c1----t2.c2 t1.c1----------t2.c2 -> ________/ @@ -370,24 +370,24 @@ When only having a t1_view.c1 source column, we need to add a View-Table M2O Rel t1_view.c1 t1_view.c1 -When only having a t2_view.c2 source column, we need to add a Table-View M2O Relation +When only having a t2_view.c2 source column, we need to add a Table-View M2O Relationship t1.c1----t2.c2 t1.c1----------t2.c2 -> \________ \ t2_view.c2 t2_view.c1 -When having t1_view.c1 and a t2_view.c2 source columns, we need to add a View-View M2O Relation in addition to the prior +When having t1_view.c1 and a t2_view.c2 source columns, we need to add a View-View M2O Relationship in addition to the prior t1.c1----t2.c2 t1.c1----------t2.c2 -> \________/ / \ t1_view.c1 t2_view.c2 t1_view.c1-------t2_view.c1 -The logic for composite pks is similar just need to make sure all the Relation columns have source columns. +The logic for composite pks is similar just need to make sure all the Relationship columns have source columns. -} -addViewM2ORels :: [SourceColumn] -> [Relation] -> [Relation] -addViewM2ORels allSrcCols = concatMap (\rel@Relation{..} -> rel : +addViewM2ORels :: [SourceColumn] -> [Relationship] -> [Relationship] +addViewM2ORels allSrcCols = concatMap (\rel@Relationship{..} -> rel : let srcColsGroupedByView :: [Column] -> [[SourceColumn]] srcColsGroupedByView relCols = L.groupBy (\(_, viewCol1) (_, viewCol2) -> colTable viewCol1 == colTable viewCol2) $ @@ -397,26 +397,26 @@ addViewM2ORels allSrcCols = concatMap (\rel@Relation{..} -> rel : getView :: [SourceColumn] -> Table getView = colTable . snd . unsafeHead srcCols `allSrcColsOf` cols = S.fromList (fst <$> srcCols) == S.fromList cols - -- Relation 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 - -- TODO: This could be avoided if the Relation type is improved with a structure that maintains the association of relColumns and relFColumns + -- TODO: This could be avoided if the Relationship type is improved with a structure that maintains the association of relColumns and relFColumns srcCols `sortAccordingTo` cols = sortOn (\(k, _) -> L.lookup k $ zip cols [0::Int ..]) srcCols viewTableM2O = - [ Relation + [ Relationship (getView srcCols) (snd <$> srcCols `sortAccordingTo` relColumns) relForeignTable relForeignColumns relCardinality | srcCols <- relSrcCols, srcCols `allSrcColsOf` relColumns ] tableViewM2O = - [ Relation + [ Relationship relTable relColumns (getView fSrcCols) (snd <$> fSrcCols `sortAccordingTo` relForeignColumns) relCardinality | fSrcCols <- relFSrcCols, fSrcCols `allSrcColsOf` relForeignColumns ] viewViewM2O = - [ Relation + [ Relationship (getView srcCols) (snd <$> srcCols `sortAccordingTo` relColumns) (getView fSrcCols) (snd <$> fSrcCols `sortAccordingTo` relForeignColumns) relCardinality @@ -425,14 +425,14 @@ addViewM2ORels allSrcCols = concatMap (\rel@Relation{..} -> rel : in viewTableM2O ++ tableViewM2O ++ viewViewM2O) -addO2MRels :: [Relation] -> [Relation] -addO2MRels rels = rels ++ [ Relation ft fc t c (O2M cons) - | Relation t c ft fc (M2O cons) <- rels ] +addO2MRels :: [Relationship] -> [Relationship] +addO2MRels rels = rels ++ [ Relationship ft fc t c (O2M cons) + | Relationship t c ft fc (M2O cons) <- rels ] -addM2MRels :: [Relation] -> [Relation] -addM2MRels rels = rels ++ [ Relation t c ft fc (M2M $ Junction jt1 cons1 jc1 cons2 jc2) - | Relation jt1 jc1 t c (M2O cons1) <- rels - , Relation jt2 jc2 ft fc (M2O cons2) <- rels +addM2MRels :: [Relationship] -> [Relationship] +addM2MRels rels = rels ++ [ Relationship t c ft fc (M2M $ Junction jt1 cons1 jc1 cons2 jc2) + | Relationship jt1 jc1 t c (M2O cons1) <- rels + , Relationship jt2 jc2 ft fc (M2O cons2) <- rels , jt1 == jt2 , cons1 /= cons2] @@ -602,7 +602,7 @@ columnFromRow tabs (s, t, n, desc, nul, typ, l, d, e) = buildColumn <$> table parseEnum :: Maybe Text -> [Text] parseEnum = maybe [] (split (==',')) -allM2ORels :: [Table] -> [Column] -> Bool -> H.Statement () [Relation] +allM2ORels :: [Table] -> [Column] -> Bool -> H.Statement () [Relationship] allM2ORels tabs cols = H.Statement sql HE.noParams (decodeRels tabs cols) where @@ -629,9 +629,9 @@ allM2ORels tabs cols = WHERE confrelid != 0 ORDER BY (conrelid, column_info.nums) |] -relFromRow :: [Table] -> [Column] -> (Text, Text, Text, [Text], Text, Text, [Text]) -> Maybe Relation +relFromRow :: [Table] -> [Column] -> (Text, Text, Text, [Text], Text, Text, [Text]) -> Maybe Relationship relFromRow allTabs allCols (rs, rt, cn, rcs, frs, frt, frcs) = - Relation <$> table <*> cols <*> tableF <*> colsF <*> pure (M2O cn) + Relationship <$> table <*> cols <*> tableF <*> colsF <*> pure (M2O cn) where findTable s t = find (\tbl -> tableSchema tbl == s && tableName tbl == t) allTabs findCol s t c = find (\col -> tableSchema (colTable col) == s && tableName (colTable col) == t && colName col == c) allCols diff --git a/src/PostgREST/DbStructure/Relation.hs b/src/PostgREST/DbStructure/Relationship.hs similarity index 80% rename from src/PostgREST/DbStructure/Relation.hs rename to src/PostgREST/DbStructure/Relationship.hs index ad83918d3..2c8f9d0bf 100644 --- a/src/PostgREST/DbStructure/Relation.hs +++ b/src/PostgREST/DbStructure/Relationship.hs @@ -1,11 +1,11 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module PostgREST.DbStructure.Relation +module PostgREST.DbStructure.Relationship ( Cardinality(..) , ForeignKey(..) , PrimaryKey(..) - , Relation(..) + , Relationship(..) , Junction(..) , isSelfReference ) where @@ -18,13 +18,13 @@ import PostgREST.DbStructure.Table (Column (..), ForeignKey (..), import Protolude --- | "Relation"ship between two tables. +-- | Relationship between two tables. -- --- The order of the relColumns and relFColumns should be maintained to get the +-- The order of the relColumns and relForeignColumns should be maintained to get the -- join conditions right. -- --- TODO merge relColumns and relFColumns to a tuple or Data.Bimap -data Relation = Relation +-- TODO merge relColumns and relForeignColumns to a tuple or Data.Bimap +data Relationship = Relationship { relTable :: Table , relColumns :: [Column] , relForeignTable :: Table @@ -54,7 +54,7 @@ data Junction = Junction } deriving (Eq, Generic, JSON.ToJSON) -isSelfReference :: Relation -> Bool +isSelfReference :: Relationship -> Bool isSelfReference r = relTable r == relForeignTable r data PrimaryKey = PrimaryKey diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 6fc53aabe..157f5d67e 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -29,9 +29,10 @@ import Network.HTTP.Types.Header (Header) import PostgREST.ContentType (ContentType (..)) import qualified PostgREST.ContentType as ContentType -import PostgREST.DbStructure.Relation (Cardinality (..), - Junction (..), Relation (..)) -import PostgREST.DbStructure.Table (Column (..), Table (..)) +import PostgREST.DbStructure.Relationship (Cardinality (..), + Junction (..), + Relationship (..)) +import PostgREST.DbStructure.Table (Column (..), Table (..)) import Protolude hiding (toS) import Protolude.Conv (toS, toSL) @@ -55,10 +56,9 @@ data ApiRequestError | InvalidBody ByteString | ParseRequestError Text Text | NoRelBetween Text Text - | AmbiguousRelBetween Text Text [Relation] + | AmbiguousRelBetween Text Text [Relationship] | InvalidFilters | UnacceptableSchema [Text] - | UnknownRelation -- Unreachable? | UnsupportedVerb -- Unreachable? instance PgrstError ApiRequestError where @@ -66,7 +66,6 @@ instance PgrstError ApiRequestError where status InvalidFilters = HT.status405 status (InvalidBody _) = HT.status400 status UnsupportedVerb = HT.status405 - status UnknownRelation = HT.status404 status ActionInappropriate = HT.status405 status (ParseRequestError _ _) = HT.status400 status (NoRelBetween _ _) = HT.status400 @@ -84,8 +83,6 @@ instance JSON.ToJSON ApiRequestError where "message" .= (toS errorMessage :: Text)] toJSON InvalidRange = JSON.object [ "message" .= ("HTTP Range error" :: Text)] - toJSON UnknownRelation = JSON.object [ - "message" .= ("Unknown relation" :: Text)] toJSON (NoRelBetween parent child) = JSON.object [ "message" .= ("Could not find foreign keys between these entities. No relationship found between " <> parent <> " and " <> child :: Text)] toJSON (AmbiguousRelBetween parent child rels) = JSON.object [ @@ -99,8 +96,8 @@ instance JSON.ToJSON ApiRequestError where toJSON (UnacceptableSchema schemas) = JSON.object [ "message" .= ("The schema must be one of the following: " <> T.intercalate ", " schemas)] -compressedRel :: Relation -> JSON.Value -compressedRel Relation{..} = +compressedRel :: Relationship -> JSON.Value +compressedRel Relationship{..} = let fmtTbl Table{..} = tableSchema <> "." <> tableName fmtEls els = "[" <> T.intercalate ", " els <> "]" diff --git a/src/PostgREST/OpenAPI.hs b/src/PostgREST/OpenAPI.hs index b839c8322..87e9e34e7 100644 --- a/src/PostgREST/OpenAPI.hs +++ b/src/PostgREST/OpenAPI.hs @@ -21,16 +21,17 @@ import Control.Lens (at, (.~), (?~)) import Data.Swagger -import PostgREST.Config (AppConfig (..), Proxy (..), - isMalformedProxyUri, toURI) -import PostgREST.DbStructure (DbStructure (..), tableCols, - tablePKCols) -import PostgREST.DbStructure.Proc (PgArg (..), - ProcDescription (..)) -import PostgREST.DbStructure.Relation (PrimaryKey (..)) -import PostgREST.DbStructure.Table (Column (..), ForeignKey (..), - Table (..)) -import PostgREST.Version (docsVersion, prettyVersion) +import PostgREST.Config (AppConfig (..), Proxy (..), + isMalformedProxyUri, toURI) +import PostgREST.DbStructure (DbStructure (..), + tableCols, tablePKCols) +import PostgREST.DbStructure.Proc (PgArg (..), + ProcDescription (..)) +import PostgREST.DbStructure.Relationship (PrimaryKey (..)) +import PostgREST.DbStructure.Table (Column (..), + ForeignKey (..), + Table (..)) +import PostgREST.Version (docsVersion, prettyVersion) import PostgREST.ContentType diff --git a/src/PostgREST/Query/QueryBuilder.hs b/src/PostgREST/Query/QueryBuilder.hs index 735375f3a..9854c8bbb 100644 --- a/src/PostgREST/Query/QueryBuilder.hs +++ b/src/PostgREST/Query/QueryBuilder.hs @@ -21,15 +21,15 @@ import qualified Hasql.DynamicStatements.Snippet as H import Data.Tree (Tree (..)) -import PostgREST.DbStructure.Identifiers (FieldName, - QualifiedIdentifier (..)) -import PostgREST.DbStructure.Proc (PgArg (..)) -import PostgREST.DbStructure.Relation (Cardinality (..), - Relation (..)) -import PostgREST.DbStructure.Table (Table (..)) -import PostgREST.Request.ApiRequest (PayloadJSON (..)) -import PostgREST.Request.Preferences (PreferParameters (..), - PreferResolution (..)) +import PostgREST.DbStructure.Identifiers (FieldName, + QualifiedIdentifier (..)) +import PostgREST.DbStructure.Proc (PgArg (..)) +import PostgREST.DbStructure.Relationship (Cardinality (..), + Relationship (..)) +import PostgREST.DbStructure.Table (Table (..)) +import PostgREST.Request.ApiRequest (PayloadJSON (..)) +import PostgREST.Request.Preferences (PreferParameters (..), + PreferResolution (..)) import PostgREST.Query.SqlFragment import PostgREST.Request.Types @@ -53,7 +53,7 @@ readRequestToQuery (Node (Select colSelects mainQi tblAlias implJoins logicFores (joins, selects) = foldr getJoinsSelects ([],[]) forest getJoinsSelects :: ReadRequest -> ([H.Snippet], [H.Snippet]) -> ([H.Snippet], [H.Snippet]) -getJoinsSelects rr@(Node (_, (name, Just Relation{relCardinality=card,relTable=Table{tableName=table}}, alias, _, _)) _) (j,s) = +getJoinsSelects rr@(Node (_, (name, Just Relationship{relCardinality=card,relTable=Table{tableName=table}}, alias, _, _)) _) (j,s) = let subquery = readRequestToQuery rr in case card of M2O _ -> diff --git a/src/PostgREST/Request/DbRequestBuilder.hs b/src/PostgREST/Request/DbRequestBuilder.hs index 88bfd85a0..17d8af81f 100644 --- a/src/PostgREST/Request/DbRequestBuilder.hs +++ b/src/PostgREST/Request/DbRequestBuilder.hs @@ -30,35 +30,35 @@ import Data.List (delete) import Data.Text (isInfixOf) import Data.Tree (Tree (..)) -import PostgREST.DbStructure.Identifiers (FieldName, - QualifiedIdentifier (..), - Schema, TableName) -import PostgREST.DbStructure.Relation (Cardinality (..), - Junction (..), - Relation (..)) -import PostgREST.DbStructure.Table (Column (..), Table (..), - tableQi) -import PostgREST.Error (ApiRequestError (..), - Error (..)) -import PostgREST.Query.SqlFragment (sourceCTEName) -import PostgREST.RangeQuery (NonnegRange, allRange, - restrictRange) -import PostgREST.Request.ApiRequest (Action (..), - ApiRequest (..), - PayloadJSON (..)) +import PostgREST.DbStructure.Identifiers (FieldName, + QualifiedIdentifier (..), + Schema, TableName) +import PostgREST.DbStructure.Relationship (Cardinality (..), + Junction (..), + Relationship (..)) +import PostgREST.DbStructure.Table (Column (..), Table (..), + tableQi) +import PostgREST.Error (ApiRequestError (..), + Error (..)) +import PostgREST.Query.SqlFragment (sourceCTEName) +import PostgREST.RangeQuery (NonnegRange, allRange, + restrictRange) +import PostgREST.Request.ApiRequest (Action (..), + ApiRequest (..), + PayloadJSON (..)) import PostgREST.Request.Parsers import PostgREST.Request.Preferences import PostgREST.Request.Types -import qualified PostgREST.DbStructure.Relation as Relation +import qualified PostgREST.DbStructure.Relationship as Relationship import Protolude hiding (from) -- | Builds the ReadRequest tree on a number of stages. -- | Adds filters, order, limits on its respective nodes. -- | Adds joins conditions obtained from resource embedding. -readRequest :: Schema -> TableName -> Maybe Integer -> [Relation] -> ApiRequest -> Either Error ReadRequest +readRequest :: Schema -> TableName -> Maybe Integer -> [Relationship] -> ApiRequest -> Either Error ReadRequest readRequest schema rootTableName maxRows allRels apiRequest = mapLeft ApiRequestError $ treeRestrictRange maxRows =<< @@ -73,17 +73,17 @@ readRequest schema rootTableName maxRows allRels apiRequest = -- This is done because of the shape of the final SQL Query. The mutation cases -- are wrapped in a WITH {sourceCTEName}(see Statements.hs). So we need a FROM -- {sourceCTEName} instead of FROM {tableName}. -rootWithRels :: Schema -> TableName -> [Relation] -> Action -> (QualifiedIdentifier, [Relation]) +rootWithRels :: Schema -> TableName -> [Relationship] -> Action -> (QualifiedIdentifier, [Relationship]) rootWithRels schema rootTableName allRels action = case action of ActionRead _ -> (QualifiedIdentifier schema rootTableName, allRels) -- normal read case _ -> (QualifiedIdentifier mempty _sourceCTEName, mapMaybe toSourceRel allRels ++ allRels) -- mutation cases and calling proc where _sourceCTEName = decodeUtf8 sourceCTEName -- To enable embedding in the sourceCTEName cases we need to replace the - -- foreign key tableName in the Relation with {sourceCTEName}. This way + -- foreign key tableName in the Relationship with {sourceCTEName}. This way -- findRel can find relationships with sourceCTEName. - toSourceRel :: Relation -> Maybe Relation - toSourceRel r@Relation{relTable=t} + toSourceRel :: Relationship -> Maybe Relationship + toSourceRel r@Relationship{relTable=t} | rootTableName == tableName t = Just $ r {relTable=t {tableName=_sourceCTEName}} | otherwise = Nothing @@ -117,12 +117,12 @@ treeRestrictRange maxRows request = pure $ nodeRestrictRange maxRows <$> request nodeRestrictRange :: Maybe Integer -> ReadNode -> ReadNode nodeRestrictRange m (q@Select {range_=r}, i) = (q{range_=restrictRange m r }, i) -augmentRequestWithJoin :: Schema -> [Relation] -> ReadRequest -> Either ApiRequestError ReadRequest +augmentRequestWithJoin :: Schema -> [Relationship] -> ReadRequest -> Either ApiRequestError ReadRequest augmentRequestWithJoin schema allRels request = addRels schema allRels Nothing request >>= addJoinConditions Nothing -addRels :: Schema -> [Relation] -> Maybe ReadRequest -> ReadRequest -> Either ApiRequestError ReadRequest +addRels :: Schema -> [Relationship] -> Maybe ReadRequest -> ReadRequest -> Either ApiRequestError ReadRequest addRels schema allRels parentNode (Node (query@Select{from=tbl}, (nodeName, _, alias, hint, depth)) forest) = case parentNode of Just (Node (Select{from=parentNodeQi}, _) _) -> @@ -148,7 +148,7 @@ addRels schema allRels parentNode (Node (query@Select{from=tbl}, (nodeName, _, a -- target = table / view / constraint / column-from-origin -- hint = table / view / constraint / column-from-origin / column-from-target -- (hint can take table / view values to aid in finding the junction in an m2m relationship) -findRel :: Schema -> [Relation] -> NodeName -> NodeName -> Maybe EmbedHint -> Either ApiRequestError Relation +findRel :: Schema -> [Relationship] -> NodeName -> NodeName -> Maybe EmbedHint -> Either ApiRequestError Relationship findRel schema allRels origin target hint = case rel of [] -> Left $ NoRelBetween origin target @@ -173,7 +173,7 @@ findRel schema allRels origin target hint = M2M Junction{junTable} -> hint_ == Just (tableName junTable) _ -> False rel = filter ( - \Relation{..} -> + \Relationship{..} -> -- Both relationship ends need to be on the exposed schema schema == tableSchema relTable && schema == tableSchema relForeignTable && ( @@ -210,13 +210,13 @@ findRel schema allRels origin target hint = addJoinConditions :: Maybe Alias -> ReadRequest -> Either ApiRequestError ReadRequest addJoinConditions previousAlias (Node node@(query@Select{from=tbl}, nodeProps@(_, rel, _, _, depth)) forest) = case rel of - Just r@Relation{relCardinality=M2M Junction{junTable}} -> + Just r@Relationship{relCardinality=M2M Junction{junTable}} -> let rq = augmentQuery r in Node (rq{implicitJoins=tableQi junTable:implicitJoins rq}, nodeProps) <$> updatedForest Just r -> Node (augmentQuery r, nodeProps) <$> updatedForest Nothing -> Node node <$> updatedForest where - newAlias = case Relation.isSelfReference <$> rel of + newAlias = case Relationship.isSelfReference <$> rel of Just True | depth /= 0 -> Just (qiName tbl <> "_" <> show depth) -- root node doesn't get aliased | otherwise -> Nothing @@ -229,8 +229,8 @@ addJoinConditions previousAlias (Node node@(query@Select{from=tbl}, nodeProps@(_ updatedForest = addJoinConditions newAlias `traverse` forest -- previousAlias and newAlias are used in the case of self joins -getJoinConditions :: Maybe Alias -> Maybe Alias -> Relation -> [JoinCondition] -getJoinConditions previousAlias newAlias (Relation Table{tableSchema=tSchema, tableName=tN} cols Table{tableName=ftN} fCols card) = +getJoinConditions :: Maybe Alias -> Maybe Alias -> Relationship -> [JoinCondition] +getJoinConditions previousAlias newAlias (Relationship Table{tableSchema=tSchema, tableName=tN} cols Table{tableName=ftN} fCols card) = case card of M2M (Junction Table{tableName=jtn} _ jc1 _ jc2) -> zipWith (toJoinCondition tN jtn) cols jc1 ++ zipWith (toJoinCondition ftN jtn) fCols jc2 @@ -359,7 +359,7 @@ returningCols rr@(Node _ forest) pkCols -- projects. So this adds the foreign key columns to ensure the embedding -- succeeds, result would be `RETURNING name, client_id`. fkCols = concat $ mapMaybe (\case - Node (_, (_, Just Relation{relColumns=cols}, _, _, _)) _ -> Just cols + Node (_, (_, Just Relationship{relColumns=cols}, _, _, _)) _ -> Just cols _ -> Nothing ) forest -- However if the "client_id" is present, e.g. mutateRequest to diff --git a/src/PostgREST/Request/Types.hs b/src/PostgREST/Request/Types.hs index 9b957c866..c833ee470 100644 --- a/src/PostgREST/Request/Types.hs +++ b/src/PostgREST/Request/Types.hs @@ -36,11 +36,11 @@ import Data.Tree (Tree (..)) import qualified GHC.Show (show) -import PostgREST.DbStructure.Identifiers (FieldName, - QualifiedIdentifier) -import PostgREST.DbStructure.Relation (Relation) -import PostgREST.RangeQuery (NonnegRange) -import PostgREST.Request.Preferences (PreferResolution) +import PostgREST.DbStructure.Identifiers (FieldName, + QualifiedIdentifier) +import PostgREST.DbStructure.Relationship (Relationship) +import PostgREST.RangeQuery (NonnegRange) +import PostgREST.Request.Preferences (PreferResolution) import Protolude @@ -49,7 +49,7 @@ type ReadRequest = Tree ReadNode type MutateRequest = MutateQuery type ReadNode = - (ReadQuery, (NodeName, Maybe Relation, Maybe Alias, Maybe EmbedHint, Depth)) + (ReadQuery, (NodeName, Maybe Relationship, Maybe Alias, Maybe EmbedHint, Depth)) type NodeName = Text type Depth = Integer @@ -121,10 +121,7 @@ data MutateQuery , returning :: [FieldName] } --- | This type will hold information about which particular 'Relation' between --- two tables to choose when there are multiple ones. --- Specifically, it will contain the name of the foreign key or the join table --- in many to many relations. +-- | The select value in `/tbl?select=alias:field::cast` type SelectItem = (Field, Maybe Cast, Maybe Alias, Maybe EmbedHint) type Field = (FieldName, JsonPath)