@@ -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,7 +17,9 @@ Squeal queries.
17 , GeneralizedNewtypeDeriving
17 , GeneralizedNewtypeDeriving
18 , LambdaCase
18 , LambdaCase
19 , MultiParamTypeClasses
19 , MultiParamTypeClasses
20 , OverloadedStrings
21 , OverloadedStrings
22+ , QuantifiedConstraints
21 , ScopedTypeVariables
23 , ScopedTypeVariables
22 , StandaloneDeriving
24 , StandaloneDeriving
23 , TypeApplications
25 , TypeApplications
@@ -30,12 +32,15 @@ Squeal queries.
31module Squeal.PostgreSQL.Query
33module Squeal.PostgreSQL.Query
32 ( -- * Queries
34 ( -- * Queries
33− Query (UnsafeQuery, renderQuery)
35+ Query_
34 -- ** Select
37 -- ** Select
37 , selectDistinct
40 , selectDistinct
38 , selectDistinct_
41 , selectDistinct_
39 , Selection (..)
44 , Selection (..)
40 -- ** Values
45 -- ** Values
@@ -48,33 +53,15 @@ module Squeal.PostgreSQL.Query
49 , exceptAll
54 , exceptAll
50 -- ** With
55 -- ** With
51− , With (with)
56+ , With (..)
52 , CommonTableExpression (..)
57 , CommonTableExpression (..)
53− , renderCommonTableExpression
58+ , withRecursive
54− , renderCommonTableExpressions
63− , jsonbPopulateRecord
64− , jsonPopulateRecordSet
65− , jsonbPopulateRecordSet
70 -- * Table Expressions
59 -- * Table Expressions
71 , TableExpression (..)
60 , TableExpression (..)
72− , renderTableExpression
80 -- * From Clauses
67 -- * From Clauses
@@ -89,45 +76,14 @@ module Squeal.PostgreSQL.Query
89 , rightOuterJoin
76 , rightOuterJoin
90 , fullOuterJoin
77 , fullOuterJoin
91 -- * Grouping
78 -- * Grouping
92− , By (By1, By2)
79+ , By (..)
94− , GroupByClause (NoGroups, Group)
80+ , GroupByClause (..)
95− , renderGroupByClause
96− , HavingClause (NoHaving, Having)
81+ , HavingClause (..)
99− , SortExpression (..)
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,7 +159,7 @@ 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 = select Star (from (table #tab))
163 query = select Star (from (table #tab))
154in printSQL query
164in printSQL query
@@ -159,21 +169,21 @@ 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 = select Star (from (subquery (select Star (from (table #tab)) `as` #sub)))
187 query = select Star (from (subquery (select Star (from (table #tab)) `as` #sub)))
178in printSQL query
188in printSQL query
@@ -183,7 +193,7 @@ 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 = select Star (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
@@ -193,7 +203,7 @@ 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 = select Star (from (table #tab) & where_ (#col1 .> param @1))
207 query = select Star (from (table #tab) & where_ (#col1 .> param @1))
198in printSQL query
208in printSQL query
@@ -203,21 +213,21 @@ 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 = select Star (from (table #tab) & orderBy [#col1 & Asc])
231 query = select Star (from (table #tab) & orderBy [#col1 & Asc])
222in printSQL query
232in printSQL query
@@ -225,14 +235,12 @@ SELECT * 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 ]
@@ -248,22 +256,27 @@ type OrdersConstraints =
249type OrdersSchema =
257type OrdersSchema =
250 '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
258 '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
251− , "customers" ::: 'Table (CustomersConstraints :=> NamesColumns)
259+ , "customers" ::: 'Table (CustomersConstraints :=> NamesColumns)
252− , "shippers" ::: 'Table (ShippersConstraints :=> 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
257− query :: Query (DBof (Public OrdersSchema))
275+ query :: Query_ (Public OrdersSchema) () Order
259− '[ "order_price" ::: 'NotNull 'PGfloat4
260− , "customer_name" ::: 'NotNull 'PGtext
261− , "shipper_name" ::: 'NotNull 'PGtext
263 query = select_
276 query = select_
264− ( #o ! #price `as` #order_price :*
277+ ( #o ! #price `as` #price :*
265− #c ! #name `as` #customer_name :*
278+ #c ! #name `as` #customerName :*
266− #s ! #name `as` #shipper_name )
279+ #s ! #name `as` #shipperName )
267 ( from (table (#orders `as` #o)
280 ( from (table (#orders `as` #o)
268 & innerJoin (table (#customers `as` #c))
281 & innerJoin (table (#customers `as` #c))
269 (#o ! #customer_id .== #c ! #id)
282 (#o ! #customer_id .== #c ! #id)
@@ -271,14 +284,16 @@ let
271 (#o ! #shipper_id .== #s ! #id)) )
284 (#o ! #shipper_id .== #s ! #id)) )
272in printSQL query
285in printSQL query
274−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")
276self-join:
289self-join:
280− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
293+ query :: Query_ (Public Schema) () (Row Int32 Int32)
281− query = select (#t1 & DotStar) (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
296+ (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
282in printSQL query
297in printSQL query
284SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
299SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
@@ -287,17 +302,19 @@ value queries:
290− query :: Query db '[] '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
305+ query :: Query_ schemas () (Row String Bool)
291− 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]
292in printSQL query
309in printSQL query
294−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")
296set operations:
313set operations:
300− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
317+ query :: Query_ (Public Schema) () (Row Int32 Int32)
301 query = select Star (from (table #tab)) `unionAll` select Star (from (table #tab))
318 query = select Star (from (table #tab)) `unionAll` select Star (from (table #tab))
302in printSQL query
319in printSQL query
@@ -307,7 +324,7 @@ with queries:
310− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
327+ query :: Query_ (Public Schema) () (Row Int32 Int32)
311 query = with (
328 query = with (
312 select Star (from (table #tab)) `as` #cte1 :>>
329 select Star (from (table #tab)) `as` #cte1 :>>
313 select Star (from (common #cte1)) `as` #cte2
330 select Star (from (common #cte1)) `as` #cte2
@@ -315,133 +332,195 @@ let
315in printSQL query
332in printSQL query
317WITH "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"))
319−newtype Query
363+type family Query_
320− (db :: DBType)
364+ (schemas :: SchemasType)
321− (params :: [NullityType])
365+ (parameters :: Type)
322− (columns :: RowType)
366+ (row :: Type) where
323− = UnsafeQuery { renderQuery :: ByteString }
367+ Query_ schemas params row =
324− deriving (GHC.Generic,Show,Eq,Ord,NFData)
368+ Query '[] '[] schemas (TuplePG params) (RowPG row)
325−instance RenderSQL (Query db params columns) where renderSQL = renderQuery
327-- | 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
328-- `union`. Duplicate rows are eliminated.
371-- `union`. Duplicate rows are eliminated.
330− :: Query db params columns
373+ :: Query outer commons schemas params columns
331− -> Query db params columns
374+ -> Query outer commons schemas params columns
332− -> Query db params columns
375+ -> Query outer commons schemas params columns
333q1 `union` q2 = UnsafeQuery $
376q1 `union` q2 = UnsafeQuery $
334− parenthesized (renderQuery q1)
377+ parenthesized (renderSQL q1)
335 <+> "UNION"
378 <+> "UNION"
336− <+> parenthesized (renderQuery q2)
379+ <+> parenthesized (renderSQL q2)
338-- | 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
339-- `unionAll`, the disjoint union. Duplicate rows are retained.
382-- `unionAll`, the disjoint union. Duplicate rows are retained.
341− :: Query db params columns
384+ :: Query outer commons schemas params columns
342− -> Query db params columns
385+ -> Query outer commons schemas params columns
343− -> Query db params columns
386+ -> Query outer commons schemas params columns
344q1 `unionAll` q2 = UnsafeQuery $
387q1 `unionAll` q2 = UnsafeQuery $
345− parenthesized (renderQuery q1)
388+ parenthesized (renderSQL q1)
346 <+> "UNION" <+> "ALL"
389 <+> "UNION" <+> "ALL"
347− <+> parenthesized (renderQuery q2)
390+ <+> parenthesized (renderSQL q2)
349-- | 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
350-- `intersect`, the intersection. Duplicate rows are eliminated.
393-- `intersect`, the intersection. Duplicate rows are eliminated.
352− :: Query db params columns
395+ :: Query outer commons schemas params columns
353− -> Query db params columns
396+ -> Query outer commons schemas params columns
354− -> Query db params columns
397+ -> Query outer commons schemas params columns
355q1 `intersect` q2 = UnsafeQuery $
398q1 `intersect` q2 = UnsafeQuery $
356− parenthesized (renderQuery q1)
399+ parenthesized (renderSQL q1)
357 <+> "INTERSECT"
400 <+> "INTERSECT"
358− <+> parenthesized (renderQuery q2)
401+ <+> parenthesized (renderSQL q2)
360-- | 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
361-- `intersectAll`, the intersection. Duplicate rows are retained.
404-- `intersectAll`, the intersection. Duplicate rows are retained.
362intersectAll
405intersectAll
363− :: Query db params columns
406+ :: Query outer commons schemas params columns
364− -> Query db params columns
407+ -> Query outer commons schemas params columns
365− -> Query db params columns
408+ -> Query outer commons schemas params columns
366q1 `intersectAll` q2 = UnsafeQuery $
409q1 `intersectAll` q2 = UnsafeQuery $
367− parenthesized (renderQuery q1)
410+ parenthesized (renderSQL q1)
368 <+> "INTERSECT" <+> "ALL"
411 <+> "INTERSECT" <+> "ALL"
369− <+> parenthesized (renderQuery q2)
412+ <+> parenthesized (renderSQL q2)
371-- | 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
372-- `except`, the set difference. Duplicate rows are eliminated.
415-- `except`, the set difference. Duplicate rows are eliminated.
374− :: Query db params columns
417+ :: Query outer commons schemas params columns
375− -> Query db params columns
418+ -> Query outer commons schemas params columns
376− -> Query db params columns
419+ -> Query outer commons schemas params columns
377q1 `except` q2 = UnsafeQuery $
420q1 `except` q2 = UnsafeQuery $
378− parenthesized (renderQuery q1)
421+ parenthesized (renderSQL q1)
379 <+> "EXCEPT"
422 <+> "EXCEPT"
380− <+> parenthesized (renderQuery q2)
423+ <+> parenthesized (renderSQL q2)
382-- | 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
383-- `exceptAll`, the set difference. Duplicate rows are retained.
426-- `exceptAll`, the set difference. Duplicate rows are retained.
385− :: Query db params columns
428+ :: Query outer commons schemas params columns
386− -> Query db params columns
429+ -> Query outer commons schemas params columns
387− -> Query db params columns
430+ -> Query outer commons schemas params columns
388q1 `exceptAll` q2 = UnsafeQuery $
431q1 `exceptAll` q2 = UnsafeQuery $
389− parenthesized (renderQuery q1)
432+ parenthesized (renderSQL q1)
390 <+> "EXCEPT" <+> "ALL"
433 <+> "EXCEPT" <+> "ALL"
391− <+> parenthesized (renderQuery q2)
434+ <+> parenthesized (renderSQL q2)
393{-----------------------------------------
436{-----------------------------------------
394SELECT queries
437SELECT queries
395-----------------------------------------}
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`.
397−data Selection db params grp from row where
446+data Selection outer commons grp schemas params from row where
400− => NP (Aliased (Expression db params grp from)) row
401− -> Selection db params grp from row
403 :: HasUnique tab from row
448 :: HasUnique tab from row
404− => Selection db params 'Ungrouped from row
449+ => Selection outer commons 'Ungrouped schemas params from row
450+ -- ^ `HasUnique` table in the `FromClause`
406 :: Has tab from row
452 :: Has tab from row
407 => Alias tab
453 => Alias tab
454+ -- ^ `Has` table with `Alias`
408− -> Selection db params 'Ungrouped from row
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
410− :: Selection db params grp from right
468+ :: Selection outer commons grp schemas params from right
469+ -- ^ `Additional` `Selection`
411− -> Selection db params grp from left
470+ -> Selection outer commons grp schemas params from left
412− -> Selection db params grp from (Join left right)
471+ -> Selection outer commons grp schemas params from (Join left right)
472+instance Additional (Selection outer commons grp schemas params from) where
413instance (KnownSymbol col, row ~ '[col ::: ty])
474instance (KnownSymbol col, row ~ '[col ::: ty])
414 => Aliasable col
475 => Aliasable col
415− (Expression db params grp from ty)
476+ (Expression outer commons grp schemas params from ty)
416− (Selection db params grp from row) where
477+ (Selection outer commons grp schemas params from row) where
417 expr `as` col = List (expr `as` col)
478 expr `as` col = List (expr `as` col)
418−instance (Has tab from row0, Has col row0 ty, row1 ~ '[col ::: ty])
479+instance (Has tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])
480+ => IsQualified tab col
419− => IsQualified tab col (Selection db params 'Ungrouped from row1) where
481+ (Selection outer commons 'Ungrouped schemas params from row1) where
420− tab ! col = tab ! col `as` col
482+ tab ! col = tab ! col `as` col
422− ( Has tab from row0
484+ ( Has tab (Join outer from) row0
423 , Has col row0 ty
485 , Has col row0 ty
424 , row1 ~ '[col ::: ty]
486 , row1 ~ '[col ::: ty]
425 , GroupedBy tab col bys )
487 , GroupedBy tab col bys )
488+ => IsQualified tab col
426− => IsQualified tab col (Selection db params ('Grouped bys) from row1) where
489+ (Selection outer commons ('Grouped bys) schemas params from row1) where
427− tab ! col = tab ! col `as` col
490+ tab ! col = tab ! col `as` col
428−instance (HasUnique tab from row0, Has col row0 ty, row1 ~ '[col ::: ty])
491+instance (HasUnique tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])
429− => IsLabel col (Selection db params 'Ungrouped from row1) where
493+ (Selection outer commons 'Ungrouped schemas params from row1) where
430− fromLabel = fromLabel @col `as` Alias
494+ fromLabel = fromLabel @col `as` Alias
432− ( HasUnique tab from row0
496+ ( HasUnique tab (Join outer from) row0
433 , Has col row0 ty
497 , Has col row0 ty
434 , row1 ~ '[col ::: ty]
498 , row1 ~ '[col ::: ty]
435 , GroupedBy tab col bys )
499 , GroupedBy tab col bys )
436− => IsLabel col (Selection db params ('Grouped bys) from row1) where
501+ (Selection outer commons ('Grouped bys) schemas params from row1) where
437− fromLabel = fromLabel @col `as` Alias
502+ fromLabel = fromLabel @col `as` Alias
439−instance RenderSQL (Selection db params grp from row) where
504+instance RenderSQL (Selection outer commons grp schemas params from row) where
440 renderSQL = \case
505 renderSQL = \case
441 List list -> renderCommaSeparated (renderAliased renderSQL) list
506 List list -> renderCommaSeparated (renderAliased renderSQL) list
442 Star -> "*"
507 Star -> "*"
443 DotStar tab -> renderSQL tab <> ".*"
508 DotStar tab -> renderSQL tab <> ".*"
444 Also right left -> renderSQL left <> ", " <> renderSQL right
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
446-- | the `TableExpression` in the `select` command constructs an intermediate
525-- | the `TableExpression` in the `select` command constructs an intermediate
447-- virtual table by possibly combining tables, views, eliminating rows,
526-- virtual table by possibly combining tables, views, eliminating rows,
@@ -450,45 +529,100 @@ instance RenderSQL (Selection db params grp from row) where
450-- the intermediate table are actually output.
529-- the intermediate table are actually output.
452 :: (SListI row, row ~ (x ': xs))
531 :: (SListI row, row ~ (x ': xs))
453− => Selection db params grp from row
532+ => Selection outer commons grp schemas params from row
454− -- ^ select list
533+ -- ^ selection
455− -> TableExpression db params grp from
534+ -> TableExpression outer commons grp schemas params from
456 -- ^ intermediate virtual table
535 -- ^ intermediate virtual table
457− -> Query db params row
536+ -> Query outer commons schemas params row
458select selection tabexpr = UnsafeQuery $
537select selection tabexpr = UnsafeQuery $
460 <+> renderSQL selection
539 <+> renderSQL selection
461− <+> renderTableExpression tabexpr
540+ <+> renderSQL tabexpr
542+-- | Like `select` but takes an `NP` list of `Expression`s instead
543+-- of a general `Selection`.
464 :: (SListI row, row ~ (x ': xs))
545 :: (SListI row, row ~ (x ': xs))
465− => NP (Aliased (Expression db params grp from)) row
546+ => NP (Aliased (Expression outer commons grp schemas params from)) row
466− -> TableExpression db params grp from
548+ -> TableExpression outer commons grp schemas params from
549+ -- ^ intermediate virtual table
467− -> Query db params row
550+ -> Query outer commons schemas params row
468−select_ list = select (List list)
551+select_ = select . List
470-- | After the select list has been processed, the result table can
553-- | After the select list has been processed, the result table can
471-- be subject to the elimination of duplicate rows using `selectDistinct`.
554-- be subject to the elimination of duplicate rows using `selectDistinct`.
472selectDistinct
555selectDistinct
473 :: (SListI columns, columns ~ (col ': cols))
556 :: (SListI columns, columns ~ (col ': cols))
474− => Selection db params 'Ungrouped from columns
557+ => Selection outer commons grp schemas params from columns
475− -- ^ select list
558+ -- ^ selection
476− -> TableExpression db params 'Ungrouped from
559+ -> TableExpression outer commons grp schemas params from
477 -- ^ intermediate virtual table
560 -- ^ intermediate virtual table
478− -> Query db params columns
561+ -> Query outer commons schemas params columns
479selectDistinct selection tabexpr = UnsafeQuery $
562selectDistinct selection tabexpr = UnsafeQuery $
480 "SELECT DISTINCT"
563 "SELECT DISTINCT"
481 <+> renderSQL selection
564 <+> renderSQL selection
482− <+> renderTableExpression tabexpr
565+ <+> renderSQL tabexpr
567+-- | Like `selectDistinct` but takes an `NP` list of `Expression`s instead
568+-- of a general `Selection`.
484selectDistinct_
569selectDistinct_
485 :: (SListI columns, columns ~ (col ': cols))
570 :: (SListI columns, columns ~ (col ': cols))
486− => NP (Aliased (Expression db params 'Ungrouped from)) columns
571+ => NP (Aliased (Expression outer commons grp schemas params from)) columns
487 -- ^ select list
572 -- ^ select list
488− -> TableExpression db params 'Ungrouped from
573+ -> TableExpression outer commons grp schemas params from
489 -- ^ intermediate virtual table
574 -- ^ intermediate virtual table
490− -> Query db params columns
575+ -> Query outer commons schemas params columns
491−selectDistinct_ list = select (List list)
576+selectDistinct_ = selectDistinct . List
579+`selectDistinctOn` keeps only the first row of each set of rows where
580+the given expressions evaluate to equal. The DISTINCT ON expressions are
581+interpreted using the same rules as for ORDER BY. ORDER BY is used to
582+ensure that the desired row appears first.
584+The DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s).
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
598+ -- ^ intermediate virtual table
599+ -> Query outer commons schemas params columns
600+selectDistinctOn distincts selection tab = UnsafeQuery $
601+ "SELECT DISTINCT ON"
602+ <+> parenthesized (commaSeparated (renderDistinctOn <$> distincts))
603+ <+> renderSQL selection
604+ <+> renderSQL (tab {orderByClause = distincts <> orderByClause tab})
606+ renderDistinctOn = \case
607+ Asc expression -> renderSQL expression
608+ Desc expression -> renderSQL expression
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
623+ -- ^ intermediate virtual table
624+ -> Query outer commons schemas params columns
625+selectDistinctOn_ distincts = selectDistinctOn distincts . List
493-- | `values` computes a row value or set of row values
627-- | `values` computes a row value or set of row values
494-- specified by value expressions. It is most commonly used
628-- specified by value expressions. It is most commonly used
@@ -496,16 +630,16 @@ selectDistinct_ list = select (List list)
496-- but it can be used on its own.
630-- but it can be used on its own.
498-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
632-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
499−-- >>> 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
500-- >>> printSQL query
634-- >>> printSQL query
501-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
635-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
503 :: SListI cols
637 :: SListI cols
504− => NP (Aliased (Expression db params 'Ungrouped '[] )) cols
638+ => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
505− -> [NP (Aliased (Expression db params 'Ungrouped '[] )) cols]
639+ -> [NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols]
506 -- ^ When more than one row is specified, all the rows must
640 -- ^ When more than one row is specified, all the rows must
507 -- must have the same number of elements
641 -- must have the same number of elements
508− -> Query db params cols
642+ -> Query outer commons schemas params cols
509values rw rws = UnsafeQuery $ "SELECT * FROM"
643values rw rws = UnsafeQuery $ "SELECT * FROM"
510 <+> parenthesized (
644 <+> parenthesized (
@@ -513,20 +647,20 @@ values rw rws = UnsafeQuery $ "SELECT * FROM"
513 ( parenthesized
647 ( parenthesized
514 . renderCommaSeparated renderValuePart <$> rw:rws )
648 . renderCommaSeparated renderValuePart <$> rw:rws )
515 ) <+> "AS t"
649 ) <+> "AS t"
516− <+> parenthesized (renderCommaSeparated renderSQLPart rw)
650+ <+> parenthesized (renderCommaSeparated renderAliasPart rw)
518− renderSQLPart, renderValuePart
652+ renderAliasPart, renderValuePart
519− :: Aliased (Expression db params 'Ungrouped '[] ) ty -> ByteString
653+ :: Aliased (Expression outer commons 'Ungrouped schemas params '[] ) ty -> ByteString
520− renderSQLPart (_ `As` name) = renderSQL name
654+ renderAliasPart (_ `As` name) = renderSQL name
521 renderValuePart (value `As` _) = renderSQL value
655 renderValuePart (value `As` _) = renderSQL value
523-- | `values_` computes a row value or set of row values
657-- | `values_` computes a row value or set of row values
524-- specified by value expressions.
658-- specified by value expressions.
526 :: SListI cols
660 :: SListI cols
527− => NP (Aliased (Expression db params 'Ungrouped '[] )) cols
661+ => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
528 -- ^ one row of values
662 -- ^ one row of values
529− -> Query db params cols
663+ -> Query outer commons schemas params cols
530values_ rw = values rw []
664values_ rw = values rw []
532{-----------------------------------------
666{-----------------------------------------
@@ -540,15 +674,17 @@ Table Expressions
540-- 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
541-- 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.
542data TableExpression
676data TableExpression
543− (db :: DBType)
677+ (outer :: FromType)
544− (params :: [NullityType])
678+ (commons :: FromType)
545 (grp :: Grouping)
679 (grp :: Grouping)
680+ (schemas :: SchemasType)
681+ (params :: [NullityType])
546 (from :: FromType)
682 (from :: FromType)
547 = TableExpression
683 = TableExpression
548− { fromClause :: FromClause db params from
684+ { fromClause :: FromClause outer commons schemas params from
549 -- ^ 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
550 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
686 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
551− , whereClause :: [Condition db params 'Ungrouped from]
687+ , whereClause :: [Condition outer commons 'Ungrouped schemas params from]
552 -- ^ optional search coditions, combined with `.&&`. After the processing
688 -- ^ optional search coditions, combined with `.&&`. After the processing
553 -- 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
554 -- is checked against the search condition. If the result of the
690 -- is checked against the search condition. If the result of the
@@ -564,13 +700,13 @@ data TableExpression
564 -- 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
565 -- 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
566 -- and/or compute aggregates that apply to these groups.
702 -- and/or compute aggregates that apply to these groups.
567− , havingClause :: HavingClause db params grp from
703+ , havingClause :: HavingClause outer commons grp schemas params from
568 -- ^ 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
569 -- are of interest, the `havingClause` can be used, much like a
705 -- are of interest, the `havingClause` can be used, much like a
570 -- `whereClause`, to eliminate groups from the result. Expressions in the
706 -- `whereClause`, to eliminate groups from the result. Expressions in the
571 -- `havingClause` can refer both to grouped expressions and to ungrouped
707 -- `havingClause` can refer both to grouped expressions and to ungrouped
572 -- expressions (which necessarily involve an aggregate function).
708 -- expressions (which necessarily involve an aggregate function).
573− , orderByClause :: [SortExpression db params grp from]
709+ , orderByClause :: [SortExpression outer commons grp schemas params from]
574 -- ^ The `orderByClause` is for optional sorting. When more than one
710 -- ^ The `orderByClause` is for optional sorting. When more than one
575 -- `SortExpression` is specified, the later (right) values are used to sort
711 -- `SortExpression` is specified, the later (right) values are used to sort
576 -- rows that are equal according to the earlier (left) values.
712 -- rows that are equal according to the earlier (left) values.
@@ -580,72 +716,69 @@ data TableExpression
580 -- will be returned (but possibly fewer, if the query itself yields
716 -- will be returned (but possibly fewer, if the query itself yields
581 -- fewer rows).
717 -- fewer rows).
582 , offsetClause :: [Word64]
718 , offsetClause :: [Word64]
583− -- ^ The `offsetClause` is combined with `+` to give an offset count
719+ -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count
584 -- 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
585 -- 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
586 -- is applied.
722 -- is applied.
587− }
723+ } deriving (GHC.Generic)
589-- | Render a `TableExpression`
725-- | Render a `TableExpression`
590−renderTableExpression
591− :: TableExpression db params grp from
726+instance RenderSQL (TableExpression outer commons grp schemas params from) where
592− -> ByteString
727+ renderSQL
593−renderTableExpression
594− (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
728+ (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
595− [ "FROM ", renderFromClause frm'
729+ [ "FROM ", renderSQL frm'
596− , renderWheres whs'
730+ , renderWheres whs'
597− , renderGroupByClause grps'
731+ , renderSQL grps'
598− , renderHavingClause hvs'
732+ , renderSQL hvs'
599− , renderOrderByClause srts'
733+ , renderOrderByClause srts'
600− , renderLimits lims'
734+ , renderLimits lims'
601− , renderOffsets offs'
735+ , renderOffsets offs' ]
604− renderWheres = \case
737+ renderWheres = \case
605− [] -> ""
738+ [] -> ""
606− wh:[] -> " WHERE" <+> renderSQL wh
739+ wh:[] -> " WHERE" <+> renderSQL wh
607− wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)
740+ wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)
608− renderOrderByClause = \case
741+ renderOrderByClause = \case
609− [] -> ""
742+ [] -> ""
610− srts -> " ORDER BY"
743+ srts -> " ORDER BY"
611− <+> commaSeparated (renderSQL <$> srts)
744+ <+> commaSeparated (renderSQL <$> srts)
612− renderLimits = \case
745+ renderLimits = \case
613− [] -> ""
746+ [] -> ""
614− lims -> " LIMIT" <+> fromString (show (minimum lims))
747+ lims -> " LIMIT" <+> fromString (show (minimum lims))
615− renderOffsets = \case
748+ renderOffsets = \case
616− [] -> ""
749+ [] -> ""
617− offs -> " OFFSET" <+> fromString (show (sum offs))
750+ offs -> " OFFSET" <+> fromString (show (sum offs))
619-- | 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
620-- 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,
621-- 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_`,
622−-- `group`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
755+-- `groupBy`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
623-- 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.
625− :: FromClause db params from -- ^ table reference
758+ :: FromClause outer commons schemas params from -- ^ table reference
626− -> TableExpression db params 'Ungrouped from
759+ -> TableExpression outer commons 'Ungrouped schemas params from
627−from rels = TableExpression rels [] NoGroups NoHaving [] [] []
760+from tab = TableExpression tab [] noGroups NoHaving [] [] []
629-- | A `where_` is an endomorphism of `TableExpression`s which adds a
762-- | A `where_` is an endomorphism of `TableExpression`s which adds a
630-- search condition to the `whereClause`.
763-- search condition to the `whereClause`.
632− :: Condition db params 'Ungrouped from -- ^ filtering condition
765+ :: Condition outer commons 'Ungrouped schemas params from -- ^ filtering condition
633− -> TableExpression db params grp from
766+ -> TableExpression outer commons grp schemas params from
634− -> TableExpression db params grp from
767+ -> TableExpression outer commons grp schemas params from
635where_ wh rels = rels {whereClause = wh : whereClause rels}
768where_ wh rels = rels {whereClause = wh : whereClause rels}
637-- | A `groupBy` is a transformation of `TableExpression`s which switches
770-- | A `groupBy` is a transformation of `TableExpression`s which switches
638−-- its `Grouping` from `Ungrouped` to `Grouped`. Use @group Nil@ to perform
771+-- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform
639-- a "grand total" aggregation query.
772-- a "grand total" aggregation query.
641 :: SListI bys
774 :: SListI bys
642 => NP (By from) bys -- ^ grouped columns
775 => NP (By from) bys -- ^ grouped columns
643− -> TableExpression db params 'Ungrouped from
776+ -> TableExpression outer commons 'Ungrouped schemas params from
644− -> TableExpression db params ('Grouped bys) from
777+ -> TableExpression outer commons ('Grouped bys) schemas params from
645groupBy bys rels = TableExpression
778groupBy bys rels = TableExpression
646 { fromClause = fromClause rels
779 { fromClause = fromClause rels
647 , whereClause = whereClause rels
780 , whereClause = whereClause rels
648− , groupByClause = Group bys
781+ , groupByClause = group bys
649 , havingClause = Having []
782 , havingClause = Having []
650 , orderByClause = []
783 , orderByClause = []
651 , limitClause = limitClause rels
784 , limitClause = limitClause rels
@@ -655,177 +788,31 @@ groupBy bys rels = TableExpression
655-- | A `having` is an endomorphism of `TableExpression`s which adds a
788-- | A `having` is an endomorphism of `TableExpression`s which adds a
656-- search condition to the `havingClause`.
789-- search condition to the `havingClause`.
658− :: Condition db params ('Grouped bys) from -- ^ having condition
791+ :: Condition outer commons ('Grouped bys) schemas params from -- ^ having condition
659− -> TableExpression db params ('Grouped bys) from
792+ -> TableExpression outer commons ('Grouped bys) schemas params from
660− -> TableExpression db params ('Grouped bys) from
793+ -> TableExpression outer commons ('Grouped bys) schemas params from
661having hv rels = rels
794having hv rels = rels
662 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
795 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
664−-- | An `orderBy` is an endomorphism of `TableExpression`s which appends an
797+instance OrderBy TableExpression where
665−-- ordering to the right of the `orderByClause`.
798+ orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
667− :: [SortExpression db params grp from] -- ^ sort expressions
668− -> TableExpression db params grp from
669− -> TableExpression db params grp from
670−orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
672-- | 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
673-- `limitClause`.
801-- `limitClause`.
675 :: Word64 -- ^ limit parameter
803 :: Word64 -- ^ limit parameter
676− -> TableExpression db params grp from
804+ -> TableExpression outer commons grp schemas params from
677− -> TableExpression db params grp from
805+ -> TableExpression outer commons grp schemas params from
678limit lim rels = rels {limitClause = lim : limitClause rels}
806limit lim rels = rels {limitClause = lim : limitClause rels}
680-- | 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
681-- `offsetClause`.
809-- `offsetClause`.
683 :: Word64 -- ^ offset parameter
811 :: Word64 -- ^ offset parameter
684− -> TableExpression db params grp from
812+ -> TableExpression outer commons grp schemas params from
685− -> TableExpression db params grp from
813+ -> TableExpression outer commons grp schemas params from
686offset off rels = rels {offsetClause = off : offsetClause rels}
814offset off rels = rels {offsetClause = off : offsetClause rels}
688−{-----------------------------------------
690−-----------------------------------------}
694− -> Expression db params 'Ungrouped '[] ty
695− -> Query db params row
696−unsafeSetOfFunction fun expr = UnsafeQuery $
697− "SELECT * FROM " <> fun <> "(" <> renderSQL expr <> ")"
699−-- | Expands the outermost JSON object into a set of key/value pairs.
701− :: Expression db params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
703− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
704−jsonEach = unsafeSetOfFunction "json_each"
706−-- | Expands the outermost binary JSON object into a set of key/value pairs.
708− :: Expression db params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
710− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjsonb]
711−jsonbEach = unsafeSetOfFunction "jsonb_each"
713−-- | Expands the outermost JSON object into a set of key/value pairs.
715− :: Expression db params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
717− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
718−jsonEachAsText = unsafeSetOfFunction "json_each_text"
720−-- | Expands the outermost binary JSON object into a set of key/value pairs.
722− :: Expression db params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
724− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
725−jsonbEachAsText = unsafeSetOfFunction "jsonb_each_text"
727−-- | Returns set of keys in the outermost JSON object.
729− :: Expression db params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
730− -> Query db params '["json_object_keys" ::: 'NotNull 'PGtext]
731−jsonObjectKeys = unsafeSetOfFunction "json_object_keys"
733−-- | Returns set of keys in the outermost JSON object.
735− :: Expression db params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
736− -> Query db params '["jsonb_object_keys" ::: 'NotNull 'PGtext]
737−jsonbObjectKeys = unsafeSetOfFunction "jsonb_object_keys"
739−unsafePopulateFunction
741− -> TypeExpression schemas (nullity ('PGcomposite row))
742− -> Expression (commons :=> schemas) params 'Ungrouped '[] ty
743− -> Query (commons :=> schemas) params row
744−unsafePopulateFunction fun ty expr = UnsafeQuery $
745− "SELECT * FROM " <> fun <> "("
746− <> "null::" <> renderSQL ty <> ", "
747− <> renderSQL expr <> ")"
749−-- | Expands the JSON expression to a row whose columns match the record
750−-- type defined by the given table.
752− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
753− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
754− -> Query (commons :=> schemas) params row
755−jsonPopulateRecord = unsafePopulateFunction "json_populate_record"
757−-- | Expands the binary JSON expression to a row whose columns match the record
758−-- type defined by the given table.
760− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
761− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
762− -> Query (commons :=> schemas) params row
763−jsonbPopulateRecord = unsafePopulateFunction "jsonb_populate_record"
765−-- | Expands the outermost array of objects in the given JSON expression to a
766−-- set of rows whose columns match the record type defined by the given table.
767−jsonPopulateRecordSet
768− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
769− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json array
770− -> Query (commons :=> schemas) params row
771−jsonPopulateRecordSet = unsafePopulateFunction "json_populate_record_set"
773−-- | Expands the outermost array of objects in the given binary JSON expression
774−-- to a set of rows whose columns match the record type defined by the given
776−jsonbPopulateRecordSet
777− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
778− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb array
779− -> Query (commons :=> schemas) params row
780−jsonbPopulateRecordSet = unsafePopulateFunction "jsonb_populate_record_set"
783− :: (SListI record, json `In` PGJsonType)
785− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity json)
786− -> NP (Aliased (TypeExpression schemas)) record
787− -> Query (commons :=> schemas) params record
788−unsafeRecordFunction fun expr types = UnsafeQuery $
789− "SELECT * FROM " <> fun <> "("
790− <> renderSQL expr <> ")"
791− <+> "AS" <+> "x" <> parenthesized (renderCommaSeparated renderTy types)
793− renderTy :: Aliased (TypeExpression db) ty -> ByteString
794− renderTy (ty `As` alias) =
795− renderSQL alias <+> renderSQL ty
797−-- | Builds an arbitrary record from a JSON object.
800− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
801− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
802− -> Query (commons :=> schemas) params record
803−jsonToRecord = unsafeRecordFunction "json_to_record"
805−-- | Builds an arbitrary record from a binary JSON object.
808− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
809− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
810− -> Query (commons :=> schemas) params record
811−jsonbToRecord = unsafeRecordFunction "jsonb_to_record"
813−-- | Builds an arbitrary set of records from a JSON array of objects.
816− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json array
817− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
818− -> Query (commons :=> schemas) params record
819−jsonToRecordSet = unsafeRecordFunction "json_to_record_set"
821−-- | Builds an arbitrary set of records from a binary JSON array of objects.
824− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb array
825− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
826− -> Query (commons :=> schemas) params record
827−jsonbToRecordSet = unsafeRecordFunction "jsonb_to_record_set"
829{-----------------------------------------
816{-----------------------------------------
830FROM clauses
817FROM clauses
831-----------------------------------------}
818-----------------------------------------}
@@ -834,67 +821,75 @@ FROM clauses
834A `FromClause` can be a table name, or a derived table such
821A `FromClause` can be a table name, or a derived table such
835as a subquery, a @JOIN@ construct, or complex combinations of these.
822as a subquery, a @JOIN@ construct, or complex combinations of these.
837−newtype FromClause db params from
824+newtype FromClause outer commons schemas params from
838 = UnsafeFromClause { renderFromClause :: ByteString }
825 = UnsafeFromClause { renderFromClause :: ByteString }
839 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
841-- | A real `table` is a table from the database.
830-- | A real `table` is a table from the database.
843 :: (Has sch schemas schema, Has tab schema ('Table table))
832 :: (Has sch schemas schema, Has tab schema ('Table table))
844 => Aliased (QualifiedAlias sch) (alias ::: tab)
833 => Aliased (QualifiedAlias sch) (alias ::: tab)
845− -> FromClause (commons :=> schemas) params '[alias ::: TableToRow table]
834+ -> FromClause outer commons schemas params '[alias ::: TableToRow table]
846table (tab `As` alias) = UnsafeFromClause $
835table (tab `As` alias) = UnsafeFromClause $
847 renderSQL tab <+> "AS" <+> renderSQL alias
836 renderSQL tab <+> "AS" <+> renderSQL alias
849-- | `subquery` derives a table from a `Query`.
838-- | `subquery` derives a table from a `Query`.
851− :: Aliased (Query db params) query
840+ :: Aliased (Query outer commons schemas params) query
852− -> FromClause db params '[query]
841+ -> FromClause outer commons schemas params '[query]
853−subquery = UnsafeFromClause . renderAliased (parenthesized . renderQuery)
842+subquery = UnsafeFromClause . renderAliased (parenthesized . renderSQL)
855-- | `view` derives a table from a `View`.
844-- | `view` derives a table from a `View`.
857 :: (Has sch schemas schema, Has vw schema ('View view))
846 :: (Has sch schemas schema, Has vw schema ('View view))
858 => Aliased (QualifiedAlias sch) (alias ::: vw)
847 => Aliased (QualifiedAlias sch) (alias ::: vw)
859− -> FromClause (commons :=> schemas) params '[alias ::: view]
848+ -> FromClause outer commons schemas params '[alias ::: view]
860view (vw `As` alias) = UnsafeFromClause $
849view (vw `As` alias) = UnsafeFromClause $
861 renderSQL vw <+> "AS" <+> renderSQL alias
850 renderSQL vw <+> "AS" <+> renderSQL alias
852+-- | `common` derives a table from a common table expression.
864 :: Has cte commons common
854 :: Has cte commons common
865 => Aliased Alias (alias ::: cte)
855 => Aliased Alias (alias ::: cte)
866− -> FromClause (commons :=> schemas) params '[alias ::: common]
856+ -> FromClause outer commons schemas params '[alias ::: common]
867common (cte `As` alias) = UnsafeFromClause $
857common (cte `As` alias) = UnsafeFromClause $
868 renderSQL cte <+> "AS" <+> renderSQL alias
858 renderSQL cte <+> "AS" <+> renderSQL alias
870−{- | @left & crossJoin right@. For every possible combination of rows from
860+instance Additional (FromClause outer commons schemas params) where
871− @left@ and @right@ (i.e., a Cartesian product), the joined table will contain
861+ also right left = UnsafeFromClause $
872− a row consisting of all columns in @left@ followed by all columns in @right@.
862+ renderSQL left <> ", " <> renderSQL right
873− If the tables have @n@ and @m@ rows respectively, the joined table will
863+
874− 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
877− :: FromClause db params right
872+ :: FromClause outer commons schemas params right
878 -- ^ right
873 -- ^ right
879− -> FromClause db params left
874+ -> FromClause outer commons schemas params left
880 -- ^ left
875 -- ^ left
881− -> FromClause db params (Join left right)
876+ -> FromClause outer commons schemas params (Join left right)
882crossJoin right left = UnsafeFromClause $
877crossJoin right left = UnsafeFromClause $
883− renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
878+ renderSQL left <+> "CROSS JOIN" <+> renderSQL right
885{- | @left & innerJoin right on@. The joined table is filtered by
880{- | @left & innerJoin right on@. The joined table is filtered by
886the @on@ condition.
881the @on@ condition.
889− :: FromClause db params right
884+ :: FromClause outer commons schemas params right
890 -- ^ right
885 -- ^ right
891− -> Condition db params 'Ungrouped (Join left right)
886+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
892 -- ^ @on@ condition
887 -- ^ @on@ condition
893− -> FromClause db params left
888+ -> FromClause outer commons schemas params left
894 -- ^ left
889 -- ^ left
895− -> FromClause db params (Join left right)
890+ -> FromClause outer commons schemas params (Join left right)
896innerJoin right on left = UnsafeFromClause $
891innerJoin right on left = UnsafeFromClause $
897− renderFromClause left <+> "INNER JOIN" <+> renderFromClause right
892+ renderSQL left <+> "INNER JOIN" <+> renderSQL right
898 <+> "ON" <+> renderSQL on
893 <+> "ON" <+> renderSQL on
900{- | @left & leftOuterJoin right on@. First, an inner join is performed.
895{- | @left & leftOuterJoin right on@. First, an inner join is performed.
@@ -903,15 +898,15 @@ innerJoin right on left = UnsafeFromClause $
903 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@.
905leftOuterJoin
900leftOuterJoin
906− :: FromClause db params right
901+ :: FromClause outer commons schemas params right
907 -- ^ right
902 -- ^ right
908− -> Condition db params 'Ungrouped (Join left right)
903+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
909 -- ^ @on@ condition
904 -- ^ @on@ condition
910− -> FromClause db params left
905+ -> FromClause outer commons schemas params left
911 -- ^ left
906 -- ^ left
912− -> FromClause db params (Join left (NullifyFrom right))
907+ -> FromClause outer commons schemas params (Join left (NullifyFrom right))
913leftOuterJoin right on left = UnsafeFromClause $
908leftOuterJoin right on left = UnsafeFromClause $
914− renderFromClause left <+> "LEFT OUTER JOIN" <+> renderFromClause right
909+ renderSQL left <+> "LEFT OUTER JOIN" <+> renderSQL right
915 <+> "ON" <+> renderSQL on
910 <+> "ON" <+> renderSQL on
917{- | @left & rightOuterJoin right on@. First, an inner join is performed.
912{- | @left & rightOuterJoin right on@. First, an inner join is performed.
@@ -921,15 +916,15 @@ leftOuterJoin right on left = UnsafeFromClause $
921 have a row for each row in @right@.
916 have a row for each row in @right@.
923rightOuterJoin
918rightOuterJoin
924− :: FromClause db params right
919+ :: FromClause outer commons schemas params right
925 -- ^ right
920 -- ^ right
926− -> Condition db params 'Ungrouped (Join left right)
921+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
927 -- ^ @on@ condition
922 -- ^ @on@ condition
928− -> FromClause db params left
923+ -> FromClause outer commons schemas params left
929 -- ^ left
924 -- ^ left
930− -> FromClause db params (Join (NullifyFrom left) right)
925+ -> FromClause outer commons schemas params (Join (NullifyFrom left) right)
931rightOuterJoin right on left = UnsafeFromClause $
926rightOuterJoin right on left = UnsafeFromClause $
932− renderFromClause left <+> "RIGHT OUTER JOIN" <+> renderFromClause right
927+ renderSQL left <+> "RIGHT OUTER JOIN" <+> renderSQL right
933 <+> "ON" <+> renderSQL on
928 <+> "ON" <+> renderSQL on
935{- | @left & fullOuterJoin right on@. First, an inner join is performed.
930{- | @left & fullOuterJoin right on@. First, an inner join is performed.
@@ -940,23 +935,23 @@ rightOuterJoin right on left = UnsafeFromClause $
940 is added.
935 is added.
942fullOuterJoin
937fullOuterJoin
943− :: FromClause db params right
938+ :: FromClause outer commons schemas params right
944 -- ^ right
939 -- ^ right
945− -> Condition db params 'Ungrouped (Join left right)
940+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
946 -- ^ @on@ condition
941 -- ^ @on@ condition
947− -> FromClause db params left
942+ -> FromClause outer commons schemas params left
948 -- ^ left
943 -- ^ left
949− -> FromClause db params
944+ -> FromClause outer commons schemas params
950 (Join (NullifyFrom left) (NullifyFrom right))
945 (Join (NullifyFrom left) (NullifyFrom right))
951fullOuterJoin right on left = UnsafeFromClause $
946fullOuterJoin right on left = UnsafeFromClause $
952− renderFromClause left <+> "FULL OUTER JOIN" <+> renderFromClause right
947+ renderSQL left <+> "FULL OUTER JOIN" <+> renderSQL right
953 <+> "ON" <+> renderSQL on
948 <+> "ON" <+> renderSQL on
955{-----------------------------------------
950{-----------------------------------------
957-----------------------------------------}
952-----------------------------------------}
959−-- | `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
960-- 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
961-- in all the columns listed. @By \#col@ will reference an unambiguous
956-- in all the columns listed. @By \#col@ will reference an unambiguous
962-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
957-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
@@ -976,6 +971,10 @@ data By
976deriving instance Show (By from by)
971deriving instance Show (By from by)
977deriving instance Eq (By from by)
972deriving instance Eq (By from by)
978deriving 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
980instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
979instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
981 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
980 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
@@ -987,424 +986,113 @@ instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])
987 => IsQualified rel col (NP (By rels) bys) where
986 => IsQualified rel col (NP (By rels) bys) where
988 rel ! col = By2 rel col :* Nil
987 rel ! col = By2 rel col :* Nil
991−renderBy :: By from by -> ByteString
993− By1 column -> renderSQL column
994− By2 rel column -> renderSQL rel <> "." <> renderSQL column
996-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
989-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
997-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
990-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
998-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
991-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
999-- done on @NoGroups@ while all output `Expression`s must be aggregated
992-- done on @NoGroups@ while all output `Expression`s must be aggregated
1000-- in @Group Nil@. In general, all output `Expression`s in the
993-- in @Group Nil@. In general, all output `Expression`s in the
1001-- complement of @bys@ must be aggregated in @Group bys@.
994-- complement of @bys@ must be aggregated in @Group bys@.
1002−data GroupByClause grp from where
995+newtype GroupByClause grp from = UnsafeGroupByClause
1003− NoGroups :: GroupByClause 'Ungrouped from
996+ { renderGroupByClause :: ByteString }
1004− Group
997+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1005− :: SListI bys
998+instance RenderSQL (GroupByClause grp from) where
1006− => NP (By from) bys
999+ renderSQL = renderGroupByClause
1007− -> GroupByClause ('Grouped bys) from
1000+noGroups :: GroupByClause 'Ungrouped from
1008−
1001+noGroups = UnsafeGroupByClause ""
1009−-- | Renders a `GroupByClause`.
1002+group
1010−renderGroupByClause :: GroupByClause grp from -> ByteString
1003+ :: SListI bys
1011−renderGroupByClause = \case
1004+ => NP (By from) bys
1012− NoGroups -> ""
1005+ -> GroupByClause ('Grouped bys) from
1013− Group Nil -> ""
1006+group bys = UnsafeGroupByClause $ case bys of
1014− Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
1007+ Nil -> ""
1008+ bys' -> " GROUP BY" <+> renderCommaSeparated renderSQL bys'
1016-- | 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.
1017-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1011-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1018-- `TableExpression` must use `Having` whose conditions are combined with
1012-- `TableExpression` must use `Having` whose conditions are combined with
1019-- `.&&`.
1013-- `.&&`.
1020−data HavingClause db params grp from where
1014+data HavingClause outer commons grp schemas params from where
1021− NoHaving :: HavingClause db params 'Ungrouped from
1015+ NoHaving :: HavingClause outer commons 'Ungrouped schemas params from
1023− :: [Condition db params ('Grouped bys) from]
1017+ :: [Condition outer commons ('Grouped bys) schemas params from]
1024− -> HavingClause db params ('Grouped bys) from
1018+ -> HavingClause outer commons ('Grouped bys) schemas params from
1025−deriving instance Show (HavingClause db params grp from)
1019+deriving instance Show (HavingClause outer commons grp schemas params from)
1026−deriving instance Eq (HavingClause db params grp from)
1020+deriving instance Eq (HavingClause outer commons grp schemas params from)
1027−deriving instance Ord (HavingClause db params grp from)
1021+deriving instance Ord (HavingClause outer commons grp schemas params from)
1029-- | Render a `HavingClause`.
1023-- | Render a `HavingClause`.
1030−renderHavingClause :: HavingClause db params grp from -> ByteString
1024+instance RenderSQL (HavingClause outer commons grp schemas params from) where
1031−renderHavingClause = \case
1034− Having conditions ->
1035− " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1037−{-----------------------------------------
1039−-----------------------------------------}
1041−-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1042−-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1043−-- column to ascending or descending. Ascending order puts smaller values
1044−-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1045−-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1046−-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1047−-- determine whether nulls appear before or after non-null values in the sort
1048−-- ordering of a `Null` result column.
1049−data SortExpression db params grp from where
1051− :: Expression db params grp from ('NotNull ty)
1052− -> SortExpression db params grp from
1054− :: Expression db params grp from ('NotNull ty)
1055− -> SortExpression db params grp from
1057− :: Expression db params grp from ('Null ty)
1058− -> SortExpression db params grp from
1060− :: Expression db params grp from ('Null ty)
1061− -> SortExpression db params grp from
1063− :: Expression db params grp from ('Null ty)
1064− -> SortExpression db params grp from
1066− :: Expression db params grp from ('Null ty)
1067− -> SortExpression db params grp from
1068−deriving instance Show (SortExpression db params grp from)
1070−-- | Render a `SortExpression`.
1071−instance RenderSQL (SortExpression db params grp from) where
1072 renderSQL = \case
1025 renderSQL = \case
1073− Asc expression -> renderSQL expression <+> "ASC"
1026+ NoHaving -> ""
1074− Desc expression -> renderSQL expression <+> "DESC"
1027+ Having [] -> ""
1075− AscNullsFirst expression -> renderSQL expression
1028+ Having conditions ->
1076− <+> "ASC NULLS FIRST"
1029+ " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1077− DescNullsFirst expression -> renderSQL expression
1078− <+> "DESC NULLS FIRST"
1079− AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
1080− DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
1082−unsafeSubqueryExpression
1084− -> Expression db params grp from ty
1085− -> Query db params '[alias ::: ty]
1086− -> Expression db params grp from (nullity 'PGbool)
1087−unsafeSubqueryExpression op x q = UnsafeExpression $
1088− renderSQL x <+> op <+> parenthesized (renderQuery q)
1090−unsafeRowSubqueryExpression
1093− -> NP (Aliased (Expression db params grp from)) row
1094− -> Query db params row
1095− -> Expression db params grp from (nullity 'PGbool)
1096−unsafeRowSubqueryExpression op xs q = UnsafeExpression $
1097− renderSQL (row xs) <+> op <+> parenthesized (renderQuery q)
1099−-- | The right-hand side is a sub`Query`, which must return exactly one column.
1100−-- The left-hand expression is evaluated and compared to each row of the
1101−-- sub`Query` result. The result of `in_` is `true` if any equal subquery row is found.
1102−-- The result is `false` if no equal row is found
1103−-- (including the case where the subquery returns no rows).
1105−-- >>> printSQL $ true `in_` values_ (true `as` #foo)
1106−-- TRUE IN (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1108− :: Expression db params grp from ty -- ^ expression
1109− -> Query db params '[alias ::: ty] -- ^ subquery
1110− -> Expression db params grp from (nullity 'PGbool)
1111−in_ = unsafeSubqueryExpression "IN"
1113−{- | The left-hand side of this form of `rowIn` is a row constructor.
1114−The right-hand side is a sub`Query`,
1115−which must return exactly as many columns as
1116−there are expressions in the left-hand row.
1117−The left-hand expressions are evaluated and compared row-wise to each row
1118−of the subquery result. The result of `rowIn`
1119−is `true` if any equal subquery row is found.
1120−The result is `false` if no equal row is found
1121−(including the case where the subquery returns no rows).
1123−>>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1124−>>> printSQL $ myRow `rowIn` values_ myRow
1125−ROW(1, FALSE) IN (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1129− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1130− -> Query db params row -- ^ subquery
1131− -> Expression db params grp from (nullity 'PGbool)
1132−rowIn = unsafeRowSubqueryExpression "IN"
1134−-- | >>> printSQL $ true `eqAll` values_ (true `as` #foo)
1135−-- TRUE = ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1137− :: Expression db params grp from ty -- ^ expression
1138− -> Query db params '[alias ::: ty] -- ^ subquery
1139− -> Expression db params grp from (nullity 'PGbool)
1140−eqAll = unsafeSubqueryExpression "= ALL"
1142−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1143−-- >>> printSQL $ myRow `rowEqAll` values_ myRow
1144−-- ROW(1, FALSE) = ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1147− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1148− -> Query db params row -- ^ subquery
1149− -> Expression db params grp from (nullity 'PGbool)
1150−rowEqAll = unsafeRowSubqueryExpression "= ALL"
1152−-- | >>> printSQL $ true `eqAny` values_ (true `as` #foo)
1153−-- TRUE = ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1155− :: Expression db params grp from ty -- ^ expression
1156− -> Query db params '[alias ::: ty] -- ^ subquery
1157− -> Expression db params grp from (nullity 'PGbool)
1158−eqAny = unsafeSubqueryExpression "= ANY"
1160−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1161−-- >>> printSQL $ myRow `rowEqAny` values_ myRow
1162−-- ROW(1, FALSE) = ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1165− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1166− -> Query db params row -- ^ subquery
1167− -> Expression db params grp from (nullity 'PGbool)
1168−rowEqAny = unsafeRowSubqueryExpression "= ANY"
1170−-- | >>> printSQL $ true `neqAll` values_ (true `as` #foo)
1171−-- TRUE <> ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1173− :: Expression db params grp from ty -- ^ expression
1174− -> Query db params '[alias ::: ty] -- ^ subquery
1175− -> Expression db params grp from (nullity 'PGbool)
1176−neqAll = unsafeSubqueryExpression "<> ALL"
1178−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1179−-- >>> printSQL $ myRow `rowNeqAll` values_ myRow
1180−-- ROW(1, FALSE) <> ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1183− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1184− -> Query db params row -- ^ subquery
1185− -> Expression db params grp from (nullity 'PGbool)
1186−rowNeqAll = unsafeRowSubqueryExpression "<> ALL"
1188−-- | >>> printSQL $ true `neqAny` values_ (true `as` #foo)
1189−-- TRUE <> ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1191− :: Expression db params grp from ty -- ^ expression
1192− -> Query db params '[alias ::: ty] -- ^ subquery
1193− -> Expression db params grp from (nullity 'PGbool)
1194−neqAny = unsafeSubqueryExpression "<> ANY"
1196−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1197−-- >>> printSQL $ myRow `rowNeqAny` values_ myRow
1198−-- ROW(1, FALSE) <> ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1201− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1202− -> Query db params row -- ^ subquery
1203− -> Expression db params grp from (nullity 'PGbool)
1204−rowNeqAny = unsafeRowSubqueryExpression "<> ANY"
1206−-- | >>> printSQL $ true `allLt` values_ (true `as` #foo)
1207−-- TRUE ALL < (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1209− :: Expression db params grp from ty -- ^ expression
1210− -> Query db params '[alias ::: ty] -- ^ subquery
1211− -> Expression db params grp from (nullity 'PGbool)
1212−allLt = unsafeSubqueryExpression "ALL <"
1214−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1215−-- >>> printSQL $ myRow `rowLtAll` values_ myRow
1216−-- ROW(1, FALSE) ALL < (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1219− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1220− -> Query db params row -- ^ subquery
1221− -> Expression db params grp from (nullity 'PGbool)
1222−rowLtAll = unsafeRowSubqueryExpression "ALL <"
1224−-- | >>> printSQL $ true `ltAny` values_ (true `as` #foo)
1225−-- TRUE ANY < (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1227− :: Expression db params grp from ty -- ^ expression
1228− -> Query db params '[alias ::: ty] -- ^ subquery
1229− -> Expression db params grp from (nullity 'PGbool)
1230−ltAny = unsafeSubqueryExpression "ANY <"
1232−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1233−-- >>> printSQL $ myRow `rowLtAll` values_ myRow
1234−-- ROW(1, FALSE) ALL < (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1237− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1238− -> Query db params row -- ^ subquery
1239− -> Expression db params grp from (nullity 'PGbool)
1240−rowLtAny = unsafeRowSubqueryExpression "ANY <"
1242−-- | >>> printSQL $ true `lteAll` values_ (true `as` #foo)
1243−-- TRUE <= ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1245− :: Expression db params grp from ty -- ^ expression
1246− -> Query db params '[alias ::: ty] -- ^ subquery
1247− -> Expression db params grp from (nullity 'PGbool)
1248−lteAll = unsafeSubqueryExpression "<= ALL"
1250−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1251−-- >>> printSQL $ myRow `rowLteAll` values_ myRow
1252−-- ROW(1, FALSE) <= ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1255− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1256− -> Query db params row -- ^ subquery
1257− -> Expression db params grp from (nullity 'PGbool)
1258−rowLteAll = unsafeRowSubqueryExpression "<= ALL"
1260−-- | >>> printSQL $ true `lteAny` values_ (true `as` #foo)
1261−-- TRUE <= ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1263− :: Expression db params grp from ty -- ^ expression
1264− -> Query db params '[alias ::: ty] -- ^ subquery
1265− -> Expression db params grp from (nullity 'PGbool)
1266−lteAny = unsafeSubqueryExpression "<= ANY"
1268−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1269−-- >>> printSQL $ myRow `rowLteAny` values_ myRow
1270−-- ROW(1, FALSE) <= ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1273− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1274− -> Query db params row -- ^ subquery
1275− -> Expression db params grp from (nullity 'PGbool)
1276−rowLteAny = unsafeRowSubqueryExpression "<= ANY"
1278−-- | >>> printSQL $ true `gtAll` values_ (true `as` #foo)
1279−-- TRUE > ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1281− :: Expression db params grp from ty -- ^ expression
1282− -> Query db params '[alias ::: ty] -- ^ subquery
1283− -> Expression db params grp from (nullity 'PGbool)
1284−gtAll = unsafeSubqueryExpression "> ALL"
1286−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1287−-- >>> printSQL $ myRow `rowGtAll` values_ myRow
1288−-- ROW(1, FALSE) > ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1291− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1292− -> Query db params row -- ^ subquery
1293− -> Expression db params grp from (nullity 'PGbool)
1294−rowGtAll = unsafeRowSubqueryExpression "> ALL"
1296−-- | >>> printSQL $ true `gtAny` values_ (true `as` #foo)
1297−-- TRUE > ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1299− :: Expression db params grp from ty -- ^ expression
1300− -> Query db params '[alias ::: ty] -- ^ subquery
1301− -> Expression db params grp from (nullity 'PGbool)
1302−gtAny = unsafeSubqueryExpression "> ANY"
1304−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1305−-- >>> printSQL $ myRow `rowGtAny` values_ myRow
1306−-- ROW(1, FALSE) > ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1309− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1310− -> Query db params row -- ^ subquery
1311− -> Expression db params grp from (nullity 'PGbool)
1312−rowGtAny = unsafeRowSubqueryExpression "> ANY"
1314−-- | >>> printSQL $ true `gteAll` values_ (true `as` #foo)
1315−-- TRUE >= ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1317− :: Expression db params grp from ty -- ^ expression
1318− -> Query db params '[alias ::: ty] -- ^ subquery
1319− -> Expression db params grp from (nullity 'PGbool)
1320−gteAll = unsafeSubqueryExpression ">= ALL"
1322−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1323−-- >>> printSQL $ myRow `rowGteAll` values_ myRow
1324−-- ROW(1, FALSE) >= ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1327− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1328− -> Query db params row -- ^ subquery
1329− -> Expression db params grp from (nullity 'PGbool)
1330−rowGteAll = unsafeRowSubqueryExpression ">= ALL"
1332−-- | >>> printSQL $ true `gteAny` values_ (true `as` #foo)
1333−-- TRUE >= ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1335− :: Expression db params grp from ty -- ^ expression
1336− -> Query db params '[alias ::: ty] -- ^ subquery
1337− -> Expression db params grp from (nullity 'PGbool)
1338−gteAny = unsafeSubqueryExpression ">= ANY"
1340−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1341−-- >>> printSQL $ myRow `rowGteAny` values_ myRow
1342−-- ROW(1, FALSE) >= ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1345− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1346− -> Query db params row -- ^ subquery
1347− -> Expression db params grp from (nullity 'PGbool)
1348−rowGteAny = unsafeRowSubqueryExpression ">= ANY"
1350-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1031-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1351data CommonTableExpression statement
1032data CommonTableExpression statement
1033+ (schemas :: SchemasType)
1352 (params :: [NullityType])
1034 (params :: [NullityType])
1353− (db0 :: DBType)
1035+ (commons0 :: FromType)
1354− (db1 :: DBType) where
1036+ (commons1 :: FromType) where
1355 CommonTableExpression
1037 CommonTableExpression
1356− :: Aliased (statement (commons :=> schemas) params) (cte ::: common)
1038+ :: Aliased (statement commons schemas params) (cte ::: common)
1357− -> CommonTableExpression statement params
1039+ -> CommonTableExpression statement schemas params commons (cte ::: common ': commons)
1358− (commons :=> schemas) ((cte ::: common ': commons) :=> schemas)
1360 ( KnownSymbol cte
1041 ( KnownSymbol cte
1361− , db0 ~ (commons :=> schemas)
1042+ , commons1 ~ (cte ::: common ': commons)
1362− , db1 ~ ((cte ::: common ': commons) :=> schemas)
1363 ) => Aliasable cte
1043 ) => Aliasable cte
1364− (statement db0 params common)
1044+ (statement commons schemas params common)
1365− (CommonTableExpression statement params db0 db1) where
1045+ (CommonTableExpression statement schemas params commons commons1) where
1366 statement `as` cte = CommonTableExpression (statement `as` cte)
1046 statement `as` cte = CommonTableExpression (statement `as` cte)
1368 ( KnownSymbol cte
1048 ( KnownSymbol cte
1369− , db0 ~ (commons :=> schemas)
1049+ , commons1 ~ (cte ::: common ': commons)
1370− , db1 ~ ((cte ::: common ': commons) :=> schemas)
1371 ) => Aliasable cte
1050 ) => Aliasable cte
1372− (statement db0 params common)
1051+ (statement commons schemas params common)
1373− (AlignedList (CommonTableExpression statement params) db0 db1) where
1052+ (Path (CommonTableExpression statement schemas params) commons commons1) where
1374− statement `as` cte = single (statement `as` cte)
1053+ statement `as` cte = csingleton (statement `as` cte)
1376−-- | render a `CommonTableExpression`.
1055+instance (forall c s p r. RenderSQL (statement c s p r)) => RenderSQL
1377−renderCommonTableExpression
1056+ (CommonTableExpression statement schemas params commons0 commons1) where
1378− :: (forall db ps row. statement db ps row -> ByteString) -- ^ render statement
1057+ renderSQL (CommonTableExpression (statement `As` cte)) =
1379− -> CommonTableExpression statement params db0 db1 -> ByteString
1058+ renderSQL cte <+> "AS" <+> parenthesized (renderSQL statement)
1380−renderCommonTableExpression renderStatement
1381− (CommonTableExpression (statement `As` alias)) =
1382− renderSQL alias <+> "AS" <+> parenthesized (renderStatement statement)
1384−-- | render a non-empty `AlignedList` of `CommonTableExpression`s.
1385−renderCommonTableExpressions
1386− :: (forall db ps row. statement db ps row -> ByteString) -- ^ render statement
1387− -> CommonTableExpression statement params db0 db1
1388− -> AlignedList (CommonTableExpression statement params) db1 db2
1390−renderCommonTableExpressions renderStatement cte ctes =
1391− renderCommonTableExpression renderStatement cte <> case ctes of
1393− cte' :>> ctes' -> "," <+>
1394− renderCommonTableExpressions renderStatement cte' ctes'
1396-- | `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.
1397-- 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
1398-- defining temporary tables that exist just for one query.
1062-- defining temporary tables that exist just for one query.
1399class With statement where
1063class With statement where
1401− :: AlignedList (CommonTableExpression statement params) db0 db1
1065+ :: Path (CommonTableExpression statement schemas params) commons0 commons1
1402 -- ^ common table expressions
1066 -- ^ common table expressions
1403− -> statement db1 params row
1067+ -> statement commons1 schemas params row
1404 -- ^ larger query
1068 -- ^ larger query
1405− -> statement db0 params row
1069+ -> statement commons0 schemas params row
1406−instance With Query where
1070+instance With (Query outer) where
1407 with Done query = query
1071 with Done query = query
1408− with (cte :>> ctes) query = UnsafeQuery $
1072+ with ctes query = UnsafeQuery $
1409− "WITH" <+> renderCommonTableExpressions renderQuery cte ctes
1073+ "WITH" <+> commaSeparated (ctoList renderSQL ctes) <+> renderSQL query
1410− <+> 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