on dev help sign in
more query docs
4c73e25Eitan Chatav
squeal-postgresql/src/Squeal/PostgreSQL/Query.hs+268−71
@@ -36,16 +36,13 @@ module Squeal.PostgreSQL.Query
36 , intersectAll
36 , intersectAll
37 , except
37 , except
38 , exceptAll
38 , exceptAll
39− -- * SELECT queries
39+ -- * Select
40 , select
40 , select
41 , selectDistinct
41 , selectDistinct
42 , selectStar
42 , selectStar
43 , selectDistinctStar
43 , selectDistinctStar
44 , selectDotStar
44 , selectDotStar
45 , selectDistinctDotStar
45 , selectDistinctDotStar
46− -- * FROM clauses
47− , FromClause (..)
48− , renderFromClause
49 -- * Table Expressions
46 -- * Table Expressions
50 , TableExpression (..)
47 , TableExpression (..)
51 , renderTableExpression
48 , renderTableExpression
@@ -56,6 +53,9 @@ module Squeal.PostgreSQL.Query
56 , orderBy
53 , orderBy
57 , limit
54 , limit
58 , offset
55 , offset
56+ -- * From
57+ , FromClause (..)
58+ , renderFromClause
59 -- * Grouping
59 -- * Grouping
60 , By (By, By2)
60 , By (By, By2)
61 , renderBy
61 , renderBy
@@ -63,7 +63,6 @@ module Squeal.PostgreSQL.Query
63 , renderGroupByClause
63 , renderGroupByClause
64 , HavingClause (NoHaving, Having)
64 , HavingClause (NoHaving, Having)
65 , renderHavingClause
65 , renderHavingClause
66− , GroupedBy (getGroup1, getGroup2)
67 -- * Sorting
66 -- * Sorting
68 , SortExpression (..)
67 , SortExpression (..)
69 , renderSortExpression
68 , renderSortExpression
@@ -84,7 +83,9 @@ import Squeal.PostgreSQL.Prettyprint
84import Squeal.PostgreSQL.Schema
83import Squeal.PostgreSQL.Schema
85
84
86-- | The process of retrieving or the command to retrieve data from a database
85-- | The process of retrieving or the command to retrieve data from a database
86+-- is called a `Query`. The `select`, `selectStar`, `selectDotStar`,
87+-- `selectDistinct`, `selectDistinctStar` and `selectDistinctDotStar` commands
87−-- is called a `Query`. The `select` command is used to specify queries.
88+-- are used to specify queries.
88newtype Query
89newtype Query
89 (schema :: TablesType)
90 (schema :: TablesType)
90 (params :: [ColumnType])
91 (params :: [ColumnType])
@@ -92,10 +93,9 @@ newtype Query
92 = UnsafeQuery { renderQuery :: ByteString }
93 = UnsafeQuery { renderQuery :: ByteString }
93 deriving (GHC.Generic,Show,Eq,Ord,NFData)
94 deriving (GHC.Generic,Show,Eq,Ord,NFData)
94
95
95−-- | The results of two queries can be combined using the set operations
96+-- | The results of two queries can be combined using the set operation
96−-- `union`, `intersect`, and `except` (set difference). Duplicates are
97+-- `union`. Duplicate rows are eliminated.
97−-- eliminated unless `unionAll`, `intersectAll` or `exceptAll` are used.
98+union
98−union, unionAll, intersect, intersectAll, except, exceptAll
99 :: Query schema params columns
99 :: Query schema params columns
100 -> Query schema params columns
100 -> Query schema params columns
101 -> Query schema params columns
101 -> Query schema params columns
@@ -103,22 +103,57 @@ q1 `union` q2 = UnsafeQuery $
103 parenthesized (renderQuery q1)
103 parenthesized (renderQuery q1)
104 <+> "UNION"
104 <+> "UNION"
105 <+> parenthesized (renderQuery q2)
105 <+> parenthesized (renderQuery q2)
106+
107+-- | The results of two queries can be combined using the set operation
108+-- `unionAll`, the disjoint union. Duplicate rows are retained.
109+unionAll
110+ :: Query schema params columns
111+ -> Query schema params columns
112+ -> Query schema params columns
106q1 `unionAll` q2 = UnsafeQuery $
113q1 `unionAll` q2 = UnsafeQuery $
107 parenthesized (renderQuery q1)
114 parenthesized (renderQuery q1)
108 <+> "UNION" <+> "ALL"
115 <+> "UNION" <+> "ALL"
109 <+> parenthesized (renderQuery q2)
116 <+> parenthesized (renderQuery q2)
117+
118+-- | The results of two queries can be combined using the set operation
119+-- `intersect`, the intersection. Duplicate rows are eliminated.
120+intersect
121+ :: Query schema params columns
122+ -> Query schema params columns
123+ -> Query schema params columns
110q1 `intersect` q2 = UnsafeQuery $
124q1 `intersect` q2 = UnsafeQuery $
111 parenthesized (renderQuery q1)
125 parenthesized (renderQuery q1)
112 <+> "INTERSECT"
126 <+> "INTERSECT"
113 <+> parenthesized (renderQuery q2)
127 <+> parenthesized (renderQuery q2)
128+
129+-- | The results of two queries can be combined using the set operation
130+-- `intersectAll`, the intersection. Duplicate rows are retained.
131+intersectAll
132+ :: Query schema params columns
133+ -> Query schema params columns
134+ -> Query schema params columns
114q1 `intersectAll` q2 = UnsafeQuery $
135q1 `intersectAll` q2 = UnsafeQuery $
115 parenthesized (renderQuery q1)
136 parenthesized (renderQuery q1)
116 <+> "INTERSECT" <+> "ALL"
137 <+> "INTERSECT" <+> "ALL"
117 <+> parenthesized (renderQuery q2)
138 <+> parenthesized (renderQuery q2)
139+
140+-- | The results of two queries can be combined using the set operation
141+-- `except`, the set difference. Duplicate rows are eliminated.
142+except
143+ :: Query schema params columns
144+ -> Query schema params columns
145+ -> Query schema params columns
118q1 `except` q2 = UnsafeQuery $
146q1 `except` q2 = UnsafeQuery $
119 parenthesized (renderQuery q1)
147 parenthesized (renderQuery q1)
120 <+> "EXCEPT"
148 <+> "EXCEPT"
121 <+> parenthesized (renderQuery q2)
149 <+> parenthesized (renderQuery q2)
150+
151+-- | The results of two queries can be combined using the set operation
152+-- `exceptAll`, the set difference. Duplicate rows are retained.
153+exceptAll
154+ :: Query schema params columns
155+ -> Query schema params columns
156+ -> Query schema params columns
122q1 `exceptAll` q2 = UnsafeQuery $
157q1 `exceptAll` q2 = UnsafeQuery $
123 parenthesized (renderQuery q1)
158 parenthesized (renderQuery q1)
124 <+> "EXCEPT" <+> "ALL"
159 <+> "EXCEPT" <+> "ALL"
@@ -128,101 +163,91 @@ q1 `exceptAll` q2 = UnsafeQuery $
128SELECT queries
163SELECT queries
129-----------------------------------------}
164-----------------------------------------}
130
165
166+-- | the `TableExpression` in the `select` command constructs an intermediate
167+-- virtual table by possibly combining tables, views, eliminating rows,
168+-- grouping, etc. This table is finally passed on to processing by
169+-- the select list. The select list determines which columns of
170+-- the intermediate table are actually output.
131select
171select
132 :: SListI columns
172 :: SListI columns
133 => NP (Aliased (Expression tables grouping params)) (column ': columns)
173 => NP (Aliased (Expression tables grouping params)) (column ': columns)
174+ -- ^ select list
134 -> TableExpression schema params tables grouping
175 -> TableExpression schema params tables grouping
176+ -- ^ intermediate virtual table
135 -> Query schema params (column ': columns)
177 -> Query schema params (column ': columns)
136select list tabs = UnsafeQuery $
178select list tabs = UnsafeQuery $
137 "SELECT"
179 "SELECT"
138 <+> renderCommaSeparated (renderAliased renderExpression) list
180 <+> renderCommaSeparated (renderAliased renderExpression) list
139 <+> renderTableExpression tabs
181 <+> renderTableExpression tabs
140
182
183+-- | After the select list has been processed, the result table can
184+-- be subject to the elimination of duplicate rows using `selectDistinct`.
141selectDistinct
185selectDistinct
142 :: SListI columns
186 :: SListI columns
143 => NP (Aliased (Expression tables 'Ungrouped params)) (column ': columns)
187 => NP (Aliased (Expression tables 'Ungrouped params)) (column ': columns)
188+ -- ^ select list
144 -> TableExpression schema params tables 'Ungrouped
189 -> TableExpression schema params tables 'Ungrouped
190+ -- ^ intermediate virtual table
145 -> Query schema params (column ': columns)
191 -> Query schema params (column ': columns)
146selectDistinct list tabs = UnsafeQuery $
192selectDistinct list tabs = UnsafeQuery $
147 "SELECT DISTINCT"
193 "SELECT DISTINCT"
148 <+> renderCommaSeparated (renderAliased renderExpression) list
194 <+> renderCommaSeparated (renderAliased renderExpression) list
149 <+> renderTableExpression tabs
195 <+> renderTableExpression tabs
150
196
151−selectStar, selectDistinctStar
197+-- | The simplest kind of query is `selectStar` which emits all columns
198+-- that the table expression produces.
199+selectStar
152 :: HasUnique table tables columns
200 :: HasUnique table tables columns
153 => TableExpression schema params tables 'Ungrouped
201 => TableExpression schema params tables 'Ungrouped
202+ -- ^ intermediate virtual table
154 -> Query schema params columns
203 -> Query schema params columns
155selectStar tabs = UnsafeQuery $ "SELECT" <+> "*" <+> renderTableExpression tabs
204selectStar tabs = UnsafeQuery $ "SELECT" <+> "*" <+> renderTableExpression tabs
205+
206+-- | A `selectDistinctStar` emits all columns that the table expression
207+-- produces and eliminates duplicate rows.
208+selectDistinctStar
209+ :: HasUnique table tables columns
210+ => TableExpression schema params tables 'Ungrouped
211+ -- ^ intermediate virtual table
212+ -> Query schema params columns
156selectDistinctStar tabs = UnsafeQuery $
213selectDistinctStar tabs = UnsafeQuery $
157 "SELECT DISTINCT" <+> "*" <+> renderTableExpression tabs
214 "SELECT DISTINCT" <+> "*" <+> renderTableExpression tabs
158
215
159−selectDotStar, selectDistinctDotStar
216+-- | When working with multiple tables, it can also be useful to ask
217+-- for all the columns of a particular table, using `selectDotStar`.
218+selectDotStar
160 :: HasTable table tables columns
219 :: HasTable table tables columns
161 => Alias table
220 => Alias table
221+ -- ^ particular virtual subtable
162 -> TableExpression schema params tables 'Ungrouped
222 -> TableExpression schema params tables 'Ungrouped
223+ -- ^ intermediate virtual table
163 -> Query schema params columns
224 -> Query schema params columns
164selectDotStar table tables = UnsafeQuery $
225selectDotStar table tables = UnsafeQuery $
165 "SELECT" <+> renderAlias table <> ".*" <+> renderTableExpression tables
226 "SELECT" <+> renderAlias table <> ".*" <+> renderTableExpression tables
227+
228+-- | A `selectDistinctDotStar` asks for all the columns of a particular table,
229+-- and eliminates duplicate rows.
230+selectDistinctDotStar
231+ :: HasTable table tables columns
232+ => Alias table
233+ -- ^ particular virtual subtable
234+ -> TableExpression schema params tables 'Ungrouped
235+ -- ^ intermediate virtual table
236+ -> Query schema params columns
166selectDistinctDotStar table tables = UnsafeQuery $
237selectDistinctDotStar table tables = UnsafeQuery $
167 "SELECT DISTINCT" <+> renderAlias table <> ".*"
238 "SELECT DISTINCT" <+> renderAlias table <> ".*"
168 <+> renderTableExpression tables
239 <+> renderTableExpression tables
169
240
170−{-----------------------------------------
171−FROM clauses
172−-----------------------------------------}
173−
174−data FromClause schema params tables where
175− Table
176− :: Aliased (Table schema) table
177− -> FromClause schema params '[table]
178− Subquery
179− :: Aliased (Query schema params) table
180− -> FromClause schema params '[table]
181− CrossJoin
182− :: FromClause schema params right
183− -> FromClause schema params left
184− -> FromClause schema params (Join left right)
185− InnerJoin
186− :: FromClause schema params right
187− -> Condition (Join left right) 'Ungrouped params
188− -> FromClause schema params left
189− -> FromClause schema params (Join left right)
190− LeftOuterJoin
191− :: FromClause schema params right
192− -> Condition (Join left right) 'Ungrouped params
193− -> FromClause schema params left
194− -> FromClause schema params (Join left (NullifyTables right))
195− RightOuterJoin
196− :: FromClause schema params right
197− -> Condition (Join left right) 'Ungrouped params
198− -> FromClause schema params left
199− -> FromClause schema params (Join (NullifyTables left) right)
200− FullOuterJoin
201− :: FromClause schema params right
202− -> Condition (Join left right) 'Ungrouped params
203− -> FromClause schema params left
204− -> FromClause schema params
205− (Join (NullifyTables left) (NullifyTables right))
206−
207−renderFromClause :: FromClause schema params tables -> ByteString
208−renderFromClause = \case
209− Table table -> renderAliased renderTable table
210− Subquery selection -> renderAliased (parenthesized . renderQuery) selection
211− CrossJoin right left ->
212− renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
213− InnerJoin right on left -> renderJoin "INNER JOIN" right on left
214− LeftOuterJoin right on left -> renderJoin "LEFT OUTER JOIN" right on left
215− RightOuterJoin right on left -> renderJoin "RIGHT OUTER JOIN" right on left
216− FullOuterJoin right on left -> renderJoin "FULL OUTER JOIN" right on left
217− where
218− renderJoin op right on left =
219− renderFromClause left <+> op <+> renderFromClause right
220− <+> "ON" <+> renderExpression on
221−
222{-----------------------------------------
241{-----------------------------------------
223Table Expressions
242Table Expressions
224-----------------------------------------}
243-----------------------------------------}
225
244
245+-- | A `TableExpression` computes a table. The table expression contains
246+-- a `fromClause` that is optionally followed by a `whereClause`,
247+-- `groupByClause`, `havingClause`, `orderByClause`, `limitClause`
248+-- and `offsetClause`s. Trivial table expressions simply refer
249+-- to a table on disk, a so-called base table, but more complex expressions
250+-- can be used to modify or combine base tables in various ways.
226data TableExpression
251data TableExpression
227 (schema :: TablesType)
252 (schema :: TablesType)
228 (params :: [ColumnType])
253 (params :: [ColumnType])
@@ -230,14 +255,47 @@ data TableExpression
230 (grouping :: Grouping)
255 (grouping :: Grouping)
231 = TableExpression
256 = TableExpression
232 { fromClause :: FromClause schema params tables
257 { fromClause :: FromClause schema params tables
258+ -- ^ A table reference that can be a table name, or a derived table such
259+ -- as a subquery, a @JOIN@ construct, or complex combinations of these.
233 , whereClause :: [Condition tables 'Ungrouped params]
260 , whereClause :: [Condition tables 'Ungrouped params]
261+ -- ^ optional search coditions, combined with `.&&`. After the processing
262+ -- of the `fromClause` is done, each row of the derived virtual table
263+ -- is checked against the search condition. If the result of the
264+ -- condition is true, the row is kept in the output table,
265+ -- otherwise it is discarded. The search condition typically references
266+ -- at least one column of the table generated in the `fromClause`;
267+ -- this is not required, but otherwise the WHERE clause will
268+ -- be fairly useless.
234 , groupByClause :: GroupByClause tables grouping
269 , groupByClause :: GroupByClause tables grouping
270+ -- ^ The `groupByClause` is used to group together those rows in a table
271+ -- that have the same values in all the columns listed. The order in which
272+ -- the columns are listed does not matter. The effect is to combine each
273+ -- set of rows having common values into one group row that represents all
274+ -- rows in the group. This is done to eliminate redundancy in the output
275+ -- and/or compute aggregates that apply to these groups.
235 , havingClause :: HavingClause tables grouping params
276 , havingClause :: HavingClause tables grouping params
277+ -- ^ If a table has been grouped using `groupBy`, but only certain groups
278+ -- are of interest, the `havingClause` can be used, much like a
279+ -- `whereClause`, to eliminate groups from the result. Expressions in the
280+ -- `havingClause` can refer both to grouped expressions and to ungrouped
281+ -- expressions (which necessarily involve an aggregate function).
236 , orderByClause :: [SortExpression tables grouping params]
282 , orderByClause :: [SortExpression tables grouping params]
283+ -- ^ The `orderByClause` is for optional sorting. When more than one
284+ -- `SortExpression` is specified, the later (right) values are used to sort
285+ -- rows that are equal according to the earlier (left) values.
237 , limitClause :: [Word64]
286 , limitClause :: [Word64]
287+ -- ^ The `limitClause` is combined with `min` to give a limit count
288+ -- if nonempty. If a limit count is given, no more than that many rows
289+ -- will be returned (but possibly fewer, if the query itself yields
290+ -- fewer rows).
238 , offsetClause :: [Word64]
291 , offsetClause :: [Word64]
292+ -- ^ The `offsetClause` is combined with `+` to give an offset count
293+ -- if nonempty. The offset count says to skip that many rows before
294+ -- beginning to return rows. The rows are skipped before the limit count
295+ -- is applied.
239 }
296 }
240
297
298+-- | Render a `TableExpression`
241renderTableExpression
299renderTableExpression
242 :: TableExpression schema params tables grouping
300 :: TableExpression schema params tables grouping
243 -> ByteString
301 -> ByteString
@@ -267,17 +325,27 @@ renderTableExpression
267 [] -> ""
325 [] -> ""
268 offs -> " OFFSET" <+> fromString (show (sum offs))
326 offs -> " OFFSET" <+> fromString (show (sum offs))
269
327
328+-- | A `from` generates a `TableExpression` from a table reference that can be
329+-- a table name, or a derived table such as a subquery, a JOIN construct,
330+-- or complex combinations of these. A `from` may be transformed by `where_`,
331+-- `group`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator
332+-- to match the left-to-right sequencing of their placement in SQL.
270from
333from
271− :: FromClause schema params tables
334+ :: FromClause schema params tables -- ^ table reference
272 -> TableExpression schema params tables 'Ungrouped
335 -> TableExpression schema params tables 'Ungrouped
273from tables = TableExpression tables [] NoGroups NoHaving [] [] []
336from tables = TableExpression tables [] NoGroups NoHaving [] [] []
274
337
338+-- | A `where_` is an endomorphism of `TableExpression`s which adds a
339+-- search condition to the `whereClause`.
275where_
340where_
276 :: Condition tables 'Ungrouped params
341 :: Condition tables 'Ungrouped params
277 -> TableExpression schema params tables grouping
342 -> TableExpression schema params tables grouping
278 -> TableExpression schema params tables grouping
343 -> TableExpression schema params tables grouping
279where_ wh tables = tables {whereClause = wh : whereClause tables}
344where_ wh tables = tables {whereClause = wh : whereClause tables}
280
345
346+-- | A `group` is a transformation of `TableExpression`s which switches
347+-- its `Grouping` from `Ungrouped` to `Grouped`. Use @group Nil@ to perform
348+-- a "grand total" aggregation query.
281group
349group
282 :: SListI bys
350 :: SListI bys
283 => NP (By tables) bys
351 => NP (By tables) bys
@@ -293,6 +361,8 @@ group bys tables = TableExpression
293 , offsetClause = offsetClause tables
361 , offsetClause = offsetClause tables
294 }
362 }
295
363
364+-- | A `having` is an endomorphism of `TableExpression`s which adds a
365+-- search condition to the `havingClause`.
296having
366having
297 :: Condition tables ('Grouped bys) params
367 :: Condition tables ('Grouped bys) params
298 -> TableExpression schema params tables ('Grouped bys)
368 -> TableExpression schema params tables ('Grouped bys)
@@ -300,28 +370,134 @@ having
300having hv tables = tables
370having hv tables = tables
301 { havingClause = case havingClause tables of Having hvs -> Having (hv:hvs) }
371 { havingClause = case havingClause tables of Having hvs -> Having (hv:hvs) }
302
372
373+-- | An `orderBy` is an endomorphism of `TableExpression`s which appends an
374+-- ordering to the right of the `orderByClause`.
303orderBy
375orderBy
304 :: [SortExpression tables grouping params]
376 :: [SortExpression tables grouping params]
305 -> TableExpression schema params tables grouping
377 -> TableExpression schema params tables grouping
306 -> TableExpression schema params tables grouping
378 -> TableExpression schema params tables grouping
307orderBy srts tables = tables {orderByClause = orderByClause tables ++ srts}
379orderBy srts tables = tables {orderByClause = orderByClause tables ++ srts}
308
380
381+-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
382+-- `limitClause`.
309limit
383limit
310 :: Word64
384 :: Word64
311 -> TableExpression schema params tables grouping
385 -> TableExpression schema params tables grouping
312 -> TableExpression schema params tables grouping
386 -> TableExpression schema params tables grouping
313limit lim tables = tables {limitClause = lim : limitClause tables}
387limit lim tables = tables {limitClause = lim : limitClause tables}
314
388
389+-- | An `offset` is an endomorphism of `TableExpression`s which adds to the
390+-- `offsetClause`.
315offset
391offset
316 :: Word64
392 :: Word64
317 -> TableExpression schema params tables grouping
393 -> TableExpression schema params tables grouping
318 -> TableExpression schema params tables grouping
394 -> TableExpression schema params tables grouping
319offset off tables = tables {offsetClause = off : offsetClause tables}
395offset off tables = tables {offsetClause = off : offsetClause tables}
320
396
397+{-----------------------------------------
398+FROM clauses
399+-----------------------------------------}
400+
401+{- |
402+A `FromClause` can be a table name, or a derived table such
403+as a subquery, a @JOIN@ construct, or complex combinations of these.
404+
405+* A real `Table` is a table from the schema.
406+
407+* `Subquery` derives a table from a `Query`.
408+
409+* A joined table is a table derived from two other (real or derived) tables
410+according to the rules of the particular join type. `CrossJoin`, `InnerJoin`,
411+`LeftOuterJoin`, `RightOuterJoin` and `FullOuterJoin` are available and can
412+be nested using the `&` operator to match the left-to-right sequencing of
413+their placement in SQL.
414+
415+ * @t1 & CrossJoin t2@. For every possible combination of rows from
416+ @t1@ and @t2@ (i.e., a Cartesian product), the joined table will contain
417+ a row consisting of all columns in @t1@ followed by all columns in @t2@.
418+ If the tables have @n@ and @m@ rows respectively, the joined table will
419+ have @n * m@ rows.
420+
421+ * @t1 & InnerJoin t2 on@. For each row @r1@ of @t1@, the joined
422+ table has a row for each row in @t2@ that satisfies the on @condition@
423+ with @r1@
424+
425+ * @t1 & LeftOuterJoin t2 on@. First, an inner join is performed.
426+ Then, for each row in @t1@ that does not satisfy the on @condition@ with
427+ any row in @t2@, a joined row is added with null values in columns of @t2@.
428+ Thus, the joined table always has at least one row for each row in @t1@.
429+
430+ * @t1 & RightOuterJoin t2 on@. First, an inner join is performed.
431+ Then, for each row in @t2@ that does not satisfy the on condition with
432+ any row in @t1@, a joined row is added with null values in columns of @t1@.
433+ This is the converse of a left join: the result table will always
434+ have a row for each row in @t2@.
435+
436+ * @t1 & FullOuterJoin t2 on@. First, an inner join is performed.
437+ Then, for each row in @t1@ that does not satisfy the on condition with
438+ any row in @t2@, a joined row is added with null values in columns of @t2@.
439+ Also, for each row of @t2@ that does not satisfy the join condition
440+ with any row in @t1@, a joined row with null values in the columns of @t1@
441+ is added.
442+-}
443+data FromClause schema params tables where
444+ Table
445+ :: Aliased (Table schema) table
446+ -> FromClause schema params '[table]
447+ Subquery
448+ :: Aliased (Query schema params) table
449+ -> FromClause schema params '[table]
450+ CrossJoin
451+ :: FromClause schema params right
452+ -> FromClause schema params left
453+ -> FromClause schema params (Join left right)
454+ InnerJoin
455+ :: FromClause schema params right
456+ -> Condition (Join left right) 'Ungrouped params
457+ -> FromClause schema params left
458+ -> FromClause schema params (Join left right)
459+ LeftOuterJoin
460+ :: FromClause schema params right
461+ -> Condition (Join left right) 'Ungrouped params
462+ -> FromClause schema params left
463+ -> FromClause schema params (Join left (NullifyTables right))
464+ RightOuterJoin
465+ :: FromClause schema params right
466+ -> Condition (Join left right) 'Ungrouped params
467+ -> FromClause schema params left
468+ -> FromClause schema params (Join (NullifyTables left) right)
469+ FullOuterJoin
470+ :: FromClause schema params right
471+ -> Condition (Join left right) 'Ungrouped params
472+ -> FromClause schema params left
473+ -> FromClause schema params
474+ (Join (NullifyTables left) (NullifyTables right))
475+
476+-- | Renders a `FromClause`.
477+renderFromClause :: FromClause schema params tables -> ByteString
478+renderFromClause = \case
479+ Table table -> renderAliased renderTable table
480+ Subquery selection -> renderAliased (parenthesized . renderQuery) selection
481+ CrossJoin right left ->
482+ renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
483+ InnerJoin right on left -> renderJoin "INNER JOIN" right on left
484+ LeftOuterJoin right on left -> renderJoin "LEFT OUTER JOIN" right on left
485+ RightOuterJoin right on left -> renderJoin "RIGHT OUTER JOIN" right on left
486+ FullOuterJoin right on left -> renderJoin "FULL OUTER JOIN" right on left
487+ where
488+ renderJoin op right on left =
489+ renderFromClause left <+> op <+> renderFromClause right
490+ <+> "ON" <+> renderExpression on
491+
321{-----------------------------------------
492{-----------------------------------------
322Grouping
493Grouping
323-----------------------------------------}
494-----------------------------------------}
324
495
496+-- | `By`s are used in `group` to reference a list of columns which are then
497+-- used to group together those rows in a table that have the same values
498+-- in all the columns listed. @By \#col@ will reference an unambiguous
499+-- column @col@; otherwise @By2 \#tab \! \#col@ will reference a table
500+-- qualified column @tab.col@.
325data By
501data By
326 (tables :: TablesType)
502 (tables :: TablesType)
327 (by :: (Symbol,Symbol)) where
503 (by :: (Symbol,Symbol)) where
@@ -336,25 +512,36 @@ data By
336deriving instance Show (By tables by)
512deriving instance Show (By tables by)
337deriving instance Eq (By tables by)
513deriving instance Eq (By tables by)
338deriving instance Ord (By tables by)
514deriving instance Ord (By tables by)
339−
515+
516+-- | Renders a `By`.
340renderBy :: By tables tabcolty -> ByteString
517renderBy :: By tables tabcolty -> ByteString
341renderBy = \case
518renderBy = \case
342 By column -> renderAlias column
519 By column -> renderAlias column
343 By2 (table, column) -> renderAlias table <> "." <> renderAlias column
520 By2 (table, column) -> renderAlias table <> "." <> renderAlias column
344−
521+
522+-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
523+-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
524+-- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be
525+-- done on @NoGroups@ while all output `Expression`s must be aggregated
526+-- in @Group Nil@.
345data GroupByClause tables grouping where
527data GroupByClause tables grouping where
346 NoGroups :: GroupByClause tables 'Ungrouped
528 NoGroups :: GroupByClause tables 'Ungrouped
347 Group
529 Group
348 :: SListI bys
530 :: SListI bys
349 => NP (By tables) bys
531 => NP (By tables) bys
350 -> GroupByClause tables ('Grouped bys)
532 -> GroupByClause tables ('Grouped bys)
351−
533+
534+-- | Renders a `GroupByClause`.
352renderGroupByClause :: GroupByClause tables grouping -> ByteString
535renderGroupByClause :: GroupByClause tables grouping -> ByteString
353renderGroupByClause = \case
536renderGroupByClause = \case
354 NoGroups -> ""
537 NoGroups -> ""
355 Group Nil -> ""
538 Group Nil -> ""
356 Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
539 Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
357−
540+
541+-- | A `HavingClause` is used to eliminate groups that are not of interest.
542+-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`
543+-- `TableExpression` must use `Having` whose conditions are combined with
544+-- `.&&`.
358data HavingClause tables grouping params where
545data HavingClause tables grouping params where
359 NoHaving :: HavingClause tables 'Ungrouped params
546 NoHaving :: HavingClause tables 'Ungrouped params
360 Having
547 Having
@@ -363,7 +550,8 @@ data HavingClause tables grouping params where
363deriving instance Show (HavingClause tables grouping params)
550deriving instance Show (HavingClause tables grouping params)
364deriving instance Eq (HavingClause tables grouping params)
551deriving instance Eq (HavingClause tables grouping params)
365deriving instance Ord (HavingClause tables grouping params)
552deriving instance Ord (HavingClause tables grouping params)
366−
553+
554+-- | Render a `HavingClause`.
367renderHavingClause :: HavingClause tables grouping params -> ByteString
555renderHavingClause :: HavingClause tables grouping params -> ByteString
368renderHavingClause = \case
556renderHavingClause = \case
369 NoHaving -> ""
557 NoHaving -> ""
@@ -375,6 +563,14 @@ renderHavingClause = \case
375Sorting
563Sorting
376-----------------------------------------}
564-----------------------------------------}
377
565
566+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
567+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
568+-- column to ascending or descending. Ascending order puts smaller values
569+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
570+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
571+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
572+-- determine whether nulls appear before or after non-null values in the sort
573+-- ordering of a `Null` result column.
378data SortExpression tables grouping params where
574data SortExpression tables grouping params where
379 Asc
575 Asc
380 :: Expression tables grouping params ('Required ('NotNull ty))
576 :: Expression tables grouping params ('Required ('NotNull ty))
@@ -395,7 +591,8 @@ data SortExpression tables grouping params where
395 :: Expression tables grouping params ('Required ('Null ty))
591 :: Expression tables grouping params ('Required ('Null ty))
396 -> SortExpression tables grouping params
592 -> SortExpression tables grouping params
397deriving instance Show (SortExpression tables grouping params)
593deriving instance Show (SortExpression tables grouping params)
398−
594+
595+-- | Render a `SortExpression`.
399renderSortExpression :: SortExpression tables grouping params -> ByteString
596renderSortExpression :: SortExpression tables grouping params -> ByteString
400renderSortExpression = \case
597renderSortExpression = \case
401 Asc expression -> renderExpression expression <+> "ASC"
598 Asc expression -> renderExpression expression <+> "ASC"