{-|
Module: Squeal.PostgreSQL.Definition
Description: data definition language
Copyright: (c) Eitan Chatav, 2019
Maintainer: eitan@morphism.tech
Stability: experimental

data definition language
-}

{-# LANGUAGE
    AllowAmbiguousTypes
  , ConstraintKinds
  , DeriveAnyClass
  , DeriveGeneric
  , DerivingStrategies
  , FlexibleContexts
  , FlexibleInstances
  , GADTs
  , LambdaCase
  , MultiParamTypeClasses
  , OverloadedLabels
  , OverloadedStrings
  , RankNTypes
  , ScopedTypeVariables
  , TypeApplications
  , TypeInType
  , TypeOperators
  , UndecidableSuperClasses
  , UndecidableInstances
#-}

module Squeal.PostgreSQL.Definition
  ( -- * Definition
    Definition (..)
  , (>>>)
  , manipulation_
  ) where

import Control.Category
import Control.DeepSeq
import Data.ByteString
import Data.Monoid
import Prelude hiding ((.), id)

import qualified GHC.Generics as GHC

import Squeal.PostgreSQL.Manipulation
import Squeal.PostgreSQL.Render
import Squeal.PostgreSQL.Type.Schema

-- $setup
-- >>> import Squeal.PostgreSQL

{-----------------------------------------
statements
-----------------------------------------}

-- | A `Definition` is a statement that changes the schemas of the
-- database, like a `Squeal.PostgreSQL.Definition.Table.createTable`,
-- `Squeal.PostgreSQL.Definition.Table.dropTable`,
-- or `Squeal.PostgreSQL.Definition.Table.alterTable` command.
-- `Definition`s may be composed using the `>>>` operator.
newtype Definition
  (db0 :: SchemasType)
  (db1 :: SchemasType)
  = UnsafeDefinition { Definition db0 db1 -> ByteString
renderDefinition :: ByteString }
  deriving ((forall x. Definition db0 db1 -> Rep (Definition db0 db1) x)
-> (forall x. Rep (Definition db0 db1) x -> Definition db0 db1)
-> Generic (Definition db0 db1)
forall (db0 :: SchemasType) (db1 :: SchemasType) x.
Rep (Definition db0 db1) x -> Definition db0 db1
forall (db0 :: SchemasType) (db1 :: SchemasType) x.
Definition db0 db1 -> Rep (Definition db0 db1) x
forall x. Rep (Definition db0 db1) x -> Definition db0 db1
forall x. Definition db0 db1 -> Rep (Definition db0 db1) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall (db0 :: SchemasType) (db1 :: SchemasType) x.
Rep (Definition db0 db1) x -> Definition db0 db1
$cfrom :: forall (db0 :: SchemasType) (db1 :: SchemasType) x.
Definition db0 db1 -> Rep (Definition db0 db1) x
GHC.Generic,Int -> Definition db0 db1 -> ShowS
[Definition db0 db1] -> ShowS
Definition db0 db1 -> String
(Int -> Definition db0 db1 -> ShowS)
-> (Definition db0 db1 -> String)
-> ([Definition db0 db1] -> ShowS)
-> Show (Definition db0 db1)
forall (db0 :: SchemasType) (db1 :: SchemasType).
Int -> Definition db0 db1 -> ShowS
forall (db0 :: SchemasType) (db1 :: SchemasType).
[Definition db0 db1] -> ShowS
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Definition db0 db1] -> ShowS
$cshowList :: forall (db0 :: SchemasType) (db1 :: SchemasType).
[Definition db0 db1] -> ShowS
show :: Definition db0 db1 -> String
$cshow :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> String
showsPrec :: Int -> Definition db0 db1 -> ShowS
$cshowsPrec :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Int -> Definition db0 db1 -> ShowS
Show,Definition db0 db1 -> Definition db0 db1 -> Bool
(Definition db0 db1 -> Definition db0 db1 -> Bool)
-> (Definition db0 db1 -> Definition db0 db1 -> Bool)
-> Eq (Definition db0 db1)
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Definition db0 db1 -> Definition db0 db1 -> Bool
$c/= :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
== :: Definition db0 db1 -> Definition db0 db1 -> Bool
$c== :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
Eq,Eq (Definition db0 db1)
Eq (Definition db0 db1)
-> (Definition db0 db1 -> Definition db0 db1 -> Ordering)
-> (Definition db0 db1 -> Definition db0 db1 -> Bool)
-> (Definition db0 db1 -> Definition db0 db1 -> Bool)
-> (Definition db0 db1 -> Definition db0 db1 -> Bool)
-> (Definition db0 db1 -> Definition db0 db1 -> Bool)
-> (Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1)
-> (Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1)
-> Ord (Definition db0 db1)
Definition db0 db1 -> Definition db0 db1 -> Bool
Definition db0 db1 -> Definition db0 db1 -> Ordering
Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
forall (db0 :: SchemasType) (db1 :: SchemasType).
Eq (Definition db0 db1)
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Ordering
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
$cmin :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
max :: Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
$cmax :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
>= :: Definition db0 db1 -> Definition db0 db1 -> Bool
$c>= :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
> :: Definition db0 db1 -> Definition db0 db1 -> Bool
$c> :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
<= :: Definition db0 db1 -> Definition db0 db1 -> Bool
$c<= :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
< :: Definition db0 db1 -> Definition db0 db1 -> Bool
$c< :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Bool
compare :: Definition db0 db1 -> Definition db0 db1 -> Ordering
$ccompare :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> Definition db0 db1 -> Ordering
$cp1Ord :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Eq (Definition db0 db1)
Ord,Definition db0 db1 -> ()
(Definition db0 db1 -> ()) -> NFData (Definition db0 db1)
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> ()
forall a. (a -> ()) -> NFData a
rnf :: Definition db0 db1 -> ()
$crnf :: forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> ()
NFData)

