module Database.PostgreSQL.PQTypes.Model.Table (
    TableColumn(..)
  , tblColumn
  , sqlAddColumn
  , sqlAlterColumn
  , sqlDropColumn
  , Rows(..)
  , Table(..)
  , tblTable
  , sqlCreateTable
  , sqlAlterTable
  , DropTableMode(..)
  , sqlDropTable
  , TableInitialSetup(..)
  ) where

import Control.Monad.Catch
import Data.ByteString (ByteString)
import Data.Int
import Data.Monoid.Utils
import Database.PostgreSQL.PQTypes
import Prelude

import Database.PostgreSQL.PQTypes.Model.Check
import Database.PostgreSQL.PQTypes.Model.ColumnType
import Database.PostgreSQL.PQTypes.Model.ForeignKey
import Database.PostgreSQL.PQTypes.Model.Index
import Database.PostgreSQL.PQTypes.Model.PrimaryKey

data TableColumn = TableColumn {
  TableColumn -> RawSQL ()
colName     :: RawSQL ()
, TableColumn -> ColumnType
colType     :: ColumnType
, TableColumn -> Bool
colNullable :: Bool
, TableColumn -> Maybe (RawSQL ())
colDefault  :: Maybe (RawSQL ())
} deriving Int -> TableColumn -> ShowS
[TableColumn] -> ShowS
TableColumn -> String
(Int -> TableColumn -> ShowS)
-> (TableColumn -> String)
-> ([TableColumn] -> ShowS)
-> Show TableColumn
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TableColumn] -> ShowS
$cshowList :: [TableColumn] -> ShowS
show :: TableColumn -> String
$cshow :: TableColumn -> String
showsPrec :: Int -> TableColumn -> ShowS
$cshowsPrec :: Int -> TableColumn -> ShowS
Show

tblColumn :: TableColumn
tblColumn :: TableColumn
tblColumn = TableColumn :: RawSQL () -> ColumnType -> Bool -> Maybe (RawSQL ()) -> TableColumn
TableColumn {
  colName :: RawSQL ()
colName = String -> RawSQL ()
forall a. HasCallStack => String -> a
error String
"tblColumn: column name must be specified"
, colType :: ColumnType
colType = String -> ColumnType
forall a. HasCallStack => String -> a
error String
"tblColumn: column type must be specified"
, colNullable :: Bool
colNullable = Bool
True
, colDefault :: Maybe (RawSQL ())
colDefault = Maybe (RawSQL ())
forall a. Maybe a
Nothing
}

sqlAddColumn :: TableColumn -> RawSQL ()
sqlAddColumn :: TableColumn -> RawSQL ()
sqlAddColumn TableColumn{Bool
Maybe (RawSQL ())
RawSQL ()
ColumnType
colDefault :: Maybe (RawSQL ())
colNullable :: Bool
colType :: ColumnType
colName :: RawSQL ()
colDefault :: TableColumn -> Maybe (RawSQL ())
colNullable :: TableColumn -> Bool
colType :: TableColumn -> ColumnType
colName :: TableColumn -> RawSQL ()
..} = [RawSQL ()] -> RawSQL ()
forall m. (IsString m, Monoid m) => [m] -> m
smconcat [
    RawSQL ()
"ADD COLUMN"
  , RawSQL ()
colName
  , ColumnType -> RawSQL ()
columnTypeToSQL ColumnType
colType
  , if Bool
colNullable then RawSQL ()
"NULL" else RawSQL ()
"NOT NULL"
  , RawSQL ()
-> (RawSQL () -> RawSQL ()) -> Maybe (RawSQL ()) -> RawSQL ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe RawSQL ()
"" (RawSQL ()
"DEFAULT" RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+>) Maybe (RawSQL ())
colDefault
  ]

sqlAlterColumn :: RawSQL () -> RawSQL () -> RawSQL ()
sqlAlterColumn :: RawSQL () -> RawSQL () -> RawSQL ()
sqlAlterColumn RawSQL ()
cname RawSQL ()
alter = RawSQL ()
"ALTER COLUMN" RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> RawSQL ()
cname RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> RawSQL ()
alter

sqlDropColumn :: RawSQL () -> RawSQL ()
sqlDropColumn :: RawSQL () -> RawSQL ()
sqlDropColumn RawSQL ()
cname = RawSQL ()
"DROP COLUMN" RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> RawSQL ()
cname

