@@ -1,7 +1,7 @@
2Module: Squeal.PostgreSQL.Query
2Module: Squeal.PostgreSQL.Query
3Description: Squeal queries
3Description: Squeal queries
4−Copyright: (c) Eitan Chatav, 2017
4+Copyright: (c) Eitan Chatav, 2019
5Maintainer: eitan@morphism.tech
5Maintainer: eitan@morphism.tech
6Stability: experimental
6Stability: experimental
@@ -17,8 +17,12 @@ Squeal queries.
17 , GeneralizedNewtypeDeriving
17 , GeneralizedNewtypeDeriving
18 , LambdaCase
18 , LambdaCase
19 , MultiParamTypeClasses
19 , MultiParamTypeClasses
20 , OverloadedStrings
21 , OverloadedStrings
22+ , QuantifiedConstraints
23+ , ScopedTypeVariables
21 , StandaloneDeriving
24 , StandaloneDeriving
22 , TypeFamilies
26 , TypeFamilies
23 , TypeInType
27 , TypeInType
24 , TypeOperators
28 , TypeOperators
@@ -28,14 +32,16 @@ Squeal queries.
29module Squeal.PostgreSQL.Query
33module Squeal.PostgreSQL.Query
30 ( -- * Queries
34 ( -- * Queries
31− Query (UnsafeQuery, renderQuery)
35+ Query_
32 -- ** Select
37 -- ** Select
34 , selectDistinct
40 , selectDistinct
35− , selectStar
41+ , selectDistinct_
36− , selectDistinctStar
42+ , selectDistinctOn
37− , selectDotStar
43+ , selectDistinctOn_
38− , selectDistinctDotStar
44+ , Selection (..)
39 -- ** Values
45 -- ** Values
@@ -47,33 +53,15 @@ module Squeal.PostgreSQL.Query
48 , exceptAll
54 , exceptAll
49 -- ** With
55 -- ** With
50− , With (with)
56+ , With (..)
51 , CommonTableExpression (..)
57 , CommonTableExpression (..)
52− , renderCommonTableExpression
58+ , withRecursive
53− , renderCommonTableExpressions
62− , jsonbPopulateRecord
63− , jsonPopulateRecordSet
64− , jsonbPopulateRecordSet
69 -- * Table Expressions
59 -- * Table Expressions
70 , TableExpression (..)
60 , TableExpression (..)
71− , renderTableExpression
79 -- * From Clauses
67 -- * From Clauses
@@ -88,46 +76,14 @@ module Squeal.PostgreSQL.Query
88 , rightOuterJoin
76 , rightOuterJoin
89 , fullOuterJoin
77 , fullOuterJoin
90 -- * Grouping
78 -- * Grouping
91− , By (By1, By2)
79+ , By (..)
93− , GroupByClause (NoGroups, Group)
80+ , GroupByClause (..)
94− , renderGroupByClause
95− , HavingClause (NoHaving, Having)
81+ , HavingClause (..)
98− , SortExpression (..)
99− , renderSortExpression
100− -- * Subquery Expressions
129import Control.DeepSeq
84import Control.DeepSeq
130import Data.ByteString (ByteString)
85import Data.ByteString (ByteString)
86+import Data.Kind (Type)
131import Data.String
87import Data.String
132import Data.Word
88import Data.Word
133import Generics.SOP hiding (from)
89import Generics.SOP hiding (from)
@@ -135,13 +91,67 @@ import GHC.TypeLits
136import qualified GHC.Generics as GHC
92import qualified GHC.Generics as GHC
94+import Squeal.PostgreSQL.Alias
138import Squeal.PostgreSQL.Expression
95import Squeal.PostgreSQL.Expression
96+import Squeal.PostgreSQL.Expression.Logic
97+import Squeal.PostgreSQL.Expression.Sort
98+import Squeal.PostgreSQL.Expression.Window
99+import Squeal.PostgreSQL.List
100+import Squeal.PostgreSQL.PG
139import Squeal.PostgreSQL.Render
101import Squeal.PostgreSQL.Render
140import Squeal.PostgreSQL.Schema
102import Squeal.PostgreSQL.Schema
105+-- >>> import Squeal.PostgreSQL
106+-- >>> import Data.Int (Int32, Int64)
107+-- >>> import Data.Monoid (Sum (..))
108+-- >>> import Data.Text (Text)
109+-- >>> import qualified Generics.SOP as SOP
143−The process of retrieving or the command to retrieve data from a database
112+The process of retrieving or the command to retrieve data from
113+a database is called a `Query`.
115+The general `Query` type is parameterized by
117+* @outer :: FromType@ - outer scope for a correlated subquery,
118+* @commons :: FromType@ - scope for all `common` table expressions,
119+* @schemas :: SchemasType@ - scope for all `table`s and `view`s,
120+* @params :: [NullityType]@ - scope for all `Squeal.Expression.Parameter.parameter`s,
121+* @row :: RowType@ - return type of the `Query`.
125+ (commons :: FromType)
126+ (schemas :: SchemasType)
127+ (params :: [NullityType])
129+ = UnsafeQuery { renderQuery :: ByteString }
130+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
131+instance RenderSQL (Query outer commons schemas params row) where renderSQL = renderQuery
134+The top level `Query_` type is parameterized by a @schemas@ `SchemasType`,
135+against which the query is type-checked, an input @parameters@ Haskell `Type`,
136+and an ouput row Haskell `Type`.
138+A top-level query can be run
139+using `Squeal.PostgreSQL.PQ.runQueryParams`, or if @parameters = ()@
140+using `Squeal.PostgreSQL.PQ.runQuery`.
142+Generally, @parameters@ will be a Haskell tuple or record whose entries
143+may be referenced using positional
144+`Squeal.PostgreSQL.Expression.Parameter.parameter`s and @row@ will be a
145+Haskell record, whose entries will be targeted using overloaded labels.
144−is called a `Query`. Let's see some examples of queries.
147+Let's see some examples of queries.
149+>>> :set -XDeriveAnyClass -XDerivingStrategies
151+data Row a b = Row { col1 :: a, col2 :: b }
152+ deriving stock (GHC.Generic)
153+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
146simple query:
156simple query:
@@ -149,8 +159,8 @@ simple query:
149>>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
159>>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
152− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
162+ query :: Query_ (Public Schema) () (Row Int32 Int32)
153− query = selectStar (from (table #tab))
163+ query = select Star (from (table #tab))
154in printSQL query
164in printSQL query
156SELECT * FROM "tab" AS "tab"
166SELECT * FROM "tab" AS "tab"
@@ -159,22 +169,22 @@ restricted query:
162− query :: Query (DBof (Public Schema)) '[] '["sum" ::: 'NotNull 'PGint4, "col1" ::: 'NotNull 'PGint4]
172+ query :: Query_ (Public Schema) () (Row Int32 Int32)
164− select ((#col1 + #col2) `as` #sum :* #col1)
174+ select_ ((#col1 + #col2) `as` #col1 :* #col1 `as` #col2)
165 ( from (table #tab)
175 ( from (table #tab)
166 & where_ (#col1 .> #col2)
176 & where_ (#col1 .> #col2)
167 & where_ (#col2 .> 0) )
177 & where_ (#col2 .> 0) )
168in printSQL query
178in printSQL query
170−SELECT ("col1" + "col2") AS "sum", "col1" AS "col1" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > 0))
180+SELECT ("col1" + "col2") AS "col1", "col1" AS "col2" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > 0))
176− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
186+ query :: Query_ (Public Schema) () (Row Int32 Int32)
177− query = selectStar (from (subquery (selectStar (from (table #tab)) `as` #sub)))
187+ query = select Star (from (subquery (select Star (from (table #tab)) `as` #sub)))
178in printSQL query
188in printSQL query
180SELECT * FROM (SELECT * FROM "tab" AS "tab") AS "sub"
190SELECT * FROM (SELECT * FROM "tab" AS "tab") AS "sub"
@@ -183,8 +193,8 @@ limits and offsets:
186− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
196+ query :: Query_ (Public Schema) () (Row Int32 Int32)
187− query = selectStar (from (table #tab) & limit 100 & offset 2 & limit 50 & offset 2)
197+ query = select Star (from (table #tab) & limit 100 & offset 2 & limit 50 & offset 2)
188in printSQL query
198in printSQL query
190SELECT * FROM "tab" AS "tab" LIMIT 50 OFFSET 4
200SELECT * FROM "tab" AS "tab" LIMIT 50 OFFSET 4
@@ -193,8 +203,8 @@ parameterized query:
196− query :: Query (DBof (Public Schema)) '[ 'NotNull 'PGint4] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
206+ query :: Query_ (Public Schema) (Only Int32) (Row Int32 Int32)
197− query = selectStar (from (table #tab) & where_ (#col1 .> param @1))
207+ query = select Star (from (table #tab) & where_ (#col1 .> param @1))
198in printSQL query
208in printSQL query
200SELECT * FROM "tab" AS "tab" WHERE ("col1" > ($1 :: int4))
210SELECT * FROM "tab" AS "tab" WHERE ("col1" > ($1 :: int4))
@@ -203,36 +213,34 @@ aggregation query:
206− query :: Query (DBof (Public Schema)) '[] '["sum" ::: 'NotNull 'PGint4, "col1" ::: 'NotNull 'PGint4 ]
216+ query :: Query_ (Public Schema) () (Row Int64 Int32)
208− select (sum_ #col2 `as` #sum :* #col1)
218+ select_ ((fromNull 0 (sum_ (All #col2))) `as` #col1 :* #col1 `as` #col2)
209 ( from (table (#tab `as` #table1))
219 ( from (table (#tab `as` #table1))
210 & groupBy #col1
220 & groupBy #col1
211− & having (#col1 + sum_ #col2 .> 1) )
221+ & having (sum_ (Distinct #col2) .> 1) )
212in printSQL query
222in printSQL query
214−SELECT sum("col2") AS "sum", "col1" AS "col1" FROM "tab" AS "table1" GROUP BY "col1" HAVING (("col1" + sum("col2")) > 1)
224+SELECT COALESCE(sum(ALL "col2"), 0) AS "col1", "col1" AS "col2" FROM "tab" AS "table1" GROUP BY "col1" HAVING (sum(DISTINCT "col2") > 1)
216sorted query:
226sorted query:
220− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
230+ query :: Query_ (Public Schema) () (Row Int32 Int32)
221− query = selectStar (from (table #tab) & orderBy [#col1 & Asc])
231+ query = select Star (from (table #tab) & orderBy [#col1 & Asc])
222in printSQL query
232in printSQL query
224SELECT * FROM "tab" AS "tab" ORDER BY "col1" ASC
234SELECT * FROM "tab" AS "tab" ORDER BY "col1" ASC
228−>>> :set -XFlexibleContexts
230type OrdersColumns =
239type OrdersColumns =
231 '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
240 '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
232− , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
241+ , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
233− , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
242+ , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
234− , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4
243+ , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4 ]
@@ -243,26 +251,32 @@ type OrdersConstraints =
245>>> type NamesColumns = '["id" ::: 'NoDef :=> 'NotNull 'PGint4, "name" ::: 'NoDef :=> 'NotNull 'PGtext]
253>>> type NamesColumns = '["id" ::: 'NoDef :=> 'NotNull 'PGint4, "name" ::: 'NoDef :=> 'NotNull 'PGtext]
246−>>> type NamesConstraints = '["pk_customers" ::: PrimaryKey '["id"]]
254+>>> type CustomersConstraints = '["pk_customers" ::: PrimaryKey '["id"]]
255+>>> type ShippersConstraints = '["pk_shippers" ::: PrimaryKey '["id"]]
248type OrdersSchema =
257type OrdersSchema =
249 '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
258 '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
250− , "customers" ::: 'Table (NamesConstraints :=> NamesColumns)
259+ , "customers" ::: 'Table (CustomersConstraints :=> NamesColumns)
251− , "shippers" ::: 'Table (NamesConstraints :=> NamesColumns) ]
260+ , "shippers" ::: 'Table (ShippersConstraints :=> NamesColumns) ]
266+ , customerName :: Text
267+ , shipperName :: Text
268+ } deriving GHC.Generic
269+instance SOP.Generic Order
270+instance SOP.HasDatatypeInfo Order
256− query :: Query (DBof (Public OrdersSchema))
275+ query :: Query_ (Public OrdersSchema) () Order
258− '[ "order_price" ::: 'NotNull 'PGfloat4
259− , "customer_name" ::: 'NotNull 'PGtext
260− , "shipper_name" ::: 'NotNull 'PGtext
262− query = select
276+ query = select_
263− ( #o ! #price `as` #order_price :*
277+ ( #o ! #price `as` #price :*
264− #c ! #name `as` #customer_name :*
278+ #c ! #name `as` #customerName :*
265− #s ! #name `as` #shipper_name )
279+ #s ! #name `as` #shipperName )
266 ( from (table (#orders `as` #o)
280 ( from (table (#orders `as` #o)
267 & innerJoin (table (#customers `as` #c))
281 & innerJoin (table (#customers `as` #c))
268 (#o ! #customer_id .== #c ! #id)
282 (#o ! #customer_id .== #c ! #id)
@@ -270,14 +284,16 @@ let
270 (#o ! #shipper_id .== #s ! #id)) )
284 (#o ! #shipper_id .== #s ! #id)) )
271in printSQL query
285in printSQL query
273−SELECT "o"."price" AS "order_price", "c"."name" AS "customer_name", "s"."name" AS "shipper_name" FROM "orders" AS "o" INNER JOIN "customers" AS "c" ON ("o"."customer_id" = "c"."id") INNER JOIN "shippers" AS "s" ON ("o"."shipper_id" = "s"."id")
287+SELECT "o"."price" AS "price", "c"."name" AS "customerName", "s"."name" AS "shipperName" FROM "orders" AS "o" INNER JOIN "customers" AS "c" ON ("o"."customer_id" = "c"."id") INNER JOIN "shippers" AS "s" ON ("o"."shipper_id" = "s"."id")
275self-join:
289self-join:
279− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
293+ query :: Query_ (Public Schema) () (Row Int32 Int32)
280− query = selectDotStar #t1 (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
296+ (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
281in printSQL query
297in printSQL query
283SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
299SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
@@ -286,18 +302,20 @@ value queries:
289− query :: Query db '[] '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
305+ query :: Query_ schemas () (Row String Bool)
290− query = values (1 `as` #foo :* true `as` #bar) [2 `as` #foo :* false `as` #bar]
306+ query = values
307+ ("true" `as` #col1 :* true `as` #col2)
308+ ["false" `as` #col1 :* false `as` #col2]
291in printSQL query
309in printSQL query
293−SELECT * FROM (VALUES (1, TRUE), (2, FALSE)) AS t ("foo", "bar")
311+SELECT * FROM (VALUES (E'true', TRUE), (E'false', FALSE)) AS t ("col1", "col2")
295set operations:
313set operations:
299− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
317+ query :: Query_ (Public Schema) () (Row Int32 Int32)
300− query = selectStar (from (table #tab)) `unionAll` selectStar (from (table #tab))
318+ query = select Star (from (table #tab)) `unionAll` select Star (from (table #tab))
301in printSQL query
319in printSQL query
303(SELECT * FROM "tab" AS "tab") UNION ALL (SELECT * FROM "tab" AS "tab")
321(SELECT * FROM "tab" AS "tab") UNION ALL (SELECT * FROM "tab" AS "tab")
@@ -306,167 +324,305 @@ with queries:
309− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
327+ query :: Query_ (Public Schema) () (Row Int32 Int32)
310 query = with (
328 query = with (
311− selectStar (from (table #tab)) `as` #cte1 :>>
329+ select Star (from (table #tab)) `as` #cte1 :>>
312− selectStar (from (common #cte1)) `as` #cte2
330+ select Star (from (common #cte1)) `as` #cte2
313− ) (selectStar (from (common #cte2)))
331+ ) (select Star (from (common #cte2)))
314in printSQL query
332in printSQL query
316WITH "cte1" AS (SELECT * FROM "tab" AS "tab"), "cte2" AS (SELECT * FROM "cte1" AS "cte1") SELECT * FROM "cte2" AS "cte2"
334WITH "cte1" AS (SELECT * FROM "tab" AS "tab"), "cte2" AS (SELECT * FROM "cte1" AS "cte1") SELECT * FROM "cte2" AS "cte2"
336+window function queries
340+ query :: Query_ (Public Schema) () (Row Int32 Int64)
342+ (#col1 & Also (rank `as` #col2 `Over` (partitionBy #col1 & orderBy [#col2 & Asc])))
346+SELECT "col1" AS "col1", rank() OVER (PARTITION BY "col1" ORDER BY "col2" ASC) AS "col2" FROM "tab" AS "tab"
348+correlated subqueries
352+ query :: Query_ (Public Schema) () (Only Int32)
354+ select (#col1 `as` #fromOnly) (from (table (#tab `as` #t1))
356+ select Star (from (table (#tab `as` #t2))
357+ & where_ (#t2 ! #col2 .== #t1 ! #col1)))))
360+SELECT "col1" AS "fromOnly" FROM "tab" AS "t1" WHERE EXISTS (SELECT * FROM "tab" AS "t2" WHERE ("t2"."col2" = "t1"."col1"))
318−newtype Query
363+type family Query_
319− (db :: DBType)
364+ (schemas :: SchemasType)
320− (params :: [NullityType])
365+ (parameters :: Type)
321− (columns :: RowType)
366+ (row :: Type) where
322− = UnsafeQuery { renderQuery :: ByteString }
367+ Query_ schemas params row =
323− deriving (GHC.Generic,Show,Eq,Ord,NFData)
368+ Query '[] '[] schemas (TuplePG params) (RowPG row)
324−instance RenderSQL (Query db params columns) where renderSQL = renderQuery
326-- | The results of two queries can be combined using the set operation
370-- | The results of two queries can be combined using the set operation
327-- `union`. Duplicate rows are eliminated.
371-- `union`. Duplicate rows are eliminated.
329− :: Query db params columns
373+ :: Query outer commons schemas params columns
330− -> Query db params columns
374+ -> Query outer commons schemas params columns
331− -> Query db params columns
375+ -> Query outer commons schemas params columns
332q1 `union` q2 = UnsafeQuery $
376q1 `union` q2 = UnsafeQuery $
333− parenthesized (renderQuery q1)
377+ parenthesized (renderSQL q1)
334 <+> "UNION"
378 <+> "UNION"
335− <+> parenthesized (renderQuery q2)
379+ <+> parenthesized (renderSQL q2)
337-- | The results of two queries can be combined using the set operation
381-- | The results of two queries can be combined using the set operation
338-- `unionAll`, the disjoint union. Duplicate rows are retained.
382-- `unionAll`, the disjoint union. Duplicate rows are retained.
340− :: Query db params columns
384+ :: Query outer commons schemas params columns
341− -> Query db params columns
385+ -> Query outer commons schemas params columns
342− -> Query db params columns
386+ -> Query outer commons schemas params columns
343q1 `unionAll` q2 = UnsafeQuery $
387q1 `unionAll` q2 = UnsafeQuery $
344− parenthesized (renderQuery q1)
388+ parenthesized (renderSQL q1)
345 <+> "UNION" <+> "ALL"
389 <+> "UNION" <+> "ALL"
346− <+> parenthesized (renderQuery q2)
390+ <+> parenthesized (renderSQL q2)
348-- | The results of two queries can be combined using the set operation
392-- | The results of two queries can be combined using the set operation
349-- `intersect`, the intersection. Duplicate rows are eliminated.
393-- `intersect`, the intersection. Duplicate rows are eliminated.
351− :: Query db params columns
395+ :: Query outer commons schemas params columns
352− -> Query db params columns
396+ -> Query outer commons schemas params columns
353− -> Query db params columns
397+ -> Query outer commons schemas params columns
354q1 `intersect` q2 = UnsafeQuery $
398q1 `intersect` q2 = UnsafeQuery $
355− parenthesized (renderQuery q1)
399+ parenthesized (renderSQL q1)
356 <+> "INTERSECT"
400 <+> "INTERSECT"
357− <+> parenthesized (renderQuery q2)
401+ <+> parenthesized (renderSQL q2)
359-- | The results of two queries can be combined using the set operation
403-- | The results of two queries can be combined using the set operation
360-- `intersectAll`, the intersection. Duplicate rows are retained.
404-- `intersectAll`, the intersection. Duplicate rows are retained.
361intersectAll
405intersectAll
362− :: Query db params columns
406+ :: Query outer commons schemas params columns
363− -> Query db params columns
407+ -> Query outer commons schemas params columns
364− -> Query db params columns
408+ -> Query outer commons schemas params columns
365q1 `intersectAll` q2 = UnsafeQuery $
409q1 `intersectAll` q2 = UnsafeQuery $
366− parenthesized (renderQuery q1)
410+ parenthesized (renderSQL q1)
367 <+> "INTERSECT" <+> "ALL"
411 <+> "INTERSECT" <+> "ALL"
368− <+> parenthesized (renderQuery q2)
412+ <+> parenthesized (renderSQL q2)
370-- | The results of two queries can be combined using the set operation
414-- | The results of two queries can be combined using the set operation
371-- `except`, the set difference. Duplicate rows are eliminated.
415-- `except`, the set difference. Duplicate rows are eliminated.
373− :: Query db params columns
417+ :: Query outer commons schemas params columns
374− -> Query db params columns
418+ -> Query outer commons schemas params columns
375− -> Query db params columns
419+ -> Query outer commons schemas params columns
376q1 `except` q2 = UnsafeQuery $
420q1 `except` q2 = UnsafeQuery $
377− parenthesized (renderQuery q1)
421+ parenthesized (renderSQL q1)
378 <+> "EXCEPT"
422 <+> "EXCEPT"
379− <+> parenthesized (renderQuery q2)
423+ <+> parenthesized (renderSQL q2)
381-- | The results of two queries can be combined using the set operation
425-- | The results of two queries can be combined using the set operation
382-- `exceptAll`, the set difference. Duplicate rows are retained.
426-- `exceptAll`, the set difference. Duplicate rows are retained.
384− :: Query db params columns
428+ :: Query outer commons schemas params columns
385− -> Query db params columns
429+ -> Query outer commons schemas params columns
386− -> Query db params columns
430+ -> Query outer commons schemas params columns
387q1 `exceptAll` q2 = UnsafeQuery $
431q1 `exceptAll` q2 = UnsafeQuery $
388− parenthesized (renderQuery q1)
432+ parenthesized (renderSQL q1)
389 <+> "EXCEPT" <+> "ALL"
433 <+> "EXCEPT" <+> "ALL"
390− <+> parenthesized (renderQuery q2)
434+ <+> parenthesized (renderSQL q2)
392{-----------------------------------------
436{-----------------------------------------
393SELECT queries
437SELECT queries
394-----------------------------------------}
438-----------------------------------------}
440+{- | The simplest kinds of `Selection` are `Star` and `DotStar` which
441+emits all columns that a `TableExpression` produces. A select `List`
442+is a list of `Expression`s. A `Selection` could be a list of
443+`WindowFunction`s `Over` `WindowDefinition`. `Additional` `Selection`s can
444+be selected with `Also`.
446+data Selection outer commons grp schemas params from row where
448+ :: HasUnique tab from row
449+ => Selection outer commons 'Ungrouped schemas params from row
450+ -- ^ `HasUnique` table in the `FromClause`
454+ -- ^ `Has` table with `Alias`
455+ -> Selection outer commons 'Ungrouped schemas params from row
458+ => NP (Aliased (Expression outer commons grp schemas params from)) row
459+ -- ^ `NP` list of `Aliased` `Expression`s
460+ -> Selection outer commons grp schemas params from row
463+ => NP (Aliased (WindowFunction outer commons grp schemas params from)) row
464+ -- ^ `NP` list of `Aliased` `WindowFunction`s
465+ -> WindowDefinition outer commons grp schemas params from
466+ -> Selection outer commons grp schemas params from row
468+ :: Selection outer commons grp schemas params from right
469+ -- ^ `Additional` `Selection`
470+ -> Selection outer commons grp schemas params from left
471+ -> Selection outer commons grp schemas params from (Join left right)
472+instance Additional (Selection outer commons grp schemas params from) where
474+instance (KnownSymbol col, row ~ '[col ::: ty])
476+ (Expression outer commons grp schemas params from ty)
477+ (Selection outer commons grp schemas params from row) where
478+ expr `as` col = List (expr `as` col)
479+instance (Has tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])
480+ => IsQualified tab col
481+ (Selection outer commons 'Ungrouped schemas params from row1) where
482+ tab ! col = tab ! col `as` col
484+ ( Has tab (Join outer from) row0
486+ , row1 ~ '[col ::: ty]
487+ , GroupedBy tab col bys )
488+ => IsQualified tab col
489+ (Selection outer commons ('Grouped bys) schemas params from row1) where
490+ tab ! col = tab ! col `as` col
491+instance (HasUnique tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])
493+ (Selection outer commons 'Ungrouped schemas params from row1) where
494+ fromLabel = fromLabel @col `as` Alias
496+ ( HasUnique tab (Join outer from) row0
498+ , row1 ~ '[col ::: ty]
499+ , GroupedBy tab col bys )
501+ (Selection outer commons ('Grouped bys) schemas params from row1) where
502+ fromLabel = fromLabel @col `as` Alias
504+instance RenderSQL (Selection outer commons grp schemas params from row) where
506+ List list -> renderCommaSeparated (renderAliased renderSQL) list
508+ DotStar tab -> renderSQL tab <> ".*"
509+ Also right left -> renderSQL left <> ", " <> renderSQL right
510+ Over winFns winDef ->
513+ :: Aliased (WindowFunction outer commons grp schemas params from) field
515+ renderOver (winFn `As` col) = renderSQL winFn
516+ <+> "OVER" <+> parenthesized (renderSQL winDef)
517+ <+> "AS" <+> renderSQL col
519+ renderCommaSeparated renderOver winFns
522+ (Selection outer commons grp schemas params from '["fromOnly" ::: 'NotNull 'PGtext]) where
523+ fromString str = fromString str `as` Alias
396-- | the `TableExpression` in the `select` command constructs an intermediate
525-- | the `TableExpression` in the `select` command constructs an intermediate
397-- virtual table by possibly combining tables, views, eliminating rows,
526-- virtual table by possibly combining tables, views, eliminating rows,
398-- grouping, etc. This table is finally passed on to processing by
527-- grouping, etc. This table is finally passed on to processing by
399−-- the select list. The select list determines which columns of
528+-- the select list. The `Selection` determines which columns of
400-- the intermediate table are actually output.
529-- the intermediate table are actually output.
402− :: (SListI columns, columns ~ (col ': cols))
531+ :: (SListI row, row ~ (x ': xs))
403− => NP (Aliased (Expression db from grouping params)) columns
532+ => Selection outer commons grp schemas params from row
404− -- ^ select list
533+ -- ^ selection
405− -> TableExpression db params from grouping
534+ -> TableExpression outer commons grp schemas params from
406 -- ^ intermediate virtual table
535 -- ^ intermediate virtual table
407− -> Query db params columns
536+ -> Query outer commons schemas params row
408−select list rels = UnsafeQuery $
537+select selection tabexpr = UnsafeQuery $
410− <+> renderCommaSeparated (renderAliasedAs renderExpression) list
539+ <+> renderSQL selection
411− <+> renderTableExpression rels
540+ <+> renderSQL tabexpr
542+-- | Like `select` but takes an `NP` list of `Expression`s instead
543+-- of a general `Selection`.
545+ :: (SListI row, row ~ (x ': xs))
546+ => NP (Aliased (Expression outer commons grp schemas params from)) row
548+ -> TableExpression outer commons grp schemas params from
549+ -- ^ intermediate virtual table
550+ -> Query outer commons schemas params row
551+select_ = select . List
413-- | After the select list has been processed, the result table can
553-- | After the select list has been processed, the result table can
414-- be subject to the elimination of duplicate rows using `selectDistinct`.
554-- be subject to the elimination of duplicate rows using `selectDistinct`.
415selectDistinct
555selectDistinct
416 :: (SListI columns, columns ~ (col ': cols))
556 :: (SListI columns, columns ~ (col ': cols))
417− => NP (Aliased (Expression db from 'Ungrouped params)) columns
557+ => Selection outer commons grp schemas params from columns
418− -- ^ select list
558+ -- ^ selection
419− -> TableExpression db params from 'Ungrouped
559+ -> TableExpression outer commons grp schemas params from
420 -- ^ intermediate virtual table
560 -- ^ intermediate virtual table
421− -> Query db params columns
561+ -> Query outer commons schemas params columns
422−selectDistinct list rels = UnsafeQuery $
562+selectDistinct selection tabexpr = UnsafeQuery $
423 "SELECT DISTINCT"
563 "SELECT DISTINCT"
424− <+> renderCommaSeparated (renderAliasedAs renderExpression) list
564+ <+> renderSQL selection
425− <+> renderTableExpression rels
565+ <+> renderSQL tabexpr
427−-- | The simplest kind of query is `selectStar` which emits all columns
567+-- | Like `selectDistinct` but takes an `NP` list of `Expression`s instead
428−-- that the table expression produces.
568+-- of a general `Selection`.
429−selectStar
569+selectDistinct_
430− :: HasUnique table from columns
570+ :: (SListI columns, columns ~ (col ': cols))
431− => TableExpression db params from 'Ungrouped
571+ => NP (Aliased (Expression outer commons grp schemas params from)) columns
432− -- ^ intermediate virtual table
572+ -- ^ select list
433− -> Query db params columns
573+ -> TableExpression outer commons grp schemas params from
434−selectStar rels = UnsafeQuery $ "SELECT" <+> "*" <+> renderTableExpression rels
436−-- | A `selectDistinctStar` emits all columns that the table expression
437−-- produces and eliminates duplicate rows.
439− :: HasUnique table from columns
440− => TableExpression db params from 'Ungrouped
441 -- ^ intermediate virtual table
574 -- ^ intermediate virtual table
442− -> Query db params columns
575+ -> Query outer commons schemas params columns
443−selectDistinctStar rels = UnsafeQuery $
576+selectDistinct_ = selectDistinct . List
444− "SELECT DISTINCT" <+> "*" <+> renderTableExpression rels
577+
446−-- | When working with multiple tables, it can also be useful to ask
579+`selectDistinctOn` keeps only the first row of each set of rows where
447−-- for all the columns of a particular table, using `selectDotStar`.
580+the given expressions evaluate to equal. The DISTINCT ON expressions are
448−selectDotStar
581+interpreted using the same rules as for ORDER BY. ORDER BY is used to
449− :: Has table from columns
582+ensure that the desired row appears first.
451− -- ^ particular virtual subtable
584+The DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s).
452− -> TableExpression db params from 'Ungrouped
585+The ORDER BY clause will normally contain additional expression(s) that
586+determine the desired precedence of rows within each DISTINCT ON group.
588+In order to guarantee they match and reduce redundancy, this function
589+will prepend the The DISTINCT ON expressions to the ORDER BY clause.
592+ :: (SListI columns, columns ~ (col ': cols))
593+ => [SortExpression outer commons grp schemas params from]
594+ -- ^ DISTINCT ON expression(s) and prepended to ORDER BY clause
595+ -> Selection outer commons grp schemas params from columns
597+ -> TableExpression outer commons grp schemas params from
453 -- ^ intermediate virtual table
598 -- ^ intermediate virtual table
454− -> Query db params columns
599+ -> Query outer commons schemas params columns
455−selectDotStar rel tab = UnsafeQuery $
600+selectDistinctOn distincts selection tab = UnsafeQuery $
456− "SELECT" <+> renderAlias rel <> ".*" <+> renderTableExpression tab
601+ "SELECT DISTINCT ON"
457−
602+ <+> parenthesized (commaSeparated (renderDistinctOn <$> distincts))
458−-- | A `selectDistinctDotStar` asks for all the columns of a particular table,
603+ <+> renderSQL selection
459−-- and eliminates duplicate rows.
604+ <+> renderSQL (tab {orderByClause = distincts <> orderByClause tab})
460−selectDistinctDotStar
605+ where
461− :: Has table from columns
606+ renderDistinctOn = \case
462− => Alias table
607+ Asc expression -> renderSQL expression
463− -- ^ particular virtual table
608+ Desc expression -> renderSQL expression
464− -> TableExpression db params from 'Ungrouped
609+ AscNullsFirst expression -> renderSQL expression
610+ DescNullsFirst expression -> renderSQL expression
611+ AscNullsLast expression -> renderSQL expression
612+ DescNullsLast expression -> renderSQL expression
614+-- | Like `selectDistinctOn` but takes an `NP` list of `Expression`s instead
615+-- of a general `Selection`.
617+ :: (SListI columns, columns ~ (col ': cols))
618+ => [SortExpression outer commons grp schemas params from]
619+ -- ^ distinct on and return the first row in ordering
620+ -> NP (Aliased (Expression outer commons grp schemas params from)) columns
622+ -> TableExpression outer commons grp schemas params from
465 -- ^ intermediate virtual table
623 -- ^ intermediate virtual table
466− -> Query db params columns
624+ -> Query outer commons schemas params columns
467−selectDistinctDotStar rel tab = UnsafeQuery $
625+selectDistinctOn_ distincts = selectDistinctOn distincts . List
468− "SELECT DISTINCT" <+> renderAlias rel <> ".*"
469− <+> renderTableExpression tab
471-- | `values` computes a row value or set of row values
627-- | `values` computes a row value or set of row values
472-- specified by value expressions. It is most commonly used
628-- specified by value expressions. It is most commonly used
@@ -474,16 +630,16 @@ selectDistinctDotStar rel tab = UnsafeQuery $
474-- but it can be used on its own.
630-- but it can be used on its own.
476-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
632-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
477−-- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query db '[] Row
633+-- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query outer commons schemas '[] Row
478-- >>> printSQL query
634-- >>> printSQL query
479-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
635-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
481 :: SListI cols
637 :: SListI cols
482− => NP (Aliased (Expression db '[] 'Ungrouped params)) cols
638+ => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
483− -> [NP (Aliased (Expression db '[] 'Ungrouped params)) cols]
639+ -> [NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols]
484 -- ^ When more than one row is specified, all the rows must
640 -- ^ When more than one row is specified, all the rows must
485 -- must have the same number of elements
641 -- must have the same number of elements
486− -> Query db params cols
642+ -> Query outer commons schemas params cols
487values rw rws = UnsafeQuery $ "SELECT * FROM"
643values rw rws = UnsafeQuery $ "SELECT * FROM"
488 <+> parenthesized (
644 <+> parenthesized (
@@ -494,17 +650,17 @@ values rw rws = UnsafeQuery $ "SELECT * FROM"
494 <+> parenthesized (renderCommaSeparated renderAliasPart rw)
650 <+> parenthesized (renderCommaSeparated renderAliasPart rw)
496 renderAliasPart, renderValuePart
652 renderAliasPart, renderValuePart
497− :: Aliased (Expression db '[] 'Ungrouped params) ty -> ByteString
653+ :: Aliased (Expression outer commons 'Ungrouped schemas params '[] ) ty -> ByteString
498− renderAliasPart (_ `As` name) = renderAlias name
654+ renderAliasPart (_ `As` name) = renderSQL name
499− renderValuePart (value `As` _) = renderExpression value
655+ renderValuePart (value `As` _) = renderSQL value
501-- | `values_` computes a row value or set of row values
657-- | `values_` computes a row value or set of row values
502-- specified by value expressions.
658-- specified by value expressions.
504 :: SListI cols
660 :: SListI cols
505− => NP (Aliased (Expression db '[] 'Ungrouped params)) cols
661+ => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
506 -- ^ one row of values
662 -- ^ one row of values
507− -> Query db params cols
663+ -> Query outer commons schemas params cols
508values_ rw = values rw []
664values_ rw = values rw []
510{-----------------------------------------
666{-----------------------------------------
@@ -518,15 +674,17 @@ Table Expressions
518-- to a table on disk, a so-called base table, but more complex expressions
674-- to a table on disk, a so-called base table, but more complex expressions
519-- can be used to modify or combine base tables in various ways.
675-- can be used to modify or combine base tables in various ways.
520data TableExpression
676data TableExpression
521− (db :: DBType)
677+ (outer :: FromType)
678+ (commons :: FromType)
680+ (schemas :: SchemasType)
522 (params :: [NullityType])
681 (params :: [NullityType])
523 (from :: FromType)
682 (from :: FromType)
524− (grouping :: Grouping)
525 = TableExpression
683 = TableExpression
526− { fromClause :: FromClause db params from
684+ { fromClause :: FromClause outer commons schemas params from
527 -- ^ A table reference that can be a table name, or a derived table such
685 -- ^ A table reference that can be a table name, or a derived table such
528 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
686 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
529− , whereClause :: [Condition db from 'Ungrouped params]
687+ , whereClause :: [Condition outer commons 'Ungrouped schemas params from]
530 -- ^ optional search coditions, combined with `.&&`. After the processing
688 -- ^ optional search coditions, combined with `.&&`. After the processing
531 -- of the `fromClause` is done, each row of the derived virtual table
689 -- of the `fromClause` is done, each row of the derived virtual table
532 -- is checked against the search condition. If the result of the
690 -- is checked against the search condition. If the result of the
@@ -535,20 +693,20 @@ data TableExpression
535 -- at least one column of the table generated in the `fromClause`;
693 -- at least one column of the table generated in the `fromClause`;
536 -- this is not required, but otherwise the WHERE clause will
694 -- this is not required, but otherwise the WHERE clause will
537 -- be fairly useless.
695 -- be fairly useless.
538− , groupByClause :: GroupByClause from grouping
696+ , groupByClause :: GroupByClause grp from
539 -- ^ The `groupByClause` is used to group together those rows in a table
697 -- ^ The `groupByClause` is used to group together those rows in a table
540 -- that have the same values in all the columns listed. The order in which
698 -- that have the same values in all the columns listed. The order in which
541 -- the columns are listed does not matter. The effect is to combine each
699 -- the columns are listed does not matter. The effect is to combine each
542 -- set of rows having common values into one group row that represents all
700 -- set of rows having common values into one group row that represents all
543 -- rows in the group. This is done to eliminate redundancy in the output
701 -- rows in the group. This is done to eliminate redundancy in the output
544 -- and/or compute aggregates that apply to these groups.
702 -- and/or compute aggregates that apply to these groups.
545− , havingClause :: HavingClause db from grouping params
703+ , havingClause :: HavingClause outer commons grp schemas params from
546 -- ^ If a table has been grouped using `groupBy`, but only certain groups
704 -- ^ If a table has been grouped using `groupBy`, but only certain groups
547 -- are of interest, the `havingClause` can be used, much like a
705 -- are of interest, the `havingClause` can be used, much like a
548 -- `whereClause`, to eliminate groups from the result. Expressions in the
706 -- `whereClause`, to eliminate groups from the result. Expressions in the
549 -- `havingClause` can refer both to grouped expressions and to ungrouped
707 -- `havingClause` can refer both to grouped expressions and to ungrouped
550 -- expressions (which necessarily involve an aggregate function).
708 -- expressions (which necessarily involve an aggregate function).
551− , orderByClause :: [SortExpression db from grouping params]
709+ , orderByClause :: [SortExpression outer commons grp schemas params from]
552 -- ^ The `orderByClause` is for optional sorting. When more than one
710 -- ^ The `orderByClause` is for optional sorting. When more than one
553 -- `SortExpression` is specified, the later (right) values are used to sort
711 -- `SortExpression` is specified, the later (right) values are used to sort
554 -- rows that are equal according to the earlier (left) values.
712 -- rows that are equal according to the earlier (left) values.
@@ -558,72 +716,69 @@ data TableExpression
558 -- will be returned (but possibly fewer, if the query itself yields
716 -- will be returned (but possibly fewer, if the query itself yields
559 -- fewer rows).
717 -- fewer rows).
560 , offsetClause :: [Word64]
718 , offsetClause :: [Word64]
561− -- ^ The `offsetClause` is combined with `+` to give an offset count
719+ -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count
562 -- if nonempty. The offset count says to skip that many rows before
720 -- if nonempty. The offset count says to skip that many rows before
563 -- beginning to return rows. The rows are skipped before the limit count
721 -- beginning to return rows. The rows are skipped before the limit count
564 -- is applied.
722 -- is applied.
565− }
723+ } deriving (GHC.Generic)
567-- | Render a `TableExpression`
725-- | Render a `TableExpression`
568−renderTableExpression
726+instance RenderSQL (TableExpression outer commons grp schemas params from) where
569− :: TableExpression db params from grouping
727+ renderSQL
570− -> ByteString
728+ (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
571−renderTableExpression
729+ [ "FROM ", renderSQL frm'
572− (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
730+ , renderWheres whs'
573− [ "FROM ", renderFromClause frm'
731+ , renderSQL grps'
574− , renderWheres whs'
732+ , renderSQL hvs'
575− , renderGroupByClause grps'
733+ , renderOrderByClause srts'
576− , renderHavingClause hvs'
734+ , renderLimits lims'
577− , renderOrderByClause srts'
735+ , renderOffsets offs' ]
578− , renderLimits lims'
736+ where
579− , renderOffsets offs'
737+ renderWheres = \case
581− where
739+ wh:[] -> " WHERE" <+> renderSQL wh
582− renderWheres = \case
740+ wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)
583− [] -> ""
741+ renderOrderByClause = \case
584− wh:[] -> " WHERE" <+> renderExpression wh
742+ [] -> ""
585− wh:whs -> " WHERE" <+> renderExpression (foldr (.&&) wh whs)
743+ srts -> " ORDER BY"
586− renderOrderByClause = \case
744+ <+> commaSeparated (renderSQL <$> srts)
587− [] -> ""
745+ renderLimits = \case
588− srts -> " ORDER BY"
746+ [] -> ""
589− <+> commaSeparated (renderSortExpression <$> srts)
747+ lims -> " LIMIT" <+> fromString (show (minimum lims))
590− renderLimits = \case
748+ renderOffsets = \case
591− [] -> ""
749+ [] -> ""
592− lims -> " LIMIT" <+> fromString (show (minimum lims))
750+ offs -> " OFFSET" <+> fromString (show (sum offs))
593− renderOffsets = \case
595− offs -> " OFFSET" <+> fromString (show (sum offs))
597-- | A `from` generates a `TableExpression` from a table reference that can be
752-- | A `from` generates a `TableExpression` from a table reference that can be
598-- a table name, or a derived table such as a subquery, a JOIN construct,
753-- a table name, or a derived table such as a subquery, a JOIN construct,
599-- or complex combinations of these. A `from` may be transformed by `where_`,
754-- or complex combinations of these. A `from` may be transformed by `where_`,
600−-- `group`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
755+-- `groupBy`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
601-- to match the left-to-right sequencing of their placement in SQL.
756-- to match the left-to-right sequencing of their placement in SQL.
603− :: FromClause db params from -- ^ table reference
758+ :: FromClause outer commons schemas params from -- ^ table reference
604− -> TableExpression db params from 'Ungrouped
759+ -> TableExpression outer commons 'Ungrouped schemas params from
605−from rels = TableExpression rels [] NoGroups NoHaving [] [] []
760+from tab = TableExpression tab [] noGroups NoHaving [] [] []
607-- | A `where_` is an endomorphism of `TableExpression`s which adds a
762-- | A `where_` is an endomorphism of `TableExpression`s which adds a
608-- search condition to the `whereClause`.
763-- search condition to the `whereClause`.
610− :: Condition db from 'Ungrouped params -- ^ filtering condition
765+ :: Condition outer commons 'Ungrouped schemas params from -- ^ filtering condition
611− -> TableExpression db params from grouping
766+ -> TableExpression outer commons grp schemas params from
612− -> TableExpression db params from grouping
767+ -> TableExpression outer commons grp schemas params from
613where_ wh rels = rels {whereClause = wh : whereClause rels}
768where_ wh rels = rels {whereClause = wh : whereClause rels}
615-- | A `groupBy` is a transformation of `TableExpression`s which switches
770-- | A `groupBy` is a transformation of `TableExpression`s which switches
616−-- its `Grouping` from `Ungrouped` to `Grouped`. Use @group Nil@ to perform
771+-- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform
617-- a "grand total" aggregation query.
772-- a "grand total" aggregation query.
619 :: SListI bys
774 :: SListI bys
620 => NP (By from) bys -- ^ grouped columns
775 => NP (By from) bys -- ^ grouped columns
621− -> TableExpression db params from 'Ungrouped
776+ -> TableExpression outer commons 'Ungrouped schemas params from
622− -> TableExpression db params from ('Grouped bys)
777+ -> TableExpression outer commons ('Grouped bys) schemas params from
623groupBy bys rels = TableExpression
778groupBy bys rels = TableExpression
624 { fromClause = fromClause rels
779 { fromClause = fromClause rels
625 , whereClause = whereClause rels
780 , whereClause = whereClause rels
626− , groupByClause = Group bys
781+ , groupByClause = group bys
627 , havingClause = Having []
782 , havingClause = Having []
628 , orderByClause = []
783 , orderByClause = []
629 , limitClause = limitClause rels
784 , limitClause = limitClause rels
@@ -633,177 +788,31 @@ groupBy bys rels = TableExpression
633-- | A `having` is an endomorphism of `TableExpression`s which adds a
788-- | A `having` is an endomorphism of `TableExpression`s which adds a
634-- search condition to the `havingClause`.
789-- search condition to the `havingClause`.
636− :: Condition db from ('Grouped bys) params -- ^ having condition
791+ :: Condition outer commons ('Grouped bys) schemas params from -- ^ having condition
637− -> TableExpression db params from ('Grouped bys)
792+ -> TableExpression outer commons ('Grouped bys) schemas params from
638− -> TableExpression db params from ('Grouped bys)
793+ -> TableExpression outer commons ('Grouped bys) schemas params from
639having hv rels = rels
794having hv rels = rels
640 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
795 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
642−-- | An `orderBy` is an endomorphism of `TableExpression`s which appends an
797+instance OrderBy TableExpression where
643−-- ordering to the right of the `orderByClause`.
798+ orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
645− :: [SortExpression db from grouping params] -- ^ sort expressions
646− -> TableExpression db params from grouping
647− -> TableExpression db params from grouping
648−orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
650-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
800-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
651-- `limitClause`.
801-- `limitClause`.
653 :: Word64 -- ^ limit parameter
803 :: Word64 -- ^ limit parameter
654− -> TableExpression db params from grouping
804+ -> TableExpression outer commons grp schemas params from
655− -> TableExpression db params from grouping
805+ -> TableExpression outer commons grp schemas params from
656limit lim rels = rels {limitClause = lim : limitClause rels}
806limit lim rels = rels {limitClause = lim : limitClause rels}
658-- | An `offset` is an endomorphism of `TableExpression`s which adds to the
808-- | An `offset` is an endomorphism of `TableExpression`s which adds to the
659-- `offsetClause`.
809-- `offsetClause`.
661 :: Word64 -- ^ offset parameter
811 :: Word64 -- ^ offset parameter
662− -> TableExpression db params from grouping
812+ -> TableExpression outer commons grp schemas params from
663− -> TableExpression db params from grouping
813+ -> TableExpression outer commons grp schemas params from
664offset off rels = rels {offsetClause = off : offsetClause rels}
814offset off rels = rels {offsetClause = off : offsetClause rels}
666−{-----------------------------------------
668−-----------------------------------------}
672− -> Expression db '[] 'Ungrouped params ty
673− -> Query db params row
674−unsafeSetOfFunction fun expr = UnsafeQuery $
675− "SELECT * FROM " <> fun <> "(" <> renderExpression expr <> ")"
677−-- | Expands the outermost JSON object into a set of key/value pairs.
679− :: Expression db '[] 'Ungrouped params (nullity 'PGjson) -- ^ json object
681− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
682−jsonEach = unsafeSetOfFunction "json_each"
684−-- | Expands the outermost binary JSON object into a set of key/value pairs.
686− :: Expression db '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb object
688− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjsonb]
689−jsonbEach = unsafeSetOfFunction "jsonb_each"
691−-- | Expands the outermost JSON object into a set of key/value pairs.
693− :: Expression db '[] 'Ungrouped params (nullity 'PGjson) -- ^ json object
695− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
696−jsonEachAsText = unsafeSetOfFunction "json_each_text"
698−-- | Expands the outermost binary JSON object into a set of key/value pairs.
700− :: Expression db '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb object
702− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
703−jsonbEachAsText = unsafeSetOfFunction "jsonb_each_text"
705−-- | Returns set of keys in the outermost JSON object.
707− :: Expression db '[] 'Ungrouped params (nullity 'PGjson) -- ^ json object
708− -> Query db params '["json_object_keys" ::: 'NotNull 'PGtext]
709−jsonObjectKeys = unsafeSetOfFunction "json_object_keys"
711−-- | Returns set of keys in the outermost JSON object.
713− :: Expression db '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb object
714− -> Query db params '["jsonb_object_keys" ::: 'NotNull 'PGtext]
715−jsonbObjectKeys = unsafeSetOfFunction "jsonb_object_keys"
717−unsafePopulateFunction
719− -> TypeExpression schemas (nullity ('PGcomposite row))
720− -> Expression (commons :=> schemas) '[] 'Ungrouped params ty
721− -> Query (commons :=> schemas) params row
722−unsafePopulateFunction fun ty expr = UnsafeQuery $
723− "SELECT * FROM " <> fun <> "("
724− <> "null::" <> renderTypeExpression ty <> ", "
725− <> renderExpression expr <> ")"
727−-- | Expands the JSON expression to a row whose columns match the record
728−-- type defined by the given table.
730− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
731− -> Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjson) -- ^ json object
732− -> Query (commons :=> schemas) params row
733−jsonPopulateRecord = unsafePopulateFunction "json_populate_record"
735−-- | Expands the binary JSON expression to a row whose columns match the record
736−-- type defined by the given table.
738− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
739− -> Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb object
740− -> Query (commons :=> schemas) params row
741−jsonbPopulateRecord = unsafePopulateFunction "jsonb_populate_record"
743−-- | Expands the outermost array of objects in the given JSON expression to a
744−-- set of rows whose columns match the record type defined by the given table.
745−jsonPopulateRecordSet
746− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
747− -> Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjson) -- ^ json array
748− -> Query (commons :=> schemas) params row
749−jsonPopulateRecordSet = unsafePopulateFunction "json_populate_record_set"
751−-- | Expands the outermost array of objects in the given binary JSON expression
752−-- to a set of rows whose columns match the record type defined by the given
754−jsonbPopulateRecordSet
755− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
756− -> Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb array
757− -> Query (commons :=> schemas) params row
758−jsonbPopulateRecordSet = unsafePopulateFunction "jsonb_populate_record_set"
761− :: (SListI record, json `In` PGJsonType)
763− -> Expression (commons :=> schemas) '[] 'Ungrouped params (nullity json)
764− -> NP (Aliased (TypeExpression schemas)) record
765− -> Query (commons :=> schemas) params record
766−unsafeRecordFunction fun expr types = UnsafeQuery $
767− "SELECT * FROM " <> fun <> "("
768− <> renderExpression expr <> ")"
769− <+> "AS" <+> "x" <> parenthesized (renderCommaSeparated renderTy types)
771− renderTy :: Aliased (TypeExpression db) ty -> ByteString
772− renderTy (ty `As` alias) =
773− renderAlias alias <+> renderTypeExpression ty
775−-- | Builds an arbitrary record from a JSON object.
778− => Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjson) -- ^ json object
779− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
780− -> Query (commons :=> schemas) params record
781−jsonToRecord = unsafeRecordFunction "json_to_record"
783−-- | Builds an arbitrary record from a binary JSON object.
786− => Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb object
787− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
788− -> Query (commons :=> schemas) params record
789−jsonbToRecord = unsafeRecordFunction "jsonb_to_record"
791−-- | Builds an arbitrary set of records from a JSON array of objects.
794− => Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjson) -- ^ json array
795− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
796− -> Query (commons :=> schemas) params record
797−jsonToRecordSet = unsafeRecordFunction "json_to_record_set"
799−-- | Builds an arbitrary set of records from a binary JSON array of objects.
802− => Expression (commons :=> schemas) '[] 'Ungrouped params (nullity 'PGjsonb) -- ^ jsonb array
803− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
804− -> Query (commons :=> schemas) params record
805−jsonbToRecordSet = unsafeRecordFunction "jsonb_to_record_set"
807{-----------------------------------------
816{-----------------------------------------
808FROM clauses
817FROM clauses
809-----------------------------------------}
818-----------------------------------------}
@@ -812,68 +821,76 @@ FROM clauses
812A `FromClause` can be a table name, or a derived table such
821A `FromClause` can be a table name, or a derived table such
813as a subquery, a @JOIN@ construct, or complex combinations of these.
822as a subquery, a @JOIN@ construct, or complex combinations of these.
815−newtype FromClause db params from
824+newtype FromClause outer commons schemas params from
816 = UnsafeFromClause { renderFromClause :: ByteString }
825 = UnsafeFromClause { renderFromClause :: ByteString }
817 deriving (GHC.Generic,Show,Eq,Ord,NFData)
826 deriving (GHC.Generic,Show,Eq,Ord,NFData)
827+instance RenderSQL (FromClause outer commons schemas params from) where
828+ renderSQL = renderFromClause
819-- | A real `table` is a table from the database.
830-- | A real `table` is a table from the database.
821 :: (Has sch schemas schema, Has tab schema ('Table table))
832 :: (Has sch schemas schema, Has tab schema ('Table table))
822 => Aliased (QualifiedAlias sch) (alias ::: tab)
833 => Aliased (QualifiedAlias sch) (alias ::: tab)
823− -> FromClause (commons :=> schemas) params '[alias ::: TableToRow table]
834+ -> FromClause outer commons schemas params '[alias ::: TableToRow table]
824table (tab `As` alias) = UnsafeFromClause $
835table (tab `As` alias) = UnsafeFromClause $
825− renderQualifiedAlias tab <+> "AS" <+> renderAlias alias
836+ renderSQL tab <+> "AS" <+> renderSQL alias
827-- | `subquery` derives a table from a `Query`.
838-- | `subquery` derives a table from a `Query`.
829− :: Aliased (Query db params) query
840+ :: Aliased (Query outer commons schemas params) query
830− -> FromClause db params '[query]
841+ -> FromClause outer commons schemas params '[query]
831−subquery = UnsafeFromClause . renderAliasedAs (parenthesized . renderQuery)
842+subquery = UnsafeFromClause . renderAliased (parenthesized . renderSQL)
833-- | `view` derives a table from a `View`.
844-- | `view` derives a table from a `View`.
835 :: (Has sch schemas schema, Has vw schema ('View view))
846 :: (Has sch schemas schema, Has vw schema ('View view))
836 => Aliased (QualifiedAlias sch) (alias ::: vw)
847 => Aliased (QualifiedAlias sch) (alias ::: vw)
837− -> FromClause (commons :=> schemas) params '[alias ::: view]
848+ -> FromClause outer commons schemas params '[alias ::: view]
838view (vw `As` alias) = UnsafeFromClause $
849view (vw `As` alias) = UnsafeFromClause $
839− renderQualifiedAlias vw <+> "AS" <+> renderAlias alias
850+ renderSQL vw <+> "AS" <+> renderSQL alias
852+-- | `common` derives a table from a common table expression.
842 :: Has cte commons common
854 :: Has cte commons common
843 => Aliased Alias (alias ::: cte)
855 => Aliased Alias (alias ::: cte)
844− -> FromClause (commons :=> schemas) params '[alias ::: common]
856+ -> FromClause outer commons schemas params '[alias ::: common]
845common (cte `As` alias) = UnsafeFromClause $
857common (cte `As` alias) = UnsafeFromClause $
846− renderAlias cte <+> "AS" <+> renderAlias alias
858+ renderSQL cte <+> "AS" <+> renderSQL alias
848−{- | @left & crossJoin right@. For every possible combination of rows from
860+instance Additional (FromClause outer commons schemas params) where
849− @left@ and @right@ (i.e., a Cartesian product), the joined table will contain
861+ also right left = UnsafeFromClause $
850− a row consisting of all columns in @left@ followed by all columns in @right@.
862+ renderSQL left <> ", " <> renderSQL right
851− If the tables have @n@ and @m@ rows respectively, the joined table will
863+
852− have @n * m@ rows.
864+{- |
865+@left & crossJoin right@. For every possible combination of rows from
866+@left@ and @right@ (i.e., a Cartesian product), the joined table will contain
867+a row consisting of all columns in @left@ followed by all columns in @right@.
868+If the tables have @n@ and @m@ rows respectively, the joined table will
855− :: FromClause db params right
872+ :: FromClause outer commons schemas params right
856 -- ^ right
873 -- ^ right
857− -> FromClause db params left
874+ -> FromClause outer commons schemas params left
858 -- ^ left
875 -- ^ left
859− -> FromClause db params (Join left right)
876+ -> FromClause outer commons schemas params (Join left right)
860crossJoin right left = UnsafeFromClause $
877crossJoin right left = UnsafeFromClause $
861− renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
878+ renderSQL left <+> "CROSS JOIN" <+> renderSQL right
863{- | @left & innerJoin right on@. The joined table is filtered by
880{- | @left & innerJoin right on@. The joined table is filtered by
864the @on@ condition.
881the @on@ condition.
867− :: FromClause db params right
884+ :: FromClause outer commons schemas params right
868 -- ^ right
885 -- ^ right
869− -> Condition db (Join left right) 'Ungrouped params
886+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
870 -- ^ @on@ condition
887 -- ^ @on@ condition
871− -> FromClause db params left
888+ -> FromClause outer commons schemas params left
872 -- ^ left
889 -- ^ left
873− -> FromClause db params (Join left right)
890+ -> FromClause outer commons schemas params (Join left right)
874innerJoin right on left = UnsafeFromClause $
891innerJoin right on left = UnsafeFromClause $
875− renderFromClause left <+> "INNER JOIN" <+> renderFromClause right
892+ renderSQL left <+> "INNER JOIN" <+> renderSQL right
876− <+> "ON" <+> renderExpression on
893+ <+> "ON" <+> renderSQL on
878{- | @left & leftOuterJoin right on@. First, an inner join is performed.
895{- | @left & leftOuterJoin right on@. First, an inner join is performed.
879 Then, for each row in @left@ that does not satisfy the @on@ condition with
896 Then, for each row in @left@ that does not satisfy the @on@ condition with
@@ -881,16 +898,16 @@ innerJoin right on left = UnsafeFromClause $
881 Thus, the joined table always has at least one row for each row in @left@.
898 Thus, the joined table always has at least one row for each row in @left@.
883leftOuterJoin
900leftOuterJoin
884− :: FromClause db params right
901+ :: FromClause outer commons schemas params right
885 -- ^ right
902 -- ^ right
886− -> Condition db (Join left right) 'Ungrouped params
903+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
887 -- ^ @on@ condition
904 -- ^ @on@ condition
888− -> FromClause db params left
905+ -> FromClause outer commons schemas params left
889 -- ^ left
906 -- ^ left
890− -> FromClause db params (Join left (NullifyFrom right))
907+ -> FromClause outer commons schemas params (Join left (NullifyFrom right))
891leftOuterJoin right on left = UnsafeFromClause $
908leftOuterJoin right on left = UnsafeFromClause $
892− renderFromClause left <+> "LEFT OUTER JOIN" <+> renderFromClause right
909+ renderSQL left <+> "LEFT OUTER JOIN" <+> renderSQL right
893− <+> "ON" <+> renderExpression on
910+ <+> "ON" <+> renderSQL on
895{- | @left & rightOuterJoin right on@. First, an inner join is performed.
912{- | @left & rightOuterJoin right on@. First, an inner join is performed.
896 Then, for each row in @right@ that does not satisfy the @on@ condition with
913 Then, for each row in @right@ that does not satisfy the @on@ condition with
@@ -899,16 +916,16 @@ leftOuterJoin right on left = UnsafeFromClause $
899 have a row for each row in @right@.
916 have a row for each row in @right@.
901rightOuterJoin
918rightOuterJoin
902− :: FromClause db params right
919+ :: FromClause outer commons schemas params right
903 -- ^ right
920 -- ^ right
904− -> Condition db (Join left right) 'Ungrouped params
921+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
905 -- ^ @on@ condition
922 -- ^ @on@ condition
906− -> FromClause db params left
923+ -> FromClause outer commons schemas params left
907 -- ^ left
924 -- ^ left
908− -> FromClause db params (Join (NullifyFrom left) right)
925+ -> FromClause outer commons schemas params (Join (NullifyFrom left) right)
909rightOuterJoin right on left = UnsafeFromClause $
926rightOuterJoin right on left = UnsafeFromClause $
910− renderFromClause left <+> "RIGHT OUTER JOIN" <+> renderFromClause right
927+ renderSQL left <+> "RIGHT OUTER JOIN" <+> renderSQL right
911− <+> "ON" <+> renderExpression on
928+ <+> "ON" <+> renderSQL on
913{- | @left & fullOuterJoin right on@. First, an inner join is performed.
930{- | @left & fullOuterJoin right on@. First, an inner join is performed.
914 Then, for each row in @left@ that does not satisfy the @on@ condition with
931 Then, for each row in @left@ that does not satisfy the @on@ condition with
@@ -918,23 +935,23 @@ rightOuterJoin right on left = UnsafeFromClause $
918 is added.
935 is added.
920fullOuterJoin
937fullOuterJoin
921− :: FromClause db params right
938+ :: FromClause outer commons schemas params right
922 -- ^ right
939 -- ^ right
923− -> Condition db (Join left right) 'Ungrouped params
940+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
924 -- ^ @on@ condition
941 -- ^ @on@ condition
925− -> FromClause db params left
942+ -> FromClause outer commons schemas params left
926 -- ^ left
943 -- ^ left
927− -> FromClause db params
944+ -> FromClause outer commons schemas params
928 (Join (NullifyFrom left) (NullifyFrom right))
945 (Join (NullifyFrom left) (NullifyFrom right))
929fullOuterJoin right on left = UnsafeFromClause $
946fullOuterJoin right on left = UnsafeFromClause $
930− renderFromClause left <+> "FULL OUTER JOIN" <+> renderFromClause right
947+ renderSQL left <+> "FULL OUTER JOIN" <+> renderSQL right
931− <+> "ON" <+> renderExpression on
948+ <+> "ON" <+> renderSQL on
933{-----------------------------------------
950{-----------------------------------------
935-----------------------------------------}
952-----------------------------------------}
937−-- | `By`s are used in `group` to reference a list of columns which are then
954+-- | `By`s are used in `groupBy` to reference a list of columns which are then
938-- used to group together those rows in a table that have the same values
955-- used to group together those rows in a table that have the same values
939-- in all the columns listed. @By \#col@ will reference an unambiguous
956-- in all the columns listed. @By \#col@ will reference an unambiguous
940-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
957-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
@@ -954,6 +971,10 @@ data By
954deriving instance Show (By from by)
971deriving instance Show (By from by)
955deriving instance Eq (By from by)
972deriving instance Eq (By from by)
956deriving instance Ord (By from by)
973deriving instance Ord (By from by)
974+instance RenderSQL (By from by) where
976+ By1 column -> renderSQL column
977+ By2 rel column -> renderSQL rel <> "." <> renderSQL column
958instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
979instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
959 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
980 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
@@ -965,431 +986,113 @@ instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])
965 => IsQualified rel col (NP (By rels) bys) where
986 => IsQualified rel col (NP (By rels) bys) where
966 rel ! col = By2 rel col :* Nil
987 rel ! col = By2 rel col :* Nil
969−renderBy :: By from by -> ByteString
971− By1 column -> renderAlias column
972− By2 rel column -> renderAlias rel <> "." <> renderAlias column
974-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
989-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
975-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
990-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
976-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
991-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
977-- done on @NoGroups@ while all output `Expression`s must be aggregated
992-- done on @NoGroups@ while all output `Expression`s must be aggregated
978-- in @Group Nil@. In general, all output `Expression`s in the
993-- in @Group Nil@. In general, all output `Expression`s in the
979-- complement of @bys@ must be aggregated in @Group bys@.
994-- complement of @bys@ must be aggregated in @Group bys@.
980−data GroupByClause from grouping where
995+newtype GroupByClause grp from = UnsafeGroupByClause
981− NoGroups :: GroupByClause from 'Ungrouped
996+ { renderGroupByClause :: ByteString }
982− Group
997+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
983− :: SListI bys
998+instance RenderSQL (GroupByClause grp from) where
984− => NP (By from) bys
999+ renderSQL = renderGroupByClause
985− -> GroupByClause from ('Grouped bys)
1000+noGroups :: GroupByClause 'Ungrouped from
986−
1001+noGroups = UnsafeGroupByClause ""
987−-- | Renders a `GroupByClause`.
1002+group
988−renderGroupByClause :: GroupByClause from grouping -> ByteString
1003+ :: SListI bys
989−renderGroupByClause = \case
1004+ => NP (By from) bys
990− NoGroups -> ""
1005+ -> GroupByClause ('Grouped bys) from
991− Group Nil -> ""
1006+group bys = UnsafeGroupByClause $ case bys of
992− Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
1007+ Nil -> ""
1008+ bys' -> " GROUP BY" <+> renderCommaSeparated renderSQL bys'
994-- | A `HavingClause` is used to eliminate groups that are not of interest.
1010-- | A `HavingClause` is used to eliminate groups that are not of interest.
995-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1011-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
996-- `TableExpression` must use `Having` whose conditions are combined with
1012-- `TableExpression` must use `Having` whose conditions are combined with
997-- `.&&`.
1013-- `.&&`.
998−data HavingClause db from grouping params where
1014+data HavingClause outer commons grp schemas params from where
999− NoHaving :: HavingClause db from 'Ungrouped params
1015+ NoHaving :: HavingClause outer commons 'Ungrouped schemas params from
1001− :: [Condition db from ('Grouped bys) params]
1017+ :: [Condition outer commons ('Grouped bys) schemas params from]
1002− -> HavingClause db from ('Grouped bys) params
1018+ -> HavingClause outer commons ('Grouped bys) schemas params from
1003−deriving instance Show (HavingClause db from grouping params)
1019+deriving instance Show (HavingClause outer commons grp schemas params from)
1004−deriving instance Eq (HavingClause db from grouping params)
1020+deriving instance Eq (HavingClause outer commons grp schemas params from)
1005−deriving instance Ord (HavingClause db from grouping params)
1021+deriving instance Ord (HavingClause outer commons grp schemas params from)
1007-- | Render a `HavingClause`.
1023-- | Render a `HavingClause`.
1008−renderHavingClause :: HavingClause db from grouping params -> ByteString
1024+instance RenderSQL (HavingClause outer commons grp schemas params from) where
1009−renderHavingClause = \case
1025+ renderSQL = \case
1010− NoHaving -> ""
1026+ NoHaving -> ""
1011− Having [] -> ""
1027+ Having [] -> ""
1012− Having conditions ->
1028+ Having conditions ->
1013− " HAVING" <+> commaSeparated (renderExpression <$> conditions)
1029+ " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1015−{-----------------------------------------
1017−-----------------------------------------}
1019−-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1020−-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1021−-- column to ascending or descending. Ascending order puts smaller values
1022−-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1023−-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1024−-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1025−-- determine whether nulls appear before or after non-null values in the sort
1026−-- ordering of a `Null` result column.
1027−data SortExpression db from grouping params where
1029− :: Expression db from grouping params ('NotNull ty)
1030− -> SortExpression db from grouping params
1032− :: Expression db from grouping params ('NotNull ty)
1033− -> SortExpression db from grouping params
1035− :: Expression db from grouping params ('Null ty)
1036− -> SortExpression db from grouping params
1038− :: Expression db from grouping params ('Null ty)
1039− -> SortExpression db from grouping params
1041− :: Expression db from grouping params ('Null ty)
1042− -> SortExpression db from grouping params
1044− :: Expression db from grouping params ('Null ty)
1045− -> SortExpression db from grouping params
1046−deriving instance Show (SortExpression db from grouping params)
1048−-- | Render a `SortExpression`.
1049−renderSortExpression :: SortExpression db from grouping params -> ByteString
1050−renderSortExpression = \case
1051− Asc expression -> renderExpression expression <+> "ASC"
1052− Desc expression -> renderExpression expression <+> "DESC"
1053− AscNullsFirst expression -> renderExpression expression
1054− <+> "ASC NULLS FIRST"
1055− DescNullsFirst expression -> renderExpression expression
1056− <+> "DESC NULLS FIRST"
1057− AscNullsLast expression -> renderExpression expression <+> "ASC NULLS LAST"
1058− DescNullsLast expression -> renderExpression expression <+> "DESC NULLS LAST"
1060−unsafeSubqueryExpression
1062− -> Expression db from grp params ty
1063− -> Query db params '[alias ::: ty]
1064− -> Expression db from grp params (nullity 'PGbool)
1065−unsafeSubqueryExpression op x q = UnsafeExpression $
1066− renderExpression x <+> op <+> parenthesized (renderQuery q)
1068−unsafeRowSubqueryExpression
1071− -> NP (Aliased (Expression db from grp params)) row
1072− -> Query db params row
1073− -> Expression db from grp params (nullity 'PGbool)
1074−unsafeRowSubqueryExpression op xs q = UnsafeExpression $
1075− renderExpression (row xs) <+> op <+> parenthesized (renderQuery q)
1077−-- | The right-hand side is a sub`Query`, which must return exactly one column.
1078−-- The left-hand expression is evaluated and compared to each row of the
1079−-- sub`Query` result. The result of `in_` is `true` if any equal subquery row is found.
1080−-- The result is `false` if no equal row is found
1081−-- (including the case where the subquery returns no rows).
1083−-- >>> printSQL $ true `in_` values_ (true `as` #foo)
1084−-- TRUE IN (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1086− :: Expression db from grp params ty -- ^ expression
1087− -> Query db params '[alias ::: ty] -- ^ subquery
1088− -> Expression db from grp params (nullity 'PGbool)
1089−in_ = unsafeSubqueryExpression "IN"
1091−{- | The left-hand side of this form of `rowIn` is a row constructor.
1092−The right-hand side is a sub`Query`,
1093−which must return exactly as many columns as
1094−there are expressions in the left-hand row.
1095−The left-hand expressions are evaluated and compared row-wise to each row
1096−of the subquery result. The result of `rowIn`
1097−is `true` if any equal subquery row is found.
1098−The result is `false` if no equal row is found
1099−(including the case where the subquery returns no rows).
1101−>>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1102−>>> printSQL $ myRow `rowIn` values_ myRow
1103−ROW(1, FALSE) IN (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1107− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1108− -> Query db params row -- ^ subquery
1109− -> Expression db from grp params (nullity 'PGbool)
1110−rowIn = unsafeRowSubqueryExpression "IN"
1112−-- | >>> printSQL $ true `eqAll` values_ (true `as` #foo)
1113−-- TRUE = ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1115− :: Expression db from grp params ty -- ^ expression
1116− -> Query db params '[alias ::: ty] -- ^ subquery
1117− -> Expression db from grp params (nullity 'PGbool)
1118−eqAll = unsafeSubqueryExpression "= ALL"
1120−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1121−-- >>> printSQL $ myRow `rowEqAll` values_ myRow
1122−-- ROW(1, FALSE) = ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1125− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1126− -> Query db params row -- ^ subquery
1127− -> Expression db from grp params (nullity 'PGbool)
1128−rowEqAll = unsafeRowSubqueryExpression "= ALL"
1130−-- | >>> printSQL $ true `eqAny` values_ (true `as` #foo)
1131−-- TRUE = ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1133− :: Expression db from grp params ty -- ^ expression
1134− -> Query db params '[alias ::: ty] -- ^ subquery
1135− -> Expression db from grp params (nullity 'PGbool)
1136−eqAny = unsafeSubqueryExpression "= ANY"
1138−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1139−-- >>> printSQL $ myRow `rowEqAny` values_ myRow
1140−-- ROW(1, FALSE) = ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1143− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1144− -> Query db params row -- ^ subquery
1145− -> Expression db from grp params (nullity 'PGbool)
1146−rowEqAny = unsafeRowSubqueryExpression "= ANY"
1148−-- | >>> printSQL $ true `neqAll` values_ (true `as` #foo)
1149−-- TRUE <> ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1151− :: Expression db from grp params ty -- ^ expression
1152− -> Query db params '[alias ::: ty] -- ^ subquery
1153− -> Expression db from grp params (nullity 'PGbool)
1154−neqAll = unsafeSubqueryExpression "<> ALL"
1156−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1157−-- >>> printSQL $ myRow `rowNeqAll` values_ myRow
1158−-- ROW(1, FALSE) <> ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1161− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1162− -> Query db params row -- ^ subquery
1163− -> Expression db from grp params (nullity 'PGbool)
1164−rowNeqAll = unsafeRowSubqueryExpression "<> ALL"
1166−-- | >>> printSQL $ true `neqAny` values_ (true `as` #foo)
1167−-- TRUE <> ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1169− :: Expression db from grp params ty -- ^ expression
1170− -> Query db params '[alias ::: ty] -- ^ subquery
1171− -> Expression db from grp params (nullity 'PGbool)
1172−neqAny = unsafeSubqueryExpression "<> ANY"
1174−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1175−-- >>> printSQL $ myRow `rowNeqAny` values_ myRow
1176−-- ROW(1, FALSE) <> ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1179− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1180− -> Query db params row -- ^ subquery
1181− -> Expression db from grp params (nullity 'PGbool)
1182−rowNeqAny = unsafeRowSubqueryExpression "<> ANY"
1184−-- | >>> printSQL $ true `allLt` values_ (true `as` #foo)
1185−-- TRUE ALL < (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1187− :: Expression db from grp params ty -- ^ expression
1188− -> Query db params '[alias ::: ty] -- ^ subquery
1189− -> Expression db from grp params (nullity 'PGbool)
1190−allLt = unsafeSubqueryExpression "ALL <"
1192−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1193−-- >>> printSQL $ myRow `rowLtAll` values_ myRow
1194−-- ROW(1, FALSE) ALL < (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1197− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1198− -> Query db params row -- ^ subquery
1199− -> Expression db from grp params (nullity 'PGbool)
1200−rowLtAll = unsafeRowSubqueryExpression "ALL <"
1202−-- | >>> printSQL $ true `ltAny` values_ (true `as` #foo)
1203−-- TRUE ANY < (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1205− :: Expression db from grp params ty -- ^ expression
1206− -> Query db params '[alias ::: ty] -- ^ subquery
1207− -> Expression db from grp params (nullity 'PGbool)
1208−ltAny = unsafeSubqueryExpression "ANY <"
1210−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1211−-- >>> printSQL $ myRow `rowLtAll` values_ myRow
1212−-- ROW(1, FALSE) ALL < (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1215− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1216− -> Query db params row -- ^ subquery
1217− -> Expression db from grp params (nullity 'PGbool)
1218−rowLtAny = unsafeRowSubqueryExpression "ANY <"
1220−-- | >>> printSQL $ true `lteAll` values_ (true `as` #foo)
1221−-- TRUE <= ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1223− :: Expression db from grp params ty -- ^ expression
1224− -> Query db params '[alias ::: ty] -- ^ subquery
1225− -> Expression db from grp params (nullity 'PGbool)
1226−lteAll = unsafeSubqueryExpression "<= ALL"
1228−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1229−-- >>> printSQL $ myRow `rowLteAll` values_ myRow
1230−-- ROW(1, FALSE) <= ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1233− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1234− -> Query db params row -- ^ subquery
1235− -> Expression db from grp params (nullity 'PGbool)
1236−rowLteAll = unsafeRowSubqueryExpression "<= ALL"
1238−-- | >>> printSQL $ true `lteAny` values_ (true `as` #foo)
1239−-- TRUE <= ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1241− :: Expression db from grp params ty -- ^ expression
1242− -> Query db params '[alias ::: ty] -- ^ subquery
1243− -> Expression db from grp params (nullity 'PGbool)
1244−lteAny = unsafeSubqueryExpression "<= ANY"
1246−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1247−-- >>> printSQL $ myRow `rowLteAny` values_ myRow
1248−-- ROW(1, FALSE) <= ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1251− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1252− -> Query db params row -- ^ subquery
1253− -> Expression db from grp params (nullity 'PGbool)
1254−rowLteAny = unsafeRowSubqueryExpression "<= ANY"
1256−-- | >>> printSQL $ true `gtAll` values_ (true `as` #foo)
1257−-- TRUE > ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1259− :: Expression db from grp params ty -- ^ expression
1260− -> Query db params '[alias ::: ty] -- ^ subquery
1261− -> Expression db from grp params (nullity 'PGbool)
1262−gtAll = unsafeSubqueryExpression "> ALL"
1264−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1265−-- >>> printSQL $ myRow `rowGtAll` values_ myRow
1266−-- ROW(1, FALSE) > ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1269− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1270− -> Query db params row -- ^ subquery
1271− -> Expression db from grp params (nullity 'PGbool)
1272−rowGtAll = unsafeRowSubqueryExpression "> ALL"
1274−-- | >>> printSQL $ true `gtAny` values_ (true `as` #foo)
1275−-- TRUE > ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1277− :: Expression db from grp params ty -- ^ expression
1278− -> Query db params '[alias ::: ty] -- ^ subquery
1279− -> Expression db from grp params (nullity 'PGbool)
1280−gtAny = unsafeSubqueryExpression "> ANY"
1282−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1283−-- >>> printSQL $ myRow `rowGtAny` values_ myRow
1284−-- ROW(1, FALSE) > ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1287− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1288− -> Query db params row -- ^ subquery
1289− -> Expression db from grp params (nullity 'PGbool)
1290−rowGtAny = unsafeRowSubqueryExpression "> ANY"
1292−-- | >>> printSQL $ true `gteAll` values_ (true `as` #foo)
1293−-- TRUE >= ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1295− :: Expression db from grp params ty -- ^ expression
1296− -> Query db params '[alias ::: ty] -- ^ subquery
1297− -> Expression db from grp params (nullity 'PGbool)
1298−gteAll = unsafeSubqueryExpression ">= ALL"
1300−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1301−-- >>> printSQL $ myRow `rowGteAll` values_ myRow
1302−-- ROW(1, FALSE) >= ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1305− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1306− -> Query db params row -- ^ subquery
1307− -> Expression db from grp params (nullity 'PGbool)
1308−rowGteAll = unsafeRowSubqueryExpression ">= ALL"
1310−-- | >>> printSQL $ true `gteAny` values_ (true `as` #foo)
1311−-- TRUE >= ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1313− :: Expression db from grp params ty -- ^ expression
1314− -> Query db params '[alias ::: ty] -- ^ subquery
1315− -> Expression db from grp params (nullity 'PGbool)
1316−gteAny = unsafeSubqueryExpression ">= ANY"
1318−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db from grp params)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1319−-- >>> printSQL $ myRow `rowGteAny` values_ myRow
1320−-- ROW(1, FALSE) >= ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1323− => NP (Aliased (Expression db from grp params)) row -- ^ row constructor
1324− -> Query db params row -- ^ subquery
1325− -> Expression db from grp params (nullity 'PGbool)
1326−rowGteAny = unsafeRowSubqueryExpression ">= ANY"
1328-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1031-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1329data CommonTableExpression statement
1032data CommonTableExpression statement
1033+ (schemas :: SchemasType)
1330 (params :: [NullityType])
1034 (params :: [NullityType])
1331− (db0 :: DBType)
1035+ (commons0 :: FromType)
1332− (db1 :: DBType) where
1036+ (commons1 :: FromType) where
1333 CommonTableExpression
1037 CommonTableExpression
1334− :: Aliased (statement (commons :=> schemas) params) (cte ::: common)
1038+ :: Aliased (statement commons schemas params) (cte ::: common)
1335− -> CommonTableExpression statement params
1039+ -> CommonTableExpression statement schemas params commons (cte ::: common ': commons)
1336− (commons :=> schemas) ((cte ::: common ': commons) :=> schemas)
1338 ( KnownSymbol cte
1041 ( KnownSymbol cte
1339− , db0 ~ (commons :=> schemas)
1042+ , commons1 ~ (cte ::: common ': commons)
1340− , db1 ~ ((cte ::: common ': commons) :=> schemas)
1341 ) => Aliasable cte
1043 ) => Aliasable cte
1342− (statement db0 params common)
1044+ (statement commons schemas params common)
1343− (CommonTableExpression statement params db0 db1) where
1045+ (CommonTableExpression statement schemas params commons commons1) where
1344 statement `as` cte = CommonTableExpression (statement `as` cte)
1046 statement `as` cte = CommonTableExpression (statement `as` cte)
1346 ( KnownSymbol cte
1048 ( KnownSymbol cte
1347− , db0 ~ (commons :=> schemas)
1049+ , commons1 ~ (cte ::: common ': commons)
1348− , db1 ~ ((cte ::: common ': commons) :=> schemas)
1349 ) => Aliasable cte
1050 ) => Aliasable cte
1350− (statement db0 params common)
1051+ (statement commons schemas params common)
1351− (AlignedList (CommonTableExpression statement params) db0 db1) where
1052+ (Path (CommonTableExpression statement schemas params) commons commons1) where
1352− statement `as` cte = single (statement `as` cte)
1053+ statement `as` cte = csingleton (statement `as` cte)
1354−-- ( KnownSymbol vw
1055+instance (forall c s p r. RenderSQL (statement c s p r)) => RenderSQL
1355−-- , Has "public" db schema
1056+ (CommonTableExpression statement schemas params commons0 commons1) where
1356−-- , Alter "public" (vw ::: 'View cte ': schema) db ~ db1
1057+ renderSQL (CommonTableExpression (statement `As` cte)) =
1357−-- ) => Aliasable vw (statement db params cte)
1058+ renderSQL cte <+> "AS" <+> parenthesized (renderSQL statement)
1358−-- (AlignedList (CommonTableExpression statement params) db db1) where
1359−-- statement `as` vw = single (statement `as` vw)
1361−-- | render a `CommonTableExpression`.
1362−renderCommonTableExpression
1363− :: (forall db ps row. statement db ps row -> ByteString) -- ^ render statement
1364− -> CommonTableExpression statement params db0 db1 -> ByteString
1365−renderCommonTableExpression renderStatement
1366− (CommonTableExpression (statement `As` alias)) =
1367− renderAlias alias <+> "AS" <+> parenthesized (renderStatement statement)
1369−-- | render a non-empty `AlignedList` of `CommonTableExpression`s.
1370−renderCommonTableExpressions
1371− :: (forall db ps row. statement db ps row -> ByteString) -- ^ render statement
1372− -> CommonTableExpression statement params db0 db1
1373− -> AlignedList (CommonTableExpression statement params) db1 db2
1375−renderCommonTableExpressions renderStatement cte ctes =
1376− renderCommonTableExpression renderStatement cte <> case ctes of
1378− cte' :>> ctes' -> "," <+>
1379− renderCommonTableExpressions renderStatement cte' ctes'
1381-- | `with` provides a way to write auxiliary statements for use in a larger query.
1060-- | `with` provides a way to write auxiliary statements for use in a larger query.
1382-- These statements, referred to as `CommonTableExpression`s, can be thought of as
1061-- These statements, referred to as `CommonTableExpression`s, can be thought of as
1383-- defining temporary tables that exist just for one query.
1062-- defining temporary tables that exist just for one query.
1384class With statement where
1063class With statement where
1386− :: AlignedList (CommonTableExpression statement params) db0 db1
1065+ :: Path (CommonTableExpression statement schemas params) commons0 commons1
1387 -- ^ common table expressions
1066 -- ^ common table expressions
1388− -> statement db1 params row
1067+ -> statement commons1 schemas params row
1389 -- ^ larger query
1068 -- ^ larger query
1390− -> statement db0 params row
1069+ -> statement commons0 schemas params row
1391−instance With Query where
1070+instance With (Query outer) where
1392− with Done query = UnsafeQuery $ renderQuery query
1071+ with Done query = query
1393− with (cte :>> ctes) query = UnsafeQuery $
1072+ with ctes query = UnsafeQuery $
1394− "WITH" <+> renderCommonTableExpressions renderQuery cte ctes
1073+ "WITH" <+> commaSeparated (ctoList renderSQL ctes) <+> renderSQL query
1395− <+> renderQuery query
1074+
1076+>>> import Data.Monoid (Sum (..))
1077+>>> import Data.Int (Int64)
1080+ query :: Query_ schema () (Sum Int64)
1081+ query = withRecursive
1082+ ( values_ ((1 & astype int) `as` #n)
1084+ select_ ((#n + 1) `as` #n)
1085+ (from (common #t) & where_ (#n .< 100)) `as` #t )
1086+ ( select_ (fromNull 0 (sum_ (All #n)) `as` #getSum) (from (common #t) & groupBy Nil))
1089+WITH RECURSIVE "t" AS ((SELECT * FROM (VALUES ((1 :: int))) AS t ("n")) UNION ALL (SELECT ("n" + 1) AS "n" FROM "t" AS "t" WHERE ("n" < 100))) SELECT COALESCE(sum(ALL "n"), 0) AS "getSum" FROM "t" AS "t"
1092+ :: Aliased (Query outer (recursive ': commons) schemas params) recursive
1093+ -> Query outer (recursive ': commons) schemas params row
1094+ -> Query outer commons schemas params row
1095+withRecursive (recursive `As` cte) query = UnsafeQuery $
1096+ "WITH RECURSIVE" <+> renderSQL cte
1097+ <+> "AS" <+> parenthesized (renderSQL recursive)
1098+ <+> renderSQL query