@@ -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,46 +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− , renderSortExpression
101− -- * Subquery Expressions
130import Control.DeepSeq
84import Control.DeepSeq
131import Data.ByteString (ByteString)
85import Data.ByteString (ByteString)
86+import Data.Kind (Type)
132import Data.String
87import Data.String
133import Data.Word
88import Data.Word
134import Generics.SOP hiding (from)
89import Generics.SOP hiding (from)
@@ -136,13 +91,67 @@ import GHC.TypeLits
137import qualified GHC.Generics as GHC
92import qualified GHC.Generics as GHC
94+import Squeal.PostgreSQL.Alias
139import 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
140import Squeal.PostgreSQL.Render
101import Squeal.PostgreSQL.Render
141import 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
144−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.
145−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)
147simple query:
156simple query:
@@ -150,7 +159,7 @@ simple query:
150>>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
159>>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
153− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
162+ query :: Query_ (Public Schema) () (Row Int32 Int32)
154 query = select Star (from (table #tab))
163 query = select Star (from (table #tab))
155in printSQL query
164in printSQL query
@@ -160,21 +169,21 @@ restricted query:
163− query :: Query (DBof (Public Schema)) '[] '["sum" ::: 'NotNull 'PGint4, "col1" ::: 'NotNull 'PGint4]
172+ query :: Query_ (Public Schema) () (Row Int32 Int32)
165− select_ ((#col1 + #col2) `as` #sum :* #col1)
174+ select_ ((#col1 + #col2) `as` #col1 :* #col1 `as` #col2)
166 ( from (table #tab)
175 ( from (table #tab)
167 & where_ (#col1 .> #col2)
176 & where_ (#col1 .> #col2)
168 & where_ (#col2 .> 0) )
177 & where_ (#col2 .> 0) )
169in printSQL query
178in printSQL query
171−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))
177− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
186+ query :: Query_ (Public Schema) () (Row Int32 Int32)
178 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)))
179in printSQL query
188in printSQL query
@@ -184,7 +193,7 @@ limits and offsets:
187− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
196+ query :: Query_ (Public Schema) () (Row Int32 Int32)
188 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)
189in printSQL query
198in printSQL query
@@ -194,7 +203,7 @@ parameterized query:
197− query :: Query (DBof (Public Schema)) '[ 'NotNull 'PGint4] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
206+ query :: Query_ (Public Schema) (Only Int32) (Row Int32 Int32)
198 query = select Star (from (table #tab) & where_ (#col1 .> param @1))
207 query = select Star (from (table #tab) & where_ (#col1 .> param @1))
199in printSQL query
208in printSQL query
@@ -204,21 +213,21 @@ aggregation query:
207− query :: Query (DBof (Public Schema)) '[] '["sum" ::: 'NotNull 'PGint4, "col1" ::: 'NotNull 'PGint4 ]
216+ query :: Query_ (Public Schema) () (Row Int64 Int32)
209− select_ (sum_ #col2 `as` #sum :* #col1)
218+ select_ ((fromNull 0 (sum_ (All #col2))) `as` #col1 :* #col1 `as` #col2)
210 ( from (table (#tab `as` #table1))
219 ( from (table (#tab `as` #table1))
211 & groupBy #col1
220 & groupBy #col1
212− & having (#col1 + sum_ #col2 .> 1) )
221+ & having (sum_ (Distinct #col2) .> 1) )
213in printSQL query
222in printSQL query
215−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)
217sorted query:
226sorted query:
221− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
230+ query :: Query_ (Public Schema) () (Row Int32 Int32)
222 query = select Star (from (table #tab) & orderBy [#col1 & Asc])
231 query = select Star (from (table #tab) & orderBy [#col1 & Asc])
223in printSQL query
232in printSQL query
@@ -226,14 +235,12 @@ SELECT * FROM "tab" AS "tab" ORDER BY "col1" ASC
229−>>> :set -XFlexibleContexts
231type OrdersColumns =
239type OrdersColumns =
232 '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
240 '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
233− , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
241+ , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
234− , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
242+ , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
235− , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4
243+ , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4 ]
@@ -249,22 +256,27 @@ type OrdersConstraints =
250type OrdersSchema =
257type OrdersSchema =
251 '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
258 '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
252− , "customers" ::: 'Table (CustomersConstraints :=> NamesColumns)
259+ , "customers" ::: 'Table (CustomersConstraints :=> NamesColumns)
253− , "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
258− query :: Query (DBof (Public OrdersSchema))
275+ query :: Query_ (Public OrdersSchema) () Order
260− '[ "order_price" ::: 'NotNull 'PGfloat4
261− , "customer_name" ::: 'NotNull 'PGtext
262− , "shipper_name" ::: 'NotNull 'PGtext
264 query = select_
276 query = select_
265− ( #o ! #price `as` #order_price :*
277+ ( #o ! #price `as` #price :*
266− #c ! #name `as` #customer_name :*
278+ #c ! #name `as` #customerName :*
267− #s ! #name `as` #shipper_name )
279+ #s ! #name `as` #shipperName )
268 ( from (table (#orders `as` #o)
280 ( from (table (#orders `as` #o)
269 & innerJoin (table (#customers `as` #c))
281 & innerJoin (table (#customers `as` #c))
270 (#o ! #customer_id .== #c ! #id)
282 (#o ! #customer_id .== #c ! #id)
@@ -272,14 +284,16 @@ let
272 (#o ! #shipper_id .== #s ! #id)) )
284 (#o ! #shipper_id .== #s ! #id)) )
273in printSQL query
285in printSQL query
275−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")
277self-join:
289self-join:
281− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
293+ query :: Query_ (Public Schema) () (Row Int32 Int32)
282− 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))))
283in printSQL query
297in printSQL query
285SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
299SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
@@ -288,17 +302,19 @@ value queries:
291− query :: Query db '[] '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
305+ query :: Query_ schemas () (Row String Bool)
292− 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]
293in printSQL query
309in printSQL query
295−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")
297set operations:
313set operations:
301− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
317+ query :: Query_ (Public Schema) () (Row Int32 Int32)
302 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))
303in printSQL query
319in printSQL query
@@ -308,7 +324,7 @@ with queries:
311− query :: Query (DBof (Public Schema)) '[] '["col1" ::: 'NotNull 'PGint4, "col2" ::: 'NotNull 'PGint4]
327+ query :: Query_ (Public Schema) () (Row Int32 Int32)
312 query = with (
328 query = with (
313 select Star (from (table #tab)) `as` #cte1 :>>
329 select Star (from (table #tab)) `as` #cte1 :>>
314 select Star (from (common #cte1)) `as` #cte2
330 select Star (from (common #cte1)) `as` #cte2
@@ -316,133 +332,195 @@ let
316in printSQL query
332in printSQL query
318WITH "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"))
320−newtype Query
363+type family Query_
321− (db :: DBType)
364+ (schemas :: SchemasType)
322− (params :: [NullityType])
365+ (parameters :: Type)
323− (columns :: RowType)
366+ (row :: Type) where
324− = UnsafeQuery { renderQuery :: ByteString }
367+ Query_ schemas params row =
325− deriving (GHC.Generic,Show,Eq,Ord,NFData)
368+ Query '[] '[] schemas (TuplePG params) (RowPG row)
326−instance RenderSQL (Query db params columns) where renderSQL = renderQuery
328-- | 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
329-- `union`. Duplicate rows are eliminated.
371-- `union`. Duplicate rows are eliminated.
331− :: Query db params columns
373+ :: Query outer commons schemas params columns
332− -> Query db params columns
374+ -> Query outer commons schemas params columns
333− -> Query db params columns
375+ -> Query outer commons schemas params columns
334q1 `union` q2 = UnsafeQuery $
376q1 `union` q2 = UnsafeQuery $
335− parenthesized (renderQuery q1)
377+ parenthesized (renderSQL q1)
336 <+> "UNION"
378 <+> "UNION"
337− <+> parenthesized (renderQuery q2)
379+ <+> parenthesized (renderSQL q2)
339-- | 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
340-- `unionAll`, the disjoint union. Duplicate rows are retained.
382-- `unionAll`, the disjoint union. Duplicate rows are retained.
342− :: Query db params columns
384+ :: Query outer commons schemas params columns
343− -> Query db params columns
385+ -> Query outer commons schemas params columns
344− -> Query db params columns
386+ -> Query outer commons schemas params columns
345q1 `unionAll` q2 = UnsafeQuery $
387q1 `unionAll` q2 = UnsafeQuery $
346− parenthesized (renderQuery q1)
388+ parenthesized (renderSQL q1)
347 <+> "UNION" <+> "ALL"
389 <+> "UNION" <+> "ALL"
348− <+> parenthesized (renderQuery q2)
390+ <+> parenthesized (renderSQL q2)
350-- | 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
351-- `intersect`, the intersection. Duplicate rows are eliminated.
393-- `intersect`, the intersection. Duplicate rows are eliminated.
353− :: Query db params columns
395+ :: Query outer commons schemas params columns
354− -> Query db params columns
396+ -> Query outer commons schemas params columns
355− -> Query db params columns
397+ -> Query outer commons schemas params columns
356q1 `intersect` q2 = UnsafeQuery $
398q1 `intersect` q2 = UnsafeQuery $
357− parenthesized (renderQuery q1)
399+ parenthesized (renderSQL q1)
358 <+> "INTERSECT"
400 <+> "INTERSECT"
359− <+> parenthesized (renderQuery q2)
401+ <+> parenthesized (renderSQL q2)
361-- | 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
362-- `intersectAll`, the intersection. Duplicate rows are retained.
404-- `intersectAll`, the intersection. Duplicate rows are retained.
363intersectAll
405intersectAll
364− :: Query db params columns
406+ :: Query outer commons schemas params columns
365− -> Query db params columns
407+ -> Query outer commons schemas params columns
366− -> Query db params columns
408+ -> Query outer commons schemas params columns
367q1 `intersectAll` q2 = UnsafeQuery $
409q1 `intersectAll` q2 = UnsafeQuery $
368− parenthesized (renderQuery q1)
410+ parenthesized (renderSQL q1)
369 <+> "INTERSECT" <+> "ALL"
411 <+> "INTERSECT" <+> "ALL"
370− <+> parenthesized (renderQuery q2)
412+ <+> parenthesized (renderSQL q2)
372-- | 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
373-- `except`, the set difference. Duplicate rows are eliminated.
415-- `except`, the set difference. Duplicate rows are eliminated.
375− :: Query db params columns
417+ :: Query outer commons schemas params columns
376− -> Query db params columns
418+ -> Query outer commons schemas params columns
377− -> Query db params columns
419+ -> Query outer commons schemas params columns
378q1 `except` q2 = UnsafeQuery $
420q1 `except` q2 = UnsafeQuery $
379− parenthesized (renderQuery q1)
421+ parenthesized (renderSQL q1)
380 <+> "EXCEPT"
422 <+> "EXCEPT"
381− <+> parenthesized (renderQuery q2)
423+ <+> parenthesized (renderSQL q2)
383-- | 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
384-- `exceptAll`, the set difference. Duplicate rows are retained.
426-- `exceptAll`, the set difference. Duplicate rows are retained.
386− :: Query db params columns
428+ :: Query outer commons schemas params columns
387− -> Query db params columns
429+ -> Query outer commons schemas params columns
388− -> Query db params columns
430+ -> Query outer commons schemas params columns
389q1 `exceptAll` q2 = UnsafeQuery $
431q1 `exceptAll` q2 = UnsafeQuery $
390− parenthesized (renderQuery q1)
432+ parenthesized (renderSQL q1)
391 <+> "EXCEPT" <+> "ALL"
433 <+> "EXCEPT" <+> "ALL"
392− <+> parenthesized (renderQuery q2)
434+ <+> parenthesized (renderSQL q2)
394{-----------------------------------------
436{-----------------------------------------
395SELECT queries
437SELECT queries
396-----------------------------------------}
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`.
398−data Selection db params grp from row where
446+data Selection outer commons grp schemas params from row where
401− => NP (Aliased (Expression db params grp from)) row
402− -> Selection db params grp from row
404 :: HasUnique tab from row
448 :: HasUnique tab from row
405− => Selection db params 'Ungrouped from row
449+ => Selection outer commons 'Ungrouped schemas params from row
450+ -- ^ `HasUnique` table in the `FromClause`
407 :: Has tab from row
452 :: Has tab from row
408 => Alias tab
453 => Alias tab
454+ -- ^ `Has` table with `Alias`
409− -> 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
411− :: Selection db params grp from right
468+ :: Selection outer commons grp schemas params from right
469+ -- ^ `Additional` `Selection`
412− -> Selection db params grp from left
470+ -> Selection outer commons grp schemas params from left
413− -> 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
414instance (KnownSymbol col, row ~ '[col ::: ty])
474instance (KnownSymbol col, row ~ '[col ::: ty])
415 => Aliasable col
475 => Aliasable col
416− (Expression db params grp from ty)
476+ (Expression outer commons grp schemas params from ty)
417− (Selection db params grp from row) where
477+ (Selection outer commons grp schemas params from row) where
418 expr `as` col = List (expr `as` col)
478 expr `as` col = List (expr `as` col)
419−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
420− => IsQualified tab col (Selection db params 'Ungrouped from row1) where
481+ (Selection outer commons 'Ungrouped schemas params from row1) where
421− tab ! col = tab ! col `as` col
482+ tab ! col = tab ! col `as` col
423− ( Has tab from row0
484+ ( Has tab (Join outer from) row0
424 , Has col row0 ty
485 , Has col row0 ty
425 , row1 ~ '[col ::: ty]
486 , row1 ~ '[col ::: ty]
426 , GroupedBy tab col bys )
487 , GroupedBy tab col bys )
488+ => IsQualified tab col
427− => IsQualified tab col (Selection db params ('Grouped bys) from row1) where
489+ (Selection outer commons ('Grouped bys) schemas params from row1) where
428− tab ! col = tab ! col `as` col
490+ tab ! col = tab ! col `as` col
429−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])
430− => IsLabel col (Selection db params 'Ungrouped from row1) where
493+ (Selection outer commons 'Ungrouped schemas params from row1) where
431− fromLabel = fromLabel @col `as` Alias
494+ fromLabel = fromLabel @col `as` Alias
433− ( HasUnique tab from row0
496+ ( HasUnique tab (Join outer from) row0
434 , Has col row0 ty
497 , Has col row0 ty
435 , row1 ~ '[col ::: ty]
498 , row1 ~ '[col ::: ty]
436 , GroupedBy tab col bys )
499 , GroupedBy tab col bys )
437− => IsLabel col (Selection db params ('Grouped bys) from row1) where
501+ (Selection outer commons ('Grouped bys) schemas params from row1) where
438− fromLabel = fromLabel @col `as` Alias
502+ fromLabel = fromLabel @col `as` Alias
440−instance RenderSQL (Selection db params grp from row) where
504+instance RenderSQL (Selection outer commons grp schemas params from row) where
441 renderSQL = \case
505 renderSQL = \case
442− List list -> renderCommaSeparated (renderAliasedAs renderSQL) list
506+ List list -> renderCommaSeparated (renderAliased renderSQL) list
443 Star -> "*"
507 Star -> "*"
444 DotStar tab -> renderSQL tab <> ".*"
508 DotStar tab -> renderSQL tab <> ".*"
445 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
447-- | the `TableExpression` in the `select` command constructs an intermediate
525-- | the `TableExpression` in the `select` command constructs an intermediate
448-- virtual table by possibly combining tables, views, eliminating rows,
526-- virtual table by possibly combining tables, views, eliminating rows,
@@ -451,45 +529,100 @@ instance RenderSQL (Selection db params grp from row) where
451-- the intermediate table are actually output.
529-- the intermediate table are actually output.
453 :: (SListI row, row ~ (x ': xs))
531 :: (SListI row, row ~ (x ': xs))
454− => Selection db params grp from row
532+ => Selection outer commons grp schemas params from row
455− -- ^ select list
533+ -- ^ selection
456− -> TableExpression db params grp from
534+ -> TableExpression outer commons grp schemas params from
457 -- ^ intermediate virtual table
535 -- ^ intermediate virtual table
458− -> Query db params row
536+ -> Query outer commons schemas params row
459select selection tabexpr = UnsafeQuery $
537select selection tabexpr = UnsafeQuery $
461 <+> renderSQL selection
539 <+> renderSQL selection
462− <+> renderTableExpression tabexpr
540+ <+> renderSQL tabexpr
542+-- | Like `select` but takes an `NP` list of `Expression`s instead
543+-- of a general `Selection`.
465 :: (SListI row, row ~ (x ': xs))
545 :: (SListI row, row ~ (x ': xs))
466− => NP (Aliased (Expression db params grp from)) row
546+ => NP (Aliased (Expression outer commons grp schemas params from)) row
467− -> TableExpression db params grp from
548+ -> TableExpression outer commons grp schemas params from
549+ -- ^ intermediate virtual table
468− -> Query db params row
550+ -> Query outer commons schemas params row
469−select_ list = select (List list)
551+select_ = select . List
471-- | After the select list has been processed, the result table can
553-- | After the select list has been processed, the result table can
472-- be subject to the elimination of duplicate rows using `selectDistinct`.
554-- be subject to the elimination of duplicate rows using `selectDistinct`.
473selectDistinct
555selectDistinct
474 :: (SListI columns, columns ~ (col ': cols))
556 :: (SListI columns, columns ~ (col ': cols))
475− => Selection db params 'Ungrouped from columns
557+ => Selection outer commons grp schemas params from columns
476− -- ^ select list
558+ -- ^ selection
477− -> TableExpression db params 'Ungrouped from
559+ -> TableExpression outer commons grp schemas params from
478 -- ^ intermediate virtual table
560 -- ^ intermediate virtual table
479− -> Query db params columns
561+ -> Query outer commons schemas params columns
480selectDistinct selection tabexpr = UnsafeQuery $
562selectDistinct selection tabexpr = UnsafeQuery $
481 "SELECT DISTINCT"
563 "SELECT DISTINCT"
482 <+> renderSQL selection
564 <+> renderSQL selection
483− <+> renderTableExpression tabexpr
565+ <+> renderSQL tabexpr
567+-- | Like `selectDistinct` but takes an `NP` list of `Expression`s instead
568+-- of a general `Selection`.
485selectDistinct_
569selectDistinct_
486 :: (SListI columns, columns ~ (col ': cols))
570 :: (SListI columns, columns ~ (col ': cols))
487− => NP (Aliased (Expression db params 'Ungrouped from)) columns
571+ => NP (Aliased (Expression outer commons grp schemas params from)) columns
488 -- ^ select list
572 -- ^ select list
489− -> TableExpression db params 'Ungrouped from
573+ -> TableExpression outer commons grp schemas params from
490 -- ^ intermediate virtual table
574 -- ^ intermediate virtual table
491− -> Query db params columns
575+ -> Query outer commons schemas params columns
492−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
494-- | `values` computes a row value or set of row values
627-- | `values` computes a row value or set of row values
495-- specified by value expressions. It is most commonly used
628-- specified by value expressions. It is most commonly used
@@ -497,16 +630,16 @@ selectDistinct_ list = select (List list)
497-- but it can be used on its own.
630-- but it can be used on its own.
499-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
632-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
500−-- >>> 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
501-- >>> printSQL query
634-- >>> printSQL query
502-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
635-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
504 :: SListI cols
637 :: SListI cols
505− => NP (Aliased (Expression db params 'Ungrouped '[] )) cols
638+ => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
506− -> [NP (Aliased (Expression db params 'Ungrouped '[] )) cols]
639+ -> [NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols]
507 -- ^ When more than one row is specified, all the rows must
640 -- ^ When more than one row is specified, all the rows must
508 -- must have the same number of elements
641 -- must have the same number of elements
509− -> Query db params cols
642+ -> Query outer commons schemas params cols
510values rw rws = UnsafeQuery $ "SELECT * FROM"
643values rw rws = UnsafeQuery $ "SELECT * FROM"
511 <+> parenthesized (
644 <+> parenthesized (
@@ -514,20 +647,20 @@ values rw rws = UnsafeQuery $ "SELECT * FROM"
514 ( parenthesized
647 ( parenthesized
515 . renderCommaSeparated renderValuePart <$> rw:rws )
648 . renderCommaSeparated renderValuePart <$> rw:rws )
516 ) <+> "AS t"
649 ) <+> "AS t"
517− <+> parenthesized (renderCommaSeparated renderSQLPart rw)
650+ <+> parenthesized (renderCommaSeparated renderAliasPart rw)
519− renderSQLPart, renderValuePart
652+ renderAliasPart, renderValuePart
520− :: Aliased (Expression db params 'Ungrouped '[] ) ty -> ByteString
653+ :: Aliased (Expression outer commons 'Ungrouped schemas params '[] ) ty -> ByteString
521− renderSQLPart (_ `As` name) = renderSQL name
654+ renderAliasPart (_ `As` name) = renderSQL name
522 renderValuePart (value `As` _) = renderSQL value
655 renderValuePart (value `As` _) = renderSQL value
524-- | `values_` computes a row value or set of row values
657-- | `values_` computes a row value or set of row values
525-- specified by value expressions.
658-- specified by value expressions.
527 :: SListI cols
660 :: SListI cols
528− => NP (Aliased (Expression db params 'Ungrouped '[] )) cols
661+ => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
529 -- ^ one row of values
662 -- ^ one row of values
530− -> Query db params cols
663+ -> Query outer commons schemas params cols
531values_ rw = values rw []
664values_ rw = values rw []
533{-----------------------------------------
666{-----------------------------------------
@@ -541,15 +674,17 @@ Table Expressions
541-- 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
542-- 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.
543data TableExpression
676data TableExpression
544− (db :: DBType)
677+ (outer :: FromType)
545− (params :: [NullityType])
678+ (commons :: FromType)
546 (grp :: Grouping)
679 (grp :: Grouping)
680+ (schemas :: SchemasType)
681+ (params :: [NullityType])
547 (from :: FromType)
682 (from :: FromType)
548 = TableExpression
683 = TableExpression
549− { fromClause :: FromClause db params from
684+ { fromClause :: FromClause outer commons schemas params from
550 -- ^ 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
551 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
686 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
552− , whereClause :: [Condition db params 'Ungrouped from]
687+ , whereClause :: [Condition outer commons 'Ungrouped schemas params from]
553 -- ^ optional search coditions, combined with `.&&`. After the processing
688 -- ^ optional search coditions, combined with `.&&`. After the processing
554 -- 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
555 -- is checked against the search condition. If the result of the
690 -- is checked against the search condition. If the result of the
@@ -565,13 +700,13 @@ data TableExpression
565 -- 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
566 -- 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
567 -- and/or compute aggregates that apply to these groups.
702 -- and/or compute aggregates that apply to these groups.
568− , havingClause :: HavingClause db params grp from
703+ , havingClause :: HavingClause outer commons grp schemas params from
569 -- ^ 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
570 -- are of interest, the `havingClause` can be used, much like a
705 -- are of interest, the `havingClause` can be used, much like a
571 -- `whereClause`, to eliminate groups from the result. Expressions in the
706 -- `whereClause`, to eliminate groups from the result. Expressions in the
572 -- `havingClause` can refer both to grouped expressions and to ungrouped
707 -- `havingClause` can refer both to grouped expressions and to ungrouped
573 -- expressions (which necessarily involve an aggregate function).
708 -- expressions (which necessarily involve an aggregate function).
574− , orderByClause :: [SortExpression db params grp from]
709+ , orderByClause :: [SortExpression outer commons grp schemas params from]
575 -- ^ The `orderByClause` is for optional sorting. When more than one
710 -- ^ The `orderByClause` is for optional sorting. When more than one
576 -- `SortExpression` is specified, the later (right) values are used to sort
711 -- `SortExpression` is specified, the later (right) values are used to sort
577 -- rows that are equal according to the earlier (left) values.
712 -- rows that are equal according to the earlier (left) values.
@@ -581,72 +716,69 @@ data TableExpression
581 -- will be returned (but possibly fewer, if the query itself yields
716 -- will be returned (but possibly fewer, if the query itself yields
582 -- fewer rows).
717 -- fewer rows).
583 , offsetClause :: [Word64]
718 , offsetClause :: [Word64]
584− -- ^ The `offsetClause` is combined with `+` to give an offset count
719+ -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count
585 -- 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
586 -- 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
587 -- is applied.
722 -- is applied.
588− }
723+ } deriving (GHC.Generic)
590-- | Render a `TableExpression`
725-- | Render a `TableExpression`
591−renderTableExpression
592− :: TableExpression db params grp from
726+instance RenderSQL (TableExpression outer commons grp schemas params from) where
593− -> ByteString
727+ renderSQL
594−renderTableExpression
595− (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
728+ (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
596− [ "FROM ", renderFromClause frm'
729+ [ "FROM ", renderSQL frm'
597− , renderWheres whs'
730+ , renderWheres whs'
598− , renderGroupByClause grps'
731+ , renderSQL grps'
599− , renderHavingClause hvs'
732+ , renderSQL hvs'
600− , renderOrderByClause srts'
733+ , renderOrderByClause srts'
601− , renderLimits lims'
734+ , renderLimits lims'
602− , renderOffsets offs'
735+ , renderOffsets offs' ]
605− renderWheres = \case
737+ renderWheres = \case
606− [] -> ""
738+ [] -> ""
607− wh:[] -> " WHERE" <+> renderSQL wh
739+ wh:[] -> " WHERE" <+> renderSQL wh
608− wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)
740+ wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)
609− renderOrderByClause = \case
741+ renderOrderByClause = \case
610− [] -> ""
742+ [] -> ""
611− srts -> " ORDER BY"
743+ srts -> " ORDER BY"
612− <+> commaSeparated (renderSortExpression <$> srts)
744+ <+> commaSeparated (renderSQL <$> srts)
613− renderLimits = \case
745+ renderLimits = \case
614− [] -> ""
746+ [] -> ""
615− lims -> " LIMIT" <+> fromString (show (minimum lims))
747+ lims -> " LIMIT" <+> fromString (show (minimum lims))
616− renderOffsets = \case
748+ renderOffsets = \case
617− [] -> ""
749+ [] -> ""
618− offs -> " OFFSET" <+> fromString (show (sum offs))
750+ offs -> " OFFSET" <+> fromString (show (sum offs))
620-- | 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
621-- 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,
622-- 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_`,
623−-- `group`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
755+-- `groupBy`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
624-- 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.
626− :: FromClause db params from -- ^ table reference
758+ :: FromClause outer commons schemas params from -- ^ table reference
627− -> TableExpression db params 'Ungrouped from
759+ -> TableExpression outer commons 'Ungrouped schemas params from
628−from rels = TableExpression rels [] NoGroups NoHaving [] [] []
760+from tab = TableExpression tab [] noGroups NoHaving [] [] []
630-- | A `where_` is an endomorphism of `TableExpression`s which adds a
762-- | A `where_` is an endomorphism of `TableExpression`s which adds a
631-- search condition to the `whereClause`.
763-- search condition to the `whereClause`.
633− :: Condition db params 'Ungrouped from -- ^ filtering condition
765+ :: Condition outer commons 'Ungrouped schemas params from -- ^ filtering condition
634− -> TableExpression db params grp from
766+ -> TableExpression outer commons grp schemas params from
635− -> TableExpression db params grp from
767+ -> TableExpression outer commons grp schemas params from
636where_ wh rels = rels {whereClause = wh : whereClause rels}
768where_ wh rels = rels {whereClause = wh : whereClause rels}
638-- | A `groupBy` is a transformation of `TableExpression`s which switches
770-- | A `groupBy` is a transformation of `TableExpression`s which switches
639−-- its `Grouping` from `Ungrouped` to `Grouped`. Use @group Nil@ to perform
771+-- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform
640-- a "grand total" aggregation query.
772-- a "grand total" aggregation query.
642 :: SListI bys
774 :: SListI bys
643 => NP (By from) bys -- ^ grouped columns
775 => NP (By from) bys -- ^ grouped columns
644− -> TableExpression db params 'Ungrouped from
776+ -> TableExpression outer commons 'Ungrouped schemas params from
645− -> TableExpression db params ('Grouped bys) from
777+ -> TableExpression outer commons ('Grouped bys) schemas params from
646groupBy bys rels = TableExpression
778groupBy bys rels = TableExpression
647 { fromClause = fromClause rels
779 { fromClause = fromClause rels
648 , whereClause = whereClause rels
780 , whereClause = whereClause rels
649− , groupByClause = Group bys
781+ , groupByClause = group bys
650 , havingClause = Having []
782 , havingClause = Having []
651 , orderByClause = []
783 , orderByClause = []
652 , limitClause = limitClause rels
784 , limitClause = limitClause rels
@@ -656,177 +788,31 @@ groupBy bys rels = TableExpression
656-- | A `having` is an endomorphism of `TableExpression`s which adds a
788-- | A `having` is an endomorphism of `TableExpression`s which adds a
657-- search condition to the `havingClause`.
789-- search condition to the `havingClause`.
659− :: Condition db params ('Grouped bys) from -- ^ having condition
791+ :: Condition outer commons ('Grouped bys) schemas params from -- ^ having condition
660− -> TableExpression db params ('Grouped bys) from
792+ -> TableExpression outer commons ('Grouped bys) schemas params from
661− -> TableExpression db params ('Grouped bys) from
793+ -> TableExpression outer commons ('Grouped bys) schemas params from
662having hv rels = rels
794having hv rels = rels
663 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
795 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
665−-- | An `orderBy` is an endomorphism of `TableExpression`s which appends an
797+instance OrderBy TableExpression where
666−-- ordering to the right of the `orderByClause`.
668− :: [SortExpression db params grp from] -- ^ sort expressions
669− -> TableExpression db params grp from
670− -> TableExpression db params grp from
671−orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
798+ orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
673-- | 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
674-- `limitClause`.
801-- `limitClause`.
676 :: Word64 -- ^ limit parameter
803 :: Word64 -- ^ limit parameter
677− -> TableExpression db params grp from
804+ -> TableExpression outer commons grp schemas params from
678− -> TableExpression db params grp from
805+ -> TableExpression outer commons grp schemas params from
679limit lim rels = rels {limitClause = lim : limitClause rels}
806limit lim rels = rels {limitClause = lim : limitClause rels}
681-- | 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
682-- `offsetClause`.
809-- `offsetClause`.
684 :: Word64 -- ^ offset parameter
811 :: Word64 -- ^ offset parameter
685− -> TableExpression db params grp from
812+ -> TableExpression outer commons grp schemas params from
686− -> TableExpression db params grp from
813+ -> TableExpression outer commons grp schemas params from
687offset off rels = rels {offsetClause = off : offsetClause rels}
814offset off rels = rels {offsetClause = off : offsetClause rels}
689−{-----------------------------------------
691−-----------------------------------------}
695− -> Expression db params 'Ungrouped '[] ty
696− -> Query db params row
697−unsafeSetOfFunction fun expr = UnsafeQuery $
698− "SELECT * FROM " <> fun <> "(" <> renderSQL expr <> ")"
700−-- | Expands the outermost JSON object into a set of key/value pairs.
702− :: Expression db params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
704− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
705−jsonEach = unsafeSetOfFunction "json_each"
707−-- | Expands the outermost binary JSON object into a set of key/value pairs.
709− :: Expression db params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
711− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjsonb]
712−jsonbEach = unsafeSetOfFunction "jsonb_each"
714−-- | Expands the outermost JSON object into a set of key/value pairs.
716− :: Expression db params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
718− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
719−jsonEachAsText = unsafeSetOfFunction "json_each_text"
721−-- | Expands the outermost binary JSON object into a set of key/value pairs.
723− :: Expression db params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
725− '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
726−jsonbEachAsText = unsafeSetOfFunction "jsonb_each_text"
728−-- | Returns set of keys in the outermost JSON object.
730− :: Expression db params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
731− -> Query db params '["json_object_keys" ::: 'NotNull 'PGtext]
732−jsonObjectKeys = unsafeSetOfFunction "json_object_keys"
734−-- | Returns set of keys in the outermost JSON object.
736− :: Expression db params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
737− -> Query db params '["jsonb_object_keys" ::: 'NotNull 'PGtext]
738−jsonbObjectKeys = unsafeSetOfFunction "jsonb_object_keys"
740−unsafePopulateFunction
742− -> TypeExpression schemas (nullity ('PGcomposite row))
743− -> Expression (commons :=> schemas) params 'Ungrouped '[] ty
744− -> Query (commons :=> schemas) params row
745−unsafePopulateFunction fun ty expr = UnsafeQuery $
746− "SELECT * FROM " <> fun <> "("
747− <> "null::" <> renderSQL ty <> ", "
748− <> renderSQL expr <> ")"
750−-- | Expands the JSON expression to a row whose columns match the record
751−-- type defined by the given table.
753− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
754− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
755− -> Query (commons :=> schemas) params row
756−jsonPopulateRecord = unsafePopulateFunction "json_populate_record"
758−-- | Expands the binary JSON expression to a row whose columns match the record
759−-- type defined by the given table.
761− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
762− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
763− -> Query (commons :=> schemas) params row
764−jsonbPopulateRecord = unsafePopulateFunction "jsonb_populate_record"
766−-- | Expands the outermost array of objects in the given JSON expression to a
767−-- set of rows whose columns match the record type defined by the given table.
768−jsonPopulateRecordSet
769− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
770− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json array
771− -> Query (commons :=> schemas) params row
772−jsonPopulateRecordSet = unsafePopulateFunction "json_populate_record_set"
774−-- | Expands the outermost array of objects in the given binary JSON expression
775−-- to a set of rows whose columns match the record type defined by the given
777−jsonbPopulateRecordSet
778− :: TypeExpression schemas (nullity ('PGcomposite row)) -- ^ row type
779− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb array
780− -> Query (commons :=> schemas) params row
781−jsonbPopulateRecordSet = unsafePopulateFunction "jsonb_populate_record_set"
784− :: (SListI record, json `In` PGJsonType)
786− -> Expression (commons :=> schemas) params 'Ungrouped '[] (nullity json)
787− -> NP (Aliased (TypeExpression schemas)) record
788− -> Query (commons :=> schemas) params record
789−unsafeRecordFunction fun expr types = UnsafeQuery $
790− "SELECT * FROM " <> fun <> "("
791− <> renderSQL expr <> ")"
792− <+> "AS" <+> "x" <> parenthesized (renderCommaSeparated renderTy types)
794− renderTy :: Aliased (TypeExpression db) ty -> ByteString
795− renderTy (ty `As` alias) =
796− renderSQL alias <+> renderSQL ty
798−-- | Builds an arbitrary record from a JSON object.
801− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json object
802− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
803− -> Query (commons :=> schemas) params record
804−jsonToRecord = unsafeRecordFunction "json_to_record"
806−-- | Builds an arbitrary record from a binary JSON object.
809− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb object
810− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
811− -> Query (commons :=> schemas) params record
812−jsonbToRecord = unsafeRecordFunction "jsonb_to_record"
814−-- | Builds an arbitrary set of records from a JSON array of objects.
817− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjson) -- ^ json array
818− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
819− -> Query (commons :=> schemas) params record
820−jsonToRecordSet = unsafeRecordFunction "json_to_record_set"
822−-- | Builds an arbitrary set of records from a binary JSON array of objects.
825− => Expression (commons :=> schemas) params 'Ungrouped '[] (nullity 'PGjsonb) -- ^ jsonb array
826− -> NP (Aliased (TypeExpression schemas)) record -- ^ record types
827− -> Query (commons :=> schemas) params record
828−jsonbToRecordSet = unsafeRecordFunction "jsonb_to_record_set"
830{-----------------------------------------
816{-----------------------------------------
831FROM clauses
817FROM clauses
832-----------------------------------------}
818-----------------------------------------}
@@ -835,67 +821,75 @@ FROM clauses
835A `FromClause` can be a table name, or a derived table such
821A `FromClause` can be a table name, or a derived table such
836as a subquery, a @JOIN@ construct, or complex combinations of these.
822as a subquery, a @JOIN@ construct, or complex combinations of these.
838−newtype FromClause db params from
824+newtype FromClause outer commons schemas params from
839 = UnsafeFromClause { renderFromClause :: ByteString }
825 = UnsafeFromClause { renderFromClause :: ByteString }
840 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
842-- | A real `table` is a table from the database.
830-- | A real `table` is a table from the database.
844 :: (Has sch schemas schema, Has tab schema ('Table table))
832 :: (Has sch schemas schema, Has tab schema ('Table table))
845 => Aliased (QualifiedAlias sch) (alias ::: tab)
833 => Aliased (QualifiedAlias sch) (alias ::: tab)
846− -> FromClause (commons :=> schemas) params '[alias ::: TableToRow table]
834+ -> FromClause outer commons schemas params '[alias ::: TableToRow table]
847table (tab `As` alias) = UnsafeFromClause $
835table (tab `As` alias) = UnsafeFromClause $
848− renderQualifiedAlias tab <+> "AS" <+> renderSQL alias
836+ renderSQL tab <+> "AS" <+> renderSQL alias
850-- | `subquery` derives a table from a `Query`.
838-- | `subquery` derives a table from a `Query`.
852− :: Aliased (Query db params) query
840+ :: Aliased (Query outer commons schemas params) query
853− -> FromClause db params '[query]
841+ -> FromClause outer commons schemas params '[query]
854−subquery = UnsafeFromClause . renderAliasedAs (parenthesized . renderQuery)
842+subquery = UnsafeFromClause . renderAliased (parenthesized . renderSQL)
856-- | `view` derives a table from a `View`.
844-- | `view` derives a table from a `View`.
858 :: (Has sch schemas schema, Has vw schema ('View view))
846 :: (Has sch schemas schema, Has vw schema ('View view))
859 => Aliased (QualifiedAlias sch) (alias ::: vw)
847 => Aliased (QualifiedAlias sch) (alias ::: vw)
860− -> FromClause (commons :=> schemas) params '[alias ::: view]
848+ -> FromClause outer commons schemas params '[alias ::: view]
861view (vw `As` alias) = UnsafeFromClause $
849view (vw `As` alias) = UnsafeFromClause $
862− renderQualifiedAlias vw <+> "AS" <+> renderSQL alias
850+ renderSQL vw <+> "AS" <+> renderSQL alias
852+-- | `common` derives a table from a common table expression.
865 :: Has cte commons common
854 :: Has cte commons common
866 => Aliased Alias (alias ::: cte)
855 => Aliased Alias (alias ::: cte)
867− -> FromClause (commons :=> schemas) params '[alias ::: common]
856+ -> FromClause outer commons schemas params '[alias ::: common]
868common (cte `As` alias) = UnsafeFromClause $
857common (cte `As` alias) = UnsafeFromClause $
869 renderSQL cte <+> "AS" <+> renderSQL alias
858 renderSQL cte <+> "AS" <+> renderSQL alias
860+instance Additional (FromClause outer commons schemas params) where
861+ also right left = UnsafeFromClause $
862+ renderSQL left <> ", " <> renderSQL right
871−{- | @left & crossJoin right@. For every possible combination of rows from
865+@left & crossJoin right@. For every possible combination of rows from
872− @left@ and @right@ (i.e., a Cartesian product), the joined table will contain
866+@left@ and @right@ (i.e., a Cartesian product), the joined table will contain
873− a row consisting of all columns in @left@ followed by all columns in @right@.
867+a row consisting of all columns in @left@ followed by all columns in @right@.
874− If the tables have @n@ and @m@ rows respectively, the joined table will
868+If the tables have @n@ and @m@ rows respectively, the joined table will
875− have @n * m@ rows.
869+have @n * m@ rows.
878− :: FromClause db params right
872+ :: FromClause outer commons schemas params right
879 -- ^ right
873 -- ^ right
880− -> FromClause db params left
874+ -> FromClause outer commons schemas params left
881 -- ^ left
875 -- ^ left
882− -> FromClause db params (Join left right)
876+ -> FromClause outer commons schemas params (Join left right)
883crossJoin right left = UnsafeFromClause $
877crossJoin right left = UnsafeFromClause $
884− renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
878+ renderSQL left <+> "CROSS JOIN" <+> renderSQL right
886{- | @left & innerJoin right on@. The joined table is filtered by
880{- | @left & innerJoin right on@. The joined table is filtered by
887the @on@ condition.
881the @on@ condition.
890− :: FromClause db params right
884+ :: FromClause outer commons schemas params right
891 -- ^ right
885 -- ^ right
892− -> Condition db params 'Ungrouped (Join left right)
886+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
893 -- ^ @on@ condition
887 -- ^ @on@ condition
894− -> FromClause db params left
888+ -> FromClause outer commons schemas params left
895 -- ^ left
889 -- ^ left
896− -> FromClause db params (Join left right)
890+ -> FromClause outer commons schemas params (Join left right)
897innerJoin right on left = UnsafeFromClause $
891innerJoin right on left = UnsafeFromClause $
898− renderFromClause left <+> "INNER JOIN" <+> renderFromClause right
892+ renderSQL left <+> "INNER JOIN" <+> renderSQL right
899 <+> "ON" <+> renderSQL on
893 <+> "ON" <+> renderSQL on
901{- | @left & leftOuterJoin right on@. First, an inner join is performed.
895{- | @left & leftOuterJoin right on@. First, an inner join is performed.
@@ -904,15 +898,15 @@ innerJoin right on left = UnsafeFromClause $
904 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@.
906leftOuterJoin
900leftOuterJoin
907− :: FromClause db params right
901+ :: FromClause outer commons schemas params right
908 -- ^ right
902 -- ^ right
909− -> Condition db params 'Ungrouped (Join left right)
903+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
910 -- ^ @on@ condition
904 -- ^ @on@ condition
911− -> FromClause db params left
905+ -> FromClause outer commons schemas params left
912 -- ^ left
906 -- ^ left
913− -> FromClause db params (Join left (NullifyFrom right))
907+ -> FromClause outer commons schemas params (Join left (NullifyFrom right))
914leftOuterJoin right on left = UnsafeFromClause $
908leftOuterJoin right on left = UnsafeFromClause $
915− renderFromClause left <+> "LEFT OUTER JOIN" <+> renderFromClause right
909+ renderSQL left <+> "LEFT OUTER JOIN" <+> renderSQL right
916 <+> "ON" <+> renderSQL on
910 <+> "ON" <+> renderSQL on
918{- | @left & rightOuterJoin right on@. First, an inner join is performed.
912{- | @left & rightOuterJoin right on@. First, an inner join is performed.
@@ -922,15 +916,15 @@ leftOuterJoin right on left = UnsafeFromClause $
922 have a row for each row in @right@.
916 have a row for each row in @right@.
924rightOuterJoin
918rightOuterJoin
925− :: FromClause db params right
919+ :: FromClause outer commons schemas params right
926 -- ^ right
920 -- ^ right
927− -> Condition db params 'Ungrouped (Join left right)
921+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
928 -- ^ @on@ condition
922 -- ^ @on@ condition
929− -> FromClause db params left
923+ -> FromClause outer commons schemas params left
930 -- ^ left
924 -- ^ left
931− -> FromClause db params (Join (NullifyFrom left) right)
925+ -> FromClause outer commons schemas params (Join (NullifyFrom left) right)
932rightOuterJoin right on left = UnsafeFromClause $
926rightOuterJoin right on left = UnsafeFromClause $
933− renderFromClause left <+> "RIGHT OUTER JOIN" <+> renderFromClause right
927+ renderSQL left <+> "RIGHT OUTER JOIN" <+> renderSQL right
934 <+> "ON" <+> renderSQL on
928 <+> "ON" <+> renderSQL on
936{- | @left & fullOuterJoin right on@. First, an inner join is performed.
930{- | @left & fullOuterJoin right on@. First, an inner join is performed.
@@ -941,23 +935,23 @@ rightOuterJoin right on left = UnsafeFromClause $
941 is added.
935 is added.
943fullOuterJoin
937fullOuterJoin
944− :: FromClause db params right
938+ :: FromClause outer commons schemas params right
945 -- ^ right
939 -- ^ right
946− -> Condition db params 'Ungrouped (Join left right)
940+ -> Condition outer commons 'Ungrouped schemas params (Join left right)
947 -- ^ @on@ condition
941 -- ^ @on@ condition
948− -> FromClause db params left
942+ -> FromClause outer commons schemas params left
949 -- ^ left
943 -- ^ left
950− -> FromClause db params
944+ -> FromClause outer commons schemas params
951 (Join (NullifyFrom left) (NullifyFrom right))
945 (Join (NullifyFrom left) (NullifyFrom right))
952fullOuterJoin right on left = UnsafeFromClause $
946fullOuterJoin right on left = UnsafeFromClause $
953− renderFromClause left <+> "FULL OUTER JOIN" <+> renderFromClause right
947+ renderSQL left <+> "FULL OUTER JOIN" <+> renderSQL right
954 <+> "ON" <+> renderSQL on
948 <+> "ON" <+> renderSQL on
956{-----------------------------------------
950{-----------------------------------------
958-----------------------------------------}
952-----------------------------------------}
960−-- | `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
961-- 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
962-- in all the columns listed. @By \#col@ will reference an unambiguous
956-- in all the columns listed. @By \#col@ will reference an unambiguous
963-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
957-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
@@ -977,6 +971,10 @@ data By
977deriving instance Show (By from by)
971deriving instance Show (By from by)
978deriving instance Eq (By from by)
972deriving instance Eq (By from by)
979deriving 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
981instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
979instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
982 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
980 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
@@ -988,424 +986,113 @@ instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])
988 => IsQualified rel col (NP (By rels) bys) where
986 => IsQualified rel col (NP (By rels) bys) where
989 rel ! col = By2 rel col :* Nil
987 rel ! col = By2 rel col :* Nil
992−renderBy :: By from by -> ByteString
994− By1 column -> renderSQL column
995− By2 rel column -> renderSQL rel <> "." <> renderSQL column
997-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
989-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
998-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
990-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
999-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
991-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
1000-- done on @NoGroups@ while all output `Expression`s must be aggregated
992-- done on @NoGroups@ while all output `Expression`s must be aggregated
1001-- in @Group Nil@. In general, all output `Expression`s in the
993-- in @Group Nil@. In general, all output `Expression`s in the
1002-- complement of @bys@ must be aggregated in @Group bys@.
994-- complement of @bys@ must be aggregated in @Group bys@.
995+newtype GroupByClause grp from = UnsafeGroupByClause
996+ { renderGroupByClause :: ByteString }
997+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1003−data GroupByClause grp from where
998+instance RenderSQL (GroupByClause grp from) where
999+ renderSQL = renderGroupByClause
1004− NoGroups :: GroupByClause 'Ungrouped from
1000+noGroups :: GroupByClause 'Ungrouped from
1005− Group
1001+noGroups = UnsafeGroupByClause ""
1006− :: SListI bys
1003+ :: SListI bys
1007− => NP (By from) bys
1004+ => NP (By from) bys
1008− -> GroupByClause ('Grouped bys) from
1005+ -> GroupByClause ('Grouped bys) from
1009−
1006+group bys = UnsafeGroupByClause $ case bys of
1010−-- | Renders a `GroupByClause`.
1011−renderGroupByClause :: GroupByClause grp from -> ByteString
1012−renderGroupByClause = \case
1014− Group Nil -> ""
1007+ Nil -> ""
1015− Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
1008+ bys' -> " GROUP BY" <+> renderCommaSeparated renderSQL bys'
1017-- | 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.
1018-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1011-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1019-- `TableExpression` must use `Having` whose conditions are combined with
1012-- `TableExpression` must use `Having` whose conditions are combined with
1020-- `.&&`.
1013-- `.&&`.
1021−data HavingClause db params grp from where
1014+data HavingClause outer commons grp schemas params from where
1022− NoHaving :: HavingClause db params 'Ungrouped from
1015+ NoHaving :: HavingClause outer commons 'Ungrouped schemas params from
1024− :: [Condition db params ('Grouped bys) from]
1017+ :: [Condition outer commons ('Grouped bys) schemas params from]
1025− -> HavingClause db params ('Grouped bys) from
1018+ -> HavingClause outer commons ('Grouped bys) schemas params from
1026−deriving instance Show (HavingClause db params grp from)
1019+deriving instance Show (HavingClause outer commons grp schemas params from)
1027−deriving instance Eq (HavingClause db params grp from)
1020+deriving instance Eq (HavingClause outer commons grp schemas params from)
1028−deriving instance Ord (HavingClause db params grp from)
1021+deriving instance Ord (HavingClause outer commons grp schemas params from)
1030-- | Render a `HavingClause`.
1023-- | Render a `HavingClause`.
1031−renderHavingClause :: HavingClause db params grp from -> ByteString
1024+instance RenderSQL (HavingClause outer commons grp schemas params from) where
1032−renderHavingClause = \case
1025+ renderSQL = \case
1033− NoHaving -> ""
1026+ NoHaving -> ""
1034− Having [] -> ""
1027+ Having [] -> ""
1035− Having conditions ->
1028+ Having conditions ->
1036− " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1029+ " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1038−{-----------------------------------------
1040−-----------------------------------------}
1042−-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1043−-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1044−-- column to ascending or descending. Ascending order puts smaller values
1045−-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1046−-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1047−-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1048−-- determine whether nulls appear before or after non-null values in the sort
1049−-- ordering of a `Null` result column.
1050−data SortExpression db params grp from where
1052− :: Expression db params grp from ('NotNull ty)
1053− -> SortExpression db params grp from
1055− :: Expression db params grp from ('NotNull ty)
1056− -> SortExpression db params grp from
1058− :: Expression db params grp from ('Null ty)
1059− -> SortExpression db params grp from
1061− :: Expression db params grp from ('Null ty)
1062− -> SortExpression db params grp from
1064− :: Expression db params grp from ('Null ty)
1065− -> SortExpression db params grp from
1067− :: Expression db params grp from ('Null ty)
1068− -> SortExpression db params grp from
1069−deriving instance Show (SortExpression db params grp from)
1071−-- | Render a `SortExpression`.
1072−renderSortExpression :: SortExpression db params grp from -> ByteString
1073−renderSortExpression = \case
1074− Asc expression -> renderSQL expression <+> "ASC"
1075− Desc expression -> renderSQL expression <+> "DESC"
1076− AscNullsFirst expression -> renderSQL expression
1077− <+> "ASC NULLS FIRST"
1078− DescNullsFirst expression -> renderSQL expression
1079− <+> "DESC NULLS FIRST"
1080− AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
1081− DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
1083−unsafeSubqueryExpression
1085− -> Expression db params grp from ty
1086− -> Query db params '[alias ::: ty]
1087− -> Expression db params grp from (nullity 'PGbool)
1088−unsafeSubqueryExpression op x q = UnsafeExpression $
1089− renderSQL x <+> op <+> parenthesized (renderQuery q)
1091−unsafeRowSubqueryExpression
1094− -> NP (Aliased (Expression db params grp from)) row
1095− -> Query db params row
1096− -> Expression db params grp from (nullity 'PGbool)
1097−unsafeRowSubqueryExpression op xs q = UnsafeExpression $
1098− renderSQL (row xs) <+> op <+> parenthesized (renderQuery q)
1100−-- | The right-hand side is a sub`Query`, which must return exactly one column.
1101−-- The left-hand expression is evaluated and compared to each row of the
1102−-- sub`Query` result. The result of `in_` is `true` if any equal subquery row is found.
1103−-- The result is `false` if no equal row is found
1104−-- (including the case where the subquery returns no rows).
1106−-- >>> printSQL $ true `in_` values_ (true `as` #foo)
1107−-- TRUE IN (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1109− :: Expression db params grp from ty -- ^ expression
1110− -> Query db params '[alias ::: ty] -- ^ subquery
1111− -> Expression db params grp from (nullity 'PGbool)
1112−in_ = unsafeSubqueryExpression "IN"
1114−{- | The left-hand side of this form of `rowIn` is a row constructor.
1115−The right-hand side is a sub`Query`,
1116−which must return exactly as many columns as
1117−there are expressions in the left-hand row.
1118−The left-hand expressions are evaluated and compared row-wise to each row
1119−of the subquery result. The result of `rowIn`
1120−is `true` if any equal subquery row is found.
1121−The result is `false` if no equal row is found
1122−(including the case where the subquery returns no rows).
1124−>>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1125−>>> printSQL $ myRow `rowIn` values_ myRow
1126−ROW(1, FALSE) IN (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1130− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1131− -> Query db params row -- ^ subquery
1132− -> Expression db params grp from (nullity 'PGbool)
1133−rowIn = unsafeRowSubqueryExpression "IN"
1135−-- | >>> printSQL $ true `eqAll` values_ (true `as` #foo)
1136−-- TRUE = ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1138− :: Expression db params grp from ty -- ^ expression
1139− -> Query db params '[alias ::: ty] -- ^ subquery
1140− -> Expression db params grp from (nullity 'PGbool)
1141−eqAll = unsafeSubqueryExpression "= ALL"
1143−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1144−-- >>> printSQL $ myRow `rowEqAll` values_ myRow
1145−-- ROW(1, FALSE) = ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1148− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1149− -> Query db params row -- ^ subquery
1150− -> Expression db params grp from (nullity 'PGbool)
1151−rowEqAll = unsafeRowSubqueryExpression "= ALL"
1153−-- | >>> printSQL $ true `eqAny` values_ (true `as` #foo)
1154−-- TRUE = ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1156− :: Expression db params grp from ty -- ^ expression
1157− -> Query db params '[alias ::: ty] -- ^ subquery
1158− -> Expression db params grp from (nullity 'PGbool)
1159−eqAny = unsafeSubqueryExpression "= ANY"
1161−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1162−-- >>> printSQL $ myRow `rowEqAny` values_ myRow
1163−-- ROW(1, FALSE) = ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1166− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1167− -> Query db params row -- ^ subquery
1168− -> Expression db params grp from (nullity 'PGbool)
1169−rowEqAny = unsafeRowSubqueryExpression "= ANY"
1171−-- | >>> printSQL $ true `neqAll` values_ (true `as` #foo)
1172−-- TRUE <> ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1174− :: Expression db params grp from ty -- ^ expression
1175− -> Query db params '[alias ::: ty] -- ^ subquery
1176− -> Expression db params grp from (nullity 'PGbool)
1177−neqAll = unsafeSubqueryExpression "<> ALL"
1179−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1180−-- >>> printSQL $ myRow `rowNeqAll` values_ myRow
1181−-- ROW(1, FALSE) <> ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1184− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1185− -> Query db params row -- ^ subquery
1186− -> Expression db params grp from (nullity 'PGbool)
1187−rowNeqAll = unsafeRowSubqueryExpression "<> ALL"
1189−-- | >>> printSQL $ true `neqAny` values_ (true `as` #foo)
1190−-- TRUE <> ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1192− :: Expression db params grp from ty -- ^ expression
1193− -> Query db params '[alias ::: ty] -- ^ subquery
1194− -> Expression db params grp from (nullity 'PGbool)
1195−neqAny = unsafeSubqueryExpression "<> ANY"
1197−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1198−-- >>> printSQL $ myRow `rowNeqAny` values_ myRow
1199−-- ROW(1, FALSE) <> ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1202− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1203− -> Query db params row -- ^ subquery
1204− -> Expression db params grp from (nullity 'PGbool)
1205−rowNeqAny = unsafeRowSubqueryExpression "<> ANY"
1207−-- | >>> printSQL $ true `allLt` values_ (true `as` #foo)
1208−-- TRUE ALL < (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1210− :: Expression db params grp from ty -- ^ expression
1211− -> Query db params '[alias ::: ty] -- ^ subquery
1212− -> Expression db params grp from (nullity 'PGbool)
1213−allLt = unsafeSubqueryExpression "ALL <"
1215−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1216−-- >>> printSQL $ myRow `rowLtAll` values_ myRow
1217−-- ROW(1, FALSE) ALL < (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1220− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1221− -> Query db params row -- ^ subquery
1222− -> Expression db params grp from (nullity 'PGbool)
1223−rowLtAll = unsafeRowSubqueryExpression "ALL <"
1225−-- | >>> printSQL $ true `ltAny` values_ (true `as` #foo)
1226−-- TRUE ANY < (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1228− :: Expression db params grp from ty -- ^ expression
1229− -> Query db params '[alias ::: ty] -- ^ subquery
1230− -> Expression db params grp from (nullity 'PGbool)
1231−ltAny = unsafeSubqueryExpression "ANY <"
1233−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1234−-- >>> printSQL $ myRow `rowLtAll` values_ myRow
1235−-- ROW(1, FALSE) ALL < (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1238− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1239− -> Query db params row -- ^ subquery
1240− -> Expression db params grp from (nullity 'PGbool)
1241−rowLtAny = unsafeRowSubqueryExpression "ANY <"
1243−-- | >>> printSQL $ true `lteAll` values_ (true `as` #foo)
1244−-- TRUE <= ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1246− :: Expression db params grp from ty -- ^ expression
1247− -> Query db params '[alias ::: ty] -- ^ subquery
1248− -> Expression db params grp from (nullity 'PGbool)
1249−lteAll = unsafeSubqueryExpression "<= ALL"
1251−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1252−-- >>> printSQL $ myRow `rowLteAll` values_ myRow
1253−-- ROW(1, FALSE) <= ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1256− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1257− -> Query db params row -- ^ subquery
1258− -> Expression db params grp from (nullity 'PGbool)
1259−rowLteAll = unsafeRowSubqueryExpression "<= ALL"
1261−-- | >>> printSQL $ true `lteAny` values_ (true `as` #foo)
1262−-- TRUE <= ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1264− :: Expression db params grp from ty -- ^ expression
1265− -> Query db params '[alias ::: ty] -- ^ subquery
1266− -> Expression db params grp from (nullity 'PGbool)
1267−lteAny = unsafeSubqueryExpression "<= ANY"
1269−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1270−-- >>> printSQL $ myRow `rowLteAny` values_ myRow
1271−-- ROW(1, FALSE) <= ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1274− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1275− -> Query db params row -- ^ subquery
1276− -> Expression db params grp from (nullity 'PGbool)
1277−rowLteAny = unsafeRowSubqueryExpression "<= ANY"
1279−-- | >>> printSQL $ true `gtAll` values_ (true `as` #foo)
1280−-- TRUE > ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1282− :: Expression db params grp from ty -- ^ expression
1283− -> Query db params '[alias ::: ty] -- ^ subquery
1284− -> Expression db params grp from (nullity 'PGbool)
1285−gtAll = unsafeSubqueryExpression "> ALL"
1287−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1288−-- >>> printSQL $ myRow `rowGtAll` values_ myRow
1289−-- ROW(1, FALSE) > ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1292− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1293− -> Query db params row -- ^ subquery
1294− -> Expression db params grp from (nullity 'PGbool)
1295−rowGtAll = unsafeRowSubqueryExpression "> ALL"
1297−-- | >>> printSQL $ true `gtAny` values_ (true `as` #foo)
1298−-- TRUE > ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1300− :: Expression db params grp from ty -- ^ expression
1301− -> Query db params '[alias ::: ty] -- ^ subquery
1302− -> Expression db params grp from (nullity 'PGbool)
1303−gtAny = unsafeSubqueryExpression "> ANY"
1305−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1306−-- >>> printSQL $ myRow `rowGtAny` values_ myRow
1307−-- ROW(1, FALSE) > ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1310− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1311− -> Query db params row -- ^ subquery
1312− -> Expression db params grp from (nullity 'PGbool)
1313−rowGtAny = unsafeRowSubqueryExpression "> ANY"
1315−-- | >>> printSQL $ true `gteAll` values_ (true `as` #foo)
1316−-- TRUE >= ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1318− :: Expression db params grp from ty -- ^ expression
1319− -> Query db params '[alias ::: ty] -- ^ subquery
1320− -> Expression db params grp from (nullity 'PGbool)
1321−gteAll = unsafeSubqueryExpression ">= ALL"
1323−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1324−-- >>> printSQL $ myRow `rowGteAll` values_ myRow
1325−-- ROW(1, FALSE) >= ALL (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1328− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1329− -> Query db params row -- ^ subquery
1330− -> Expression db params grp from (nullity 'PGbool)
1331−rowGteAll = unsafeRowSubqueryExpression ">= ALL"
1333−-- | >>> printSQL $ true `gteAny` values_ (true `as` #foo)
1334−-- TRUE >= ANY (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))
1336− :: Expression db params grp from ty -- ^ expression
1337− -> Query db params '[alias ::: ty] -- ^ subquery
1338− -> Expression db params grp from (nullity 'PGbool)
1339−gteAny = unsafeSubqueryExpression ">= ANY"
1341−-- | >>> let myRow = 1 `as` #foo :* false `as` #bar :: NP (Aliased (Expression db params grp from)) '["foo" ::: 'NotNull 'PGint2, "bar" ::: 'NotNull 'PGbool]
1342−-- >>> printSQL $ myRow `rowGteAny` values_ myRow
1343−-- ROW(1, FALSE) >= ANY (SELECT * FROM (VALUES (1, FALSE)) AS t ("foo", "bar"))
1346− => NP (Aliased (Expression db params grp from)) row -- ^ row constructor
1347− -> Query db params row -- ^ subquery
1348− -> Expression db params grp from (nullity 'PGbool)
1349−rowGteAny = unsafeRowSubqueryExpression ">= ANY"
1351-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1031-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1352data CommonTableExpression statement
1032data CommonTableExpression statement
1033+ (schemas :: SchemasType)
1353 (params :: [NullityType])
1034 (params :: [NullityType])
1354− (db0 :: DBType)
1035+ (commons0 :: FromType)
1355− (db1 :: DBType) where
1036+ (commons1 :: FromType) where
1356 CommonTableExpression
1037 CommonTableExpression
1357− :: Aliased (statement (commons :=> schemas) params) (cte ::: common)
1038+ :: Aliased (statement commons schemas params) (cte ::: common)
1358− -> CommonTableExpression statement params
1039+ -> CommonTableExpression statement schemas params commons (cte ::: common ': commons)
1359− (commons :=> schemas) ((cte ::: common ': commons) :=> schemas)
1361 ( KnownSymbol cte
1041 ( KnownSymbol cte
1362− , db0 ~ (commons :=> schemas)
1363− , db1 ~ ((cte ::: common ': commons) :=> schemas)
1042+ , commons1 ~ (cte ::: common ': commons)
1364 ) => Aliasable cte
1043 ) => Aliasable cte
1365− (statement db0 params common)
1044+ (statement commons schemas params common)
1366− (CommonTableExpression statement params db0 db1) where
1045+ (CommonTableExpression statement schemas params commons commons1) where
1367 statement `as` cte = CommonTableExpression (statement `as` cte)
1046 statement `as` cte = CommonTableExpression (statement `as` cte)
1369 ( KnownSymbol cte
1048 ( KnownSymbol cte
1370− , db0 ~ (commons :=> schemas)
1371− , db1 ~ ((cte ::: common ': commons) :=> schemas)
1049+ , commons1 ~ (cte ::: common ': commons)
1372 ) => Aliasable cte
1050 ) => Aliasable cte
1373− (statement db0 params common)
1051+ (statement commons schemas params common)
1374− (AlignedList (CommonTableExpression statement params) db0 db1) where
1052+ (Path (CommonTableExpression statement schemas params) commons commons1) where
1375− statement `as` cte = single (statement `as` cte)
1053+ statement `as` cte = csingleton (statement `as` cte)
1377−-- | render a `CommonTableExpression`.
1055+instance (forall c s p r. RenderSQL (statement c s p r)) => RenderSQL
1378−renderCommonTableExpression
1379− :: (forall db ps row. statement db ps row -> ByteString) -- ^ render statement
1380− -> CommonTableExpression statement params db0 db1 -> ByteString
1056+ (CommonTableExpression statement schemas params commons0 commons1) where
1381−renderCommonTableExpression renderStatement
1382− (CommonTableExpression (statement `As` alias)) =
1057+ renderSQL (CommonTableExpression (statement `As` cte)) =
1383− renderSQL alias <+> "AS" <+> parenthesized (renderStatement statement)
1058+ renderSQL cte <+> "AS" <+> parenthesized (renderSQL statement)
1385−-- | render a non-empty `AlignedList` of `CommonTableExpression`s.
1386−renderCommonTableExpressions
1387− :: (forall db ps row. statement db ps row -> ByteString) -- ^ render statement
1388− -> CommonTableExpression statement params db0 db1
1389− -> AlignedList (CommonTableExpression statement params) db1 db2
1391−renderCommonTableExpressions renderStatement cte ctes =
1392− renderCommonTableExpression renderStatement cte <> case ctes of
1394− cte' :>> ctes' -> "," <+>
1395− renderCommonTableExpressions renderStatement cte' ctes'
1397-- | `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.
1398-- 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
1399-- defining temporary tables that exist just for one query.
1062-- defining temporary tables that exist just for one query.
1400class With statement where
1063class With statement where
1402− :: AlignedList (CommonTableExpression statement params) db0 db1
1065+ :: Path (CommonTableExpression statement schemas params) commons0 commons1
1403 -- ^ common table expressions
1066 -- ^ common table expressions
1404− -> statement db1 params row
1067+ -> statement commons1 schemas params row
1405 -- ^ larger query
1068 -- ^ larger query
1406− -> statement db0 params row
1069+ -> statement commons0 schemas params row
1407−instance With Query where
1070+instance With (Query outer) where
1408 with Done query = query
1071 with Done query = query
1409− with (cte :>> ctes) query = UnsafeQuery $
1072+ with ctes query = UnsafeQuery $
1410− "WITH" <+> renderCommonTableExpressions renderQuery cte ctes
1073+ "WITH" <+> commaSeparated (ctoList renderSQL ctes) <+> renderSQL query
1411− <+> 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