@@ -1,7 +1,7 @@
2Module: Squeal.PostgreSQL.Query
2Module: Squeal.PostgreSQL.Query
3Description: Squeal queries
3Description: Squeal queries
4−Copyright: (c) Eitan Chatav, 2019
4+Copyright: (c) Eitan Chatav, 2017
5Maintainer: eitan@morphism.tech
5Maintainer: eitan@morphism.tech
6Stability: experimental
6Stability: experimental
@@ -17,12 +17,8 @@ Squeal queries.
17 , GeneralizedNewtypeDeriving
17 , GeneralizedNewtypeDeriving
18 , LambdaCase
18 , LambdaCase
19 , MultiParamTypeClasses
19 , MultiParamTypeClasses
21 , OverloadedStrings
20 , OverloadedStrings
22− , QuantifiedConstraints
23− , ScopedTypeVariables
24 , StandaloneDeriving
21 , StandaloneDeriving
26 , TypeFamilies
22 , TypeFamilies
27 , TypeInType
23 , TypeInType
28 , TypeOperators
24 , TypeOperators
@@ -32,58 +28,101 @@ Squeal queries.
33module Squeal.PostgreSQL.Query
29module Squeal.PostgreSQL.Query
34 ( -- * Queries
30 ( -- * Queries
35− Query_
31+ Query (UnsafeQuery, renderQuery)
50 , unionAll
33 , unionAll
51 , intersect
34 , intersect
52 , intersectAll
35 , intersectAll
54 , exceptAll
37 , exceptAll
55− -- ** With
38+ -- * Select
56− , With (..)
39+ , select
57− , CommonTableExpression (..)
40+ , selectDistinct
58− , withRecursive
41+ , selectStar
44+ , selectDistinctDotStar
59 -- * Table Expressions
47 -- * Table Expressions
60 , TableExpression (..)
48 , TableExpression (..)
49+ , renderTableExpression
57+ -- ** JSON table expressions
64+ , jsonPopulateRecordAs
65+ , jsonbPopulateRecordAs
66+ , jsonPopulateRecordSetAs
67+ , jsonbPopulateRecordSetAs
67− -- * From Clauses
72+ -- * From
68 , FromClause (..)
73 , FromClause (..)
70 , subquery
75 , subquery
73 , crossJoin
77 , crossJoin
74 , innerJoin
78 , innerJoin
75 , leftOuterJoin
79 , leftOuterJoin
76 , rightOuterJoin
80 , rightOuterJoin
77 , fullOuterJoin
81 , fullOuterJoin
78 -- * Grouping
82 -- * Grouping
79− , By (..)
83+ , By (By1, By2)
80− , GroupByClause (..)
85+ , GroupByClause (NoGroups, Group)
86+ , renderGroupByClause
81− , HavingClause (..)
87+ , HavingClause (NoHaving, Having)
90+ , SortExpression (..)
91+ , renderSortExpression
92+ -- * Subquery expressions
93+ , unsafeSubqueryExpression
94+ , unsafeRowSubqueryExpression
84import Control.DeepSeq
123import Control.DeepSeq
85import Data.ByteString (ByteString)
124import Data.ByteString (ByteString)
86−import Data.Kind (Type)
125+import Data.Monoid hiding (All)
87import Data.String
126import Data.String
88import Data.Word
127import Data.Word
89import Generics.SOP hiding (from)
128import Generics.SOP hiding (from)
@@ -91,76 +130,25 @@ import GHC.TypeLits
92import qualified GHC.Generics as GHC
131import qualified GHC.Generics as GHC
94−import Squeal.PostgreSQL.Alias
95import Squeal.PostgreSQL.Expression
133import 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
101import Squeal.PostgreSQL.Render
134import Squeal.PostgreSQL.Render
102import Squeal.PostgreSQL.Schema
135import 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
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`,
138+The process of retrieving or the command to retrieve data from a database
135−against which the query is type-checked, an input @parameters@ Haskell `Type`,
139+is called a `Query`. The `select`, `selectStar`, `selectDotStar`,
136−and an ouput row Haskell `Type`.
140+`selectDistinct`, `selectDistinctStar` and `selectDistinctDotStar` commands
137−
141+are used to specify queries.
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.
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)
156simple query:
143simple query:
158−>>> type Columns = '["col1" ::: 'NoDef :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]
159−>>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
162− query :: Query_ (Public Schema) () (Row Int32 Int32)
147+ query :: Query
148+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
150+ '["col" ::: 'Null 'PGint4]
163− query = select Star (from (table #tab))
151+ query = selectStar (from (table #tab))
164in printSQL query
152in printSQL query
166SELECT * FROM "tab" AS "tab"
154SELECT * FROM "tab" AS "tab"
@@ -169,22 +157,34 @@ restricted query:
172− query :: Query_ (Public Schema) () (Row Int32 Int32)
160+ query :: Query
161+ '[ "tab" ::: 'Table ('[] :=>
162+ '[ "col1" ::: 'NoDef :=> 'NotNull 'PGint4
163+ , "col2" ::: 'NoDef :=> 'NotNull 'PGint4 ])]
165+ '[ "sum" ::: 'NotNull 'PGint4
166+ , "col1" ::: 'NotNull 'PGint4 ]
174− select_ ((#col1 + #col2) `as` #col1 :* #col1 `as` #col2)
169+ ((#col1 + #col2) `as` #sum :* #col1)
175 ( from (table #tab)
170 ( from (table #tab)
176 & where_ (#col1 .> #col2)
171 & where_ (#col1 .> #col2)
177 & where_ (#col2 .> 0) )
172 & where_ (#col2 .> 0) )
178in printSQL query
173in printSQL query
180−SELECT ("col1" + "col2") AS "col1", "col1" AS "col2" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > 0))
175+SELECT ("col1" + "col2") AS "sum", "col1" AS "col1" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > 0))
186− query :: Query_ (Public Schema) () (Row Int32 Int32)
181+ query :: Query
182+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
184+ '["col" ::: 'Null 'PGint4]
187− query = select Star (from (subquery (select Star (from (table #tab)) `as` #sub)))
187+ (from (subquery (selectStar (from (table #tab)) `as` #sub)))
188in printSQL query
188in printSQL query
190SELECT * FROM (SELECT * FROM "tab" AS "tab") AS "sub"
190SELECT * FROM (SELECT * FROM "tab" AS "tab") AS "sub"
@@ -193,8 +193,12 @@ limits and offsets:
196− query :: Query_ (Public Schema) () (Row Int32 Int32)
196+ query :: Query
197+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
199+ '["col" ::: 'Null 'PGint4]
197− query = select Star (from (table #tab) & limit 100 & offset 2 & limit 50 & offset 2)
201+ (from (table #tab) & limit 100 & offset 2 & limit 50 & offset 2)
198in printSQL query
202in printSQL query
200SELECT * FROM "tab" AS "tab" LIMIT 50 OFFSET 4
204SELECT * FROM "tab" AS "tab" LIMIT 50 OFFSET 4
@@ -203,80 +207,85 @@ parameterized query:
206− query :: Query_ (Public Schema) (Only Int32) (Row Int32 Int32)
210+ query :: Query
211+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGfloat8])]
212+ '[ 'NotNull 'PGfloat8]
213+ '["col" ::: 'NotNull 'PGfloat8]
207− query = select Star (from (table #tab) & where_ (#col1 .> param @1))
215+ (from (table #tab) & where_ (#col .> param @1))
208in printSQL query
216in printSQL query
210−SELECT * FROM "tab" AS "tab" WHERE ("col1" > ($1 :: int4))
218+SELECT * FROM "tab" AS "tab" WHERE ("col" > ($1 :: float8))
212aggregation query:
220aggregation query:
216− query :: Query_ (Public Schema) () (Row Int64 Int32)
224+ query :: Query
225+ '[ "tab" ::: 'Table ('[] :=>
226+ '[ "col1" ::: 'NoDef :=> 'NotNull 'PGint4
227+ , "col2" ::: 'NoDef :=> 'NotNull 'PGint4 ])]
229+ '[ "sum" ::: 'NotNull 'PGint4
230+ , "col1" ::: 'NotNull 'PGint4 ]
218− select_ ((fromNull 0 (sum_ (All #col2))) `as` #col1 :* #col1 `as` #col2)
232+ select (sum_ #col2 `as` #sum :* #col1)
219 ( from (table (#tab `as` #table1))
233 ( from (table (#tab `as` #table1))
220 & groupBy #col1
234 & groupBy #col1
221− & having (sum_ (Distinct #col2) .> 1) )
235+ & having (#col1 + sum_ #col2 .> 1) )
222in printSQL query
236in printSQL query
224−SELECT COALESCE(sum(ALL "col2"), 0) AS "col1", "col1" AS "col2" FROM "tab" AS "table1" GROUP BY "col1" HAVING (sum(DISTINCT "col2") > 1)
238+SELECT sum("col2") AS "sum", "col1" AS "col1" FROM "tab" AS "table1" GROUP BY "col1" HAVING (("col1" + sum("col2")) > 1)
226sorted query:
240sorted query:
230− query :: Query_ (Public Schema) () (Row Int32 Int32)
244+ query :: Query
245+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
247+ '["col" ::: 'Null 'PGint4]
231− query = select Star (from (table #tab) & orderBy [#col1 & Asc])
249+ (from (table #tab) & orderBy [#col & AscNullsFirst])
232in printSQL query
250in printSQL query
234−SELECT * FROM "tab" AS "tab" ORDER BY "col1" ASC
252+SELECT * FROM "tab" AS "tab" ORDER BY "col" ASC NULLS FIRST
238−>>> :{
256+>>> :set -XFlexibleContexts
240− '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
241− , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
242− , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
243− , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4 ]
247−type OrdersConstraints =
248− '["pk_orders" ::: PrimaryKey '["id"]
249− ,"fk_customers" ::: ForeignKey '["customer_id"] "customers" '["id"]
250− ,"fk_shippers" ::: ForeignKey '["shipper_id"] "shippers" '["id"] ]
253−>>> type NamesColumns = '["id" ::: 'NoDef :=> 'NotNull 'PGint4, "name" ::: 'NoDef :=> 'NotNull 'PGtext]
254−>>> type CustomersConstraints = '["pk_customers" ::: PrimaryKey '["id"]]
255−>>> type ShippersConstraints = '["pk_shippers" ::: PrimaryKey '["id"]]
258− '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
259− , "customers" ::: 'Table (CustomersConstraints :=> 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
275− query :: Query_ (Public OrdersSchema) () Order
259+ query :: Query
260+ '[ "orders" ::: 'Table (
261+ '["pk_orders" ::: PrimaryKey '["id"]
262+ ,"fk_customers" ::: ForeignKey '["customer_id"] "customers" '["id"]
263+ ,"fk_shippers" ::: ForeignKey '["shipper_id"] "shippers" '["id"]] :=>
264+ '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
265+ , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
266+ , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
267+ , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4
269+ , "customers" ::: 'Table (
270+ '["pk_customers" ::: PrimaryKey '["id"]] :=>
271+ '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
272+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
274+ , "shippers" ::: 'Table (
275+ '["pk_shippers" ::: PrimaryKey '["id"]] :=>
276+ '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
277+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
281+ '[ "order_price" ::: 'NotNull 'PGfloat4
282+ , "customer_name" ::: 'NotNull 'PGtext
283+ , "shipper_name" ::: 'NotNull 'PGtext
276− query = select_
285+ query = select
277− ( #o ! #price `as` #price :*
286+ ( #o ! #price `as` #order_price :*
278− #c ! #name `as` #customerName :*
287+ #c ! #name `as` #customer_name :*
279− #s ! #name `as` #shipperName )
288+ #s ! #name `as` #shipper_name )
280 ( from (table (#orders `as` #o)
289 ( from (table (#orders `as` #o)
281 & innerJoin (table (#customers `as` #c))
290 & innerJoin (table (#customers `as` #c))
282 (#o ! #customer_id .== #c ! #id)
291 (#o ! #customer_id .== #c ! #id)
@@ -284,345 +293,190 @@ let
284 (#o ! #shipper_id .== #s ! #id)) )
293 (#o ! #shipper_id .== #s ! #id)) )
285in printSQL query
294in printSQL query
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")
296+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")
289self-join:
298self-join:
293− query :: Query_ (Public Schema) () (Row Int32 Int32)
302+ query :: Query
294− query = select
303+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
295− (#t1 & DotStar)
304+ '[]
305+ '["col" ::: 'Null 'PGint4]
306+ query = selectDotStar #t1
296 (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
307 (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
297in printSQL query
308in printSQL query
299SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
310SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
305− query :: Query_ schemas () (Row String Bool)
307− ("true" `as` #col1 :* true `as` #col2)
308− ["false" `as` #col1 :* false `as` #col2]
311−SELECT * FROM (VALUES (E'true', TRUE), (E'false', FALSE)) AS t ("col1", "col2")
313set operations:
312set operations:
317− query :: Query_ (Public Schema) () (Row Int32 Int32)
316+ query :: Query
318− query = select Star (from (table #tab)) `unionAll` select Star (from (table #tab))
317+ '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]
319−in printSQL query
318+ '[]
320−:}
319+ '["col" ::: 'Null 'PGint4]
321−(SELECT * FROM "tab" AS "tab") UNION ALL (SELECT * FROM "tab" AS "tab")
327− query :: Query_ (Public Schema) () (Row Int32 Int32)
329− select Star (from (table #tab)) `as` #cte1 :>>
330− select Star (from (common #cte1)) `as` #cte2
331− ) (select Star (from (common #cte2)))
334−WITH "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))
321+ selectStar (from (table #tab))
355− & where_ (exists (
322+ `unionAll`
356− select Star (from (table (#tab `as` #t2))
323+ selectStar (from (table #tab))
357− & where_ (#t2 ! #col2 .== #t1 ! #col1)))))
358in printSQL query
324in printSQL query
360−SELECT "col1" AS "fromOnly" FROM "tab" AS "t1" WHERE EXISTS (SELECT * FROM "tab" AS "t2" WHERE ("t2"."col2" = "t1"."col1"))
326+(SELECT * FROM "tab" AS "tab") UNION ALL (SELECT * FROM "tab" AS "tab")
363−type family Query_
328+newtype Query
364− (schemas :: SchemasType)
329+ (schema :: SchemaType)
365− (parameters :: Type)
330+ (params :: [NullityType])
366− (row :: Type) where
331+ (columns :: RowType)
367− Query_ schemas params row =
332+ = UnsafeQuery { renderQuery :: ByteString }
368− Query '[] '[] schemas (TuplePG params) (RowPG row)
333+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
334+instance RenderSQL (Query schema params columns) where renderSQL = renderQuery
370-- | The results of two queries can be combined using the set operation
336-- | The results of two queries can be combined using the set operation
371-- `union`. Duplicate rows are eliminated.
337-- `union`. Duplicate rows are eliminated.
373− :: Query outer commons schemas params columns
339+ :: Query schema params columns
374− -> Query outer commons schemas params columns
340+ -> Query schema params columns
375− -> Query outer commons schemas params columns
341+ -> Query schema params columns
376q1 `union` q2 = UnsafeQuery $
342q1 `union` q2 = UnsafeQuery $
377− parenthesized (renderSQL q1)
343+ parenthesized (renderQuery q1)
378 <+> "UNION"
344 <+> "UNION"
379− <+> parenthesized (renderSQL q2)
345+ <+> parenthesized (renderQuery q2)
381-- | The results of two queries can be combined using the set operation
347-- | The results of two queries can be combined using the set operation
382-- `unionAll`, the disjoint union. Duplicate rows are retained.
348-- `unionAll`, the disjoint union. Duplicate rows are retained.
384− :: Query outer commons schemas params columns
350+ :: Query schema params columns
385− -> Query outer commons schemas params columns
351+ -> Query schema params columns
386− -> Query outer commons schemas params columns
352+ -> Query schema params columns
387q1 `unionAll` q2 = UnsafeQuery $
353q1 `unionAll` q2 = UnsafeQuery $
388− parenthesized (renderSQL q1)
354+ parenthesized (renderQuery q1)
389 <+> "UNION" <+> "ALL"
355 <+> "UNION" <+> "ALL"
390− <+> parenthesized (renderSQL q2)
356+ <+> parenthesized (renderQuery q2)
392-- | The results of two queries can be combined using the set operation
358-- | The results of two queries can be combined using the set operation
393-- `intersect`, the intersection. Duplicate rows are eliminated.
359-- `intersect`, the intersection. Duplicate rows are eliminated.
395− :: Query outer commons schemas params columns
361+ :: Query schema params columns
396− -> Query outer commons schemas params columns
362+ -> Query schema params columns
397− -> Query outer commons schemas params columns
363+ -> Query schema params columns
398q1 `intersect` q2 = UnsafeQuery $
364q1 `intersect` q2 = UnsafeQuery $
399− parenthesized (renderSQL q1)
365+ parenthesized (renderQuery q1)
400 <+> "INTERSECT"
366 <+> "INTERSECT"
401− <+> parenthesized (renderSQL q2)
367+ <+> parenthesized (renderQuery q2)
403-- | 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
404-- `intersectAll`, the intersection. Duplicate rows are retained.
370-- `intersectAll`, the intersection. Duplicate rows are retained.
405intersectAll
371intersectAll
406− :: Query outer commons schemas params columns
372+ :: Query schema params columns
407− -> Query outer commons schemas params columns
373+ -> Query schema params columns
408− -> Query outer commons schemas params columns
374+ -> Query schema params columns
409q1 `intersectAll` q2 = UnsafeQuery $
375q1 `intersectAll` q2 = UnsafeQuery $
410− parenthesized (renderSQL q1)
376+ parenthesized (renderQuery q1)
411 <+> "INTERSECT" <+> "ALL"
377 <+> "INTERSECT" <+> "ALL"
412− <+> parenthesized (renderSQL q2)
378+ <+> parenthesized (renderQuery q2)
414-- | 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
415-- `except`, the set difference. Duplicate rows are eliminated.
381-- `except`, the set difference. Duplicate rows are eliminated.
417− :: Query outer commons schemas params columns
383+ :: Query schema params columns
418− -> Query outer commons schemas params columns
384+ -> Query schema params columns
419− -> Query outer commons schemas params columns
385+ -> Query schema params columns
420q1 `except` q2 = UnsafeQuery $
386q1 `except` q2 = UnsafeQuery $
421− parenthesized (renderSQL q1)
387+ parenthesized (renderQuery q1)
422 <+> "EXCEPT"
388 <+> "EXCEPT"
423− <+> parenthesized (renderSQL q2)
389+ <+> parenthesized (renderQuery q2)
425-- | 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
426-- `exceptAll`, the set difference. Duplicate rows are retained.
392-- `exceptAll`, the set difference. Duplicate rows are retained.
428− :: Query outer commons schemas params columns
394+ :: Query schema params columns
429− -> Query outer commons schemas params columns
395+ -> Query schema params columns
430− -> Query outer commons schemas params columns
396+ -> Query schema params columns
431q1 `exceptAll` q2 = UnsafeQuery $
397q1 `exceptAll` q2 = UnsafeQuery $
432− parenthesized (renderSQL q1)
398+ parenthesized (renderQuery q1)
433 <+> "EXCEPT" <+> "ALL"
399 <+> "EXCEPT" <+> "ALL"
434− <+> parenthesized (renderSQL q2)
400+ <+> parenthesized (renderQuery q2)
436{-----------------------------------------
402{-----------------------------------------
437SELECT queries
403SELECT queries
438-----------------------------------------}
404-----------------------------------------}
440−{- | The simplest kinds of `Selection` are `Star` and `DotStar` which
441−emits all columns that a `TableExpression` produces. A select `List`
442−is a list of `Expression`s. A `Selection` could be a list of
443−`WindowFunction`s `Over` `WindowDefinition`. `Additional` `Selection`s can
444−be selected with `Also`.
446−data Selection outer commons grp schemas params from row where
448− :: HasUnique tab from row
449− => Selection outer commons 'Ungrouped schemas params from row
450− -- ^ `HasUnique` table in the `FromClause`
454− -- ^ `Has` table with `Alias`
455− -> Selection outer commons 'Ungrouped schemas params from row
458− => NP (Aliased (Expression outer commons grp schemas params from)) row
459− -- ^ `NP` list of `Aliased` `Expression`s
460− -> Selection outer commons grp schemas params from row
463− => NP (Aliased (WindowFunction outer commons grp schemas params from)) row
464− -- ^ `NP` list of `Aliased` `WindowFunction`s
465− -> WindowDefinition outer commons grp schemas params from
466− -> Selection outer commons grp schemas params from row
468− :: Selection outer commons grp schemas params from right
469− -- ^ `Additional` `Selection`
470− -> Selection outer commons grp schemas params from left
471− -> Selection outer commons grp schemas params from (Join left right)
472−instance Additional (Selection outer commons grp schemas params from) where
474−instance (KnownSymbol col, row ~ '[col ::: ty])
476− (Expression outer commons grp schemas params from ty)
477− (Selection outer commons grp schemas params from row) where
478− expr `as` col = List (expr `as` col)
479−instance (Has tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])
480− => IsQualified tab col
481− (Selection outer commons 'Ungrouped schemas params from row1) where
482− tab ! col = tab ! col `as` col
484− ( Has tab (Join outer from) row0
486− , row1 ~ '[col ::: ty]
487− , GroupedBy tab col bys )
488− => IsQualified tab col
489− (Selection outer commons ('Grouped bys) schemas params from row1) where
490− tab ! col = tab ! col `as` col
491−instance (HasUnique tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])
493− (Selection outer commons 'Ungrouped schemas params from row1) where
494− fromLabel = fromLabel @col `as` Alias
496− ( HasUnique tab (Join outer from) row0
498− , row1 ~ '[col ::: ty]
499− , GroupedBy tab col bys )
501− (Selection outer commons ('Grouped bys) schemas params from row1) where
502− fromLabel = fromLabel @col `as` Alias
504−instance RenderSQL (Selection outer commons grp schemas params from row) where
506− List list -> renderCommaSeparated (renderAliased renderSQL) list
508− DotStar tab -> renderSQL tab <> ".*"
509− Also right left -> renderSQL left <> ", " <> renderSQL right
510− Over winFns winDef ->
513− :: Aliased (WindowFunction outer commons grp schemas params from) field
515− renderOver (winFn `As` col) = renderSQL winFn
516− <+> "OVER" <+> parenthesized (renderSQL winDef)
517− <+> "AS" <+> renderSQL col
519− renderCommaSeparated renderOver winFns
522− (Selection outer commons grp schemas params from '["fromOnly" ::: 'NotNull 'PGtext]) where
523− fromString str = fromString str `as` Alias
525-- | the `TableExpression` in the `select` command constructs an intermediate
406-- | the `TableExpression` in the `select` command constructs an intermediate
526-- virtual table by possibly combining tables, views, eliminating rows,
407-- virtual table by possibly combining tables, views, eliminating rows,
527-- grouping, etc. This table is finally passed on to processing by
408-- grouping, etc. This table is finally passed on to processing by
528−-- the select list. The `Selection` determines which columns of
409+-- the select list. The select list determines which columns of
529-- the intermediate table are actually output.
410-- the intermediate table are actually output.
531− :: (SListI row, row ~ (x ': xs))
412+ :: SListI columns
532− => Selection outer commons grp schemas params from row
534− -> TableExpression outer commons grp schemas params from
535− -- ^ intermediate virtual table
536− -> Query outer commons schemas params row
537−select selection tabexpr = UnsafeQuery $
539− <+> renderSQL selection
540− <+> renderSQL tabexpr
542−-- | Like `select` but takes an `NP` list of `Expression`s instead
543−-- of a general `Selection`.
545− :: (SListI row, row ~ (x ': xs))
546− => NP (Aliased (Expression outer commons grp schemas params from)) row
413+ => NP (Aliased (Expression schema from grouping params)) (column ': columns)
547 -- ^ select list
414 -- ^ select list
548− -> TableExpression outer commons grp schemas params from
415+ -> TableExpression schema params from grouping
549 -- ^ intermediate virtual table
416 -- ^ intermediate virtual table
550− -> Query outer commons schemas params row
417+ -> Query schema params (column ': columns)
551−select_ = select . List
418+select list rels = UnsafeQuery $
420+ <+> renderCommaSeparated (renderAliasedAs renderExpression) list
421+ <+> renderTableExpression rels
553-- | After the select list has been processed, the result table can
423-- | After the select list has been processed, the result table can
554-- be subject to the elimination of duplicate rows using `selectDistinct`.
424-- be subject to the elimination of duplicate rows using `selectDistinct`.
555selectDistinct
425selectDistinct
556− :: (SListI columns, columns ~ (col ': cols))
426+ :: SListI columns
557− => Selection outer commons grp schemas params from columns
427+ => NP (Aliased (Expression schema from 'Ungrouped params)) (column ': columns)
558− -- ^ selection
428+ -- ^ select list
559− -> TableExpression outer commons grp schemas params from
429+ -> TableExpression schema params from 'Ungrouped
560 -- ^ intermediate virtual table
430 -- ^ intermediate virtual table
561− -> Query outer commons schemas params columns
431+ -> Query schema params (column ': columns)
562−selectDistinct selection tabexpr = UnsafeQuery $
432+selectDistinct list rels = UnsafeQuery $
563 "SELECT DISTINCT"
433 "SELECT DISTINCT"
564− <+> renderSQL selection
434+ <+> renderCommaSeparated (renderAliasedAs renderExpression) list
565− <+> renderSQL tabexpr
435+ <+> renderTableExpression rels
567−-- | Like `selectDistinct` but takes an `NP` list of `Expression`s instead
437+-- | The simplest kind of query is `selectStar` which emits all columns
568−-- of a general `Selection`.
438+-- that the table expression produces.
569−selectDistinct_
439+selectStar
570− :: (SListI columns, columns ~ (col ': cols))
440+ :: HasUnique relation from columns
571− => NP (Aliased (Expression outer commons grp schemas params from)) columns
573− -> TableExpression outer commons grp schemas params from
441+ => TableExpression schema params from 'Ungrouped
574 -- ^ intermediate virtual table
442 -- ^ intermediate virtual table
575− -> Query outer commons schemas params columns
443+ -> Query schema params columns
576−selectDistinct_ = selectDistinct . List
444+selectStar rels = UnsafeQuery $ "SELECT" <+> "*" <+> renderTableExpression rels
578−{-|
446+-- | A `selectDistinctStar` emits all columns that the table expression
579−`selectDistinctOn` keeps only the first row of each set of rows where
447+-- produces and eliminates duplicate rows.
580−the given expressions evaluate to equal. The DISTINCT ON expressions are
448+selectDistinctStar
581−interpreted using the same rules as for ORDER BY. ORDER BY is used to
449+ :: HasUnique relation from columns
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
450+ => TableExpression schema params from 'Ungrouped
598 -- ^ intermediate virtual table
451 -- ^ intermediate virtual table
599− -> Query outer commons schemas params columns
452+ -> Query schema params columns
600−selectDistinctOn distincts selection tab = UnsafeQuery $
453+selectDistinctStar rels = UnsafeQuery $
601− "SELECT DISTINCT ON"
454+ "SELECT DISTINCT" <+> "*" <+> renderTableExpression rels
602− <+> parenthesized (commaSeparated (renderDistinctOn <$> distincts))
455+
603− <+> renderSQL selection
456+-- | When working with multiple tables, it can also be useful to ask
604− <+> renderSQL (tab {orderByClause = distincts <> orderByClause tab})
457+-- for all the columns of a particular table, using `selectDotStar`.
605− where
458+selectDotStar
606− renderDistinctOn = \case
459+ :: Has relation from columns
607− Asc expression -> renderSQL expression
460+ => Alias relation
608− Desc expression -> renderSQL expression
461+ -- ^ particular virtual subtable
609− AscNullsFirst expression -> renderSQL expression
462+ -> TableExpression schema params from 'Ungrouped
610− DescNullsFirst expression -> renderSQL expression
463+ -- ^ intermediate virtual table
611− AscNullsLast expression -> renderSQL expression
464+ -> Query schema params columns
612− DescNullsLast expression -> renderSQL expression
465+selectDotStar rel tab = UnsafeQuery $
613−
466+ "SELECT" <+> renderAlias rel <> ".*" <+> renderTableExpression tab
614−-- | Like `selectDistinctOn` but takes an `NP` list of `Expression`s instead
467+
615−-- of a general `Selection`.
468+-- | A `selectDistinctDotStar` asks for all the columns of a particular table,
616−selectDistinctOn_
469+-- and eliminates duplicate rows.
617− :: (SListI columns, columns ~ (col ': cols))
470+selectDistinctDotStar
618− => [SortExpression outer commons grp schemas params from]
471+ :: Has relation from columns
619− -- ^ distinct on and return the first row in ordering
472+ => Alias relation
620− -> NP (Aliased (Expression outer commons grp schemas params from)) columns
473+ -- ^ particular virtual table
622− -> TableExpression outer commons grp schemas params from
474+ -> TableExpression schema params from 'Ungrouped
623 -- ^ intermediate virtual table
475 -- ^ intermediate virtual table
624− -> Query outer commons schemas params columns
476+ -> Query schema params columns
625−selectDistinctOn_ distincts = selectDistinctOn distincts . List
477+selectDistinctDotStar rel tab = UnsafeQuery $
478+ "SELECT DISTINCT" <+> renderAlias rel <> ".*"
479+ <+> renderTableExpression tab
627-- | `values` computes a row value or set of row values
481-- | `values` computes a row value or set of row values
628-- specified by value expressions. It is most commonly used
482-- specified by value expressions. It is most commonly used
@@ -630,16 +484,16 @@ selectDistinctOn_ distincts = selectDistinctOn distincts . List
630-- but it can be used on its own.
484-- but it can be used on its own.
632-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
486-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
633−-- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query outer commons schemas '[] Row
487+-- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query '[] '[] Row
634-- >>> printSQL query
488-- >>> printSQL query
635-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
489-- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")
637 :: SListI cols
491 :: SListI cols
638− => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
492+ => NP (Aliased (Expression schema '[] 'Ungrouped params)) cols
639− -> [NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols]
493+ -> [NP (Aliased (Expression schema '[] 'Ungrouped params)) cols]
640 -- ^ When more than one row is specified, all the rows must
494 -- ^ When more than one row is specified, all the rows must
641 -- must have the same number of elements
495 -- must have the same number of elements
642− -> Query outer commons schemas params cols
496+ -> Query schema params cols
643values rw rws = UnsafeQuery $ "SELECT * FROM"
497values rw rws = UnsafeQuery $ "SELECT * FROM"
644 <+> parenthesized (
498 <+> parenthesized (
@@ -650,17 +504,17 @@ values rw rws = UnsafeQuery $ "SELECT * FROM"
650 <+> parenthesized (renderCommaSeparated renderAliasPart rw)
504 <+> parenthesized (renderCommaSeparated renderAliasPart rw)
652 renderAliasPart, renderValuePart
506 renderAliasPart, renderValuePart
653− :: Aliased (Expression outer commons 'Ungrouped schemas params '[] ) ty -> ByteString
507+ :: Aliased (Expression schema '[] 'Ungrouped params) ty -> ByteString
654− renderAliasPart (_ `As` name) = renderSQL name
508+ renderAliasPart (_ `As` name) = renderAlias name
655− renderValuePart (value `As` _) = renderSQL value
509+ renderValuePart (value `As` _) = renderExpression value
657-- | `values_` computes a row value or set of row values
511-- | `values_` computes a row value or set of row values
658-- specified by value expressions.
512-- specified by value expressions.
660 :: SListI cols
514 :: SListI cols
661− => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols
515+ => NP (Aliased (Expression schema '[] 'Ungrouped params)) cols
662 -- ^ one row of values
516 -- ^ one row of values
663− -> Query outer commons schemas params cols
517+ -> Query schema params cols
664values_ rw = values rw []
518values_ rw = values rw []
666{-----------------------------------------
520{-----------------------------------------
@@ -674,17 +528,15 @@ Table Expressions
674-- to a table on disk, a so-called base table, but more complex expressions
528-- to a table on disk, a so-called base table, but more complex expressions
675-- can be used to modify or combine base tables in various ways.
529-- can be used to modify or combine base tables in various ways.
676data TableExpression
530data TableExpression
677− (outer :: FromType)
531+ (schema :: SchemaType)
678− (commons :: FromType)
680− (schemas :: SchemasType)
681 (params :: [NullityType])
532 (params :: [NullityType])
682 (from :: FromType)
533 (from :: FromType)
534+ (grouping :: Grouping)
683 = TableExpression
535 = TableExpression
684− { fromClause :: FromClause outer commons schemas params from
536+ { fromClause :: FromClause schema params from
685 -- ^ A table reference that can be a table name, or a derived table such
537 -- ^ A table reference that can be a table name, or a derived table such
686 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
538 -- as a subquery, a @JOIN@ construct, or complex combinations of these.
687− , whereClause :: [Condition outer commons 'Ungrouped schemas params from]
539+ , whereClause :: [Condition schema from 'Ungrouped params]
688 -- ^ optional search coditions, combined with `.&&`. After the processing
540 -- ^ optional search coditions, combined with `.&&`. After the processing
689 -- of the `fromClause` is done, each row of the derived virtual table
541 -- of the `fromClause` is done, each row of the derived virtual table
690 -- is checked against the search condition. If the result of the
542 -- is checked against the search condition. If the result of the
@@ -693,20 +545,20 @@ data TableExpression
693 -- at least one column of the table generated in the `fromClause`;
545 -- at least one column of the table generated in the `fromClause`;
694 -- this is not required, but otherwise the WHERE clause will
546 -- this is not required, but otherwise the WHERE clause will
695 -- be fairly useless.
547 -- be fairly useless.
696− , groupByClause :: GroupByClause grp from
548+ , groupByClause :: GroupByClause from grouping
697 -- ^ The `groupByClause` is used to group together those rows in a table
549 -- ^ The `groupByClause` is used to group together those rows in a table
698 -- that have the same values in all the columns listed. The order in which
550 -- that have the same values in all the columns listed. The order in which
699 -- the columns are listed does not matter. The effect is to combine each
551 -- the columns are listed does not matter. The effect is to combine each
700 -- set of rows having common values into one group row that represents all
552 -- set of rows having common values into one group row that represents all
701 -- rows in the group. This is done to eliminate redundancy in the output
553 -- rows in the group. This is done to eliminate redundancy in the output
702 -- and/or compute aggregates that apply to these groups.
554 -- and/or compute aggregates that apply to these groups.
703− , havingClause :: HavingClause outer commons grp schemas params from
555+ , havingClause :: HavingClause schema from grouping params
704 -- ^ If a table has been grouped using `groupBy`, but only certain groups
556 -- ^ If a table has been grouped using `groupBy`, but only certain groups
705 -- are of interest, the `havingClause` can be used, much like a
557 -- are of interest, the `havingClause` can be used, much like a
706 -- `whereClause`, to eliminate groups from the result. Expressions in the
558 -- `whereClause`, to eliminate groups from the result. Expressions in the
707 -- `havingClause` can refer both to grouped expressions and to ungrouped
559 -- `havingClause` can refer both to grouped expressions and to ungrouped
708 -- expressions (which necessarily involve an aggregate function).
560 -- expressions (which necessarily involve an aggregate function).
709− , orderByClause :: [SortExpression outer commons grp schemas params from]
561+ , orderByClause :: [SortExpression schema from grouping params]
710 -- ^ The `orderByClause` is for optional sorting. When more than one
562 -- ^ The `orderByClause` is for optional sorting. When more than one
711 -- `SortExpression` is specified, the later (right) values are used to sort
563 -- `SortExpression` is specified, the later (right) values are used to sort
712 -- rows that are equal according to the earlier (left) values.
564 -- rows that are equal according to the earlier (left) values.
@@ -716,69 +568,72 @@ data TableExpression
716 -- will be returned (but possibly fewer, if the query itself yields
568 -- will be returned (but possibly fewer, if the query itself yields
717 -- fewer rows).
569 -- fewer rows).
718 , offsetClause :: [Word64]
570 , offsetClause :: [Word64]
719− -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count
571+ -- ^ The `offsetClause` is combined with `+` to give an offset count
720 -- if nonempty. The offset count says to skip that many rows before
572 -- if nonempty. The offset count says to skip that many rows before
721 -- beginning to return rows. The rows are skipped before the limit count
573 -- beginning to return rows. The rows are skipped before the limit count
722 -- is applied.
574 -- is applied.
723− } deriving (GHC.Generic)
575+ }
725-- | Render a `TableExpression`
577-- | Render a `TableExpression`
578+renderTableExpression
726−instance RenderSQL (TableExpression outer commons grp schemas params from) where
579+ :: TableExpression schema params from grouping
727− renderSQL
580+ -> ByteString
581+renderTableExpression
728− (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
582+ (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat
729− [ "FROM ", renderSQL frm'
583+ [ "FROM ", renderFromClause frm'
730− , renderWheres whs'
584+ , renderWheres whs'
731− , renderSQL grps'
585+ , renderGroupByClause grps'
732− , renderSQL hvs'
586+ , renderHavingClause hvs'
733− , renderOrderByClause srts'
587+ , renderOrderByClause srts'
734− , renderLimits lims'
588+ , renderLimits lims'
735− , renderOffsets offs' ]
589+ , renderOffsets offs'
737− renderWheres = \case
592+ renderWheres = \case
738− [] -> ""
593+ [] -> ""
739− wh:[] -> " WHERE" <+> renderSQL wh
594+ wh:[] -> " WHERE" <+> renderExpression wh
740− wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)
595+ wh:whs -> " WHERE" <+> renderExpression (foldr (.&&) wh whs)
741− renderOrderByClause = \case
596+ renderOrderByClause = \case
742− [] -> ""
597+ [] -> ""
743− srts -> " ORDER BY"
598+ srts -> " ORDER BY"
744− <+> commaSeparated (renderSQL <$> srts)
599+ <+> commaSeparated (renderSortExpression <$> srts)
745− renderLimits = \case
600+ renderLimits = \case
746− [] -> ""
601+ [] -> ""
747− lims -> " LIMIT" <+> fromString (show (minimum lims))
602+ lims -> " LIMIT" <+> fromString (show (minimum lims))
748− renderOffsets = \case
603+ renderOffsets = \case
749− [] -> ""
604+ [] -> ""
750− offs -> " OFFSET" <+> fromString (show (sum offs))
605+ offs -> " OFFSET" <+> fromString (show (sum offs))
752-- | A `from` generates a `TableExpression` from a table reference that can be
607-- | A `from` generates a `TableExpression` from a table reference that can be
753-- a table name, or a derived table such as a subquery, a JOIN construct,
608-- a table name, or a derived table such as a subquery, a JOIN construct,
754-- or complex combinations of these. A `from` may be transformed by `where_`,
609-- or complex combinations of these. A `from` may be transformed by `where_`,
755−-- `groupBy`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
610+-- `group`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
756-- to match the left-to-right sequencing of their placement in SQL.
611-- to match the left-to-right sequencing of their placement in SQL.
758− :: FromClause outer commons schemas params from -- ^ table reference
613+ :: FromClause schema params from -- ^ table reference
759− -> TableExpression outer commons 'Ungrouped schemas params from
614+ -> TableExpression schema params from 'Ungrouped
760−from tab = TableExpression tab [] noGroups NoHaving [] [] []
615+from rels = TableExpression rels [] NoGroups NoHaving [] [] []
762-- | A `where_` is an endomorphism of `TableExpression`s which adds a
617-- | A `where_` is an endomorphism of `TableExpression`s which adds a
763-- search condition to the `whereClause`.
618-- search condition to the `whereClause`.
765− :: Condition outer commons 'Ungrouped schemas params from -- ^ filtering condition
620+ :: Condition schema from 'Ungrouped params -- ^ filtering condition
766− -> TableExpression outer commons grp schemas params from
621+ -> TableExpression schema params from grouping
767− -> TableExpression outer commons grp schemas params from
622+ -> TableExpression schema params from grouping
768where_ wh rels = rels {whereClause = wh : whereClause rels}
623where_ wh rels = rels {whereClause = wh : whereClause rels}
770-- | A `groupBy` is a transformation of `TableExpression`s which switches
625-- | A `groupBy` is a transformation of `TableExpression`s which switches
771−-- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform
626+-- its `Grouping` from `Ungrouped` to `Grouped`. Use @group Nil@ to perform
772-- a "grand total" aggregation query.
627-- a "grand total" aggregation query.
774 :: SListI bys
629 :: SListI bys
775 => NP (By from) bys -- ^ grouped columns
630 => NP (By from) bys -- ^ grouped columns
776− -> TableExpression outer commons 'Ungrouped schemas params from
631+ -> TableExpression schema params from 'Ungrouped
777− -> TableExpression outer commons ('Grouped bys) schemas params from
632+ -> TableExpression schema params from ('Grouped bys)
778groupBy bys rels = TableExpression
633groupBy bys rels = TableExpression
779 { fromClause = fromClause rels
634 { fromClause = fromClause rels
780 , whereClause = whereClause rels
635 , whereClause = whereClause rels
781− , groupByClause = group bys
636+ , groupByClause = Group bys
782 , havingClause = Having []
637 , havingClause = Having []
783 , orderByClause = []
638 , orderByClause = []
784 , limitClause = limitClause rels
639 , limitClause = limitClause rels
@@ -788,31 +643,219 @@ groupBy bys rels = TableExpression
788-- | A `having` is an endomorphism of `TableExpression`s which adds a
643-- | A `having` is an endomorphism of `TableExpression`s which adds a
789-- search condition to the `havingClause`.
644-- search condition to the `havingClause`.
791− :: Condition outer commons ('Grouped bys) schemas params from -- ^ having condition
646+ :: Condition schema from ('Grouped bys) params -- ^ having condition
792− -> TableExpression outer commons ('Grouped bys) schemas params from
647+ -> TableExpression schema params from ('Grouped bys)
793− -> TableExpression outer commons ('Grouped bys) schemas params from
648+ -> TableExpression schema params from ('Grouped bys)
794having hv rels = rels
649having hv rels = rels
795 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
650 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
652+-- | An `orderBy` is an endomorphism of `TableExpression`s which appends an
653+-- ordering to the right of the `orderByClause`.
655+ :: [SortExpression schema from grouping params] -- ^ sort expressions
797−instance OrderBy TableExpression where
656+ -> TableExpression schema params from grouping
657+ -> TableExpression schema params from grouping
798− orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
658+orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
800-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
660-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
801-- `limitClause`.
661-- `limitClause`.
803 :: Word64 -- ^ limit parameter
663 :: Word64 -- ^ limit parameter
804− -> TableExpression outer commons grp schemas params from
664+ -> TableExpression schema params from grouping
805− -> TableExpression outer commons grp schemas params from
665+ -> TableExpression schema params from grouping
806limit lim rels = rels {limitClause = lim : limitClause rels}
666limit lim rels = rels {limitClause = lim : limitClause rels}
808-- | An `offset` is an endomorphism of `TableExpression`s which adds to the
668-- | An `offset` is an endomorphism of `TableExpression`s which adds to the
809-- `offsetClause`.
669-- `offsetClause`.
811 :: Word64 -- ^ offset parameter
671 :: Word64 -- ^ offset parameter
812− -> TableExpression outer commons grp schemas params from
672+ -> TableExpression schema params from grouping
813− -> TableExpression outer commons grp schemas params from
673+ -> TableExpression schema params from grouping
814offset off rels = rels {offsetClause = off : offsetClause rels}
674offset off rels = rels {offsetClause = off : offsetClause rels}
676+{-----------------------------------------
678+-----------------------------------------}
680+type PGjson_each_variant val tab =
681+ '[ tab ::: '[ "key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull val ] ]
683+-- | The type of a `json_each` `FromClause`.
684+type PGjson_each tab = PGjson_each_variant 'PGjson tab
685+-- | The type of a `jsonb_each` `FromClause`.
686+type PGjsonb_each tab = PGjson_each_variant 'PGjsonb tab
687+-- | The type of a `json_each_text` `FromClause`.
688+type PGjson_each_text tab = PGjson_each_variant 'PGtext tab
689+-- | The type of a `jsonb_each_text` `FromClause`.
690+type PGjsonb_each_text tab = PGjson_each_variant 'PGtext tab
692+unsafeAliasedFromClauseExpression
693+ :: Aliased (Expression schema' from' grouping' params') ty'
694+ -> FromClause schema params from
695+unsafeAliasedFromClauseExpression aliasedExpr = UnsafeFromClause
696+ (renderAliasedAs renderExpression aliasedExpr)
698+-- | Expands the outermost JSON object into a set of key/value pairs.
700+ :: Aliased (Expression schema '[] 'Ungrouped params) '(tab, nullity 'PGjson)
701+ -> FromClause schema params (PGjson_each tab)
702+jsonEach (As jexpr jname) = unsafeAliasedFromClauseExpression
703+ (As (unsafeFunction "json_each" jexpr) jname)
705+-- | Expands the outermost binary JSON object into a set of key/value pairs.
707+ :: Aliased (Expression schema '[] 'Ungrouped params) '(tab, nullity 'PGjsonb)
708+ -> FromClause schema params (PGjsonb_each tab)
709+jsonbEach (As jexpr jname) = unsafeAliasedFromClauseExpression
710+ (As (unsafeFunction "jsonb_each" jexpr) jname)
712+-- | Expands the outermost JSON object into a set of key/value pairs.
714+ :: Aliased (Expression schema '[] 'Ungrouped params) '(tab, nullity 'PGjson)
715+ -> FromClause schema params (PGjson_each_text tab)
716+jsonEachAsText (As jexpr jname) = unsafeAliasedFromClauseExpression
717+ (As (unsafeFunction "json_each" jexpr) jname)
719+-- | Expands the outermost binary JSON object into a set of key/value pairs.
721+ :: Aliased (Expression schema '[] 'Ungrouped params) '(tab, nullity 'PGjsonb)
722+ -> FromClause schema params (PGjsonb_each_text tab)
723+jsonbEachAsText (As jexpr jname) = unsafeAliasedFromClauseExpression
724+ (As (unsafeFunction "jsonb_each" jexpr) jname)
727+ :: Has tab schema ('Table table)
729+ -> Expression schema from grouping params
730+ (nullity ('PGcomposite (TableToRow table)))
731+nullRow tab = UnsafeExpression ("null::"<+>renderAlias tab)
733+-- | Expands the JSON expression to a row whose columns match the record
734+-- type defined by the given table.
736+ :: (KnownSymbol alias, Has tab schema ('Table table))
738+ -> Expression schema '[] 'Ungrouped params (nullity 'PGjson)
740+ -> FromClause schema params '[alias ::: TableToRow table]
741+jsonPopulateRecordAs tableName expr alias = unsafeAliasedFromClauseExpression
742+ (unsafeVariadicFunction "json_populate_record"
743+ (nullRow tableName :* expr :* Nil) `As` alias)
745+-- | Expands the binary JSON expression to a row whose columns match the record
746+-- type defined by the given table.
747+jsonbPopulateRecordAs
748+ :: (KnownSymbol alias, Has tab schema ('Table table))
750+ -> Expression schema '[] 'Ungrouped params (nullity 'PGjsonb)
752+ -> FromClause schema params '[alias ::: TableToRow table]
753+jsonbPopulateRecordAs tableName expr alias = unsafeAliasedFromClauseExpression
754+ (unsafeVariadicFunction "jsonb_populate_record"
755+ (nullRow tableName :* expr :* Nil) `As` alias)
757+-- | Expands the outermost array of objects in the given JSON expression to a
758+-- set of rows whose columns match the record type defined by the given table.
759+jsonPopulateRecordSetAs
760+ :: (KnownSymbol alias, Has tab schema ('Table table))
762+ -> Expression schema '[] 'Ungrouped params (nullity 'PGjson)
764+ -> FromClause schema params '[alias ::: TableToRow table]
765+jsonPopulateRecordSetAs tableName expr alias = unsafeAliasedFromClauseExpression
766+ (unsafeVariadicFunction "json_populate_record_set"
767+ (nullRow tableName :* expr :* Nil) `As` alias)
769+-- | Expands the outermost array of objects in the given binary JSON expression
770+-- to a set of rows whose columns match the record type defined by the given
772+jsonbPopulateRecordSetAs
773+ :: (KnownSymbol alias, Has tab schema ('Table table))
775+ -> Expression schema '[] 'Ungrouped params (nullity 'PGjsonb)
777+ -> FromClause schema params '[alias ::: TableToRow table]
778+jsonbPopulateRecordSetAs tableName expr alias = unsafeAliasedFromClauseExpression
779+ (unsafeVariadicFunction "jsonb_populate_record_set"
780+ (nullRow tableName :* expr :* Nil) `As` alias)
782+renderTableTypeExpression
784+ => Aliased (NP (Aliased (TypeExpression schema))) (tab ::: types)
786+renderTableTypeExpression (hc `As` tab)
787+ = (renderAlias tab <>)
792+ (Proxy :: Proxy Top)
793+ (\(ty `As` name) -> Endo
794+ ((renderAlias name <+> renderTypeExpression ty):))
797+unsafeTableAliasedFromClauseExpression
799+ => Expression schema' from' grouping' params' ty'
800+ -> Aliased (NP (Aliased (TypeExpression schema))) (tab ::: types)
801+ -> FromClause schema params '[alias ::: types]
802+unsafeTableAliasedFromClauseExpression expr types = UnsafeFromClause
803+ (renderExpression expr
805+ <+> renderTableTypeExpression types)
807+-- | Builds an arbitrary record from a JSON object. As with all functions
808+-- returning record, the caller must explicitly define the structure of the
809+-- record with an AS clause.
812+ => Expression schema '[] 'Ungrouped params (nullity 'PGjson)
813+ -> Aliased (NP (Aliased (TypeExpression schema))) (tab ::: types)
814+ -> FromClause schema params '[tab ::: types]
815+jsonToRecordAs expr types =
816+ unsafeTableAliasedFromClauseExpression
817+ (unsafeFunction "json_to_record" expr)
820+-- | Builds an arbitrary record from a binary JSON object. As with all functions
821+-- returning record, the caller must explicitly define the structure of the
822+-- record with an AS clause.
825+ => Expression schema '[] 'Ungrouped params (nullity 'PGjsonb)
826+ -> Aliased (NP (Aliased (TypeExpression schema))) (tab ::: types)
827+ -> FromClause schema params '[tab ::: types]
828+jsonbToRecordAs expr types =
829+ unsafeTableAliasedFromClauseExpression
830+ (unsafeFunction "jsonb_to_record" expr)
833+-- | Builds an arbitrary set of records from a JSON array of objects (see note
834+-- below). As with all functions returning record, the caller must explicitly
835+-- define the structure of the record with an AS clause.
838+ => Expression schema '[] 'Ungrouped params (nullity 'PGjson)
839+ -> Aliased (NP (Aliased (TypeExpression schema))) (tab ::: types)
840+ -> FromClause schema params '[tab ::: types]
841+jsonToRecordSetAs expr types =
842+ unsafeTableAliasedFromClauseExpression
843+ (unsafeFunction "json_to_recordset" expr)
846+-- | Builds an arbitrary set of records from a binary JSON array of objects (see
847+-- note below). As with all functions returning record, the caller must
848+-- explicitly define the structure of the record with an AS clause.
851+ => Expression schema '[] 'Ungrouped params (nullity 'PGjsonb)
852+ -> Aliased (NP (Aliased (TypeExpression schema))) (tab ::: types)
853+ -> FromClause schema params '[tab ::: types]
854+jsonbToRecordSetAs expr types =
855+ unsafeTableAliasedFromClauseExpression
856+ (unsafeFunction "jsonb_to_recordset" expr)
816{-----------------------------------------
859{-----------------------------------------
817FROM clauses
860FROM clauses
818-----------------------------------------}
861-----------------------------------------}
@@ -821,76 +864,61 @@ FROM clauses
821A `FromClause` can be a table name, or a derived table such
864A `FromClause` can be a table name, or a derived table such
822as a subquery, a @JOIN@ construct, or complex combinations of these.
865as a subquery, a @JOIN@ construct, or complex combinations of these.
824−newtype FromClause outer commons schemas params from
867+newtype FromClause schema params from
825 = UnsafeFromClause { renderFromClause :: ByteString }
868 = UnsafeFromClause { renderFromClause :: ByteString }
826 deriving (GHC.Generic,Show,Eq,Ord,NFData)
869 deriving (GHC.Generic,Show,Eq,Ord,NFData)
827−instance RenderSQL (FromClause outer commons schemas params from) where
828− renderSQL = renderFromClause
830−-- | A real `table` is a table from the database.
871+-- | A real `table` is a table from the schema.
832− :: (Has sch schemas schema, Has tab schema ('Table table))
873+ :: Has tab schema ('Table table)
833− => Aliased (QualifiedAlias sch) (alias ::: tab)
874+ => Aliased Alias (alias ::: tab)
834− -> FromClause outer commons schemas params '[alias ::: TableToRow table]
875+ -> FromClause schema params '[alias ::: TableToRow table]
835table (tab `As` alias) = UnsafeFromClause $
876table (tab `As` alias) = UnsafeFromClause $
836− renderSQL tab <+> "AS" <+> renderSQL alias
877+ renderAlias tab <+> "AS" <+> renderAlias alias
838-- | `subquery` derives a table from a `Query`.
879-- | `subquery` derives a table from a `Query`.
840− :: Aliased (Query outer commons schemas params) query
881+ :: Aliased (Query schema params) rel
841− -> FromClause outer commons schemas params '[query]
882+ -> FromClause schema params '[rel]
842−subquery = UnsafeFromClause . renderAliased (parenthesized . renderSQL)
883+subquery = UnsafeFromClause . renderAliasedAs (parenthesized . renderQuery)
844-- | `view` derives a table from a `View`.
885-- | `view` derives a table from a `View`.
846− :: (Has sch schemas schema, Has vw schema ('View view))
887+ :: Has view schema ('View rel)
847− => Aliased (QualifiedAlias sch) (alias ::: vw)
888+ => Aliased Alias (alias ::: view)
848− -> FromClause outer commons schemas params '[alias ::: view]
889+ -> FromClause schema params '[alias ::: rel]
849view (vw `As` alias) = UnsafeFromClause $
890view (vw `As` alias) = UnsafeFromClause $
850− renderSQL vw <+> "AS" <+> renderSQL alias
891+ renderAlias vw <+> "AS" <+> renderAlias alias
852−-- | `common` derives a table from a common table expression.
854− :: Has cte commons common
855− => Aliased Alias (alias ::: cte)
856− -> FromClause outer commons schemas params '[alias ::: common]
857−common (cte `As` alias) = UnsafeFromClause $
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
865−@left & crossJoin right@. For every possible combination of rows from
893+{- | @left & crossJoin right@. For every possible combination of rows from
866−@left@ and @right@ (i.e., a Cartesian product), the joined table will contain
894+ @left@ and @right@ (i.e., a Cartesian product), the joined table will contain
867−a row consisting of all columns in @left@ followed by all columns in @right@.
895+ a row consisting of all columns in @left@ followed by all columns in @right@.
868−If the tables have @n@ and @m@ rows respectively, the joined table will
896+ If the tables have @n@ and @m@ rows respectively, the joined table will
869−have @n * m@ rows.
897+ have @n * m@ rows.
872− :: FromClause outer commons schemas params right
900+ :: FromClause schema params right
873 -- ^ right
901 -- ^ right
874− -> FromClause outer commons schemas params left
902+ -> FromClause schema params left
875 -- ^ left
903 -- ^ left
876− -> FromClause outer commons schemas params (Join left right)
904+ -> FromClause schema params (Join left right)
877crossJoin right left = UnsafeFromClause $
905crossJoin right left = UnsafeFromClause $
878− renderSQL left <+> "CROSS JOIN" <+> renderSQL right
906+ renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
880{- | @left & innerJoin right on@. The joined table is filtered by
908{- | @left & innerJoin right on@. The joined table is filtered by
881the @on@ condition.
909the @on@ condition.
884− :: FromClause outer commons schemas params right
912+ :: FromClause schema params right
885 -- ^ right
913 -- ^ right
886− -> Condition outer commons 'Ungrouped schemas params (Join left right)
914+ -> Condition schema (Join left right) 'Ungrouped params
887 -- ^ @on@ condition
915 -- ^ @on@ condition
888− -> FromClause outer commons schemas params left
916+ -> FromClause schema params left
889 -- ^ left
917 -- ^ left
890− -> FromClause outer commons schemas params (Join left right)
918+ -> FromClause schema params (Join left right)
891innerJoin right on left = UnsafeFromClause $
919innerJoin right on left = UnsafeFromClause $
892− renderSQL left <+> "INNER JOIN" <+> renderSQL right
920+ renderFromClause left <+> "INNER JOIN" <+> renderFromClause right
893− <+> "ON" <+> renderSQL on
921+ <+> "ON" <+> renderExpression on
895{- | @left & leftOuterJoin right on@. First, an inner join is performed.
923{- | @left & leftOuterJoin right on@. First, an inner join is performed.
896 Then, for each row in @left@ that does not satisfy the @on@ condition with
924 Then, for each row in @left@ that does not satisfy the @on@ condition with
@@ -898,16 +926,16 @@ innerJoin right on left = UnsafeFromClause $
898 Thus, the joined table always has at least one row for each row in @left@.
926 Thus, the joined table always has at least one row for each row in @left@.
900leftOuterJoin
928leftOuterJoin
901− :: FromClause outer commons schemas params right
929+ :: FromClause schema params right
902 -- ^ right
930 -- ^ right
903− -> Condition outer commons 'Ungrouped schemas params (Join left right)
931+ -> Condition schema (Join left right) 'Ungrouped params
904 -- ^ @on@ condition
932 -- ^ @on@ condition
905− -> FromClause outer commons schemas params left
933+ -> FromClause schema params left
906 -- ^ left
934 -- ^ left
907− -> FromClause outer commons schemas params (Join left (NullifyFrom right))
935+ -> FromClause schema params (Join left (NullifyRelations right))
908leftOuterJoin right on left = UnsafeFromClause $
936leftOuterJoin right on left = UnsafeFromClause $
909− renderSQL left <+> "LEFT OUTER JOIN" <+> renderSQL right
937+ renderFromClause left <+> "LEFT OUTER JOIN" <+> renderFromClause right
910− <+> "ON" <+> renderSQL on
938+ <+> "ON" <+> renderExpression on
912{- | @left & rightOuterJoin right on@. First, an inner join is performed.
940{- | @left & rightOuterJoin right on@. First, an inner join is performed.
913 Then, for each row in @right@ that does not satisfy the @on@ condition with
941 Then, for each row in @right@ that does not satisfy the @on@ condition with
@@ -916,16 +944,16 @@ leftOuterJoin right on left = UnsafeFromClause $
916 have a row for each row in @right@.
944 have a row for each row in @right@.
918rightOuterJoin
946rightOuterJoin
919− :: FromClause outer commons schemas params right
947+ :: FromClause schema params right
920 -- ^ right
948 -- ^ right
921− -> Condition outer commons 'Ungrouped schemas params (Join left right)
949+ -> Condition schema (Join left right) 'Ungrouped params
922 -- ^ @on@ condition
950 -- ^ @on@ condition
923− -> FromClause outer commons schemas params left
951+ -> FromClause schema params left
924 -- ^ left
952 -- ^ left
925− -> FromClause outer commons schemas params (Join (NullifyFrom left) right)
953+ -> FromClause schema params (Join (NullifyRelations left) right)
926rightOuterJoin right on left = UnsafeFromClause $
954rightOuterJoin right on left = UnsafeFromClause $
927− renderSQL left <+> "RIGHT OUTER JOIN" <+> renderSQL right
955+ renderFromClause left <+> "RIGHT OUTER JOIN" <+> renderFromClause right
928− <+> "ON" <+> renderSQL on
956+ <+> "ON" <+> renderExpression on
930{- | @left & fullOuterJoin right on@. First, an inner join is performed.
958{- | @left & fullOuterJoin right on@. First, an inner join is performed.
931 Then, for each row in @left@ that does not satisfy the @on@ condition with
959 Then, for each row in @left@ that does not satisfy the @on@ condition with
@@ -935,23 +963,23 @@ rightOuterJoin right on left = UnsafeFromClause $
935 is added.
963 is added.
937fullOuterJoin
965fullOuterJoin
938− :: FromClause outer commons schemas params right
966+ :: FromClause schema params right
939 -- ^ right
967 -- ^ right
940− -> Condition outer commons 'Ungrouped schemas params (Join left right)
968+ -> Condition schema (Join left right) 'Ungrouped params
941 -- ^ @on@ condition
969 -- ^ @on@ condition
942− -> FromClause outer commons schemas params left
970+ -> FromClause schema params left
943 -- ^ left
971 -- ^ left
944− -> FromClause outer commons schemas params
972+ -> FromClause schema params
945− (Join (NullifyFrom left) (NullifyFrom right))
973+ (Join (NullifyRelations left) (NullifyRelations right))
946fullOuterJoin right on left = UnsafeFromClause $
974fullOuterJoin right on left = UnsafeFromClause $
947− renderSQL left <+> "FULL OUTER JOIN" <+> renderSQL right
975+ renderFromClause left <+> "FULL OUTER JOIN" <+> renderFromClause right
948− <+> "ON" <+> renderSQL on
976+ <+> "ON" <+> renderExpression on
950{-----------------------------------------
978{-----------------------------------------
952-----------------------------------------}
980-----------------------------------------}
954−-- | `By`s are used in `groupBy` to reference a list of columns which are then
982+-- | `By`s are used in `group` to reference a list of columns which are then
955-- used to group together those rows in a table that have the same values
983-- used to group together those rows in a table that have the same values
956-- in all the columns listed. @By \#col@ will reference an unambiguous
984-- in all the columns listed. @By \#col@ will reference an unambiguous
957-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
985-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table
@@ -960,21 +988,17 @@ data By
960 (from :: FromType)
988 (from :: FromType)
961 (by :: (Symbol,Symbol)) where
989 (by :: (Symbol,Symbol)) where
963− :: (HasUnique table from columns, Has column columns ty)
991+ :: (HasUnique relation from columns, Has column columns ty)
964 => Alias column
992 => Alias column
965− -> By from '(table, column)
993+ -> By from '(relation, column)
967− :: (Has table from columns, Has column columns ty)
995+ :: (Has relation from columns, Has column columns ty)
968− => Alias table
996+ => Alias relation
969 -> Alias column
997 -> Alias column
970− -> By from '(table, column)
998+ -> By from '(relation, column)
971deriving instance Show (By from by)
999deriving instance Show (By from by)
972deriving instance Eq (By from by)
1000deriving instance Eq (By from by)
973deriving instance Ord (By from by)
1001deriving 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
979instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
1003instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))
980 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
1004 => IsLabel col (By rels by) where fromLabel = By1 fromLabel
@@ -986,113 +1010,280 @@ instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])
986 => IsQualified rel col (NP (By rels) bys) where
1010 => IsQualified rel col (NP (By rels) bys) where
987 rel ! col = By2 rel col :* Nil
1011 rel ! col = By2 rel col :* Nil
1013+-- | Renders a `By`.
1014+renderBy :: By from by -> ByteString
1016+ By1 column -> renderAlias column
1017+ By2 rel column -> renderAlias rel <> "." <> renderAlias column
989-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
1019-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
990-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
1020-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
991-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
1021-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
992-- done on @NoGroups@ while all output `Expression`s must be aggregated
1022-- done on @NoGroups@ while all output `Expression`s must be aggregated
993-- in @Group Nil@. In general, all output `Expression`s in the
1023-- in @Group Nil@. In general, all output `Expression`s in the
994-- complement of @bys@ must be aggregated in @Group bys@.
1024-- complement of @bys@ must be aggregated in @Group bys@.
995−newtype GroupByClause grp from = UnsafeGroupByClause
1025+data GroupByClause from grouping where
996− { renderGroupByClause :: ByteString }
997− deriving (GHC.Generic,Show,Eq,Ord,NFData)
998−instance RenderSQL (GroupByClause grp from) where
999− renderSQL = renderGroupByClause
1000−noGroups :: GroupByClause 'Ungrouped from
1026+ NoGroups :: GroupByClause from 'Ungrouped
1001−noGroups = UnsafeGroupByClause ""
1027+ Group
1003− :: SListI bys
1028+ :: SListI bys
1004− => NP (By from) bys
1029+ => NP (By from) bys
1005− -> GroupByClause ('Grouped bys) from
1030+ -> GroupByClause from ('Grouped bys)
1006−group bys = UnsafeGroupByClause $ case bys of
1031+
1032+-- | Renders a `GroupByClause`.
1033+renderGroupByClause :: GroupByClause from grouping -> ByteString
1034+renderGroupByClause = \case
1007− Nil -> ""
1036+ Group Nil -> ""
1008− bys' -> " GROUP BY" <+> renderCommaSeparated renderSQL bys'
1037+ Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
1010-- | A `HavingClause` is used to eliminate groups that are not of interest.
1039-- | A `HavingClause` is used to eliminate groups that are not of interest.
1011-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1040-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
1012-- `TableExpression` must use `Having` whose conditions are combined with
1041-- `TableExpression` must use `Having` whose conditions are combined with
1013-- `.&&`.
1042-- `.&&`.
1014−data HavingClause outer commons grp schemas params from where
1043+data HavingClause schema from grouping params where
1015− NoHaving :: HavingClause outer commons 'Ungrouped schemas params from
1044+ NoHaving :: HavingClause schema from 'Ungrouped params
1017− :: [Condition outer commons ('Grouped bys) schemas params from]
1046+ :: [Condition schema from ('Grouped bys) params]
1018− -> HavingClause outer commons ('Grouped bys) schemas params from
1047+ -> HavingClause schema from ('Grouped bys) params
1019−deriving instance Show (HavingClause outer commons grp schemas params from)
1048+deriving instance Show (HavingClause schema from grouping params)
1020−deriving instance Eq (HavingClause outer commons grp schemas params from)
1049+deriving instance Eq (HavingClause schema from grouping params)
1021−deriving instance Ord (HavingClause outer commons grp schemas params from)
1050+deriving instance Ord (HavingClause schema from grouping params)
1023-- | Render a `HavingClause`.
1052-- | Render a `HavingClause`.
1024−instance RenderSQL (HavingClause outer commons grp schemas params from) where
1053+renderHavingClause :: HavingClause schema from grouping params -> ByteString
1025− renderSQL = \case
1054+renderHavingClause = \case
1026− NoHaving -> ""
1055+ NoHaving -> ""
1027− Having [] -> ""
1056+ Having [] -> ""
1028− Having conditions ->
1057+ Having conditions ->
1029− " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1058+ " HAVING" <+> commaSeparated (renderExpression <$> conditions)
1031−-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.
1032−data CommonTableExpression statement
1033− (schemas :: SchemasType)
1034− (params :: [NullityType])
1035− (commons0 :: FromType)
1036− (commons1 :: FromType) where
1037− CommonTableExpression
1038− :: Aliased (statement commons schemas params) (cte ::: common)
1039− -> CommonTableExpression statement schemas params commons (cte ::: common ': commons)
1042− , commons1 ~ (cte ::: common ': commons)
1044− (statement commons schemas params common)
1045− (CommonTableExpression statement schemas params commons commons1) where
1046− statement `as` cte = CommonTableExpression (statement `as` cte)
1049− , commons1 ~ (cte ::: common ': commons)
1051− (statement commons schemas params common)
1052− (Path (CommonTableExpression statement schemas params) commons commons1) where
1053− statement `as` cte = csingleton (statement `as` cte)
1055−instance (forall c s p r. RenderSQL (statement c s p r)) => RenderSQL
1056− (CommonTableExpression statement schemas params commons0 commons1) where
1057− renderSQL (CommonTableExpression (statement `As` cte)) =
1058− renderSQL cte <+> "AS" <+> parenthesized (renderSQL statement)
1060−-- | `with` provides a way to write auxiliary statements for use in a larger query.
1061−-- These statements, referred to as `CommonTableExpression`s, can be thought of as
1062−-- defining temporary tables that exist just for one query.
1063−class With statement where
1065− :: Path (CommonTableExpression statement schemas params) commons0 commons1
1066− -- ^ common table expressions
1067− -> statement commons1 schemas params row
1069− -> statement commons0 schemas params row
1070−instance With (Query outer) where
1071− with Done query = query
1072− with ctes query = UnsafeQuery $
1073− "WITH" <+> commaSeparated (ctoList renderSQL ctes) <+> renderSQL query
1075−{- |
1060+{-----------------------------------------
1076−>>> import Data.Monoid (Sum (..))
1061+Sorting
1077−>>> import Data.Int (Int64)
1062+-----------------------------------------}
1079− let
1064+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1080− query :: Query_ schema () (Sum Int64)
1065+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1081− query = withRecursive
1066+-- column to ascending or descending. Ascending order puts smaller values
1082− ( values_ ((1 & astype int) `as` #n)
1067+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1083− `unionAll`
1068+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1084− select_ ((#n + 1) `as` #n)
1069+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1085− (from (common #t) & where_ (#n .< 100)) `as` #t )
1070+-- determine whether nulls appear before or after non-null values in the sort
1086− ( select_ (fromNull 0 (sum_ (All #n)) `as` #getSum) (from (common #t) & groupBy Nil))
1071+-- ordering of a `Null` result column.
1087− in printSQL query
1072+data SortExpression schema from grouping params where
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"
1074+ :: Expression schema from grouping params ('NotNull ty)
1090−-}
1075+ -> SortExpression schema from grouping params
1091−withRecursive
1076+ Desc
1092− :: Aliased (Query outer (recursive ': commons) schemas params) recursive
1077+ :: Expression schema from grouping params ('NotNull ty)
1093− -> Query outer (recursive ': commons) schemas params row
1078+ -> SortExpression schema from grouping params
1094− -> Query outer commons schemas params row
1079+ AscNullsFirst
1095−withRecursive (recursive `As` cte) query = UnsafeQuery $
1080+ :: Expression schema from grouping params ('Null ty)
1096− "WITH RECURSIVE" <+> renderSQL cte
1081+ -> SortExpression schema from grouping params
1097− <+> "AS" <+> parenthesized (renderSQL recursive)
1082+ AscNullsLast
1098− <+> renderSQL query
1083+ :: Expression schema from grouping params ('Null ty)
1084+ -> SortExpression schema from grouping params
1086+ :: Expression schema from grouping params ('Null ty)
1087+ -> SortExpression schema from grouping params
1089+ :: Expression schema from grouping params ('Null ty)
1090+ -> SortExpression schema from grouping params
1091+deriving instance Show (SortExpression schema from grouping params)
1093+-- | Render a `SortExpression`.
1094+renderSortExpression :: SortExpression schema from grouping params -> ByteString
1095+renderSortExpression = \case
1096+ Asc expression -> renderExpression expression <+> "ASC"
1097+ Desc expression -> renderExpression expression <+> "DESC"
1098+ AscNullsFirst expression -> renderExpression expression
1099+ <+> "ASC NULLS FIRST"
1100+ DescNullsFirst expression -> renderExpression expression
1101+ <+> "DESC NULLS FIRST"
1102+ AscNullsLast expression -> renderExpression expression <+> "ASC NULLS LAST"
1103+ DescNullsLast expression -> renderExpression expression <+> "DESC NULLS LAST"
1105+unsafeSubqueryExpression
1107+ -> Expression schema from grp params ty
1108+ -> Query schema params '[alias ::: ty]
1109+ -> Condition schema from grp params
1110+unsafeSubqueryExpression op x q = UnsafeExpression $
1111+ renderExpression x <+> op <+> parenthesized (renderQuery q)
1113+unsafeRowSubqueryExpression
1116+ -> NP (Aliased (Expression schema from grp params)) row
1117+ -> Query schema params row
1118+ -> Condition schema from grp params
1119+unsafeRowSubqueryExpression op xs q = UnsafeExpression $
1120+ renderExpression (row xs) <+> op <+> parenthesized (renderQuery q)
1123+ :: Expression schema from grp params ty
1124+ -> Query schema params '[alias ::: ty]
1125+ -> Condition schema from grp params
1126+in_ = unsafeSubqueryExpression "IN"
1130+ => NP (Aliased (Expression schema from grp params)) row
1131+ -> Query schema params row
1132+ -> Condition schema from grp params
1133+rowIn = unsafeRowSubqueryExpression "IN"
1136+ :: Expression schema from grp params ty
1137+ -> Query schema params '[alias ::: ty]
1138+ -> Condition schema from grp params
1139+allEq = unsafeSubqueryExpression "ALL ="
1143+ => NP (Aliased (Expression schema from grp params)) row
1144+ -> Query schema params row
1145+ -> Condition schema from grp params
1146+rowAllEq = unsafeRowSubqueryExpression "ALL ="
1149+ :: Expression schema from grp params ty
1150+ -> Query schema params '[alias ::: ty]
1151+ -> Condition schema from grp params
1152+anyEq = unsafeSubqueryExpression "ANY ="
1156+ => NP (Aliased (Expression schema from grp params)) row
1157+ -> Query schema params row
1158+ -> Condition schema from grp params
1159+rowAnyEq = unsafeRowSubqueryExpression "ANY ="
1162+ :: Expression schema from grp params ty
1163+ -> Query schema params '[alias ::: ty]
1164+ -> Condition schema from grp params
1165+allNeq = unsafeSubqueryExpression "ALL <>"
1169+ => NP (Aliased (Expression schema from grp params)) row
1170+ -> Query schema params row
1171+ -> Condition schema from grp params
1172+rowAllNeq = unsafeRowSubqueryExpression "ALL <>"
1175+ :: Expression schema from grp params ty
1176+ -> Query schema params '[alias ::: ty]
1177+ -> Condition schema from grp params
1178+anyNeq = unsafeSubqueryExpression "ANY <>"
1182+ => NP (Aliased (Expression schema from grp params)) row
1183+ -> Query schema params row
1184+ -> Condition schema from grp params
1185+rowAnyNeq = unsafeRowSubqueryExpression "ANY <>"
1188+ :: Expression schema from grp params ty
1189+ -> Query schema params '[alias ::: ty]
1190+ -> Condition schema from grp params
1191+allLt = unsafeSubqueryExpression "ALL <"
1195+ => NP (Aliased (Expression schema from grp params)) row
1196+ -> Query schema params row
1197+ -> Condition schema from grp params
1198+rowAllLt = unsafeRowSubqueryExpression "ALL <"
1201+ :: Expression schema from grp params ty
1202+ -> Query schema params '[alias ::: ty]
1203+ -> Condition schema from grp params
1204+anyLt = unsafeSubqueryExpression "ANY <"
1208+ => NP (Aliased (Expression schema from grp params)) row
1209+ -> Query schema params row
1210+ -> Condition schema from grp params
1211+rowAnyLt = unsafeRowSubqueryExpression "ANY <"
1214+ :: Expression schema from grp params ty
1215+ -> Query schema params '[alias ::: ty]
1216+ -> Condition schema from grp params
1217+allLte = unsafeSubqueryExpression "ALL <="
1221+ => NP (Aliased (Expression schema from grp params)) row
1222+ -> Query schema params row
1223+ -> Condition schema from grp params
1224+rowAllLte = unsafeRowSubqueryExpression "ALL <="
1227+ :: Expression schema from grp params ty
1228+ -> Query schema params '[alias ::: ty]
1229+ -> Condition schema from grp params
1230+anyLte = unsafeSubqueryExpression "ANY <="
1234+ => NP (Aliased (Expression schema from grp params)) row
1235+ -> Query schema params row
1236+ -> Condition schema from grp params
1237+rowAnyLte = unsafeRowSubqueryExpression "ANY <="
1240+ :: Expression schema from grp params ty
1241+ -> Query schema params '[alias ::: ty]
1242+ -> Condition schema from grp params
1243+allGt = unsafeSubqueryExpression "ALL >"
1247+ => NP (Aliased (Expression schema from grp params)) row
1248+ -> Query schema params row
1249+ -> Condition schema from grp params
1250+rowAllGt = unsafeRowSubqueryExpression "ALL >"
1253+ :: Expression schema from grp params ty
1254+ -> Query schema params '[alias ::: ty]
1255+ -> Condition schema from grp params
1256+anyGt = unsafeSubqueryExpression "ANY >"
1260+ => NP (Aliased (Expression schema from grp params)) row
1261+ -> Query schema params row
1262+ -> Condition schema from grp params
1263+rowAnyGt = unsafeRowSubqueryExpression "ANY >"
1266+ :: Expression schema from grp params ty
1267+ -> Query schema params '[alias ::: ty]
1268+ -> Condition schema from grp params
1269+allGte = unsafeSubqueryExpression "ALL >="
1273+ => NP (Aliased (Expression schema from grp params)) row
1274+ -> Query schema params row
1275+ -> Condition schema from grp params
1276+rowAllGte = unsafeRowSubqueryExpression "ALL >="
1279+ :: Expression schema from grp params ty
1280+ -> Query schema params '[alias ::: ty]
1281+ -> Condition schema from grp params
1282+anyGte = unsafeSubqueryExpression "ANY >="
1286+ => NP (Aliased (Expression schema from grp params)) row
1287+ -> Query schema params row
1288+ -> Condition schema from grp params
1289+rowAnyGte = unsafeRowSubqueryExpression "ANY >="