Hawk-0.0.2: src/Hawk/Model/WithForeignKey.hs
-- --------------------------------------------------------------------------
{- |
Module : $Header$
Copyright : Copyright (C) 2009 Björn Peemöller, Stefan Roggensack
License : BSD3
Maintainer : {inf6254, inf6509}fh-wedel.de
Stability : experimental
Portability : portable
Version : $Id: Main.hs 57 2009-05-29 11:33:59Z inf6254 $
-}
-- --------------------------------------------------------------------------
{-# LANGUAGE TypeFamilies, FlexibleContexts, MultiParamTypeClasses #-}
module Hawk.Model.WithForeignKey
( ForeignKeyRelationship (..)
, getMaybeReferenced
, getOneReferenced
, setReferenced
, removeReferenced
, getReferencings
, getMaybeReferencing
, getOneReferencing
, addReferencing
, removeReferencing
, replaceReferencing
) where
import Hawk.Model.Criteria
import Hawk.Model.Exception
import Hawk.Model.MonadDB
import Hawk.Model.Persistent
import Hawk.Model.WithPrimaryKey
import Hawk.Model.Types
import Hawk.Model.Util
import Control.Monad (liftM)
import Control.Exception (throw)
-- | Typeclass for ForeignKey relationships
{-
class (Persistent self, WithPrimaryKey other) =>
WithForeignKey self relationshipName other |
relationshipName -> self other where
-}
class (Persistent (Referencing r), WithPrimaryKey (Referenced r)) =>
ForeignKeyRelationship r where
type Referencing r :: *
type Referenced r :: *
relationshipName :: r -> String
-- | Get the 'ColumnName' containing the 'ForeignKey'
fkColumn :: r -> ColumnName
-- | Get the value of the 'ForeignKey'
foreignKey :: r -> Referencing r -> ForeignKey
-- | Set the value of the 'ForeignKey'
setForeignKey :: r -> Referencing r -> ForeignKey -> Referencing r
-- --------------------------------------------------------------------------
-- Functions derived from WithForeignKey
-- --------------------------------------------------------------------------
getMaybeReferenced :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referencing r
-> m (Maybe (Referenced r))
getMaybeReferenced rel referencing
= case foreignKey rel referencing of
Nothing -> return Nothing
Just key -> findMaybeByPK key
getOneReferenced :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referencing r
-> m (Referenced r)
getOneReferenced rel referencing
= case foreignKey rel referencing of
Nothing -> throw $ RecordNotFound msg
Just key -> findOneByPK key
where msg = "Persistent '" ++ persistentType referencing
++ "' has no foreign key for relationship '"
++ relationshipName rel ++ "'"
setReferenced :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referencing r
-> Maybe (Referenced r)
-> m (Referencing r)
setReferenced rel referencing
= return . setForeignKey rel referencing . fmap primaryKey
removeReferenced :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referencing r
-> Referenced r
-> m (Referencing r)
removeReferenced rel referencing referenced
= if Just (primaryKey referenced) == foreignKey rel referencing
then setReferenced rel referencing Nothing
else return referencing
getReferencings :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referenced r
-> m [Referencing r]
getReferencings rel referenced
= selectPersistents $ restrictionCriteria restr
where restr = eqExpr (col $ fkColumn rel) (val $ primaryKey referenced)
getMaybeReferencing :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referenced r
-> m (Maybe (Referencing r))
getMaybeReferencing rel = liftM safeHead . getReferencings rel
getOneReferencing :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referenced r
-> m (Referencing r)
getOneReferencing rel parent
= liftM (unsafeHeadMsg msg) $ getReferencings rel parent
where msg = "Persistent '" ++ persistentType parent
++ "' with primary key '" ++ show (primaryKey parent)
++ "' has no child in the foreign key relationship '"
++ show (relationshipName rel) ++ "'"
addReferencing :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referenced r
-> Referencing r
-> m (Referencing r)
addReferencing rel referenced referencing
= setReferenced rel referencing (Just referenced)
removeReferencing :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referenced r
-> Referencing r
-> m (Referencing r)
removeReferencing = flip . removeReferenced
replaceReferencing :: (MonadDB m, ForeignKeyRelationship r)
=> r
-> Referenced r
-> Maybe (Referencing r)
-> m (Maybe (Referencing r), Maybe (Referencing r))
replaceReferencing rel referenced newReferencing = do
oldReferencing <- getMaybeReferencing rel referenced
oldReferencing' <- case oldReferencing of
Nothing -> return Nothing
Just o -> liftM Just $ setReferenced rel o Nothing
newReferencing' <- case newReferencing of
Nothing -> return Nothing
Just n -> liftM Just $ setReferenced rel n (Just referenced)
return (oldReferencing', newReferencing')