on dev help sign in
docs changes and newline between definitions
1e229acEitan Chatav
squeal-postgresql/src/Squeal/PostgreSQL.hs+206−202
@@ -1,206 +1,210 @@
1+{-|
1−-- | Module: Squeal.PostgreSQL
2+Module: Squeal.PostgreSQL
2−-- Description: Squeel export module
3+Description: Squeel export module
3−-- Copyright: (c) Eitan Chatav, 2017
4+Copyright: (c) Eitan Chatav, 2017
4−-- Maintainer: eitan@morphism.tech
5+Maintainer: eitan@morphism.tech
5−-- Stability: experimental
6+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"}]
203
7
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+-}
204module Squeal.PostgreSQL
208module Squeal.PostgreSQL
205 ( module Squeal.PostgreSQL.Binary
209 ( module Squeal.PostgreSQL.Binary
206 , module Squeal.PostgreSQL.Definition
210 , module Squeal.PostgreSQL.Definition
squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+208−202
@@ -116,20 +116,21 @@ newtype Definition
116instance Category Definition where
116instance Category Definition where
117 id = UnsafeDefinition ";"
117 id = UnsafeDefinition ";"
118 ddl1 . ddl0 = UnsafeDefinition $
118 ddl1 . ddl0 = UnsafeDefinition $
119− renderDefinition ddl0 <+> renderDefinition ddl1
119+ renderDefinition ddl0 <> "\n" <> renderDefinition ddl1
120
120
121{-----------------------------------------
121{-----------------------------------------
122CREATE statements
122CREATE statements
123-----------------------------------------}
123-----------------------------------------}
124
124
125−-- | `createTable` adds a table to the schema.
125+{- | `createTable` adds a table to the schema.
126−--
126+
127−-- >>> :set -XOverloadedLabels
127+>>> :set -XOverloadedLabels
128−-- >>> :{
128+>>> :{
129−-- renderDefinition $
129+Data.ByteString.Char8.putStrLn . renderDefinition $
130−-- createTable #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil
130+ createTable #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil
131−-- :}
131+:}
132−-- "CREATE TABLE \"tab\" (\"a\" int NULL, \"b\" real NULL);"
132+CREATE TABLE "tab" ("a" int NULL, "b" real NULL);
133+-}
133createTable
134createTable
134 :: ( KnownSymbol table
135 :: ( KnownSymbol table
135 , columns ~ (col ': cols)
136 , columns ~ (col ': cols)
@@ -145,18 +146,19 @@ createTable
145createTable tab columns constraints = UnsafeDefinition $
146createTable tab columns constraints = UnsafeDefinition $
146 "CREATE TABLE" <+> renderCreation tab columns constraints
147 "CREATE TABLE" <+> renderCreation tab columns constraints
147
148
148−-- | `createTableIfNotExists` creates a table if it doesn't exist, but does not add it to the schema.
149+{-| `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+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+`createTableIfNotExists` fixes this. Interestingly, this property makes it an idempotent in the `Category` `Definition`.
151−--
152+
152−-- >>> :set -XOverloadedLabels -XTypeApplications
153+>>> :set -XOverloadedLabels -XTypeApplications
153−-- >>> type Table = '[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGfloat4]
154+>>> type Table = '[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGfloat4]
154−-- >>> type Schema = '["tab" ::: 'Table Table]
155+>>> type Schema = '["tab" ::: 'Table Table]
155−-- >>> :{
156+>>> :{
156−-- renderDefinition
157+Data.ByteString.Char8.putStrLn $ renderDefinition
157−-- (createTableIfNotExists #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil :: Definition Schema Schema)
158+ (createTableIfNotExists #tab ((int & nullable) `As` #a :* (real & nullable) `As` #b :* Nil) Nil :: Definition Schema Schema)
158−-- :}
159+:}
159−-- "CREATE TABLE IF NOT EXISTS \"tab\" (\"a\" int NULL, \"b\" real NULL);"
160+CREATE TABLE IF NOT EXISTS "tab" ("a" int NULL, "b" real NULL);
161+-}
160createTableIfNotExists
162createTableIfNotExists
161 :: ( Has table schema ('Table (constraints :=> columns))
163 :: ( Has table schema ('Table (constraints :=> columns))
162 , SOP.SListI columns
164 , SOP.SListI columns
@@ -220,29 +222,30 @@ newtype TableConstraintExpression
220 { renderTableConstraintExpression :: ByteString }
222 { renderTableConstraintExpression :: ByteString }
221 deriving (GHC.Generic,Show,Eq,Ord,NFData)
223 deriving (GHC.Generic,Show,Eq,Ord,NFData)
222
224
223−-- | A `check` constraint is the most generic `TableConstraint` type.
225+{-| A `check` constraint is the most generic `TableConstraint` type.
224−-- It allows you to specify that the value in a certain column must satisfy
226+It allows you to specify that the value in a certain column must satisfy
225−-- a Boolean (truth-value) expression.
227+a Boolean (truth-value) expression.
226−--
228+
227−-- >>> :{
229+>>> :{
228−-- type Schema = '[
230+type Schema = '[
229−-- "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[
231+ "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[
230−-- "a" ::: 'NoDef :=> 'NotNull 'PGint4,
232+ "a" ::: 'NoDef :=> 'NotNull 'PGint4,
231−-- "b" ::: 'NoDef :=> 'NotNull 'PGint4
233+ "b" ::: 'NoDef :=> 'NotNull 'PGint4
232−-- ])]
234+ ])]
233−-- :}
235+:}
234−--
236+
235−-- >>> :{
237+>>> :{
236−-- let
238+let
237−-- definition :: Definition '[] Schema
239+ definition :: Definition '[] Schema
238−-- definition = createTable #tab
240+ definition = createTable #tab
239−-- ( (int & notNullable) `As` #a :*
241+ ( (int & notNullable) `As` #a :*
240−-- (int & notNullable) `As` #b :* Nil )
242+ (int & notNullable) `As` #b :* Nil )
241−-- ( check (#a :* #b :* Nil) (#a .> #b) `As` #inequality :* Nil )
243+ ( check (#a :* #b :* Nil) (#a .> #b) `As` #inequality :* Nil )
242−-- :}
244+:}
243−--
245+
244−-- >>> renderDefinition definition
246+>>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
245−-- "CREATE TABLE \"tab\" (\"a\" int NOT NULL, \"b\" int NOT NULL, CONSTRAINT \"inequality\" CHECK ((\"a\" > \"b\")));"
247+CREATE TABLE "tab" ("a" int NOT NULL, "b" int NOT NULL, CONSTRAINT "inequality" CHECK (("a" > "b")));
248+-}
246check
249check
247 :: ( Has alias schema ('Table table)
250 :: ( Has alias schema ('Table table)
248 , HasAll aliases (TableToRelation table) subcolumns )
251 , HasAll aliases (TableToRelation table) subcolumns )
@@ -254,28 +257,29 @@ check
254check _cols condition = UnsafeTableConstraintExpression $
257check _cols condition = UnsafeTableConstraintExpression $
255 "CHECK" <+> parenthesized (renderExpression condition)
258 "CHECK" <+> parenthesized (renderExpression condition)
256
259
257−-- | A `unique` constraint ensure that the data contained in a column,
260+{-| 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.
261+or a group of columns, is unique among all the rows in the table.
259−--
262+
260−-- >>> :{
263+>>> :{
261−-- type Schema = '[
264+type Schema = '[
262−-- "tab" ::: 'Table( '[ "uq_a_b" ::: 'Unique '["a","b"]] :=> '[
265+ "tab" ::: 'Table( '[ "uq_a_b" ::: 'Unique '["a","b"]] :=> '[
263−-- "a" ::: 'NoDef :=> 'Null 'PGint4,
266+ "a" ::: 'NoDef :=> 'Null 'PGint4,
264−-- "b" ::: 'NoDef :=> 'Null 'PGint4
267+ "b" ::: 'NoDef :=> 'Null 'PGint4
265−-- ])]
268+ ])]
266−-- :}
269+:}
267−--
270+
268−-- >>> :{
271+>>> :{
269−-- let
272+let
270−-- definition :: Definition '[] Schema
273+ definition :: Definition '[] Schema
271−-- definition = createTable #tab
274+ definition = createTable #tab
272−-- ( (int & nullable) `As` #a :*
275+ ( (int & nullable) `As` #a :*
273−-- (int & nullable) `As` #b :* Nil )
276+ (int & nullable) `As` #b :* Nil )
274−-- ( unique (#a :* #b :* Nil) `As` #uq_a_b :* Nil )
277+ ( unique (#a :* #b :* Nil) `As` #uq_a_b :* Nil )
275−-- :}
278+:}
276−--
279+
277−-- >>> renderDefinition definition
280+>>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
278−-- "CREATE TABLE \"tab\" (\"a\" int NULL, \"b\" int NULL, CONSTRAINT \"uq_a_b\" UNIQUE (\"a\", \"b\"));"
281+CREATE TABLE "tab" ("a" int NULL, "b" int NULL, CONSTRAINT "uq_a_b" UNIQUE ("a", "b"));
282+-}
279unique
283unique
280 :: ( Has alias schema ('Table table)
284 :: ( Has alias schema ('Table table)
281 , HasAll aliases (TableToRelation table) subcolumns )
285 , HasAll aliases (TableToRelation table) subcolumns )
@@ -285,29 +289,30 @@ unique
285unique columns = UnsafeTableConstraintExpression $
289unique columns = UnsafeTableConstraintExpression $
286 "UNIQUE" <+> parenthesized (commaSeparated (renderAliases columns))
290 "UNIQUE" <+> parenthesized (commaSeparated (renderAliases columns))
287
291
288−-- | A `primaryKey` constraint indicates that a column, or group of columns,
292+{-| A `primaryKey` constraint indicates that a column, or group of columns,
289−-- can be used as a unique identifier for rows in the table.
293+can be used as a unique identifier for rows in the table.
290−-- This requires that the values be both unique and not null.
294+This requires that the values be both unique and not null.
291−--
295+
292−-- >>> :{
296+>>> :{
293−-- type Schema = '[
297+type Schema = '[
294−-- "tab" ::: 'Table ('[ "pk_id" ::: 'PrimaryKey '["id"]] :=> '[
298+ "tab" ::: 'Table ('[ "pk_id" ::: 'PrimaryKey '["id"]] :=> '[
295−-- "id" ::: 'Def :=> 'NotNull 'PGint4,
299+ "id" ::: 'Def :=> 'NotNull 'PGint4,
296−-- "name" ::: 'NoDef :=> 'NotNull 'PGtext
300+ "name" ::: 'NoDef :=> 'NotNull 'PGtext
297−-- ])]
301+ ])]
298−-- :}
302+:}
299−--
303+
300−-- >>> :{
304+>>> :{
301−-- let
305+let
302−-- definition :: Definition '[] Schema
306+ definition :: Definition '[] Schema
303−-- definition = createTable #tab
307+ definition = createTable #tab
304−-- ( serial `As` #id :*
308+ ( serial `As` #id :*
305−-- (text & notNullable) `As` #name :* Nil )
309+ (text & notNullable) `As` #name :* Nil )
306−-- ( primaryKey #id `As` #pk_id :* Nil )
310+ ( primaryKey #id `As` #pk_id :* Nil )
307−-- :}
311+:}
308−--
312+
309−-- >>> renderDefinition definition
313+>>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
310−-- "CREATE TABLE \"tab\" (\"id\" serial, \"name\" text NOT NULL, CONSTRAINT \"pk_id\" PRIMARY KEY (\"id\"));"
314+CREATE TABLE "tab" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_id" PRIMARY KEY ("id"));
315+-}
311primaryKey
316primaryKey
312 :: ( Has alias schema ('Table table)
317 :: ( Has alias schema ('Table table)
313 , HasAll aliases (TableToColumns table) subcolumns
318 , HasAll aliases (TableToColumns table) subcolumns
@@ -318,78 +323,79 @@ primaryKey
318primaryKey columns = UnsafeTableConstraintExpression $
323primaryKey columns = UnsafeTableConstraintExpression $
319 "PRIMARY KEY" <+> parenthesized (commaSeparated (renderAliases columns))
324 "PRIMARY KEY" <+> parenthesized (commaSeparated (renderAliases columns))
320
325
321−-- | A `foreignKey` specifies that the values in a column
326+{-| A `foreignKey` specifies that the values in a column
322−-- (or a group of columns) must match the values appearing in some row of
327+(or a group of columns) must match the values appearing in some row of
323−-- another table. We say this maintains the referential integrity
328+another table. We say this maintains the referential integrity
324−-- between two related tables.
329+between two related tables.
325−--
330+
326−-- >>> :{
331+>>> :{
327−-- type Schema =
332+type Schema =
328−-- '[ "users" ::: 'Table (
333+ '[ "users" ::: 'Table (
329−-- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
334+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
330−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
335+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
331−-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext
336+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
332−-- ])
337+ ])
333−-- , "emails" ::: 'Table (
338+ , "emails" ::: 'Table (
334−-- '[ "pk_emails" ::: 'PrimaryKey '["id"]
339+ '[ "pk_emails" ::: 'PrimaryKey '["id"]
335−-- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
340+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
336−-- ] :=>
341+ ] :=>
337−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
342+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
338−-- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
343+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
339−-- , "email" ::: 'NoDef :=> 'Null 'PGtext
344+ , "email" ::: 'NoDef :=> 'Null 'PGtext
340−-- ])
345+ ])
341−-- ]
346+ ]
342−-- :}
347+:}
343−--
348+
344−-- >>> :{
349+>>> :{
345−-- let
350+let
346−-- setup :: Definition '[] Schema
351+ setup :: Definition '[] Schema
347−-- setup =
352+ setup =
348−-- createTable #users
353+ createTable #users
349−-- ( serial `As` #id :*
354+ ( serial `As` #id :*
350−-- (text & notNullable) `As` #name :* Nil )
355+ (text & notNullable) `As` #name :* Nil )
351−-- ( primaryKey #id `As` #pk_users :* Nil ) >>>
356+ ( primaryKey #id `As` #pk_users :* Nil ) >>>
352−-- createTable #emails
357+ createTable #emails
353−-- ( serial `As` #id :*
358+ ( serial `As` #id :*
354−-- (int & notNullable) `As` #user_id :*
359+ (int & notNullable) `As` #user_id :*
355−-- (text & nullable) `As` #email :* Nil )
360+ (text & nullable) `As` #email :* Nil )
356−-- ( primaryKey #id `As` #pk_emails :*
361+ ( primaryKey #id `As` #pk_emails :*
357−-- foreignKey #user_id #users #id
362+ foreignKey #user_id #users #id
358−-- OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
363+ OnDeleteCascade OnUpdateCascade `As` #fk_user_id :* Nil )
359−-- in renderDefinition setup
364+in Data.ByteString.Char8.putStrLn $ renderDefinition setup
360−-- :}
365+:}
366+CREATE TABLE "users" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"));
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);"
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);
362−--
368+
363−-- A `foreignKey` can even be a table self-reference.
369+A `foreignKey` can even be a table self-reference.
364−--
370+
365−-- >>> :{
371+>>> :{
366−-- type Schema =
372+type Schema =
367−-- '[ "employees" ::: 'Table (
373+ '[ "employees" ::: 'Table (
368−-- '[ "employees_pk" ::: 'PrimaryKey '["id"]
374+ '[ "employees_pk" ::: 'PrimaryKey '["id"]
369−-- , "employees_employer_fk" ::: 'ForeignKey '["employer_id"] "employees" '["id"]
375+ , "employees_employer_fk" ::: 'ForeignKey '["employer_id"] "employees" '["id"]
370−-- ] :=>
376+ ] :=>
371−-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
377+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
372−-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext
378+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
373−-- , "employer_id" ::: 'NoDef :=> 'Null 'PGint4
379+ , "employer_id" ::: 'NoDef :=> 'Null 'PGint4
374−-- ])
380+ ])
375−-- ]
381+ ]
376−-- :}
382+:}
377−--
383+
378−-- >>> :{
384+>>> :{
379−-- let
385+let
380−-- setup :: Definition '[] Schema
386+ setup :: Definition '[] Schema
381−-- setup =
387+ setup =
382−-- createTable #employees
388+ createTable #employees
383−-- ( serial `As` #id :*
389+ ( serial `As` #id :*
384−-- (text & notNullable) `As` #name :*
390+ (text & notNullable) `As` #name :*
385−-- (integer & nullable) `As` #employer_id :* Nil )
391+ (integer & nullable) `As` #employer_id :* Nil )
386−-- ( primaryKey #id `As` #employees_pk :*
392+ ( primaryKey #id `As` #employees_pk :*
387−-- foreignKey #employer_id #employees #id
393+ foreignKey #employer_id #employees #id
388−-- OnDeleteCascade OnUpdateCascade `As` #employees_employer_fk :* Nil )
394+ OnDeleteCascade OnUpdateCascade `As` #employees_employer_fk :* Nil )
389−-- in renderDefinition setup
395+in Data.ByteString.Char8.putStrLn $ renderDefinition setup
390−-- :}
396+:}
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);"
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);
392−--
398+-}
393foreignKey
399foreignKey
394 :: (ForeignKeyed schema child parent
400 :: (ForeignKeyed schema child parent
395 table reftable
401 table reftable
@@ -481,8 +487,8 @@ DROP statements
481-- definition = dropTable #muh_table
487-- definition = dropTable #muh_table
482-- :}
488-- :}
483--
489--
484−-- >>> renderDefinition definition
490+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition definition
485−-- "DROP TABLE \"muh_table\";"
491+-- DROP TABLE "muh_table";
486dropTable
492dropTable
487 :: Has table schema ('Table t)
493 :: Has table schema ('Table t)
488 => Alias table -- ^ table to remove
494 => Alias table -- ^ table to remove
@@ -507,8 +513,8 @@ alterTable tab alteration = UnsafeDefinition $
507
513
508-- | `alterTableRename` changes the name of a table from the schema.
514-- | `alterTableRename` changes the name of a table from the schema.
509--
515--
510−-- >>> renderDefinition $ alterTableRename #foo #bar
516+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ alterTableRename #foo #bar
511−-- "ALTER TABLE \"foo\" RENAME TO \"bar\";"
517+-- ALTER TABLE "foo" RENAME TO "bar";
512alterTableRename
518alterTableRename
513 :: (KnownSymbol table0, KnownSymbol table1)
519 :: (KnownSymbol table0, KnownSymbol table1)
514 => Alias table0 -- ^ table to rename
520 => Alias table0 -- ^ table to rename
@@ -535,9 +541,9 @@ newtype AlterTable
535-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
541-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
536-- '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
542-- '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
537-- definition = alterTable #tab (addConstraint #positive (check (#col :* Nil) (#col .> 0)))
543-- definition = alterTable #tab (addConstraint #positive (check (#col :* Nil) (#col .> 0)))
538−-- in renderDefinition definition
544+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
539-- :}
545-- :}
540−-- "ALTER TABLE \"tab\" ADD CONSTRAINT \"positive\" CHECK ((\"col\" > 0));"
546+-- ALTER TABLE "tab" ADD CONSTRAINT "positive" CHECK (("col" > 0));
541addConstraint
547addConstraint
542 :: ( KnownSymbol alias
548 :: ( KnownSymbol alias
543 , Has tab schema ('Table table0)
549 , Has tab schema ('Table table0)
@@ -559,9 +565,9 @@ addConstraint alias constraint = UnsafeAlterTable $
559-- '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
565-- '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
560-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
566-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
561-- definition = alterTable #tab (dropConstraint #positive)
567-- definition = alterTable #tab (dropConstraint #positive)
562−-- in renderDefinition definition
568+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
563-- :}
569-- :}
564−-- "ALTER TABLE \"tab\" DROP CONSTRAINT \"positive\";"
570+-- ALTER TABLE "tab" DROP CONSTRAINT "positive";
565dropConstraint
571dropConstraint
566 :: ( KnownSymbol constraint
572 :: ( KnownSymbol constraint
567 , Has tab schema ('Table table0)
573 , Has tab schema ('Table table0)
@@ -586,9 +592,9 @@ class AddColumn ty where
586 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
592 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
587 -- , "col2" ::: 'Def :=> 'Null 'PGtext ])]
593 -- , "col2" ::: 'Def :=> 'Null 'PGtext ])]
588 -- definition = alterTable #tab (addColumn #col2 (text & nullable & default_ "foo"))
594 -- definition = alterTable #tab (addColumn #col2 (text & nullable & default_ "foo"))
589− -- in renderDefinition definition
595+ -- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
590 -- :}
596 -- :}
591− -- "ALTER TABLE \"tab\" ADD COLUMN \"col2\" text NULL DEFAULT E'foo';"
597+ -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL DEFAULT E'foo';
592 --
598 --
593 -- >>> :{
599 -- >>> :{
594 -- let
600 -- let
@@ -598,9 +604,9 @@ class AddColumn ty where
598 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
604 -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
599 -- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
605 -- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
600 -- definition = alterTable #tab (addColumn #col2 (text & nullable))
606 -- definition = alterTable #tab (addColumn #col2 (text & nullable))
601− -- in renderDefinition definition
607+ -- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
602 -- :}
608 -- :}
603− -- "ALTER TABLE \"tab\" ADD COLUMN \"col2\" text NULL;"
609+ -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL;
604 addColumn
610 addColumn
605 :: ( KnownSymbol column
611 :: ( KnownSymbol column
606 , Has tab schema ('Table table0)
612 , Has tab schema ('Table table0)
@@ -627,9 +633,9 @@ instance {-# OVERLAPPABLE #-} AddColumn ('NoDef :=> 'Null ty)
627-- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
633-- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]
628-- '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]
634-- '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]
629-- definition = alterTable #tab (dropColumn #col2)
635-- definition = alterTable #tab (dropColumn #col2)
630−-- in renderDefinition definition
636+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
631-- :}
637-- :}
632−-- "ALTER TABLE \"tab\" DROP COLUMN \"col2\";"
638+-- ALTER TABLE "tab" DROP COLUMN "col2";
633dropColumn
639dropColumn
634 :: ( KnownSymbol column
640 :: ( KnownSymbol column
635 , Has tab schema ('Table table0)
641 , Has tab schema ('Table table0)
@@ -648,9 +654,9 @@ dropColumn column = UnsafeAlterTable $
648-- '["tab" ::: 'Table ('[] :=> '["foo" ::: 'NoDef :=> 'Null 'PGint4])]
654-- '["tab" ::: 'Table ('[] :=> '["foo" ::: 'NoDef :=> 'Null 'PGint4])]
649-- '["tab" ::: 'Table ('[] :=> '["bar" ::: 'NoDef :=> 'Null 'PGint4])]
655-- '["tab" ::: 'Table ('[] :=> '["bar" ::: 'NoDef :=> 'Null 'PGint4])]
650-- definition = alterTable #tab (renameColumn #foo #bar)
656-- definition = alterTable #tab (renameColumn #foo #bar)
651−-- in renderDefinition definition
657+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
652-- :}
658-- :}
653−-- "ALTER TABLE \"tab\" RENAME COLUMN \"foo\" TO \"bar\";"
659+-- ALTER TABLE "tab" RENAME COLUMN "foo" TO "bar";
654renameColumn
660renameColumn
655 :: ( KnownSymbol column0
661 :: ( KnownSymbol column0
656 , KnownSymbol column1
662 , KnownSymbol column1
@@ -691,9 +697,9 @@ newtype AlterColumn (schema :: SchemaType) (ty0 :: ColumnType) (ty1 :: ColumnTyp
691-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
697-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
692-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]
698-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]
693-- definition = alterTable #tab (alterColumn #col (setDefault 5))
699-- definition = alterTable #tab (alterColumn #col (setDefault 5))
694−-- in renderDefinition definition
700+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
695-- :}
701-- :}
696−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" SET DEFAULT 5;"
702+-- ALTER TABLE "tab" ALTER COLUMN "col" SET DEFAULT 5;
697setDefault
703setDefault
698 :: Expression schema '[] 'Ungrouped '[] ty -- ^ default value to set
704 :: Expression schema '[] 'Ungrouped '[] ty -- ^ default value to set
699 -> AlterColumn schema (constraint :=> ty) ('Def :=> ty)
705 -> AlterColumn schema (constraint :=> ty) ('Def :=> ty)
@@ -708,9 +714,9 @@ setDefault expression = UnsafeAlterColumn $
708-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]
714-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]
709-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
715-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
710-- definition = alterTable #tab (alterColumn #col dropDefault)
716-- definition = alterTable #tab (alterColumn #col dropDefault)
711−-- in renderDefinition definition
717+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
712-- :}
718-- :}
713−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" DROP DEFAULT;"
719+-- ALTER TABLE "tab" ALTER COLUMN "col" DROP DEFAULT;
714dropDefault :: AlterColumn schema ('Def :=> ty) ('NoDef :=> ty)
720dropDefault :: AlterColumn schema ('Def :=> ty) ('NoDef :=> ty)
715dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
721dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
716
722
@@ -724,9 +730,9 @@ dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
724-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
730-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
725-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
731-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
726-- definition = alterTable #tab (alterColumn #col setNotNull)
732-- definition = alterTable #tab (alterColumn #col setNotNull)
727−-- in renderDefinition definition
733+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
728-- :}
734-- :}
729−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" SET NOT NULL;"
735+-- ALTER TABLE "tab" ALTER COLUMN "col" SET NOT NULL;
730setNotNull
736setNotNull
731 :: AlterColumn schema (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)
737 :: AlterColumn schema (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)
732setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
738setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
@@ -739,9 +745,9 @@ setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
739-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
745-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]
740-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
746-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
741-- definition = alterTable #tab (alterColumn #col dropNotNull)
747-- definition = alterTable #tab (alterColumn #col dropNotNull)
742−-- in renderDefinition definition
748+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
743-- :}
749-- :}
744−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" DROP NOT NULL;"
750+-- ALTER TABLE "tab" ALTER COLUMN "col" DROP NOT NULL;
745dropNotNull
751dropNotNull
746 :: AlterColumn schema (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)
752 :: AlterColumn schema (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)
747dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
753dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
@@ -757,9 +763,9 @@ dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
757-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGnumeric])]
763-- '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGnumeric])]
758-- definition =
764-- definition =
759-- alterTable #tab (alterColumn #col (alterType (numeric & notNullable)))
765-- alterTable #tab (alterColumn #col (alterType (numeric & notNullable)))
760−-- in renderDefinition definition
766+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
761-- :}
767-- :}
762−-- "ALTER TABLE \"tab\" ALTER COLUMN \"col\" TYPE numeric NOT NULL;"
768+-- ALTER TABLE "tab" ALTER COLUMN "col" TYPE numeric NOT NULL;
763alterType :: ColumnTypeExpression schema ty -> AlterColumn schema ty0 ty
769alterType :: ColumnTypeExpression schema ty -> AlterColumn schema ty0 ty
764alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
770alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
765
771
@@ -772,10 +778,10 @@ alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
772-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])
778-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])
773-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
779-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
774-- definition =
780-- definition =
775−-- createView #bc (select (#b `As` #b :* #c `As` #c :* Nil) (from (table (#abc `As` #abc))))
781+-- createView #bc (select (#b :* #c :* Nil) (from (table #abc)))
776−-- in renderDefinition definition
782+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
777-- :}
783-- :}
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";
779createView
785createView
780 :: KnownSymbol view
786 :: KnownSymbol view
781 => Alias view -- ^ the name of the table to add
787 => Alias view -- ^ the name of the table to add
@@ -795,9 +801,9 @@ createView alias query = UnsafeDefinition $
795-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
801-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]
796-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]
802-- '[ "abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]
797-- definition = dropView #bc
803-- definition = dropView #bc
798−-- in renderDefinition definition
804+-- in Data.ByteString.Char8.putStrLn $ renderDefinition definition
799-- :}
805-- :}
800−-- "DROP VIEW \"bc\";"
806+-- DROP VIEW "bc";
801dropView
807dropView
802 :: Has view schema ('View v)
808 :: Has view schema ('View v)
803 => Alias view -- ^ view to remove
809 => Alias view -- ^ view to remove
@@ -806,8 +812,8 @@ dropView v = UnsafeDefinition $ "DROP VIEW" <+> renderAlias v <> ";"
806
812
807-- | Enumerated types are created using the `createTypeEnum` command, for example
813-- | Enumerated types are created using the `createTypeEnum` command, for example
808--
814--
809−-- >>> renderDefinition $ createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy" :* Nil)
815+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy" :* Nil)
810−-- "CREATE TYPE \"mood\" AS ENUM ('sad', 'ok', 'happy');"
816+-- CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');
811createTypeEnum
817createTypeEnum
812 :: (KnownSymbol enum, SOP.All KnownSymbol labels)
818 :: (KnownSymbol enum, SOP.All KnownSymbol labels)
813 => Alias enum
819 => Alias enum
@@ -824,8 +830,8 @@ createTypeEnum enum labels = UnsafeDefinition $
824-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
830-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
825-- >>> instance SOP.Generic Schwarma
831-- >>> instance SOP.Generic Schwarma
826-- >>> instance SOP.HasDatatypeInfo Schwarma
832-- >>> instance SOP.HasDatatypeInfo Schwarma
827−-- >>> renderDefinition $ createTypeEnumWith @Schwarma #schwarma
833+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeEnumWith @Schwarma #schwarma
828−-- "CREATE TYPE \"schwarma\" AS ENUM ('Beef', 'Lamb', 'Chicken');"
834+-- CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');
829createTypeEnumWith
835createTypeEnumWith
830 :: forall hask enum schema.
836 :: forall hask enum schema.
831 ( SOP.Generic hask
837 ( SOP.Generic hask
@@ -841,8 +847,8 @@ createTypeEnumWith enum = createTypeEnum enum
841-- | `createTypeComposite` creates a composite type. The composite type is
847-- | `createTypeComposite` creates a composite type. The composite type is
842-- specified by a list of attribute names and data types.
848-- specified by a list of attribute names and data types.
843--
849--
844−-- >>> renderDefinition $ createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
850+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
845−-- "CREATE TYPE \"complex\" AS (\"real\" float8, \"imaginary\" float8);"
851+-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
846createTypeComposite
852createTypeComposite
847 :: (KnownSymbol ty, SOP.SListI fields)
853 :: (KnownSymbol ty, SOP.SListI fields)
848 => Alias ty
854 => Alias ty
@@ -863,8 +869,8 @@ createTypeComposite ty fields = UnsafeDefinition $
863-- >>> data Complex = Complex {real :: Maybe Double, imaginary :: Maybe Double} deriving GHC.Generic
869-- >>> data Complex = Complex {real :: Maybe Double, imaginary :: Maybe Double} deriving GHC.Generic
864-- >>> instance SOP.Generic Complex
870-- >>> instance SOP.Generic Complex
865-- >>> instance SOP.HasDatatypeInfo Complex
871-- >>> instance SOP.HasDatatypeInfo Complex
866−-- >>> renderDefinition $ createTypeCompositeWith @Complex #complex
872+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition $ createTypeCompositeWith @Complex #complex
867−-- "CREATE TYPE \"complex\" AS (\"real\" float8, \"imaginary\" float8);"
873+-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
868createTypeCompositeWith
874createTypeCompositeWith
869 :: forall hask ty schema.
875 :: forall hask ty schema.
870 ( ZipAliased (FieldNamesWith hask) (FieldTypesWith hask)
876 ( ZipAliased (FieldNamesWith hask) (FieldTypesWith hask)
@@ -884,8 +890,8 @@ createTypeCompositeWith ty = createTypeComposite ty $ zipAs
884-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
890-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
885-- >>> instance SOP.Generic Schwarma
891-- >>> instance SOP.Generic Schwarma
886-- >>> instance SOP.HasDatatypeInfo Schwarma
892-- >>> instance SOP.HasDatatypeInfo Schwarma
887−-- >>> renderDefinition (dropType #schwarma :: Definition '["schwarma" ::: 'Typedef (EnumWith Schwarma)] '[])
893+-- >>> Data.ByteString.Char8.putStrLn $ renderDefinition (dropType #schwarma :: Definition '["schwarma" ::: 'Typedef (EnumWith Schwarma)] '[])
888−-- "DROP TYPE \"schwarma\";"
894+-- DROP TYPE "schwarma";
889dropType
895dropType
890 :: Has tydef schema ('Typedef ty)
896 :: Has tydef schema ('Typedef ty)
891 => Alias tydef
897 => Alias tydef