----------------------------------------

data Rows = forall row. (Show row, ToRow row) => Rows [ByteString] [row]

data Table =
  Table {
  Table -> RawSQL ()
tblName               :: RawSQL () -- ^ Must be in lower case.
, Table -> Int32
tblVersion            :: Int32
, Table -> [TableColumn]
tblColumns            :: [TableColumn]
, Table -> Maybe PrimaryKey
tblPrimaryKey         :: Maybe PrimaryKey
, Table -> [Check]
tblChecks             :: [Check]
, Table -> [ForeignKey]
tblForeignKeys        :: [ForeignKey]
, Table -> [TableIndex]
tblIndexes            :: [TableIndex]
, Table -> Maybe TableInitialSetup
tblInitialSetup       :: Maybe TableInitialSetup
}

data TableInitialSetup = TableInitialSetup {
  TableInitialSetup
-> forall (m :: * -> *). (MonadDB m, MonadThrow m) => m Bool
checkInitialSetup :: forall m. (MonadDB m, MonadThrow m) => m Bool
, TableInitialSetup
-> forall (m :: * -> *). (MonadDB m, MonadThrow m) => m ()
initialSetup      :: forall m. (MonadDB m, MonadThrow m) => m ()
}

tblTable :: Table
tblTable :: Table
tblTable = Table :: RawSQL ()
-> Int32
-> [TableColumn]
-> Maybe PrimaryKey
-> [Check]
-> [ForeignKey]
-> [TableIndex]
-> Maybe TableInitialSetup
-> Table
Table {
  tblName :: RawSQL ()
tblName = String -> RawSQL ()
forall a. HasCallStack => String -> a
error String
"tblTable: table name must be specified"
, tblVersion :: Int32
tblVersion = String -> Int32
forall a. HasCallStack => String -> a
error String
"tblTable: table version must be specified"
, tblColumns :: [TableColumn]
tblColumns = String -> [TableColumn]
forall a. HasCallStack => String -> a
error String
"tblTable: table columns must be specified"
, tblPrimaryKey :: Maybe PrimaryKey
tblPrimaryKey = Maybe PrimaryKey
forall a. Maybe a
Nothing
, tblChecks :: [Check]
tblChecks = []
, tblForeignKeys :: [ForeignKey]
tblForeignKeys = []
, tblIndexes :: [TableIndex]
tblIndexes = []
, tblInitialSetup :: Maybe TableInitialSetup
tblInitialSetup = Maybe TableInitialSetup
forall a. Maybe a
Nothing
}

sqlCreateTable :: RawSQL () -> RawSQL ()
sqlCreateTable :: RawSQL () -> RawSQL ()
sqlCreateTable RawSQL ()
tname = RawSQL ()
"CREATE TABLE" RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> RawSQL ()
tname RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> RawSQL ()
"()"

-- | Whether to also drop objects that depend on the table.
data DropTableMode =
  -- | Automatically drop objects that depend on the table (such as views).
  DropTableCascade |
  -- | Refuse to drop the table if any objects depend on it. This is the default.
  DropTableRestrict

sqlDropTable :: RawSQL () -> DropTableMode -> RawSQL ()
sqlDropTable :: RawSQL () -> DropTableMode -> RawSQL ()
sqlDropTable RawSQL ()
tname DropTableMode
mode = RawSQL ()
"DROP TABLE" RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> RawSQL ()
tname
  RawSQL () -> RawSQL () -> RawSQL ()
forall m. (IsString m, Monoid m) => m -> m -> m
<+> case DropTableMode
mode of
        DropTableMode
DropTableCascade  -> RawSQL ()
"CASCADE"
        DropTableMode
DropTableRestrict -> RawSQL ()
"RESTRICT"

sqlAlterTable :: RawSQL () -> [RawSQL ()] -> RawSQL ()
sqlAlterTable :: RawSQL () -> [RawSQL ()] -> RawSQL ()
sqlAlterTable RawSQL ()
tname [RawSQL ()]
alter_statements = [RawSQL ()] -> RawSQL ()
forall m. (IsString m, Monoid m) => [m] -> m
smconcat [
    RawSQL ()
"ALTER TABLE"
  , RawSQL ()
tname
  , RawSQL () -> [RawSQL ()] -> RawSQL ()
forall m. Monoid m => m -> [m] -> m
mintercalate RawSQL ()
", " [RawSQL ()]
alter_statements
  ]