packages feed

selda-0.1.0.0: src/Database/Selda/Table/Compile.hs

{-# LANGUAGE OverloadedStrings #-}
-- | Generating SQL for creating and deleting tables.
module Database.Selda.Table.Compile where
import Database.Selda.Table
import Data.Monoid
import Data.Text (Text, intercalate, pack)
import qualified Data.Text as Text

data OnError = Fail | Ignore
  deriving (Eq, Ord, Show)

-- | Compile a @CREATAE TABLE@ query from a table definition.
compileCreateTable :: (Text -> [ColAttr] -> Maybe Text) -> OnError -> Table a -> Text
compileCreateTable customColType ifex tbl = mconcat
  [ "CREATE TABLE ", ifNotExists ifex, tableName tbl, "("
  , intercalate ", " (map (compileTableCol customColType) (tableCols tbl))
  , ")"
  ]
  where
    ifNotExists Fail   = ""
    ifNotExists Ignore = "IF NOT EXISTS "

-- | Compile a table column.
compileTableCol :: (Text -> [ColAttr] -> Maybe Text) -> ColInfo -> Text
compileTableCol customColType ci = Text.unwords
  [ colName ci
  , case customColType typ attrs of
      Just s -> s
      _      -> typ <> " " <> Text.unwords (map compileColAttr attrs)
  ]
  where
    typ = colType ci
    attrs = colAttrs ci

-- | Compile a @DROP TABLE@ query.
compileDropTable :: OnError -> Table a -> Text
compileDropTable Fail t = Text.unwords ["DROP TABLE",tableName t]
compileDropTable _ t    = Text.unwords ["DROP TABLE IF EXISTS",tableName t]

-- | Compile an @INSERT INTO@ query inserting @m@ rows with @n@ cols each.
--   Note that backends expect insertions to NOT have a semicolon at the end.
compInsert :: Table a -> Int -> Text
compInsert tbl mrows =
    Text.unwords ["INSERT INTO", tableName tbl, names, "VALUES", vals]
  where
    nonAutos =
      [ colName c
      | c <- tableCols tbl
      , not (AutoIncrement `elem` colAttrs c)
      ]
    ncols = length nonAutos
    names = "(" <>  Text.intercalate ", " nonAutos <> ")"
    cols n = "(" <> Text.intercalate ", " (mkParams ncols n) <> ")"
    vals = Text.intercalate ", " $ zipWith (\f n -> f n)
                                           (replicate mrows cols)
                                           [0, ncols ..]
    mkParams cs n = map (pack . ('$':) . show . (+n)) [1..cs]

-- | Compile a column attribute.
compileColAttr :: ColAttr -> Text
compileColAttr Primary       = "PRIMARY KEY"
compileColAttr AutoIncrement = "AUTOINCREMENT"
compileColAttr Required      = "NOT NULL"
compileColAttr Optional      = "NULL"