on dev help sign in
docs changes and newline between definitions
commit1e229aca9716918bf564b92ab7dc4bf2572e5443 authorEitan Chatav <eitan.chatav@gmail.com> dateThu 21 Jun 2018, 16:14 (8 years ago) parent6e3d875
2 files changed+414−404
squeal-postgresql/src/Squeal/PostgreSQL.hs+206−202 squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+208−202
squeal-postgresql/src/Squeal/PostgreSQL.hs+206−202
@@ -1,206 +1,210 @@
1−-- | Module: Squeal.PostgreSQL
2−-- Description: Squeel export module
3−-- Copyright: (c) Eitan Chatav, 2017
4−-- Maintainer: eitan@morphism.tech
5−-- Stability: experimental
6−--
7−-- Squeal is a deep embedding of [PostgreSQL](https://www.postgresql.org) in Haskell.
8−-- Let's see an example!
9−--
10−-- First, we need some language extensions because Squeal uses modern GHC
11−-- features.
12−--
13−-- >>> :set -XDataKinds -XDeriveGeneric -XOverloadedLabels
14−-- >>> :set -XOverloadedStrings -XTypeApplications -XTypeOperators
15−--
16−-- We'll need some imports.
17−--
18−-- >>> import Control.Monad (void)
19−-- >>> import Control.Monad.Base (liftBase)
20−-- >>> import Data.Int (Int32)
21−-- >>> import Data.Text (Text)
22−-- >>> import Squeal.PostgreSQL
23−--
24−-- We'll use generics to easily convert between Haskell and PostgreSQL values.
25−--
26−-- >>> import qualified Generics.SOP as SOP
27−-- >>> import qualified GHC.Generics as GHC
28−--
29−-- The first step is to define the schema of our database. This is where
30−-- we use @DataKinds@ and @TypeOperators@.
31−--
32−-- >>> :{
33−-- type Schema =
34−-- '[ "users" ::: 'Table (
35−-- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
36−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
37−-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext
38−-- ])
39−-- , "emails" ::: 'Table (
40−-- '[ "pk_emails" ::: 'PrimaryKey '["id"]
41−-- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
42−-- ] :=>
43−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
44−-- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
45−-- , "email" ::: 'NoDef :=> 'Null 'PGtext
46−-- ])
47−-- ]
48−-- :}
49−--
50−-- Notice the use of type operators. `:::` is used
51−-- to pair an alias `Symbol` with either a `TableType` or a `ColumnType`.
52−-- `:=>` is used to pair a `TableConstraint`s with a `ColumnsType`,
53−-- yielding a `TableType`, or to pair a `ColumnConstraint` with a `NullityType`,
54−-- yielding a `ColumnType`.
55−--
56−-- Next, we'll write `Definition`s to set up and tear down the schema. In
57−-- Squeal, a `Definition` is a `createTable`, `alterTable` or `dropTable`
58−-- command and has two type parameters, corresponding to the schema
59−-- before being run and the schema after. We can compose definitions using
60−-- `>>>`. Here and in the rest of our commands we make use of overloaded
61−-- labels to refer to named tables and columns in our schema.
62−--
63−-- >>> :{
64−-- let
65−-- setup :: Definition '[] Schema
66−-- setup =
67−-- createTable #users
68−-- ( serial `As` #id :*
69−-- (text & notNullable) `As` #name :* Nil )
70−-- ( primaryKey #id `As` #pk_users :* Nil ) >>>
71−-- createTable #emails
72−-- ( serial `As` #id :*
73−-- (int & notNullable) `As` #user_id :*
74−-- (text & nullable) `As` #email :* Nil )
75−-- ( primaryKey #id `As` #pk_emails :*
76−-- foreignKey #user_id #users #id
77−-- OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
78−-- :}
79−--
80−-- We can easily see the generated SQL is unsuprising looking.
81−--
82−-- >>> renderDefinition setup
83−-- "CREATE TABLE \"users\" (\"id\" serial, \"name\" text NOT NULL, CONSTRAINT \"pk_users\" PRIMARY KEY (\"id\")); CREATE TABLE \"emails\" (\"id\" serial, \"user_id\" int NOT NULL, \"email\" text NULL, CONSTRAINT \"pk_emails\" PRIMARY KEY (\"id\"), CONSTRAINT \"fk_user_id\" FOREIGN KEY (\"user_id\") REFERENCES \"users\" (\"id\") ON DELETE CASCADE ON UPDATE CASCADE);"
84−--
85−-- Notice that @setup@ starts with an empty schema @'[]@ and produces @Schema@.
86−-- In our `createTable` commands we included `TableConstraint`s to define
87−-- primary and foreign keys, making them somewhat complex. Our tear down
88−-- `Definition` is simpler.
89−--
90−-- >>> :{
91−-- let
92−-- teardown :: Definition Schema '[]
93−-- teardown = dropTable #emails >>> dropTable #users
94−-- :}
95−--
96−-- >>> renderDefinition teardown
97−-- "DROP TABLE \"emails\"; DROP TABLE \"users\";"
98−--
99−-- Next, we'll write `Manipulation`s to insert data into our two tables.
100−-- A `Manipulation` is an `insertRow` (or other inserts), `update`
101−-- or `deleteFrom` command and
102−-- has three type parameters, the schema it refers to, a list of parameters
103−-- it can take as input, and a list of columns it produces as output. When
104−-- we insert into the users table, we will need a parameter for the @name@
105−-- field but not for the @id@ field. Since it's optional, we can use a default
106−-- value. However, since the emails table refers to the users table, we will
107−-- need to retrieve the user id that the insert generates and insert it into
108−-- the emails table. Take a careful look at the type and definition of both
109−-- of our inserts.
110−--
111−-- >>> :{
112−-- let
113−-- insertUser :: Manipulation Schema '[ 'NotNull 'PGtext ] '[ "fromOnly" ::: 'NotNull 'PGint4 ]
114−-- insertUser = insertRow #users
115−-- (Default `As` #id :* Set (param @1) `As` #name :* Nil)
116−-- OnConflictDoNothing (Returning (#id `As` #fromOnly :* Nil))
117−-- :}
118−--
119−-- >>> :{
120−-- let
121−-- insertEmail :: Manipulation Schema '[ 'NotNull 'PGint4, 'Null 'PGtext] '[]
122−-- insertEmail = insertRow #emails
123−-- ( Default `As` #id :*
124−-- Set (param @1) `As` #user_id :*
125−-- Set (param @2) `As` #email :* Nil )
126−-- OnConflictDoNothing (Returning Nil)
127−-- :}
128−--
129−-- >>> renderManipulation insertUser
130−-- "INSERT INTO \"users\" (\"id\", \"name\") VALUES (DEFAULT, ($1 :: text)) ON CONFLICT DO NOTHING RETURNING \"id\" AS \"fromOnly\""
131−-- >>> renderManipulation insertEmail
132−-- "INSERT INTO \"emails\" (\"id\", \"user_id\", \"email\") VALUES (DEFAULT, ($1 :: int4), ($2 :: text)) ON CONFLICT DO NOTHING"
133−--
134−-- Next we write a `Query` to retrieve users from the database. We're not
135−-- interested in the ids here, just the usernames and email addresses. We
136−-- need to use an inner join to get the right result. A `Query` is like a
137−-- `Manipulation` with the same kind of type parameters.
138−--
139−-- >>> :{
140−-- let
141−-- getUsers :: Query Schema '[]
142−-- '[ "userName" ::: 'NotNull 'PGtext
143−-- , "userEmail" ::: 'Null 'PGtext ]
144−-- getUsers = select
145−-- (#u ! #name `As` #userName :* #e ! #email `As` #userEmail :* Nil)
146−-- ( from (table (#users `As` #u)
147−-- & innerJoin (table (#emails `As` #e))
148−-- (#u ! #id .== #e ! #user_id)) )
149−-- :}
150−--
151−-- >>> renderQuery getUsers
152−-- "SELECT \"u\".\"name\" AS \"userName\", \"e\".\"email\" AS \"userEmail\" FROM \"users\" AS \"u\" INNER JOIN \"emails\" AS \"e\" ON (\"u\".\"id\" = \"e\".\"user_id\")"
153−--
154−-- Now that we've defined the SQL side of things, we'll need a Haskell type
155−-- for users. We give the type `Generics.SOP.Generic` and
156−-- `Generics.SOP.HasDatatypeInfo` instances so that we can decode the rows
157−-- we receive when we run @getUsers@. Notice that the record fields of the
158−-- @User@ type match the column names of @getUsers@.
159−--
160−-- >>> data User = User { userName :: Text, userEmail :: Maybe Text } deriving (Show, GHC.Generic)
161−-- >>> instance SOP.Generic User
162−-- >>> instance SOP.HasDatatypeInfo User
163−--
164−-- Let's also create some users to add to the database.
165−--
166−-- >>> :{
167−-- let
168−-- users :: [User]
169−-- users =
170−-- [ User "Alice" (Just "alice@gmail.com")
171−-- , User "Bob" Nothing
172−-- , User "Carole" (Just "carole@hotmail.com")
173−-- ]
174−-- :}
175−--
176−-- Now we can put together all the pieces into a program. The program
177−-- connects to the database, sets up the schema, inserts the user data
178−-- (using prepared statements as an optimization), queries the user
179−-- data and prints it out and finally closes the connection. We can thread
180−-- the changing schema information through by using the indexed `PQ` monad
181−-- transformer and when the schema doesn't change we can use `Monad` and
182−-- `MonadPQ` functionality.
183−--
184−-- >>> :{
185−-- let
186−-- session :: PQ Schema Schema IO ()
187−-- session = do
188−-- idResults <- traversePrepared insertUser (Only . userName <$> users)
189−-- ids <- traverse (fmap fromOnly . getRow 0) idResults
190−-- traversePrepared_ insertEmail (zip (ids :: [Int32]) (userEmail <$> users))
191−-- usersResult <- runQuery getUsers
192−-- usersRows <- getRows usersResult
193−-- liftBase $ print (usersRows :: [User])
194−-- :}
195−--
196−-- >>> :{
197−-- void . withConnection "host=localhost port=5432 dbname=exampledb" $
198−-- define setup
199−-- & pqThen session
200−-- & pqThen (define teardown)
201−-- :}
202−-- [User {userName = "Alice", userEmail = Just "alice@gmail.com"},User {userName = "Bob", userEmail = Nothing},User {userName = "Carole", userEmail = Just "carole@hotmail.com"}]
1+{-|
2+Module: Squeal.PostgreSQL
3+Description: Squeel export module
4+Copyright: (c) Eitan Chatav, 2017
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
2037
8+Squeal is a deep embedding of [PostgreSQL](https://www.postgresql.org) in Haskell.
9+Let's see an example!
10+
11+First, we need some language extensions because Squeal uses modern GHC
12+features.
13+
14+>>> :set -XDataKinds -XDeriveGeneric -XOverloadedLabels
15+>>> :set -XOverloadedStrings -XTypeApplications -XTypeOperators
16+
17+We'll need some imports.
18+
19+>>> import Control.Monad (void)
20+>>> import Control.Monad.Base (liftBase)
21+>>> import Data.Int (Int32)
22+>>> import Data.Text (Text)
23+>>> import Squeal.PostgreSQL
24+>>> import qualified Data.ByteString.Char8 as Char8 (putStrLn)
25+
26+We'll use generics to easily convert between Haskell and PostgreSQL values.
27+
28+>>> import qualified Generics.SOP as SOP
29+>>> import qualified GHC.Generics as GHC
30+
31+The first step is to define the schema of our database. This is where
32+we use @DataKinds@ and @TypeOperators@.
33+
34+>>> :{
35+type Schema =
36+ '[ "users" ::: 'Table (
37+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
38+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
39+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
40+ ])
41+ , "emails" ::: 'Table (
42+ '[ "pk_emails" ::: 'PrimaryKey '["id"]
43+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
44+ ] :=>
45+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
46+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
47+ , "email" ::: 'NoDef :=> 'Null 'PGtext
48+ ])
49+ ]
50+:}
51+
52+Notice the use of type operators. `:::` is used
53+to pair an alias `Symbol` with either a `TableType` or a `ColumnType`.
54+`:=>` is used to pair a `TableConstraint`s with a `ColumnsType`,
55+yielding a `TableType`, or to pair a `ColumnConstraint` with a `NullityType`,
56+yielding a `ColumnType`.
57+
58+Next, we'll write `Definition`s to set up and tear down the schema. In
59+Squeal, a `Definition` is a `createTable`, `alterTable` or `dropTable`
60+command and has two type parameters, corresponding to the schema
61+before being run and the schema after. We can compose definitions using `>>>`.
62+Here and in the rest of our commands we make use of overloaded
63+labels to refer to named tables and columns in our schema.
64+
65+>>> :{
66+let
67+ setup :: Definition '[] Schema
68+ setup =
69+ createTable #users
70+ ( serial `As` #id :*
71+ (text & notNullable) `As` #name :* Nil )
72+ ( primaryKey #id `As` #pk_users :* Nil ) >>>
73+ createTable #emails
74+ ( serial `As` #id :*
75+ (int & notNullable) `As` #user_id :*
76+ (text & nullable) `As` #email :* Nil )
77+ ( primaryKey #id `As` #pk_emails :*
78+ foreignKey #user_id #users #id
79+ OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
80+:}
81+
82+We can easily see the generated SQL is unsuprising looking.
83+
84+>>> Char8.putStrLn $ renderDefinition setup
85+CREATE TABLE "users" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"));
86+CREATE TABLE "emails" ("id" serial, "user_id" int NOT NULL, "email" text NULL, CONSTRAINT "pk_emails" PRIMARY KEY ("id"), CONSTRAINT "fk_user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE);
87+
88+Notice that @setup@ starts with an empty schema @'[]@ and produces @Schema@.
89+In our `createTable` commands we included `TableConstraint`s to define
90+primary and foreign keys, making them somewhat complex. Our tear down
91+`Definition` is simpler.
92+
93+>>> :{
94+let
95+ teardown :: Definition Schema '[]
96+ teardown = dropTable #emails >>> dropTable #users
97+:}
98+
99+>>> Char8.putStrLn $ renderDefinition teardown
100+DROP TABLE "emails";
101+DROP TABLE "users";
102+
103+Next, we'll write `Manipulation`s to insert data into our two tables.
104+A `Manipulation` is an `insertRow` (or other inserts), `update`
105+or `deleteFrom` command and
106+has three type parameters, the schema it refers to, a list of parameters
107+it can take as input, and a list of columns it produces as output. When
108+we insert into the users table, we will need a parameter for the @name@
109+field but not for the @id@ field. Since it's optional, we can use a default
110+value. However, since the emails table refers to the users table, we will
111+need to retrieve the user id that the insert generates and insert it into
112+the emails table. Take a careful look at the type and definition of both
113+of our inserts.
114+
115+>>> :{
116+let
117+ insertUser :: Manipulation Schema '[ 'NotNull 'PGtext ] '[ "fromOnly" ::: 'NotNull 'PGint4 ]
118+ insertUser = insertRow #users
119+ (Default `As` #id :* Set (param @1) `As` #name :* Nil)
120+ OnConflictDoNothing (Returning (#id `As` #fromOnly :* Nil))
121+:}
122+
123+>>> :{
124+let
125+ insertEmail :: Manipulation Schema '[ 'NotNull 'PGint4, 'Null 'PGtext] '[]
126+ insertEmail = insertRow #emails
127+ ( Default `As` #id :*
128+ Set (param @1) `As` #user_id :*
129+ Set (param @2) `As` #email :* Nil )
130+ OnConflictDoNothing (Returning Nil)
131+:}
132+
133+>>> Char8.putStrLn $ renderManipulation insertUser
134+INSERT INTO "users" ("id", "name") VALUES (DEFAULT, ($1 :: text)) ON CONFLICT DO NOTHING RETURNING "id" AS "fromOnly"
135+>>> Char8.putStrLn $ renderManipulation insertEmail
136+INSERT INTO "emails" ("id", "user_id", "email") VALUES (DEFAULT, ($1 :: int4), ($2 :: text)) ON CONFLICT DO NOTHING
137+
138+Next we write a `Query` to retrieve users from the database. We're not
139+interested in the ids here, just the usernames and email addresses. We
140+need to use an inner join to get the right result. A `Query` is like a
141+`Manipulation` with the same kind of type parameters.
142+
143+>>> :{
144+let
145+ getUsers :: Query Schema '[]
146+ '[ "userName" ::: 'NotNull 'PGtext
147+ , "userEmail" ::: 'Null 'PGtext ]
148+ getUsers = select
149+ (#u ! #name `As` #userName :* #e ! #email `As` #userEmail :* Nil)
150+ ( from (table (#users `As` #u)
151+ & innerJoin (table (#emails `As` #e))
152+ (#u ! #id .== #e ! #user_id)) )
153+:}
154+
155+>>> Char8.putStrLn $ renderQuery getUsers
156+SELECT "u"."name" AS "userName", "e"."email" AS "userEmail" FROM "users" AS "u" INNER JOIN "emails" AS "e" ON ("u"."id" = "e"."user_id")
157+
158+Now that we've defined the SQL side of things, we'll need a Haskell type
159+for users. We give the type `Generics.SOP.Generic` and
160+`Generics.SOP.HasDatatypeInfo` instances so that we can decode the rows
161+we receive when we run @getUsers@. Notice that the record fields of the
162+@User@ type match the column names of @getUsers@.
163+
164+>>> data User = User { userName :: Text, userEmail :: Maybe Text } deriving (Show, GHC.Generic)
165+>>> instance SOP.Generic User
166+>>> instance SOP.HasDatatypeInfo User
167+
168+Let's also create some users to add to the database.
169+
170+>>> :{
171+let
172+ users :: [User]
173+ users =
174+ [ User "Alice" (Just "alice@gmail.com")
175+ , User "Bob" Nothing
176+ , User "Carole" (Just "carole@hotmail.com")
177+ ]
178+:}
179+
180+Now we can put together all the pieces into a program. The program
181+connects to the database, sets up the schema, inserts the user data
182+(using prepared statements as an optimization), queries the user
183+data and prints it out and finally closes the connection. We can thread
184+the changing schema information through by using the indexed `PQ` monad
185+transformer and when the schema doesn't change we can use `Monad` and
186+`MonadPQ` functionality.
187+
188+>>> :{
189+let
190+ session :: PQ Schema Schema IO ()
191+ session = do
192+ idResults <- traversePrepared insertUser (Only . userName <$> users)
193+ ids <- traverse (fmap fromOnly . getRow 0) idResults
194+ traversePrepared_ insertEmail (zip (ids :: [Int32]) (userEmail <$> users))
195+ usersResult <- runQuery getUsers
196+ usersRows <- getRows usersResult
197+ liftBase $ print (usersRows :: [User])
198+:}
199+
200+>>> :{
201+void . withConnection "host=localhost port=5432 dbname=exampledb" $
202+ define setup
203+ & pqThen session
204+ & pqThen (define teardown)
205+:}
206+[User {userName = "Alice", userEmail = Just "alice@gmail.com"},User {userName = "Bob", userEmail = Nothing},User {userName = "Carole", userEmail = Just "carole@hotmail.com"}]
207+-}
204208module Squeal.PostgreSQL
205209 ( module Squeal.PostgreSQL.Binary
206210 , module Squeal.PostgreSQL.Definition
squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+208−202
@@ -116,20 +116,21 @@ newtype Definition
116116instance Category Definition where
117117 id = UnsafeDefinition ";"
118118 ddl1 . ddl0 = UnsafeDefinition $
119− renderDefinition ddl0 <+> renderDefinition ddl1
119+ renderDefinition ddl0 <> "\n" <> renderDefinition ddl1
120120
121121{-----------------------------------------
122122CREATE statements
123123-----------------------------------------}
124124
125−-- | `createTable` adds a table to the schema.
126−--
127−-- >>> :set -XOverloadedLabels
128−-- >>> :{
129−-- renderDefinition $
130−-- createTable #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil
131−-- :}
132−-- "CREATE TABLE \"tab\" (\"a\" int NULL, \"b\" real NULL);"
125+{- | `createTable` adds a table to the schema.
126+
127+>>> :set -XOverloadedLabels
128+>>> :{
129+Data.ByteString.Char8.putStrLn . renderDefinition $
130+ createTable #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil
131+:}
132+CREATE TABLE "tab" ("a" int NULL, "b" real NULL);
133+-}
133134createTable
134135 :: ( KnownSymbol table
135136 , columns ~ (col ': cols)
@@ -145,18 +146,19 @@ createTable
145146createTable tab columns constraints = UnsafeDefinition $
146147 "CREATE TABLE" <+> renderCreation tab columns constraints
147148
148−-- | `createTableIfNotExists` creates a table if it doesn't exist, but does not add it to the schema.
149−-- Instead, the schema already has the table so if the table did not yet exist, the schema was wrong.
150−-- `createTableIfNotExists` fixes this. Interestingly, this property makes it an idempotent in the `Category` `Definition`.
151−--
152−-- >>> :set -XOverloadedLabels -XTypeApplications
153−-- >>> type Table = '[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGfloat4]
154−-- >>> type Schema = '["tab" ::: 'Table Table]
155−-- >>> :{
156−-- renderDefinition
157−-- (createTableIfNotExists #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil :: Definition Schema Schema)
158−-- :}
159−-- "CREATE TABLE IF NOT EXISTS \"tab\" (\"a\" int NULL, \"b\" real NULL);"
149+{-| `createTableIfNotExists` creates a table if it doesn't exist, but does not add it to the schema.
150+Instead, the schema already has the table so if the table did not yet exist, the schema was wrong.
151+`createTableIfNotExists` fixes this. Interestingly, this property makes it an idempotent in the `Category` `Definition`.
152+
153+>>> :set -XOverloadedLabels -XTypeApplications
154+>>> type Table = '[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGfloat4]
155+>>> type Schema = '["tab" ::: 'Table Table]
156+>>> :{
157+Data.ByteString.Char8.putStrLn $ renderDefinition
158+ (createTableIfNotExists #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil :: Definition Schema Schema)
159+:}
160+CREATE TABLE IF NOT EXISTS "tab" ("a" int NULL, "b" real NULL);
161+-}
160162createTableIfNotExists
161163 :: ( Has table schema ('Table (constraints :=> columns))
162164 , SOP.SListI columns
@@ -220,29 +222,30 @@ newtype TableConstraintExpression
220222 { renderTableConstraintExpression :: ByteString }
221223 deriving (GHC.Generic,Show,Eq,Ord,NFData)
222224
223−-- | A `check` constraint is the most generic `TableConstraint` type.
224−-- It allows you to specify that the value in a certain column must satisfy
225−-- a Boolean (truth-value) expression.
226−--
227−-- >>> :{
228−-- type Schema = '[
229−-- "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[
230−-- "a" ::: 'NoDef :=> 'NotNull 'PGint4,
231−-- "b" ::: 'NoDef :=> 'NotNull 'PGint4
232−-- ])]
233−-- :}
234−--
235−-- >>> :{
236−-- let
237−-- definition :: Definition '[] Schema
238−-- definition = createTable #tab
239−-- ( (int & notNullable) `As` #a :*
240−-- (int & notNullable) `As` #b :* Nil )
241−-- ( check (#a :* #b :* Nil) (#a .> #b) `As` #inequality :* Nil )
242−-- :}
243−--
244−-- >>> renderDefinition definition
245−-- "CREATE TABLE \"tab\" (\"a\" int NOT NULL, \"b\" int NOT NULL, CONSTRAINT \"inequality\" CHECK ((\"a\" > \"b\")));"
225+{-| A `check` constraint is the most generic `TableConstraint` type.
226+It allows you to specify that the value in a certain column must satisfy
227+a Boolean (truth-value) expression.
228+
229+>>> :{
230+type Schema = '[
231+ "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[
232+ "a" ::: 'NoDef :=> 'NotNull 'PGint4,
233+ "b" ::: 'NoDef :=> 'NotNull 'PGint4
234+ ])]
235+:}
236+
237+>>> :{
238+let
239+ definition :: Definition '[] Schema
240+ definition = createTable #tab
241+ ( (int & notNullable) `As` #a :*
242+ (int & notNullable) `As` #b :* Nil )
243+ ( check (#a :* #b :* Nil) (#a .> #b) `As` #inequality :* Nil )
244+:}
245+
246+>>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
247+CREATE TABLE "tab" ("a" int NOT NULL, "b" int NOT NULL, CONSTRAINT "inequality" CHECK (("a" > "b")));
248+-}
246249check
247250 :: ( Has alias schema ('Table table)
248251 , HasAll aliases (TableToRelation table) subcolumns )
@@ -254,28 +257,29 @@ check
254257check _cols condition = UnsafeTableConstraintExpression $
255258 "CHECK" <+> parenthesized (renderExpression condition)
256259
257−-- | A `unique` constraint ensure that the data contained in a column,
258−-- or a group of columns, is unique among all the rows in the table.
259−--
260−-- >>> :{
261−-- type Schema = '[
262−-- "tab" ::: 'Table( '[ "uq_a_b" ::: 'Unique '["a","b"]] :=> '[
263−-- "a" ::: 'NoDef :=> 'Null 'PGint4,
264−-- "b" ::: 'NoDef :=> 'Null 'PGint4
265−-- ])]
266−-- :}
267−--
268−-- >>> :{
269−-- let
270−-- definition :: Definition '[] Schema
271−-- definition = createTable #tab
272−-- ( (int & nullable) `As` #a :*
273−-- (int & nullable) `As` #b :* Nil )
274−-- ( unique (#a :* #b :* Nil) `As` #uq_a_b :* Nil )
275−-- :}
276−--
277−-- >>> renderDefinition definition
278−-- "CREATE TABLE \"tab\" (\"a\" int NULL, \"b\" int NULL, CONSTRAINT \"uq_a_b\" UNIQUE (\"a\", \"b\"));"
260+{-| A `unique` constraint ensure that the data contained in a column,
261+or a group of columns, is unique among all the rows in the table.
262+
263+>>> :{
264+type Schema = '[
265+ "tab" ::: 'Table( '[ "uq_a_b" ::: 'Unique '["a","b"]] :=> '[
266+ "a" ::: 'NoDef :=> 'Null 'PGint4,
267+ "b" ::: 'NoDef :=> 'Null 'PGint4
268+ ])]
269+:}
270+
271+>>> :{
272+let
273+ definition :: Definition '[] Schema
274+ definition = createTable #tab
275+ ( (int & nullable) `As` #a :*
276+ (int & nullable) `As` #b :* Nil )
277+ ( unique (#a :* #b :* Nil) `As` #uq_a_b :* Nil )
278+:}
279+
280+>>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
281+CREATE TABLE "tab" ("a" int NULL, "b" int NULL, CONSTRAINT "uq_a_b" UNIQUE ("a", "b"));
282+-}
279283unique
280284 :: ( Has alias schema ('Table table)
281285 , HasAll aliases (TableToRelation table) subcolumns )
@@ -285,29 +289,30 @@ unique
285289unique columns = UnsafeTableConstraintExpression $
286290 "UNIQUE" <+> parenthesized (commaSeparated (renderAliases columns))
287291
288−-- | A `primaryKey` constraint indicates that a column, or group of columns,
289−-- can be used as a unique identifier for rows in the table.
290−-- This requires that the values be both unique and not null.
291−--
292−-- >>> :{
293−-- type Schema = '[
294−-- "tab" ::: 'Table ('[ "pk_id" ::: 'PrimaryKey '["id"]] :=> '[
295−-- "id" ::: 'Def :=> 'NotNull 'PGint4,
296−-- "name" ::: 'NoDef :=> 'NotNull 'PGtext
297−-- ])]
298−-- :}
299−--
300−-- >>> :{
301−-- let
302−-- definition :: Definition '[] Schema
303−-- definition = createTable #tab
304−-- ( serial `As` #id :*
305−-- (text & notNullable) `As` #name :* Nil )
306−-- ( primaryKey #id `As` #pk_id :* Nil )
307−-- :}
308−--
309−-- >>> renderDefinition definition
310−-- "CREATE TABLE \"tab\" (\"id\" serial, \"name\" text NOT NULL, CONSTRAINT \"pk_id\" PRIMARY KEY (\"id\"));"
292+{-| A `primaryKey` constraint indicates that a column, or group of columns,
293+can be used as a unique identifier for rows in the table.
294+This requires that the values be both unique and not null.
295+
296+>>> :{
297+type Schema = '[
298+ "tab" ::: 'Table ('[ "pk_id" ::: 'PrimaryKey '["id"]] :=> '[
299+ "id" ::: 'Def :=> 'NotNull 'PGint4,
300+ "name" ::: 'NoDef :=> 'NotNull 'PGtext
301+ ])]
302+:}
303+
304+>>> :{
305+let
306+ definition :: Definition '[] Schema
307+ definition = createTable #tab
308+ ( serial `As` #id :*
309+ (text & notNullable) `As` #name :* Nil )
310+ ( primaryKey #id `As` #pk_id :* Nil )
311+:}
312+
313+>>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
314+CREATE TABLE "tab" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_id" PRIMARY KEY ("id"));
315+-}
311316primaryKey
312317 :: ( Has alias schema ('Table table)
313318 , HasAll aliases (TableToColumns table) subcolumns
@@ -318,78 +323,79 @@ primaryKey
318323primaryKey columns = UnsafeTableConstraintExpression $
319324 "PRIMARY KEY" <+> parenthesized (commaSeparated (renderAliases columns))
320325
321−-- | A `foreignKey` specifies that the values in a column
322−-- (or a group of columns) must match the values appearing in some row of
323−-- another table. We say this maintains the referential integrity
324−-- between two related tables.
325−--
326−-- >>> :{
327−-- type Schema =
328−-- '[ "users" ::: 'Table (
329−-- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
330−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
331−-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext
332−-- ])
333−-- , "emails" ::: 'Table (
334−-- '[ "pk_emails" ::: 'PrimaryKey '["id"]
335−-- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
336−-- ] :=>
337−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
338−-- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
339−-- , "email" ::: 'NoDef :=> 'Null 'PGtext
340−-- ])
341−-- ]
342−-- :}
343−--
344−-- >>> :{
345−-- let
346−-- setup :: Definition '[] Schema
347−-- setup =
348−-- createTable #users
349−-- ( serial `As` #id :*
350−-- (text & notNullable) `As` #name :* Nil )
351−-- ( primaryKey #id `As` #pk_users :* Nil ) >>>
352−-- createTable #emails
353−-- ( serial `As` #id :*
354−-- (int & notNullable) `As` #user_id :*
355−-- (text & nullable) `As` #email :* Nil )
356−-- ( primaryKey #id `As` #pk_emails :*
357−-- foreignKey #user_id #users #id
358−-- OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
359−-- in renderDefinition setup
360−-- :}
361−-- "CREATE TABLE \"users\" (\"id\" serial, \"name\" text NOT NULL, CONSTRAINT \"pk_users\" PRIMARY KEY (\"id\")); CREATE TABLE \"emails\" (\"id\" serial, \"user_id\" int NOT NULL, \"email\" text NULL, CONSTRAINT \"pk_emails\" PRIMARY KEY (\"id\"), CONSTRAINT \"fk_user_id\" FOREIGN KEY (\"user_id\") REFERENCES \"users\" (\"id\") ON DELETE CASCADE ON UPDATE CASCADE);"
362−--
363−-- A `foreignKey` can even be a table self-reference.
364−--
365−-- >>> :{
366−-- type Schema =
367−-- '[ "employees" ::: 'Table (
368−-- '[ "employees_pk" ::: 'PrimaryKey '["id"]
369−-- , "employees_employer_fk" ::: 'ForeignKey '["employer_id"] "employees" '["id"]
370−-- ] :=>
371−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
372−-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext
373−-- , "employer_id" ::: 'NoDef :=> 'Null 'PGint4
374−-- ])
375−-- ]
376−-- :}
377−--
378−-- >>> :{
379−-- let
380−-- setup :: Definition '[] Schema
381−-- setup =
382−-- createTable #employees
383−-- ( serial `As` #id :*
384−-- (text & notNullable) `As` #name :*
385−-- (integer & nullable) `As` #employer_id :* Nil )
386−-- ( primaryKey #id `As` #employees_pk :*
387−-- foreignKey #employer_id #employees #id
388−-- OnDeleteCascade OnUpdateCascade `As` #employees_employer_fk :* Nil )
389−-- in renderDefinition setup
390−-- :}
391−-- "CREATE TABLE \"employees\" (\"id\" serial, \"name\" text NOT NULL, \"employer_id\" integer NULL, CONSTRAINT \"employees_pk\" PRIMARY KEY (\"id\"), CONSTRAINT \"employees_employer_fk\" FOREIGN KEY (\"employer_id\") REFERENCES \"employees\" (\"id\") ON DELETE CASCADE ON UPDATE CASCADE);"
392−--
326+{-| A `foreignKey` specifies that the values in a column
327+(or a group of columns) must match the values appearing in some row of
328+another table. We say this maintains the referential integrity
329+between two related tables.
330+
331+>>> :{
332+type Schema =
333+ '[ "users" ::: 'Table (
334+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
335+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
336+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
337+ ])
338+ , "emails" ::: 'Table (
339+ '[ "pk_emails" ::: 'PrimaryKey '["id"]
340+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
341+ ] :=>
342+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
343+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
344+ , "email" ::: 'NoDef :=> 'Null 'PGtext
345+ ])
346+ ]
347+:}
348+
349+>>> :{
350+let
351+ setup :: Definition '[] Schema
352+ setup =
353+ createTable #users
354+ ( serial `As` #id :*
355+ (text & notNullable) `As` #name :* Nil )
356+ ( primaryKey #id `As` #pk_users :* Nil ) >>>
357+ createTable #emails
358+ ( serial `As` #id :*
359+ (int & notNullable) `As` #user_id :*
360+ (text & nullable) `As` #email :* Nil )
361+ ( primaryKey #id `As` #pk_emails :*
362+ foreignKey #user_id #users #id
363+ OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
364+in Data.ByteString.Char8.putStrLn $ renderDefinition setup
365+:}
366+CREATE TABLE "users" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"));
367+CREATE TABLE "emails" ("id" serial, "user_id" int NOT NULL, "email" text NULL, CONSTRAINT "pk_emails" PRIMARY KEY ("id"), CONSTRAINT "fk_user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE);
368+
369+A `foreignKey` can even be a table self-reference.
370+
371+>>> :{
372+type Schema =
373+ '[ "employees" ::: 'Table (
374+ '[ "employees_pk" ::: 'PrimaryKey '["id"]
375+ , "employees_employer_fk" ::: 'ForeignKey '["employer_id"] "employees" '["id"]
376+ ] :=>
377+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
378+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
379+ , "employer_id" ::: 'NoDef :=> 'Null 'PGint4
380+ ])
381+ ]
382+:}
383+
384+>>> :{
385+let
386+ setup :: Definition '[] Schema
387+ setup =
388+ createTable #employees
389+ ( serial `As` #id :*
390+ (text & notNullable) `As` #name :*
391+ (integer & nullable) `As` #employer_id :* Nil )
392+ ( primaryKey #id `As` #employees_pk :*
393+ foreignKey #employer_id #employees #id
394+ OnDeleteCascade OnUpdateCascade `As` #employees_employer_fk :* Nil )
395+in Data.ByteString.Char8.putStrLn $ renderDefinition setup
396+:}
397+CREATE TABLE "employees" ("id" serial, "name" text NOT NULL, "employer_id" integer NULL, CONSTRAINT "employees_pk" PRIMARY KEY ("id"), CONSTRAINT "employees_employer_fk" FOREIGN KEY ("employer_id") REFERENCES "employees" ("id") ON DELETE CASCADE ON UPDATE CASCADE);
398+-}
393399foreignKey
394400 :: (ForeignKeyed schema child parent
395401 table reftable
@@ -481,8 +487,8 @@ DROP statements
481487-- definition = dropTable #muh_table
482488-- :}
483489--
484−-- >>> renderDefinition definition
485−-- "DROP TABLE \"muh_table\";"
490+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
491+-- DROP TABLE "muh_table";
486492dropTable
487493 :: Has table schema ('Table t)
488494 => Alias table -- ^ table to remove
@@ -507,8 +513,8 @@ alterTable tab alteration = UnsafeDefinition $
507513
508514-- | `alterTableRename` changes the name of a table from the schema.
509515--
510−-- >>> renderDefinition $ alterTableRename #foo #bar
511−-- "ALTER TABLE \"foo\" RENAME TO \"bar\";"
516+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ alterTableRename #foo #bar
517+-- ALTER TABLE "foo" RENAME TO "bar";
512518alterTableRename
513519 :: (KnownSymbol table0, KnownSymbol table1)
514520 => Alias table0 -- ^ table to rename
@@ -535,9 +541,9 @@ newtype AlterTable
535541-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
536542-- '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
537543-- definition = alterTable #tab (addConstraint #positive (check (#col :* Nil) (#col .> 0)))
538−-- in renderDefinition definition
544+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
539545-- :}
540−-- "ALTER TABLE \"tab\" ADD CONSTRAINT \"positive\" CHECK ((\"col\" > 0));"
546+-- ALTER TABLE "tab" ADD CONSTRAINT "positive" CHECK (("col" > 0));
541547addConstraint
542548 :: ( KnownSymbol alias
543549 , Has tab schema ('Table table0)
@@ -559,9 +565,9 @@ addConstraint alias constraint = UnsafeAlterTable $
559565-- '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
560566-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
561567-- definition = alterTable #tab (dropConstraint #positive)
562−-- in renderDefinition definition
568+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
563569-- :}
564−-- "ALTER TABLE \"tab\" DROP CONSTRAINT \"positive\";"
570+-- ALTER TABLE "tab" DROP CONSTRAINT "positive";
565571dropConstraint
566572 :: ( KnownSymbol constraint
567573 , Has tab schema ('Table table0)
@@ -586,9 +592,9 @@ class AddColumn ty where
586592 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
587593 -- , "col2" ::: 'Def :=> 'Null 'PGtext ])]
588594 -- definition = alterTable #tab (addColumn #col2 (text & nullable & default_ "foo"))
589− -- in renderDefinition definition
595+ -- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
590596 -- :}
591− -- "ALTER TABLE \"tab\" ADD COLUMN \"col2\" text NULL DEFAULT E'foo';"
597+ -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL DEFAULT E'foo';
592598 --
593599 -- >>> :{
594600 -- let
@@ -598,9 +604,9 @@ class AddColumn ty where
598604 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
599605 -- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
600606 -- definition = alterTable #tab (addColumn #col2 (text & nullable))
601− -- in renderDefinition definition
607+ -- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
602608 -- :}
603− -- "ALTER TABLE \"tab\" ADD COLUMN \"col2\" text NULL;"
609+ -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL;
604610 addColumn
605611 :: ( KnownSymbol column
606612 , Has tab schema ('Table table0)
@@ -627,9 +633,9 @@ instance {-# OVERLAPPABLE #-} AddColumn ('NoDef :=> 'Null ty)
627633-- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
628634-- '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]
629635-- definition = alterTable #tab (dropColumn #col2)
630−-- in renderDefinition definition
636+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
631637-- :}
632−-- "ALTER TABLE \"tab\" DROP COLUMN \"col2\";"
638+-- ALTER TABLE "tab" DROP COLUMN "col2";
633639dropColumn
634640 :: ( KnownSymbol column
635641 , Has tab schema ('Table table0)
@@ -648,9 +654,9 @@ dropColumn column = UnsafeAlterTable $
648654-- '["tab" ::: 'Table ('[] :=> '["foo" ::: 'NoDef :=> 'Null 'PGint4])]
649655-- '["tab" ::: 'Table ('[] :=> '["bar" ::: 'NoDef :=> 'Null 'PGint4])]
650656-- definition = alterTable #tab (renameColumn #foo #bar)
651−-- in renderDefinition definition
657+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
652658-- :}
653−-- "ALTER TABLE \"tab\" RENAME COLUMN \"foo\" TO \"bar\";"
659+-- ALTER TABLE "tab" RENAME COLUMN "foo" TO "bar";
654660renameColumn
655661 :: ( KnownSymbol column0
656662 , KnownSymbol column1
@@ -691,9 +697,9 @@ newtype AlterColumn (schema :: SchemaType) (ty0 :: ColumnType) (ty1 :: ColumnTyp
691697-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
692698-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]
693699-- definition = alterTable #tab (alterColumn #col (setDefault 5))
694−-- in renderDefinition definition
700+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
695701-- :}
696−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" SET DEFAULT 5;"
702+-- ALTER TABLE "tab" ALTER COLUMN "col" SET DEFAULT 5;
697703setDefault
698704 :: Expression schema '[] 'Ungrouped '[] ty -- ^ default value to set
699705 -> AlterColumn schema (constraint :=> ty) ('Def :=> ty)
@@ -708,9 +714,9 @@ setDefault expression = UnsafeAlterColumn $
708714-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]
709715-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
710716-- definition = alterTable #tab (alterColumn #col dropDefault)
711−-- in renderDefinition definition
717+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
712718-- :}
713−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" DROP DEFAULT;"
719+-- ALTER TABLE "tab" ALTER COLUMN "col" DROP DEFAULT;
714720dropDefault :: AlterColumn schema ('Def :=> ty) ('NoDef :=> ty)
715721dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
716722
@@ -724,9 +730,9 @@ dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
724730-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
725731-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
726732-- definition = alterTable #tab (alterColumn #col setNotNull)
727−-- in renderDefinition definition
733+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
728734-- :}
729−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" SET NOT NULL;"
735+-- ALTER TABLE "tab" ALTER COLUMN "col" SET NOT NULL;
730736setNotNull
731737 :: AlterColumn schema (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)
732738setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
@@ -739,9 +745,9 @@ setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
739745-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
740746-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
741747-- definition = alterTable #tab (alterColumn #col dropNotNull)
742−-- in renderDefinition definition
748+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
743749-- :}
744−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" DROP NOT NULL;"
750+-- ALTER TABLE "tab" ALTER COLUMN "col" DROP NOT NULL;
745751dropNotNull
746752 :: AlterColumn schema (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)
747753dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
@@ -757,9 +763,9 @@ dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
757763-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGnumeric])]
758764-- definition =
759765-- alterTable #tab (alterColumn #col (alterType (numeric & notNullable)))
760−-- in renderDefinition definition
766+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
761767-- :}
762−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" TYPE numeric NOT NULL;"
768+-- ALTER TABLE "tab" ALTER COLUMN "col" TYPE numeric NOT NULL;
763769alterType :: ColumnTypeExpression schema ty -> AlterColumn schema ty0 ty
764770alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
765771
@@ -772,10 +778,10 @@ alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
772778-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])
773779-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
774780-- definition =
775−-- createView #bc (select (#b `As` #b :* #c `As` #c :* Nil) (from (table (#abc `As` #abc))))
776−-- in renderDefinition definition
781+-- createView #bc (select (#b :* #c :* Nil) (from (table #abc)))
782+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
777783-- :}
778−-- "CREATE VIEW \"bc\" AS SELECT \"b\" AS \"b\", \"c\" AS \"c\" FROM \"abc\" AS \"abc\";"
784+-- CREATE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";
779785createView
780786 :: KnownSymbol view
781787 => Alias view -- ^ the name of the table to add
@@ -795,9 +801,9 @@ createView alias query = UnsafeDefinition $
795801-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
796802-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]
797803-- definition = dropView #bc
798−-- in renderDefinition definition
804+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
799805-- :}
800−-- "DROP VIEW \"bc\";"
806+-- DROP VIEW "bc";
801807dropView
802808 :: Has view schema ('View v)
803809 => Alias view -- ^ view to remove
@@ -806,8 +812,8 @@ dropView v = UnsafeDefinition $ "DROP VIEW" <+> renderAlias v <> ";"
806812
807813-- | Enumerated types are created using the `createTypeEnum` command, for example
808814--
809−-- >>> renderDefinition $ createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy" :* Nil)
810−-- "CREATE TYPE \"mood\" AS ENUM ('sad', 'ok', 'happy');"
815+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy" :* Nil)
816+-- CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');
811817createTypeEnum
812818 :: (KnownSymbol enum, SOP.All KnownSymbol labels)
813819 => Alias enum
@@ -824,8 +830,8 @@ createTypeEnum enum labels = UnsafeDefinition $
824830-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
825831-- >>> instance SOP.Generic Schwarma
826832-- >>> instance SOP.HasDatatypeInfo Schwarma
827−-- >>> renderDefinition $ createTypeEnumWith @Schwarma #schwarma
828−-- "CREATE TYPE \"schwarma\" AS ENUM ('Beef', 'Lamb', 'Chicken');"
833+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeEnumWith @Schwarma #schwarma
834+-- CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');
829835createTypeEnumWith
830836 :: forall hask enum schema.
831837 ( SOP.Generic hask
@@ -841,8 +847,8 @@ createTypeEnumWith enum = createTypeEnum enum
841847-- | `createTypeComposite` creates a composite type. The composite type is
842848-- specified by a list of attribute names and data types.
843849--
844−-- >>> renderDefinition $ createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
845−-- "CREATE TYPE \"complex\" AS (\"real\" float8, \"imaginary\" float8);"
850+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
851+-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
846852createTypeComposite
847853 :: (KnownSymbol ty, SOP.SListI fields)
848854 => Alias ty
@@ -863,8 +869,8 @@ createTypeComposite ty fields = UnsafeDefinition $
863869-- >>> data Complex = Complex {real :: Maybe Double, imaginary :: Maybe Double} deriving GHC.Generic
864870-- >>> instance SOP.Generic Complex
865871-- >>> instance SOP.HasDatatypeInfo Complex
866−-- >>> renderDefinition $ createTypeCompositeWith @Complex #complex
867−-- "CREATE TYPE \"complex\" AS (\"real\" float8, \"imaginary\" float8);"
872+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeCompositeWith @Complex #complex
873+-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
868874createTypeCompositeWith
869875 :: forall hask ty schema.
870876 ( ZipAliased (FieldNamesWith hask) (FieldTypesWith hask)
@@ -884,8 +890,8 @@ createTypeCompositeWith ty = createTypeComposite ty $ zipAs
884890-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
885891-- >>> instance SOP.Generic Schwarma
886892-- >>> instance SOP.HasDatatypeInfo Schwarma
887−-- >>> renderDefinition (dropType #schwarma :: Definition '["schwarma" ::: 'Typedef (EnumWith Schwarma)] '[])
888−-- "DROP TYPE \"schwarma\";"
893+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition (dropType #schwarma :: Definition '["schwarma" ::: 'Typedef (EnumWith Schwarma)] '[])
894+-- DROP TYPE "schwarma";
889895dropType
890896 :: Has tydef schema ('Typedef ty)
891897 => Alias tydef