@@ -66,14 +66,15 @@ module Squeal.PostgreSQL.Definition
6666 , createView
6767 , dropView
6868 -- * Types
69− , createTypeComposite
7069 , createTypeEnum
71− , HasPGcomposite (..)
72− , HasPGenum (..)
70+ , createTypeEnumWith
71+ , createTypeComposite
72+ , createTypeCompositeWith
7373 , dropType
74+ -- * Columns
7475 , ColumnTypeExpression (..)
75− , hasNull
76− , hasNotNull
76+ , nullable
77+ , notNullable
7778 , default_
7879 , serial2
7980 , smallserial
@@ -125,7 +126,7 @@ CREATE statements
125126-- >>> :set -XOverloadedLabels
126127-- >>> :{
127128-- renderDefinition $
128−-- createTable #tab ((int & hasNull) `As` #a :* (real & hasNull) `As` #b :* Nil) Nil
129+-- createTable #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil
129130-- :}
130131-- "CREATE TABLE \"tab\" (\"a\" int NULL, \"b\" real NULL);"
131132createTable
@@ -152,7 +153,7 @@ createTable tab columns constraints = UnsafeDefinition $
152153-- >>> type Schema = '["tab" ::: 'Table Table]
153154-- >>> :{
154155-- renderDefinition
155−-- (createTableIfNotExists #tab ((int & hasNull) `As` #a :* (real & hasNull) `As` #b :* Nil) Nil :: Definition Schema Schema)
156+-- (createTableIfNotExists #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil :: Definition Schema Schema)
156157-- :}
157158-- "CREATE TABLE IF NOT EXISTS \"tab\" (\"a\" int NULL, \"b\" real NULL);"
158159createTableIfNotExists
@@ -234,8 +235,8 @@ newtype TableConstraintExpression
234235-- let
235236-- definition :: Definition '[] Schema
236237-- definition = createTable #tab
237−-- ( (int & hasNotNull) `As` #a :*
238−-- (int & hasNotNull) `As` #b :* Nil )
238+-- ( (int & notNullable) `As` #a :*
239+-- (int & notNullable) `As` #b :* Nil )
239240-- ( check (#a :* #b :* Nil) (#a .> #b) `As` #inequality :* Nil )
240241-- :}
241242--
@@ -265,8 +266,8 @@ check _cols condition = UnsafeTableConstraintExpression $
265266-- let
266267-- definition :: Definition '[] Schema
267268-- definition = createTable #tab
268−-- ( (int & hasNull) `As` #a :*
269−-- (int & hasNull) `As` #b :* Nil )
269+-- ( (int & nullable) `As` #a :*
270+-- (int & nullable) `As` #b :* Nil )
270271-- ( unique (#a :* #b :* Nil) `As` #uq_a_b :* Nil )
271272-- :}
272273--
@@ -297,7 +298,7 @@ unique columns = UnsafeTableConstraintExpression $
297298-- definition :: Definition '[] Schema
298299-- definition = createTable #tab
299300-- ( serial `As` #id :*
300−-- (text & hasNotNull) `As` #name :* Nil )
301+-- (text & notNullable) `As` #name :* Nil )
301302-- ( primaryKey #id `As` #pk_id :* Nil )
302303-- :}
303304--
@@ -341,12 +342,12 @@ primaryKey columns = UnsafeTableConstraintExpression $
341342-- setup =
342343-- createTable #users
343344-- ( serial `As` #id :*
344−-- (text & hasNotNull) `As` #name :* Nil )
345+-- (text & notNullable) `As` #name :* Nil )
345346-- ( primaryKey #id `As` #pk_users :* Nil ) >>>
346347-- createTable #emails
347348-- ( serial `As` #id :*
348−-- (int & hasNotNull) `As` #user_id :*
349−-- (text & hasNull) `As` #email :* Nil )
349+-- (int & notNullable) `As` #user_id :*
350+-- (text & nullable) `As` #email :* Nil )
350351-- ( primaryKey #id `As` #pk_emails :*
351352-- foreignKey #user_id #users #id
352353-- OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
@@ -375,8 +376,8 @@ primaryKey columns = UnsafeTableConstraintExpression $
375376-- setup =
376377-- createTable #employees
377378-- ( serial `As` #id :*
378−-- (text & hasNotNull) `As` #name :*
379−-- (integer & hasNull) `As` #employer_id :* Nil )
379+-- (text & notNullable) `As` #name :*
380+-- (integer & nullable) `As` #employer_id :* Nil )
380381-- ( primaryKey #id `As` #employees_pk :*
381382-- foreignKey #employer_id #employees #id
382383-- OnDeleteCascade OnUpdateCascade `As` #employees_employer_fk :* Nil )
@@ -409,6 +410,7 @@ foreignKey keys parent refs ondel onupd = UnsafeTableConstraintExpression $
409410 <+> renderOnDeleteClause ondel
410411 <+> renderOnUpdateClause onupd
411412
413+-- | A constraint synonym between types involved in a foreign key constraint.
412414type ForeignKeyed schema
413415 child parent
414416 table reftable
@@ -578,7 +580,7 @@ class AddColumn ty where
578580 -- '["tab" ::: 'Table ('[] :=>
579581 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
580582 -- , "col2" ::: 'Def :=> 'Null 'PGtext ])]
581− -- definition = alterTable #tab (addColumn #col2 (text & hasNull & default_ "foo"))
583+ -- definition = alterTable #tab (addColumn #col2 (text & nullable & default_ "foo"))
582584 -- in renderDefinition definition
583585 -- :}
584586 -- "ALTER TABLE \"tab\" ADD COLUMN \"col2\" text NULL DEFAULT E'foo';"
@@ -590,7 +592,7 @@ class AddColumn ty where
590592 -- '["tab" ::: 'Table ('[] :=>
591593 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
592594 -- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
593− -- definition = alterTable #tab (addColumn #col2 (text & hasNull))
595+ -- definition = alterTable #tab (addColumn #col2 (text & nullable))
594596 -- in renderDefinition definition
595597 -- :}
596598 -- "ALTER TABLE \"tab\" ADD COLUMN \"col2\" text NULL;"
@@ -749,14 +751,15 @@ dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
749751-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
750752-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGnumeric])]
751753-- definition =
752−-- alterTable #tab (alterColumn #col (alterType (numeric & hasNotNull)))
754+-- alterTable #tab (alterColumn #col (alterType (numeric & notNullable)))
753755-- in renderDefinition definition
754756-- :}
755757-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" TYPE numeric NOT NULL;"
756758alterType :: ColumnTypeExpression schema ty -> AlterColumn schema ty0 ty
757759alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
758760
759−-- | create a view...
761+-- | Create a view.
762+--
760763-- >>> :{
761764-- let
762765-- definition :: Definition
@@ -778,12 +781,28 @@ createView alias query = UnsafeDefinition $
778781 "CREATE" <+> "VIEW" <+> renderAlias alias <+> "AS"
779782 <+> renderQuery query <> ";"
780783
784+-- | Drop a view.
785+--
786+-- >>> :{
787+-- let
788+-- definition :: Definition
789+-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])
790+-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
791+-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]
792+-- definition = dropView #bc
793+-- in renderDefinition definition
794+-- :}
795+-- "DROP VIEW \"bc\";"
781796dropView
782797 :: Has view schema ('View v)
783798 => Alias view -- ^ view to remove
784799 -> Definition schema (Drop view schema)
785800dropView v = UnsafeDefinition $ "DROP VIEW" <+> renderAlias v <> ";"
786801
802+-- | Enumerated types are created using the `createTypeEnum` command, for example
803+--
804+-- >>> renderDefinition $ createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy" :* Nil)
805+-- "CREATE TYPE \"mood\" AS ('sad', 'ok', 'happy');"
787806createTypeEnum
788807 :: (KnownSymbol enum, SOP.All KnownSymbol labels)
789808 => Alias enum
@@ -793,17 +812,29 @@ createTypeEnum enum labels = UnsafeDefinition $
793812 "CREATE" <+> "TYPE" <+> renderAlias enum <+> "AS" <+>
794813 parenthesized (commaSeparated (renderLabels labels)) <> ";"
795814
796−class
797− ( SOP.IsEnumType hask
815+-- | Enumerated types can also be generated from a Haskell type, for example
816+--
817+-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
818+-- >>> instance SOP.Generic Schwarma
819+-- >>> instance SOP.HasDatatypeInfo Schwarma
820+-- >>> renderDefinition $ createTypeEnumWith @Schwarma #schwarma
821+-- "CREATE TYPE \"schwarma\" AS ('Beef', 'Lamb', 'Chicken');"
822+createTypeEnumWith
823+ :: forall hask enum schema.
824+ ( SOP.Generic hask
798825 , SOP.All KnownSymbol (LabelsWith hask)
799− ) => HasPGenum hask where
800− createTypeEnumWith
801− :: KnownSymbol enum
802− => Alias enum
803− -> Definition schema (Create enum ('Typedef (EnumWith hask)) schema)
804− createTypeEnumWith enum = createTypeEnum enum
805− (SOP.hpure label :: NP PGlabel (LabelsWith hask))
826+ , KnownSymbol enum
827+ )
828+ => Alias enum
829+ -> Definition schema (Create enum ('Typedef (EnumWith hask)) schema)
830+createTypeEnumWith enum = createTypeEnum enum
831+ (SOP.hpure label :: NP PGlabel (LabelsWith hask))
806832
833+-- | `createTypeComposite` creates a composite type. The composite type is
834+-- specified by a list of attribute names and data types.
835+--
836+-- >>> renderDefinition $ createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
837+-- "CREATE TYPE \"complex\" AS (float8 AS \"real\", float8 AS \"imaginary\");"
807838createTypeComposite
808839 :: (KnownSymbol ty, SOP.SListI fields)
809840 => Alias ty
@@ -813,19 +844,33 @@ createTypeComposite ty fields = UnsafeDefinition $
813844 "CREATE" <+> "TYPE" <+> renderAlias ty <+> "AS" <+> parenthesized
814845 (renderCommaSeparated (renderAliasedAs renderTypeExpression) fields) <> ";"
815846
816−class
847+-- | Composite types can also be generated from a Haskell type, for example
848+--
849+-- >>> data Complex = Complex {real :: Maybe Double, imaginary :: Maybe Double} deriving GHC.Generic
850+-- >>> instance SOP.Generic Complex
851+-- >>> instance SOP.HasDatatypeInfo Complex
852+-- >>> renderDefinition $ createTypeCompositeWith @Complex #complex
853+-- "CREATE TYPE \"complex\" AS (float8 AS \"real\", float8 AS \"imaginary\");"
854+createTypeCompositeWith
855+ :: forall hask ty schema.
817856 ( ZipAliased (FieldNamesWith hask) (FieldTypesWith hask)
818857 , SOP.All PGTyped (FieldTypesWith hask)
819− ) => HasPGcomposite hask where
820− createTypeCompositeWith
821− :: KnownSymbol ty
822− => Alias ty
823− -> Definition schema (Create ty ( 'Typedef (CompositeWith hask)) schema)
824− createTypeCompositeWith ty = createTypeComposite ty $ zipAs
825− (SOP.hpure Alias :: NP Alias (FieldNamesWith hask))
826− (SOP.hcpure (SOP.Proxy :: SOP.Proxy PGTyped) pgtype
827− :: NP TypeExpression (FieldTypesWith hask))
858+ , KnownSymbol ty
859+ )
860+ => Alias ty
861+ -> Definition schema (Create ty ( 'Typedef (CompositeWith hask)) schema)
862+createTypeCompositeWith ty = createTypeComposite ty $ zipAs
863+ (SOP.hpure Alias :: NP Alias (FieldNamesWith hask))
864+ (SOP.hcpure (SOP.Proxy :: SOP.Proxy PGTyped) pgtype
865+ :: NP TypeExpression (FieldTypesWith hask))
828866
867+-- | Drop a type.
868+--
869+-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
870+-- >>> instance SOP.Generic Schwarma
871+-- >>> instance SOP.HasDatatypeInfo Schwarma
872+-- >>> renderDefinition (dropType #schwarma :: Definition '["schwarma" ::: 'Typedef (EnumWith Schwarma)] '[])
873+-- "DROP TYPE \"schwarma\";"
829874dropType
830875 :: Has tydef schema ('Typedef ty)
831876 => Alias tydef
@@ -841,17 +886,19 @@ instance (Has alias schema ('Typedef ty))
841886 => IsLabel alias (ColumnTypeExpression schema ('NoDef :=> 'NotNull ty)) where
842887 fromLabel = UnsafeColumnTypeExpression (renderAlias (fromLabel @alias))
843888
844−hasNull
889+-- | used in `createTable` commands as a column constraint to note that
890+-- @NULL@ may be present in a column
891+nullable
845892 :: TypeExpression ty
846893 -> ColumnTypeExpression schema ('NoDef :=> 'Null ty)
847−hasNull ty = UnsafeColumnTypeExpression $ renderTypeExpression ty <+> "NULL"
894+nullable ty = UnsafeColumnTypeExpression $ renderTypeExpression ty <+> "NULL"
848895
849896-- | used in `createTable` commands as a column constraint to ensure
850−-- @NULL@ is not present
851−hasNotNull
897+-- @NULL@ is not present in a column
898+notNullable
852899 :: TypeExpression ty
853900 -> ColumnTypeExpression schema (def :=> 'NotNull ty)
854−hasNotNull ty = UnsafeColumnTypeExpression $ renderTypeExpression ty <+> "NOT NULL"
901+notNullable ty = UnsafeColumnTypeExpression $ renderTypeExpression ty <+> "NOT NULL"
855902
856903-- | used in `createTable` commands as a column constraint to give a default
857904default_