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