module Database.PostgreSQL.PQTypes.Model.ForeignKey (
ForeignKey(..)
, ForeignKeyAction(..)
, fkOnColumn
, fkOnColumns
, fkName
, sqlAddFK
, sqlAddValidFK
, sqlAddNotValidFK
, sqlValidateFK
, sqlDropFK
) where
import Data.Monoid
import Data.Monoid.Utils
import Database.PostgreSQL.PQTypes
import Prelude
import qualified Data.Text as T
data ForeignKey = ForeignKey {
fkColumns :: [RawSQL ()]
, fkRefTable :: RawSQL ()
, fkRefColumns :: [RawSQL ()]
, fkOnUpdate :: ForeignKeyAction
, fkOnDelete :: ForeignKeyAction
, fkDeferrable :: Bool
, fkDeferred :: Bool
, fkValidated :: Bool
} deriving (Eq, Ord, Show)
data ForeignKeyAction
= ForeignKeyNoAction
| ForeignKeyRestrict
| ForeignKeyCascade
| ForeignKeySetNull
| ForeignKeySetDefault
deriving (Eq, Ord, Show)
fkOnColumn :: RawSQL () -> RawSQL () -> RawSQL () -> ForeignKey
fkOnColumn column reftable refcolumn =
fkOnColumns [column] reftable [refcolumn]
fkOnColumns :: [RawSQL ()] -> RawSQL () -> [RawSQL ()] -> ForeignKey
fkOnColumns columns reftable refcolumns = ForeignKey {
fkColumns = columns
, fkRefTable = reftable
, fkRefColumns = refcolumns
, fkOnUpdate = ForeignKeyCascade
, fkOnDelete = ForeignKeyNoAction
, fkDeferrable = True
, fkDeferred = False
, fkValidated = True
}
fkName :: RawSQL () -> ForeignKey -> RawSQL ()
fkName tname ForeignKey{..} = shorten $ mconcat [
"fk__"
, tname
, "__"
, mintercalate "__" fkColumns
, "__"
, fkRefTable
]
where
shorten = flip rawSQL () . T.take 63 . unRawSQL
{-# DEPRECATED sqlAddFK "Use sqlAddValidFK instead" #-}
sqlAddFK :: RawSQL () -> ForeignKey -> RawSQL ()
sqlAddFK = sqlAddFK_ True
sqlAddValidFK :: RawSQL () -> ForeignKey -> RawSQL ()
sqlAddValidFK = sqlAddFK_ True
sqlAddNotValidFK :: RawSQL () -> ForeignKey -> RawSQL ()
sqlAddNotValidFK = sqlAddFK_ False
sqlValidateFK :: RawSQL () -> ForeignKey -> RawSQL ()
sqlValidateFK tname fk = "VALIDATE" <+> fkName tname fk
sqlAddFK_ :: Bool -> RawSQL () -> ForeignKey -> RawSQL ()
sqlAddFK_ valid tname fk@ForeignKey{..} = mconcat [
"ADD CONSTRAINT" <+> fkName tname fk <+> "FOREIGN KEY ("
, mintercalate ", " fkColumns
, ") REFERENCES" <+> fkRefTable <+> "("
, mintercalate ", " fkRefColumns
, ") ON UPDATE" <+> foreignKeyActionToSQL fkOnUpdate
, " ON DELETE" <+> foreignKeyActionToSQL fkOnDelete
, " " <> if fkDeferrable then "DEFERRABLE" else "NOT DEFERRABLE"
, " INITIALLY" <+> if fkDeferred then "DEFERRED" else "IMMEDIATE"
, if valid then "" else " NOT VALID"
]
where
foreignKeyActionToSQL ForeignKeyNoAction = "NO ACTION"
foreignKeyActionToSQL ForeignKeyRestrict = "RESTRICT"
foreignKeyActionToSQL ForeignKeyCascade = "CASCADE"
foreignKeyActionToSQL ForeignKeySetNull = "SET NULL"
foreignKeyActionToSQL ForeignKeySetDefault = "SET DEFAULT"
sqlDropFK :: RawSQL () -> ForeignKey -> RawSQL ()
sqlDropFK tname fk = "DROP CONSTRAINT" <+> fkName tname fk