packages feed

squeal-postgresql-0.1.0.0: test/Squeal/PostgreSQL/DefinitionSpec.hs

{-# LANGUAGE
    DataKinds
  , MagicHash
  , OverloadedLabels
  , OverloadedStrings
  , TypeApplications
  , TypeOperators
#-}

module Squeal.PostgreSQL.DefinitionSpec where

import Control.Category ((>>>))
import Data.Function
import Generics.SOP hiding (from)
import Test.Hspec

import Squeal.PostgreSQL

spec :: Spec
spec = do
  let
    definition `definitionRenders` str =
      renderDefinition definition `shouldBe` str
  it "should render CREATE TABLE statements" $ do
    createTable #table1
      ((int4 & notNull) `As` #col1 :* (int4 & notNull) `As` #col2 :* Nil)
      [primaryKey (Column #col1 :* Column #col2 :* Nil)]
      `definitionRenders`
      "CREATE TABLE table1\
      \ (col1 int4 NOT NULL, col2 int4 NOT NULL,\
      \ PRIMARY KEY (col1, col2));"
    createTable #table2
      ( serial `As` #col1 :*
        text `As` #col2 :*
        (int8 & notNull & default_ 8) `As` #col3 :* Nil )
        [check (#col3 .> 0)]
      `definitionRenders`
      "CREATE TABLE table2\
      \ (col1 serial,\
      \ col2 text,\
      \ col3 int8 NOT NULL DEFAULT 8,\
      \ CHECK ((col3 > 0)));"
    let
      statement :: Definition '[]
        '[ "users" :::
           '[ "id" ::: 'Optional ('NotNull 'PGint4)
            , "username" ::: 'Required ('NotNull 'PGtext)
            ]
         , "emails" :::
           '[ "id" ::: 'Optional ('NotNull 'PGint4)
            , "userid" ::: 'Required ('NotNull 'PGint4)
            , "email" ::: 'Required ('NotNull 'PGtext)
            ]
         ]
      statement =
        createTable #users
          (serial `As` #id :* (text & notNull) `As` #username :* Nil)
          [primaryKey (Column #id :* Nil)]
        >>>
        createTable #emails
          ( serial `As` #id :*
            (integer & notNull) `As` #userid :*
            (text & notNull) `As` #email :* Nil )
          [ primaryKey (Column #id :* Nil)
          , foreignKey (Column #userid :* Nil) #users (Column #id :* Nil)
            OnDeleteCascade OnUpdateRestrict
          , unique (Column #email :* Nil)
          , check (#email ./= "")
          ]
    statement `definitionRenders`
      "CREATE TABLE users\
      \ (id serial, username text NOT NULL,\
      \ PRIMARY KEY (id));\
      \ \
      \CREATE TABLE emails\
      \ (id serial,\
      \ userid integer NOT NULL,\
      \ email text NOT NULL,\
      \ PRIMARY KEY (id),\
      \ FOREIGN KEY (userid) REFERENCES users (id)\
      \ ON DELETE CASCADE ON UPDATE RESTRICT,\
      \ UNIQUE (email),\
      \ CHECK ((email <> E'')));"
  it "should render DROP TABLE statements" $ do
    let
      statement :: Definition Tables '[]
      statement = dropTable #table1
    statement `definitionRenders` "DROP TABLE table1;"

type Columns =
  '[ "col1" ::: 'Required ('NotNull 'PGint4)
   , "col2" ::: 'Required ('NotNull 'PGint4)
   ]
type Tables = '[ "table1" ::: Columns ]
type SumAndCol1 =
  '[ "sum" ::: 'Required ('NotNull 'PGint4)
   , "col1" ::: 'Required ('NotNull 'PGint4)
   ]
type StudentsColumns = '["name" ::: 'Required ('NotNull 'PGtext)]
type StudentsTable = '["students" ::: StudentsColumns]
type OrderColumns =
  '[ "orderID"    ::: 'Required ('NotNull 'PGint4)
   , "orderVal"   ::: 'Required ('NotNull 'PGtext)
   , "customerID" ::: 'Required ('NotNull 'PGint4)
   , "shipperID"  ::: 'Required ('NotNull 'PGint4)
   ]
type CustomerColumns =
  '[ "customerID" ::: 'Required ('NotNull 'PGint4)
   , "customerVal" ::: 'Required ('NotNull 'PGfloat4)
   ]
type ShipperColumns =
  '[ "shipperID" ::: 'Required ('NotNull 'PGint4)
   , "shipperVal" ::: 'Required ('NotNull 'PGbool)
   ]
type JoinTables =
  '[ "orders"    ::: OrderColumns
   , "customers" ::: CustomerColumns
   , "shippers"  ::: ShipperColumns
   ]
type ValueColumns =
  '[ "orderVal"    ::: 'Required ('NotNull 'PGtext)
   , "customerVal" ::: 'Required ('NotNull 'PGfloat4)
   , "shipperVal"  ::: 'Required ('NotNull 'PGbool)
   ]