instance RenderSQL (Definition db0 db1) where
  renderSQL :: Definition db0 db1 -> ByteString
renderSQL = Definition db0 db1 -> ByteString
forall (db0 :: SchemasType) (db1 :: SchemasType).
Definition db0 db1 -> ByteString
renderDefinition

instance Category Definition where
  id :: Definition a a
id = ByteString -> Definition a a
forall (db0 :: SchemasType) (db1 :: SchemasType).
ByteString -> Definition db0 db1
UnsafeDefinition ByteString
";"
  Definition b c
ddl1 . :: Definition b c -> Definition a b -> Definition a c
. Definition a b
ddl0 = ByteString -> Definition a c
forall (db0 :: SchemasType) (db1 :: SchemasType).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString -> Definition a c) -> ByteString -> Definition a c
forall a b. (a -> b) -> a -> b
$
    Definition a b -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Definition a b
ddl0 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"\n" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Definition b c -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Definition b c
ddl1

instance db0 ~ db1 => Semigroup (Definition db0 db1) where <> :: Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
(<>) = Definition db0 db1 -> Definition db0 db1 -> Definition db0 db1
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
(>>>)
instance db0 ~ db1 => Monoid (Definition db0 db1) where mempty :: Definition db0 db1
mempty = Definition db0 db1
forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id

-- | A `Manipulation` without input or output can be run as a statement
-- along with other `Definition`s, by embedding it using `manipulation_`.
manipulation_
  :: Manipulation '[] db '[] '[]
  -- ^ no input or output
  -> Definition db db
manipulation_ :: Manipulation '[] db '[] '[] -> Definition db db
manipulation_ = ByteString -> Definition db db
forall (db0 :: SchemasType) (db1 :: SchemasType).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString -> Definition db db)
-> (Manipulation '[] db '[] '[] -> ByteString)
-> Manipulation '[] db '[] '[]
-> Definition db db
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";") (ByteString -> ByteString)
-> (Manipulation '[] db '[] '[] -> ByteString)
-> Manipulation '[] db '[] '[]
-> ByteString
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Manipulation '[] db '[] '[] -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL