@@ -45,8 +45,8 @@ module Squeal.PostgreSQL.Manipulation
4545import Control.DeepSeq
4646import Data.ByteString
4747import Data.Monoid
48−import Generics.SOP
4948
49+import qualified Generics.SOP as SOP
5050import qualified GHC.Generics as GHC
5151
5252import Squeal.PostgreSQL.Expression
@@ -75,46 +75,109 @@ queryStatement q = UnsafeManipulation $ renderQuery q <> ";"
7575INSERT statements
7676-----------------------------------------}
7777
78−-- | When a table is created, it contains no data. The first thing to do
79−-- before a database can be of much use is to insert data. Data is
80−-- conceptually inserted one row at a time. Of course you can also insert
81−-- more than one row, but there is no way to insert less than one row.
82−-- Even if you know only some column values, a complete row must be created.
83−--
84−-- >>> :{
85−-- let
86−-- manipulation :: Manipulation
87−-- '[ "tab" :::
88−-- '[ "col1" ::: 'Required ('NotNull 'PGint4)
89−-- , "col2" ::: 'Required ('NotNull 'PGint4) ]] '[] '[]
90−-- manipulation =
91−-- insertInto #tab (Values (2 `As` #col1 :* 4 `As` #col2 :* Nil) [])
92−-- OnConflictDoRaise (Returning Nil)
93−-- in renderManipulation manipulation
94−-- :}
95−-- "INSERT INTO tab (col1, col2) VALUES (2, 4);"
96−--
97−-- >>> :{
98−-- let
99−-- manipulation :: Manipulation
100−-- '[ "tab" :::
101−-- '[ "col1" ::: 'Required ('NotNull 'PGint4)
102−-- , "col2" ::: 'Required ('NotNull 'PGint4) ]]
103−-- '[] '[ "sum" ::: 'Required ('NotNull 'PGint4)]
104−-- manipulation =
105−-- insertInto #tab
106−-- (Values
107−-- (2 `As` #col1 :* 4 `As` #col2 :* Nil)
108−-- [6 `As` #col1 :* 8 `As` #col2 :* Nil])
109−-- (OnConflictDoUpdate
110−-- (Set 2 `As` #col1 :* Same `As` #col2 :* Nil)
111−-- (Just (#col1 .== #col2)))
112−-- (Returning $ (#col1 + #col2) `As` #sum :* Nil)
113−-- in renderManipulation manipulation
114−-- :}
115−-- "INSERT INTO tab (col1, col2) VALUES (2, 4), (6, 8) ON CONFLICT DO UPDATE SET col1 = 2 WHERE (col1 = col2) RETURNING (col1 + col2) AS sum;"
78+{- |
79+When a table is created, it contains no data. The first thing to do
80+before a database can be of much use is to insert data. Data is
81+conceptually inserted one row at a time. Of course you can also insert
82+more than one row, but there is no way to insert less than one row.
83+Even if you know only some column values, a complete row must be created.
84+
85+simple insert:
86+
87+>>> :{
88+let
89+ manipulation :: Manipulation
90+ '[ "tab" :::
91+ '[ "col1" ::: 'Required ('NotNull 'PGint4)
92+ , "col2" ::: 'Required ('NotNull 'PGint4) ]] '[] '[]
93+ manipulation =
94+ insertInto #tab (Values (2 `As` #col1 :* 4 `As` #col2 :* Nil) [])
95+ OnConflictDoRaise (Returning Nil)
96+in renderManipulation manipulation
97+:}
98+"INSERT INTO tab (col1, col2) VALUES (2, 4);"
99+
100+parameterized insert:
101+
102+>>> :{
103+let
104+ manipulation :: Manipulation
105+ '[ "tab" :::
106+ '[ "col1" ::: 'Required ('NotNull 'PGint4)
107+ , "col2" ::: 'Required ('NotNull 'PGint4) ]]
108+ '[ 'Required ('NotNull 'PGint4)
109+ , 'Required ('NotNull 'PGint4) ] '[]
110+ manipulation =
111+ insertInto #tab
112+ (Values (param @1 `As` #col1 :* param @2 `As` #col2 :* Nil) [])
113+ OnConflictDoRaise (Returning Nil)
114+in renderManipulation manipulation
115+:}
116+"INSERT INTO tab (col1, col2) VALUES (($1 :: int4), ($2 :: int4));"
117+
118+returning insert:
119+
120+>>> :{
121+let
122+ manipulation :: Manipulation
123+ '[ "tab" :::
124+ '[ "col1" ::: 'Required ('NotNull 'PGint4)
125+ , "col2" ::: 'Required ('NotNull 'PGint4) ]] '[]
126+ '["fromOnly" ::: 'Required ('NotNull 'PGint4)]
127+ manipulation =
128+ insertInto #tab (Values (2 `As` #col1 :* 4 `As` #col2 :* Nil) [])
129+ OnConflictDoRaise (Returning (#col1 `As` #fromOnly :* Nil))
130+in renderManipulation manipulation
131+:}
132+"INSERT INTO tab (col1, col2) VALUES (2, 4) RETURNING col1 AS fromOnly;"
133+
134+query insert:
135+
136+>>> :{
137+let
138+ manipulation :: Manipulation
139+ '[ "tab" :::
140+ '[ "col1" ::: 'Required ('NotNull 'PGint4)
141+ , "col2" ::: 'Required ('NotNull 'PGint4)
142+ ]
143+ , "other_tab" :::
144+ '[ "col1" ::: 'Required ('NotNull 'PGint4)
145+ , "col2" ::: 'Required ('NotNull 'PGint4)
146+ ]
147+ ] '[] '[]
148+ manipulation =
149+ insertInto #tab
150+ ( ValuesQuery $
151+ selectStar (from (Table (#other_tab `As` #t))) )
152+ OnConflictDoRaise (Returning Nil)
153+in renderManipulation manipulation
154+:}
155+"INSERT INTO tab SELECT * FROM other_tab AS t;"
156+
157+upsert:
158+
159+>>> :{
160+let
161+ manipulation :: Manipulation
162+ '[ "tab" :::
163+ '[ "col1" ::: 'Required ('NotNull 'PGint4)
164+ , "col2" ::: 'Required ('NotNull 'PGint4) ]]
165+ '[] '[ "sum" ::: 'Required ('NotNull 'PGint4)]
166+ manipulation =
167+ insertInto #tab
168+ (Values
169+ (2 `As` #col1 :* 4 `As` #col2 :* Nil)
170+ [6 `As` #col1 :* 8 `As` #col2 :* Nil])
171+ (OnConflictDoUpdate
172+ (Set 2 `As` #col1 :* Same `As` #col2 :* Nil)
173+ (Just (#col1 .== #col2)))
174+ (Returning $ (#col1 + #col2) `As` #sum :* Nil)
175+in renderManipulation manipulation
176+:}
177+"INSERT INTO tab (col1, col2) VALUES (2, 4), (6, 8) ON CONFLICT DO UPDATE SET col1 = 2 WHERE (col1 = col2) RETURNING (col1 + col2) AS sum;"
178+-}
116179insertInto
117− :: (SListI columns, SListI results, HasTable table schema columns)
180+ :: (SOP.SListI columns, SOP.SListI results, HasTable table schema columns)
118181 => Alias table -- ^ table to insert into
119182 -> ValuesClause schema params columns -- ^ values to insert
120183 -> ConflictClause columns params
@@ -141,7 +204,7 @@ data ValuesClause
141204
142205-- | Render a `ValuesClause`.
143206renderValuesClause
144− :: SListI columns
207+ :: SOP.SListI columns
145208 => ValuesClause schema params columns
146209 -> ByteString
147210renderValuesClause = \case
@@ -181,7 +244,7 @@ data ReturningClause
181244
182245-- | Render a `ReturningClause`.
183246renderReturningClause
184− :: SListI results
247+ :: SOP.SListI results
185248 => ReturningClause params columns results
186249 -> ByteString
187250renderReturningClause = \case
@@ -205,7 +268,7 @@ data ConflictClause columns params where
205268
206269-- | Render a `ConflictClause`.
207270renderConflictClause
208− :: SListI columns
271+ :: SOP.SListI columns
209272 => ConflictClause columns params
210273 -> ByteString
211274renderConflictClause = \case
@@ -238,7 +301,7 @@ UPDATE statements
238301-- :}
239302-- "UPDATE tab SET col1 = 2 WHERE (col1 <> col2);"
240303update
241− :: (HasTable table schema columns, SListI columns, SListI results)
304+ :: (HasTable table schema columns, SOP.SListI columns, SOP.SListI results)
242305 => Alias table -- ^ table to update
243306 -> NP (Aliased (UpdateExpression columns params)) columns
244307 -- ^ modified values to replace old values
@@ -293,7 +356,7 @@ DELETE statements
293356-- :}
294357-- "DELETE FROM tab WHERE (col1 = col2) RETURNING *;"
295358deleteFrom
296− :: (SListI results, HasTable table schema columns)
359+ :: (SOP.SListI results, HasTable table schema columns)
297360 => Alias table -- ^ table to delete from
298361 -> Condition '[table ::: columns] 'Ungrouped params
299362 -- ^ condition under which to delete a row