module Database.PostgreSQL.PQTypes.Model.CompositeType (
    CompositeType(..)
  , CompositeColumn(..)
  , defineComposites
  ) where

import Data.Monoid.Utils
import Database.PostgreSQL.PQTypes
import Prelude

import Database.PostgreSQL.PQTypes.Model.ColumnType

data CompositeType = CompositeType {
  ctName    :: !(RawSQL ())
, ctColumns :: ![CompositeColumn]
} deriving (Eq, Ord, Show)

data CompositeColumn = CompositeColumn {
  ccName :: !(RawSQL ())
, ccType :: ColumnType
} deriving (Eq, Ord, Show)

-- | Composite types are static in a sense that they can either
-- be created or dropped, altering them is not possible. Therefore
-- they are not part of the migration process. This is not a problem
-- since their exclusive usage is for intermediate representation
-- of complex nested data structures fetched from the database.
defineComposites :: MonadDB m => [CompositeType] -> m ()
defineComposites ctypes = do
  mapM_ (runQuery_ . sqlDropComposite)   $ reverse ctypes
  mapM_ (runQuery_ . sqlCreateComposite) $ ctypes
  where
    sqlCreateComposite CompositeType{..} = smconcat [
        "CREATE TYPE"
      , ctName
      , "AS ("
      , mintercalate ", " $ map columnToSQL ctColumns
      , ")"
      ]
      where
        columnToSQL CompositeColumn{..} = ccName <+> columnTypeToSQL ccType

    sqlDropComposite = ("DROP TYPE IF EXISTS" <+>) . ctName