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