{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} module PostgREST.SchemaCache.Relationship ( Cardinality(..) , Relationship(..) , Junction(..) , RelationshipsMap , relIsToOne ) where import qualified Data.Aeson as JSON import qualified Data.HashMap.Strict as HM import PostgREST.SchemaCache.Identifiers (FieldName, QualifiedIdentifier, Schema) import Protolude -- | Relationship between two tables. data Relationship = Relationship { relTable :: QualifiedIdentifier , relForeignTable :: QualifiedIdentifier , relIsSelf :: Bool -- ^ Whether is a self relationship , relCardinality :: Cardinality , relTableIsView :: Bool , relFTableIsView :: Bool } | ComputedRelationship { relFunction :: QualifiedIdentifier , relTable :: QualifiedIdentifier , relForeignTable :: QualifiedIdentifier , relTableAlias :: QualifiedIdentifier , relToOne :: Bool , relIsSelf :: Bool } deriving (Eq, Show, Ord, Generic, JSON.ToJSON) -- | The relationship cardinality -- | https://en.wikipedia.org/wiki/Cardinality_(data_modeling) data Cardinality = O2M {relCons :: FKConstraint, relColumns :: [(FieldName, FieldName)]} -- ^ one-to-many | M2O {relCons :: FKConstraint, relColumns :: [(FieldName, FieldName)]} -- ^ many-to-one | O2O {relCons :: FKConstraint, relColumns :: [(FieldName, FieldName)], isParent :: Bool} -- ^ one-to-one, this is a refinement over M2O, operating on it is pretty much the same as M2O when isParent == False | M2M Junction -- ^ many-to-many deriving (Eq, Show, Ord, Generic, JSON.ToJSON) type FKConstraint = Text -- | Junction table on an M2M relationship data Junction = Junction { junTable :: QualifiedIdentifier , junConstraint1 :: FKConstraint , junConstraint2 :: FKConstraint , junColsSource :: [(FieldName, FieldName)] , junColsTarget :: [(FieldName, FieldName)] } deriving (Eq, Show, Ord, Generic, JSON.ToJSON) -- | Key based on the source table and the foreign table schema type RelationshipsMap = HM.HashMap (QualifiedIdentifier, Schema) [Relationship] relIsToOne :: Relationship -> Bool relIsToOne rel = case rel of Relationship{relCardinality=M2O {}} -> True Relationship{relCardinality=O2O {}} -> True ComputedRelationship{relToOne=True} -> True _ -> False