on dev help sign in
group by
6a62475Eitan Chatav
squeel-postgresql/src/Squeel/PostgreSQL/Schema.hs+5
@@ -35,6 +35,7 @@ module Squeel.PostgreSQL.Schema
35 , Alter
35 , Alter
36 , Rename
36 , Rename
37 , Join
37 , Join
38+ , Grouping (..)
38 , module GHC.OverloadedLabels
39 , module GHC.OverloadedLabels
39 , module GHC.TypeLits
40 , module GHC.TypeLits
40 ) where
41 ) where
@@ -167,3 +168,7 @@ type family Rename alias0 alias1 xs where
167type family Join xs ys where
168type family Join xs ys where
168 Join '[] ys = ys
169 Join '[] ys = ys
169 Join (x ': xs) ys = x ': Join xs ys
170 Join (x ': xs) ys = x ': Join xs ys
171+
172+data Grouping
173+ = Ungrouped
174+ | Grouped [(Symbol,(Symbol,ColumnType))]
squeel-postgresql/src/Squeel/PostgreSQL/Statement.hs+283−165
@@ -42,31 +42,34 @@ column expressions
42newtype Expression
42newtype Expression
43 (params :: [ColumnType])
43 (params :: [ColumnType])
44 (tables :: [(Symbol,[(Symbol,ColumnType)])])
44 (tables :: [(Symbol,[(Symbol,ColumnType)])])
45+ (grouping :: Grouping)
45 (ty :: ColumnType)
46 (ty :: ColumnType)
46 = UnsafeExpression { renderExpression :: ByteString }
47 = UnsafeExpression { renderExpression :: ByteString }
47 deriving (Show,Eq)
48 deriving (Show,Eq)
48
49
49class KnownNat n => HasParameter (n :: Nat) params ty | n params -> ty where
50class KnownNat n => HasParameter (n :: Nat) params ty | n params -> ty where
50− param :: Proxy# n -> Expression params tables ty
51+ param :: Proxy# n -> Expression params tables grouping ty
51 param p = UnsafeExpression $ ("$" <>) $ fromString $ show $ natVal' p
52 param p = UnsafeExpression $ ("$" <>) $ fromString $ show $ natVal' p
52instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
53instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
53instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
54instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
54 => HasParameter n (ty' : params) ty
55 => HasParameter n (ty' : params) ty
55
56
56−param1 :: Expression (ty1:tys) tables ty1
57+param1 :: Expression (ty1:tys) tables grouping ty1
57param1 = param (proxy# :: Proxy# 1)
58param1 = param (proxy# :: Proxy# 1)
58−param2 :: Expression (ty1:ty2:tys) tables ty2
59+param2 :: Expression (ty1:ty2:tys) tables grouping ty2
59param2 = param (proxy# :: Proxy# 2)
60param2 = param (proxy# :: Proxy# 2)
60−param3 :: Expression (ty1:ty2:ty3:tys) tables ty3
61+param3 :: Expression (ty1:ty2:ty3:tys) tables grouping ty3
61param3 = param (proxy# :: Proxy# 3)
62param3 = param (proxy# :: Proxy# 3)
62−param4 :: Expression (ty1:ty2:ty3:ty4:tys) tables ty4
63+param4 :: Expression (ty1:ty2:ty3:ty4:tys) tables grouping ty4
63param4 = param (proxy# :: Proxy# 4)
64param4 = param (proxy# :: Proxy# 4)
64−param5 :: Expression (ty1:ty2:ty3:ty4:ty5:tys) tables ty5
65+param5 :: Expression (ty1:ty2:ty3:ty4:ty5:tys) tables grouping ty5
65param5 = param (proxy# :: Proxy# 5)
66param5 = param (proxy# :: Proxy# 5)
66
67
67class KnownSymbol column => HasColumn column columns ty
68class KnownSymbol column => HasColumn column columns ty
68 | column columns -> ty where
69 | column columns -> ty where
70+ getColumn
71+ :: Proxy# column
69− getColumn :: Proxy# column -> Expression params '[table ::: columns] ty
72+ -> Expression params '[table ::: columns] 'Ungrouped ty
70 getColumn column = UnsafeExpression $ fromString $ symbolVal' column
73 getColumn column = UnsafeExpression $ fromString $ symbolVal' column
71instance {-# OVERLAPPING #-} KnownSymbol column
74instance {-# OVERLAPPING #-} KnownSymbol column
72 => HasColumn column ((column ::: optionality ty) ': tys) ('Required ty)
75 => HasColumn column ((column ::: optionality ty) ': tys) ('Required ty)
@@ -74,30 +77,30 @@ instance {-# OVERLAPPABLE #-} (KnownSymbol column, HasColumn column table ty)
74 => HasColumn column (ty' ': table) ty
77 => HasColumn column (ty' ': table) ty
75
78
76instance (HasColumn column columns ty, tables ~ '[table ::: columns])
79instance (HasColumn column columns ty, tables ~ '[table ::: columns])
77− => IsLabel column (Expression params tables ty) where
80+ => IsLabel column (Expression params tables 'Ungrouped ty) where
78 fromLabel = getColumn
81 fromLabel = getColumn
79
82
80(&.)
83(&.)
81 :: (HasTable table tables columns, HasColumn column columns ty)
84 :: (HasTable table tables columns, HasColumn column columns ty)
82− => Alias table -> Alias column -> Expression params tables ty
85+ => Alias table -> Alias column -> Expression params tables 'Ungrouped ty
83table &. column = UnsafeExpression $
86table &. column = UnsafeExpression $
84 renderAlias table <> "." <> renderAlias column
87 renderAlias table <> "." <> renderAlias column
85
88
86−def :: Expression params '[] ('Optional (nullity ty))
89+def :: Expression params '[] grouping ('Optional (nullity ty))
87def = UnsafeExpression "DEFAULT"
90def = UnsafeExpression "DEFAULT"
88
91
89notDef
92notDef
90− :: Expression params '[] ('Required (nullity ty))
93+ :: Expression params '[] grouping ('Required (nullity ty))
91− -> Expression params '[] ('Optional (nullity ty))
94+ -> Expression params '[] grouping ('Optional (nullity ty))
92notDef = UnsafeExpression . renderExpression
95notDef = UnsafeExpression . renderExpression
93
96
94−null :: Expression params tables (optionality ('Null ty))
97+null :: Expression params tables grouping (optionality ('Null ty))
95null = UnsafeExpression "NULL"
98null = UnsafeExpression "NULL"
96
99
97coalesce
100coalesce
98− :: [Expression params tables ('Required ('Null x))]
101+ :: [Expression params tables grouping ('Required ('Null x))]
99− -> Expression params tables ('Required ('NotNull x))
102+ -> Expression params tables grouping ('Required ('NotNull x))
100− -> Expression params tables ('Required ('NotNull x))
103+ -> Expression params tables grouping ('Required ('NotNull x))
101coalesce nulls isn'tNull = UnsafeExpression $ mconcat
104coalesce nulls isn'tNull = UnsafeExpression $ mconcat
102 [ "COALESCE("
105 [ "COALESCE("
103 , ByteString.intercalate ", " $ map renderExpression nulls
106 , ByteString.intercalate ", " $ map renderExpression nulls
@@ -107,28 +110,28 @@ coalesce nulls isn'tNull = UnsafeExpression $ mconcat
107
110
108unsafeBinaryOp
111unsafeBinaryOp
109 :: ByteString
112 :: ByteString
110− -> Expression params tables ty0
113+ -> Expression params tables grouping ty0
111− -> Expression params tables ty1
114+ -> Expression params tables grouping ty1
112− -> Expression params tables ty2
115+ -> Expression params tables grouping ty2
113unsafeBinaryOp op x y = UnsafeExpression $ mconcat
116unsafeBinaryOp op x y = UnsafeExpression $ mconcat
114 ["(", renderExpression x, " ", op, " ", renderExpression y, ")"]
117 ["(", renderExpression x, " ", op, " ", renderExpression y, ")"]
115
118
116unsafeUnaryOp
119unsafeUnaryOp
117 :: ByteString
120 :: ByteString
118− -> Expression params tables ty0
121+ -> Expression params tables grouping ty0
119− -> Expression params tables ty1
122+ -> Expression params tables grouping ty1
120unsafeUnaryOp op x = UnsafeExpression $ mconcat
123unsafeUnaryOp op x = UnsafeExpression $ mconcat
121 ["(", op, " ", renderExpression x, ")"]
124 ["(", op, " ", renderExpression x, ")"]
122
125
123unsafeFunction
126unsafeFunction
124 :: ByteString
127 :: ByteString
125− -> Expression params tables xty
128+ -> Expression params tables grouping xty
126− -> Expression params tables yty
129+ -> Expression params tables grouping yty
127unsafeFunction fun x = UnsafeExpression $ mconcat
130unsafeFunction fun x = UnsafeExpression $ mconcat
128 [fun, "(", renderExpression x, ")"]
131 [fun, "(", renderExpression x, ")"]
129
132
130instance PGNum ty
133instance PGNum ty
131− => Num (Expression params tables ('Required (nullity ty))) where
134+ => Num (Expression params tables grouping ('Required (nullity ty))) where
132 (+) = unsafeBinaryOp "+"
135 (+) = unsafeBinaryOp "+"
133 (-) = unsafeBinaryOp "-"
136 (-) = unsafeBinaryOp "-"
134 (*) = unsafeBinaryOp "*"
137 (*) = unsafeBinaryOp "*"
@@ -140,13 +143,13 @@ instance PGNum ty
140 . fromString
143 . fromString
141 . show
144 . show
142
145
143−instance PGFractional ty
146+instance PGFractional ty => Fractional
144− => Fractional (Expression params tables ('Required (nullity ty))) where
147+ (Expression params tables grouping ('Required (nullity ty))) where
145 (/) = unsafeBinaryOp "/"
148 (/) = unsafeBinaryOp "/"
146 fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
149 fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
147
150
148−instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty)
151+instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty) => Floating
149− => Floating (Expression params tables ('Required (nullity ty))) where
152+ (Expression params tables grouping ('Required (nullity ty))) where
150 pi = UnsafeExpression "pi()"
153 pi = UnsafeExpression "pi()"
151 exp = unsafeFunction "exp"
154 exp = unsafeFunction "exp"
152 log = unsafeFunction "ln"
155 log = unsafeFunction "ln"
@@ -156,9 +159,9 @@ instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty)
156 logBase b y = cast pgtype $ logBaseNumeric b y
159 logBase b y = cast pgtype $ logBaseNumeric b y
157 where
160 where
158 logBaseNumeric
161 logBaseNumeric
159− :: Expression params tables ('Required (nullity ty))
162+ :: Expression params tables grouping ('Required (nullity ty))
160− -> Expression params tables ('Required (nullity ty))
163+ -> Expression params tables grouping ('Required (nullity ty))
161− -> Expression params tables ('Required (nullity 'PGNumeric))
164+ -> Expression params tables grouping ('Required (nullity 'PGNumeric))
162 logBaseNumeric b' y' = UnsafeExpression $ mconcat
165 logBaseNumeric b' y' = UnsafeExpression $ mconcat
163 [ "log("
166 [ "log("
164 , renderExpression b' <> "::numeric"
167 , renderExpression b' <> "::numeric"
@@ -181,17 +184,17 @@ instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty)
181
184
182atan2
185atan2
183 :: PGFloating float
186 :: PGFloating float
184− => Expression params tables ('Required (nullity float))
187+ => Expression params tables grouping ('Required (nullity float))
185− -> Expression params tables ('Required (nullity float))
188+ -> Expression params tables grouping ('Required (nullity float))
186− -> Expression params tables ('Required (nullity float))
189+ -> Expression params tables grouping ('Required (nullity float))
187atan2 y x = UnsafeExpression $
190atan2 y x = UnsafeExpression $
188 "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
191 "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
189
192
190class PGCast (ty0 :: PGType) (ty1 :: PGType) where
193class PGCast (ty0 :: PGType) (ty1 :: PGType) where
191 cast
194 cast
192 :: TypeExpression ('Required ('Null ty1))
195 :: TypeExpression ('Required ('Null ty1))
193− -> Expression params tables ('Required (nullity ty0))
196+ -> Expression params tables grouping ('Required (nullity ty0))
194− -> Expression params tables ('Required (nullity ty1))
197+ -> Expression params tables grouping ('Required (nullity ty1))
195 cast ty x = UnsafeExpression $
198 cast ty x = UnsafeExpression $
196 "(" <> renderExpression x <> "::" <> renderTypeExpression ty <> ")"
199 "(" <> renderExpression x <> "::" <> renderTypeExpression ty <> ")"
197instance PGCast 'PGInt2 'PGInt2
200instance PGCast 'PGInt2 'PGInt2
@@ -209,96 +212,97 @@ instance PGCast 'PGInt8 'PGNumeric
209
212
210div
213div
211 :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
214 :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
212− => Expression params tables ('Required (nullity ty))
215+ => Expression params tables grouping ('Required (nullity ty))
213− -> Expression params tables ('Required (nullity ty))
216+ -> Expression params tables grouping ('Required (nullity ty))
214− -> Expression params tables ('Required (nullity ty))
217+ -> Expression params tables grouping ('Required (nullity ty))
215div = unsafeBinaryOp "/"
218div = unsafeBinaryOp "/"
216
219
217mod
220mod
218 :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
221 :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
219− => Expression params tables ('Required (nullity ty))
222+ => Expression params tables grouping ('Required (nullity ty))
220− -> Expression params tables ('Required (nullity ty))
223+ -> Expression params tables grouping ('Required (nullity ty))
221− -> Expression params tables ('Required (nullity ty))
224+ -> Expression params tables grouping ('Required (nullity ty))
222mod = unsafeBinaryOp "%"
225mod = unsafeBinaryOp "%"
223
226
224truncate
227truncate
225 :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
228 :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
226− => Expression params tables ('Required (nullity frac))
229+ => Expression params tables grouping ('Required (nullity frac))
227− -> Expression params tables ('Required (nullity int))
230+ -> Expression params tables grouping ('Required (nullity int))
228truncate = cast pgtype . truncate'
231truncate = cast pgtype . truncate'
229 where
232 where
230 truncate'
233 truncate'
231− :: Expression params tables ('Required (nullity frac))
234+ :: Expression params tables grouping ('Required (nullity frac))
232− -> Expression params tables ('Required (nullity 'PGInt4))
235+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
233 truncate' = unsafeFunction "trunc"
236 truncate' = unsafeFunction "trunc"
234
237
235round
238round
236 :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
239 :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
237− => Expression params tables ('Required (nullity frac))
240+ => Expression params tables grouping ('Required (nullity frac))
238− -> Expression params tables ('Required (nullity int))
241+ -> Expression params tables grouping ('Required (nullity int))
239round = cast pgtype . round'
242round = cast pgtype . round'
240 where
243 where
241 round'
244 round'
242− :: Expression params tables ('Required (nullity frac))
245+ :: Expression params tables grouping ('Required (nullity frac))
243− -> Expression params tables ('Required (nullity 'PGInt4))
246+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
244 round' = unsafeFunction "round"
247 round' = unsafeFunction "round"
245
248
246ceiling
249ceiling
247 :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
250 :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
248− => Expression params tables ('Required (nullity frac))
251+ => Expression params tables grouping ('Required (nullity frac))
249− -> Expression params tables ('Required (nullity int))
252+ -> Expression params tables grouping ('Required (nullity int))
250ceiling = cast pgtype . ceiling'
253ceiling = cast pgtype . ceiling'
251 where
254 where
252 ceiling'
255 ceiling'
253− :: Expression params tables ('Required (nullity frac))
256+ :: Expression params tables grouping ('Required (nullity frac))
254− -> Expression params tables ('Required (nullity 'PGInt4))
257+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
255 ceiling' = unsafeFunction "ceiling"
258 ceiling' = unsafeFunction "ceiling"
256
259
260+instance IsString
257−instance IsString (Expression params tables ('Required (nullity 'PGText))) where
261+ (Expression params tables grouping ('Required (nullity 'PGText))) where
258− fromString str = UnsafeExpression $
262+ fromString str = UnsafeExpression $
259− "E\'" <> fromString (escape =<< str) <> "\'"
263+ "E\'" <> fromString (escape =<< str) <> "\'"
260− where
264+ where
261− escape = \case
265+ escape = \case
262− '\NUL' -> "\\0"
266+ '\NUL' -> "\\0"
263− '\'' -> "''"
267+ '\'' -> "''"
264− '"' -> "\\\""
268+ '"' -> "\\\""
265− '\b' -> "\\b"
269+ '\b' -> "\\b"
266− '\n' -> "\\n"
270+ '\n' -> "\\n"
267− '\r' -> "\\r"
271+ '\r' -> "\\r"
268− '\t' -> "\\t"
272+ '\t' -> "\\t"
269− '\\' -> "\\\\"
273+ '\\' -> "\\\\"
270− c -> [c]
274+ c -> [c]
271−
275+
272−type Condition params tables =
276+type Condition params tables grouping =
273− Expression params tables ('Required ('NotNull 'PGBool))
277+ Expression params tables grouping ('Required ('NotNull 'PGBool))
274−
278+
275−true :: Condition params tables
279+true :: Condition params tables grouping
276true = UnsafeExpression "TRUE"
280true = UnsafeExpression "TRUE"
277
281
278−false :: Condition params tables
282+false :: Condition params tables grouping
279false = UnsafeExpression "FALSE"
283false = UnsafeExpression "FALSE"
280
284
281−notB
285+not_
282− :: Condition params tables
286+ :: Condition params tables grouping
283− -> Condition params tables
287+ -> Condition params tables grouping
284−notB = unsafeUnaryOp "NOT"
288+not_ = unsafeUnaryOp "NOT"
285
289
286(&&*)
290(&&*)
287− :: Condition params tables
291+ :: Condition params tables grouping
288− -> Condition params tables
292+ -> Condition params tables grouping
289− -> Condition params tables
293+ -> Condition params tables grouping
290(&&*) = unsafeBinaryOp "AND"
294(&&*) = unsafeBinaryOp "AND"
291
295
292(||*)
296(||*)
293− :: Condition params tables
297+ :: Condition params tables grouping
294− -> Condition params tables
298+ -> Condition params tables grouping
295− -> Condition params tables
299+ -> Condition params tables grouping
296(||*) = unsafeBinaryOp "OR"
300(||*) = unsafeBinaryOp "OR"
297
301
298caseWhenThenElse
302caseWhenThenElse
299− :: [(Condition params tables, Expression params tables ty)]
303+ :: [(Condition params tables grouping, Expression params tables grouping ty)]
300− -> Expression params tables ty
304+ -> Expression params tables grouping ty
301− -> Expression params tables ty
305+ -> Expression params tables grouping ty
302caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
306caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
303 [ "CASE"
307 [ "CASE"
304 , mconcat
308 , mconcat
@@ -313,48 +317,86 @@ caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
313 ]
317 ]
314
318
315ifThenElse
319ifThenElse
316− :: Condition params tables
320+ :: Condition params tables grouping
317− -> Expression params tables ty
321+ -> Expression params tables grouping ty
318− -> Expression params tables ty
322+ -> Expression params tables grouping ty
319− -> Expression params tables ty
323+ -> Expression params tables grouping ty
320ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
324ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
321
325
322(==*)
326(==*)
323− :: Expression params tables ty
327+ :: Expression params tables grouping ('Required (nullity ty))
324− -> Expression params tables ty
328+ -> Expression params tables grouping ('Required (nullity ty))
325− -> Condition params tables
329+ -> Expression params tables grouping ('Required (nullity 'PGBool))
326(==*) = unsafeBinaryOp "="
330(==*) = unsafeBinaryOp "="
327
331
328(/=*)
332(/=*)
329− :: Expression params tables ty
333+ :: Expression params tables grouping ('Required (nullity ty))
330− -> Expression params tables ty
334+ -> Expression params tables grouping ('Required (nullity ty))
331− -> Condition params tables
335+ -> Expression params tables grouping ('Required (nullity 'PGBool))
332(/=*) = unsafeBinaryOp "<>"
336(/=*) = unsafeBinaryOp "<>"
333
337
334(>=*)
338(>=*)
335− :: Expression params tables ty
339+ :: Expression params tables grouping ('Required (nullity ty))
336− -> Expression params tables ty
340+ -> Expression params tables grouping ('Required (nullity ty))
337− -> Condition params tables
341+ -> Expression params tables grouping ('Required (nullity 'PGBool))
338(>=*) = unsafeBinaryOp ">="
342(>=*) = unsafeBinaryOp ">="
339
343
340(<*)
344(<*)
341− :: Expression params tables ty
345+ :: Expression params tables grouping ('Required (nullity ty))
342− -> Expression params tables ty
346+ -> Expression params tables grouping ('Required (nullity ty))
343− -> Condition params tables
347+ -> Expression params tables grouping ('Required (nullity 'PGBool))
344(<*) = unsafeBinaryOp "<"
348(<*) = unsafeBinaryOp "<"
345
349
346(<=*)
350(<=*)
347− :: Expression params tables ty
351+ :: Expression params tables grouping ('Required (nullity ty))
348− -> Expression params tables ty
352+ -> Expression params tables grouping ('Required (nullity ty))
349− -> Condition params tables
353+ -> Expression params tables grouping ('Required (nullity 'PGBool))
350(<=*) = unsafeBinaryOp "<="
354(<=*) = unsafeBinaryOp "<="
351
355
352(>*)
356(>*)
353− :: Expression params tables ty
357+ :: Expression params tables grouping ('Required (nullity ty))
354− -> Expression params tables ty
358+ -> Expression params tables grouping ('Required (nullity ty))
355− -> Condition params tables
359+ -> Expression params tables grouping ('Required (nullity 'PGBool))
356(>*) = unsafeBinaryOp ">"
360(>*) = unsafeBinaryOp ">"
357
361
362+data SortExpression params tables grouping where
363+ Asc
364+ :: Expression params tables grouping ty
365+ -> SortExpression params tables grouping
366+ Desc
367+ :: Expression params tables grouping ty
368+ -> SortExpression params tables grouping
369+
370+renderSortExpression :: SortExpression params tables grouping -> ByteString
371+renderSortExpression = \case
372+ Asc expression -> renderExpression expression <> " ASC"
373+ Desc expression -> renderExpression expression <> " DESC"
374+
375+data Aggregate (ty0 :: ColumnType) (ty1 :: ColumnType) =
376+ UnsafeAggregate { renderAggregate :: ByteString }
377+
378+sumAggregate
379+ :: PGNum ty
380+ => Aggregate ('Required (nullity ty)) ('Required (nullity ty))
381+sumAggregate = UnsafeAggregate "sum"
382+
383+class (KnownSymbol table, KnownSymbol column)
384+ => GroupedBy table column distincts ty where
385+ getGroup
386+ :: (HasTable table tables columns, HasColumn column columns ty)
387+ => Alias table
388+ -> Alias column
389+ -> Expression params tables ('Grouped distincts) ty
390+
391+class (KnownSymbol table, KnownSymbol column)
392+ => Aggregated table column distincts ty where
393+ getAggregate
394+ :: (HasTable table tables columns, HasColumn column columns ty0)
395+ => Alias table
396+ -> Alias column
397+ -> Aggregate ty0 ty
398+ -> Expression params tables ('Grouped distincts) ty
399+
358{-----------------------------------------
400{-----------------------------------------
359tables
401tables
360-----------------------------------------}
402-----------------------------------------}
@@ -392,22 +434,22 @@ data TableReference params schema tables where
392 -> TableReference params schema (Join left right)
434 -> TableReference params schema (Join left right)
393 InnerJoin
435 InnerJoin
394 :: TableReference params schema right
436 :: TableReference params schema right
395− -> Condition params (Join left right)
437+ -> Condition params (Join left right) 'Ungrouped
396 -> TableReference params schema left
438 -> TableReference params schema left
397 -> TableReference params schema (Join left right)
439 -> TableReference params schema (Join left right)
398 LeftOuterJoin
440 LeftOuterJoin
399 :: TableReference params schema right
441 :: TableReference params schema right
400− -> Condition params (Join left right)
442+ -> Condition params (Join left right) 'Ungrouped
401 -> TableReference params schema left
443 -> TableReference params schema left
402 -> TableReference params schema (Join left (NullifyTables right))
444 -> TableReference params schema (Join left (NullifyTables right))
403 RightOuterJoin
445 RightOuterJoin
404 :: TableReference params schema right
446 :: TableReference params schema right
405− -> Condition params (Join left right)
447+ -> Condition params (Join left right) 'Ungrouped
406 -> TableReference params schema left
448 -> TableReference params schema left
407 -> TableReference params schema (Join (NullifyTables left) right)
449 -> TableReference params schema (Join (NullifyTables left) right)
408 FullOuterJoin
450 FullOuterJoin
409 :: TableReference params schema right
451 :: TableReference params schema right
410− -> Condition params (Join left right)
452+ -> Condition params (Join left right) 'Ungrouped
411 -> TableReference params schema left
453 -> TableReference params schema left
412 -> TableReference params schema
454 -> TableReference params schema
413 (Join (NullifyTables left) (NullifyTables right))
455 (Join (NullifyTables left) (NullifyTables right))
@@ -450,61 +492,137 @@ renderTableReference = \case
450 , renderExpression on
492 , renderExpression on
451 ]
493 ]
452
494
495+data By tables tabcolty where
496+ By
497+ :: (HasTable table tables columns, HasColumn column columns ty)
498+ => Alias table
499+ -> Alias column
500+ -> By tables (table ::: (column ::: ty))
501+
502+renderBy :: By tables tabcolty -> ByteString
503+renderBy (By table column) = renderAlias table <> "." <> renderAlias column
504+
505+data GroupByClause tables grouping where
506+ NoGroups :: GroupByClause tables 'Ungrouped
507+ Distinct
508+ :: SListI distincts
509+ => NP (By tables) distincts
510+ -> GroupByClause tables ('Grouped distincts)
511+
512+renderGroupByClause :: GroupByClause tables grouping -> ByteString
513+renderGroupByClause = \case
514+ NoGroups -> ""
515+ Distinct Nil -> ""
516+ Distinct distincts -> " GROUP BY " <> ByteString.intercalate ", "
517+ (hcollapse (hmap (K . renderBy) distincts))
518+
519+data HavingClause params tables grouping where
520+ NoHaving :: HavingClause params tables 'Ungrouped
521+ Having
522+ :: [Condition params tables ('Grouped distincts)]
523+ -> HavingClause params tables ('Grouped distincts)
524+
525+renderHavingClause :: HavingClause params tables grouping -> ByteString
526+renderHavingClause = \case
527+ NoHaving -> ""
528+ Having [] -> ""
529+ Having conditions -> " HAVING " <> ByteString.intercalate ", "
530+ (renderExpression <$> conditions)
531+
453data TableExpression
532data TableExpression
454 (params :: [ColumnType])
533 (params :: [ColumnType])
455 (schema :: [(Symbol,[(Symbol,ColumnType)])])
534 (schema :: [(Symbol,[(Symbol,ColumnType)])])
456 (tables :: [(Symbol,[(Symbol,ColumnType)])])
535 (tables :: [(Symbol,[(Symbol,ColumnType)])])
536+ (grouping :: Grouping)
457 = TableExpression
537 = TableExpression
458 { fromClause :: TableReference params schema tables
538 { fromClause :: TableReference params schema tables
459− , whereClause :: [Condition params tables]
539+ , whereClause :: [Condition params tables 'Ungrouped]
540+ , groupByClause :: GroupByClause tables grouping
541+ , havingClause :: HavingClause params tables grouping
542+ , orderByClause :: [SortExpression params tables grouping]
460− , limitClause :: Maybe Word64
543+ , limitClause :: [Word64]
461− , offsetClause :: Maybe Word64
544+ , offsetClause :: [Word64]
462 }
545 }
463
546
464renderTableExpression
547renderTableExpression
465− :: TableExpression params schema tables
548+ :: TableExpression params schema tables grouping
466 -> ByteString
549 -> ByteString
550+renderTableExpression
467−renderTableExpression (TableExpression tables whs' lims' offs') = mconcat
551+ (TableExpression tables whs' grps' hvs' srts' lims' offs') = mconcat
468− [ "FROM ", renderTableReference tables
552+ [ "FROM ", renderTableReference tables
469− , renderWheres whs'
553+ , renderWheres whs'
554+ , renderGroupByClause grps'
555+ , renderHavingClause hvs'
556+ , renderSorts srts'
470− , renderLimits lims'
557+ , renderLimits lims'
471− , renderOffsets offs'
558+ , renderOffsets offs'
559+ ]
472− ] where
560+ where
473− renderWheres = \case
561+ renderWheres = \case
474− [] -> ""
562+ [] -> ""
475− wh:[] -> " WHERE " <> renderExpression wh
563+ wh:[] -> " WHERE " <> renderExpression wh
476− wh:whs -> " WHERE " <> renderExpression (foldr (&&*) wh whs)
564+ wh:whs -> " WHERE " <> renderExpression (foldr (&&*) wh whs)
477− renderLimits = \case
565+ renderSorts = \case
478− Nothing -> ""
566+ [] -> ""
567+ srts -> " SORT BY "
568+ <> ByteString.intercalate ", " (renderSortExpression <$> srts)
569+ renderLimits = \case
570+ [] -> ""
479− Just lim -> " LIMIT " <> fromString (show lim)
571+ lims -> " LIMIT " <> fromString (show (minimum lims))
480− renderOffsets = \case
572+ renderOffsets = \case
481− Nothing -> ""
573+ [] -> ""
482− Just off -> " OFFSET " <> fromString (show off)
574+ offs -> " OFFSET " <> fromString (show (sum offs))
483
575
484from
576from
485 :: TableReference params schema tables
577 :: TableReference params schema tables
486− -> TableExpression params schema tables
578+ -> TableExpression params schema tables 'Ungrouped
487−from tables = TableExpression tables [] Nothing Nothing
579+from tables = TableExpression tables [] NoGroups NoHaving [] [] []
488
580
489where_
581where_
490− :: Condition params tables
582+ :: Condition params tables 'Ungrouped
491− -> TableExpression params schema tables
583+ -> TableExpression params schema tables grouping
492− -> TableExpression params schema tables
584+ -> TableExpression params schema tables grouping
493where_ wh tables = tables {whereClause = wh : whereClause tables}
585where_ wh tables = tables {whereClause = wh : whereClause tables}
494
586
587+group
588+ :: SListI distincts
589+ => NP (By tables) distincts
590+ -> TableExpression params schema tables 'Ungrouped
591+ -> TableExpression params schema tables ('Grouped distincts)
592+group distincts tables = TableExpression
593+ { fromClause = fromClause tables
594+ , whereClause = whereClause tables
595+ , groupByClause = Distinct distincts
596+ , havingClause = Having []
597+ , orderByClause = []
598+ , limitClause = limitClause tables
599+ , offsetClause = offsetClause tables
600+ }
601+
602+having
603+ :: Condition params tables ('Grouped distincts)
604+ -> TableExpression params schema tables ('Grouped distincts)
605+ -> TableExpression params schema tables ('Grouped distincts)
606+having hv tables = tables
607+ { havingClause = case havingClause tables of Having hvs -> Having (hv:hvs) }
608+
609+orderBy
610+ :: [SortExpression params tables grouping]
611+ -> TableExpression params schema tables grouping
612+ -> TableExpression params schema tables grouping
613+orderBy srts tables = tables {orderByClause = orderByClause tables ++ srts}
614+
495limit
615limit
496 :: Word64
616 :: Word64
497− -> TableExpression params schema tables
617+ -> TableExpression params schema tables grouping
498− -> TableExpression params schema tables
618+ -> TableExpression params schema tables grouping
499−limit lim tables = tables
500− {limitClause = maybe (Just lim) (Just . min lim) (limitClause tables)}
619+limit lim tables = tables {limitClause = lim : limitClause tables}
501
620
502offset
621offset
503 :: Word64
622 :: Word64
504− -> TableExpression params schema tables
623+ -> TableExpression params schema tables grouping
505− -> TableExpression params schema tables
624+ -> TableExpression params schema tables grouping
506−offset off tables = tables
507− {offsetClause = maybe (Just off) (Just . (off +)) (offsetClause tables)}
625+offset off tables = tables {offsetClause = off : offsetClause tables}
508
626
509{-----------------------------------------
627{-----------------------------------------
510type expressions
628type expressions
@@ -606,7 +724,7 @@ notNull
606 -> TypeExpression ('Required ('NotNull ty))
724 -> TypeExpression ('Required ('NotNull ty))
607notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <> " NOT NULL"
725notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <> " NOT NULL"
608default_
726default_
609− :: Expression '[] '[] ('Required ty)
727+ :: Expression '[] '[] 'Ungrouped ('Required ty)
610 -> TypeExpression ('Required ty)
728 -> TypeExpression ('Required ty)
611 -> TypeExpression ('Optional ty)
729 -> TypeExpression ('Optional ty)
612default_ x ty = UnsafeTypeExpression $
730default_ x ty = UnsafeTypeExpression $
@@ -690,8 +808,8 @@ SELECT statements
690
808
691select
809select
692 :: SListI columns
810 :: SListI columns
693− => NP (Aliased (Expression params tables)) columns
811+ => NP (Aliased (Expression params tables grouping)) columns
694− -> TableExpression params schema tables
812+ -> TableExpression params schema tables grouping
695 -> Query schema params columns
813 -> Query schema params columns
696select list tabs = UnsafeQuery $
814select list tabs = UnsafeQuery $
697 "SELECT " <> renderList list <> " " <> renderTableExpression tabs
815 "SELECT " <> renderList list <> " " <> renderTableExpression tabs
@@ -703,14 +821,14 @@ select list tabs = UnsafeQuery $
703
821
704selectStar
822selectStar
705 :: (tables ~ '[table ::: columns])
823 :: (tables ~ '[table ::: columns])
706− => TableExpression params schema tables
824+ => TableExpression params schema tables 'Ungrouped
707 -> Query schema params columns
825 -> Query schema params columns
708selectStar tabs = UnsafeQuery $ "SELECT * " <> renderTableExpression tabs
826selectStar tabs = UnsafeQuery $ "SELECT * " <> renderTableExpression tabs
709
827
710selectDotStar
828selectDotStar
711 :: HasTable table tables columns
829 :: HasTable table tables columns
712 => Alias table
830 => Alias table
713− -> TableExpression params schema tables
831+ -> TableExpression params schema tables 'Ungrouped
714 -> Query schema params columns
832 -> Query schema params columns
715selectDotStar table tables = UnsafeQuery $
833selectDotStar table tables = UnsafeQuery $
716 "SELECT " <> renderAlias table <> ".* " <> renderTableExpression tables
834 "SELECT " <> renderAlias table <> ".* " <> renderTableExpression tables
@@ -831,7 +949,7 @@ data AlterColumn (ty0 :: ColumnType) (ty1 :: ColumnType) =
831 UnsafeAlterColumn {renderAlterColumn :: ByteString}
949 UnsafeAlterColumn {renderAlterColumn :: ByteString}
832
950
833setDefault
951setDefault
834− :: Expression '[] '[] ('Required ty)
952+ :: Expression '[] '[] 'Ungrouped ('Required ty)
835 -> AlterColumn ('Required ty) ('Optional ty)
953 -> AlterColumn ('Required ty) ('Optional ty)
836setDefault expression = UnsafeAlterColumn $
954setDefault expression = UnsafeAlterColumn $
837 "SET DEFAULT " <> renderExpression expression
955 "SET DEFAULT " <> renderExpression expression
@@ -860,7 +978,7 @@ INSERT statements
860insertInto
978insertInto
861 :: (SListI columns, HasTable table schema columns)
979 :: (SListI columns, HasTable table schema columns)
862 => Alias table
980 => Alias table
863− -> NP (Aliased (Expression params '[])) columns
981+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
864 -> Manipulation schema params '[]
982 -> Manipulation schema params '[]
865insertInto table expressions = UnsafeManipulation $ "INSERT INTO "
983insertInto table expressions = UnsafeManipulation $ "INSERT INTO "
866 <> renderAlias table
984 <> renderAlias table
@@ -879,8 +997,8 @@ insertInto table expressions = UnsafeManipulation $ "INSERT INTO "
879insertIntoReturning
997insertIntoReturning
880 :: (SListI columns, SListI results, HasTable table schema columns)
998 :: (SListI columns, SListI results, HasTable table schema columns)
881 => Alias table
999 => Alias table
882− -> NP (Aliased (Expression params '[])) columns
1000+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
883− -> NP (Aliased (Expression params '[table ::: columns])) results
1001+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
884 -> Manipulation schema params results
1002 -> Manipulation schema params results
885insertIntoReturning table inserts results
1003insertIntoReturning table inserts results
886 = UnsafeManipulation . mconcat $
1004 = UnsafeManipulation . mconcat $
@@ -911,7 +1029,7 @@ UPDATE statements
911
1029
912data UpdateExpression params table ty
1030data UpdateExpression params table ty
913 = Same
1031 = Same
914− | Set (Expression params table ty)
1032+ | Set (Expression params table 'Ungrouped ty)
915
1033
916renderUpdateExpression
1034renderUpdateExpression
917 :: Aliased (UpdateExpression params '[table ::: columns]) column
1035 :: Aliased (UpdateExpression params '[table ::: columns]) column
@@ -928,7 +1046,7 @@ update
928 :: (HasTable table schema columns, SListI columns)
1046 :: (HasTable table schema columns, SListI columns)
929 => Alias table
1047 => Alias table
930 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1048 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
931− -> Condition params '[table ::: columns]
1049+ -> Condition params '[table ::: columns] 'Ungrouped
932 -> Manipulation schema params '[]
1050 -> Manipulation schema params '[]
933update table columns wh = UnsafeManipulation $ mconcat
1051update table columns wh = UnsafeManipulation $ mconcat
934 [ "UPDATE "
1052 [ "UPDATE "
@@ -943,8 +1061,8 @@ updateReturning
943 :: (SListI columns, SListI results, HasTable table schema columns)
1061 :: (SListI columns, SListI results, HasTable table schema columns)
944 => Alias table
1062 => Alias table
945 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1063 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
946− -> Condition params '[table ::: columns]
1064+ -> Condition params '[table ::: columns] 'Ungrouped
947− -> NP (Aliased (Expression params '[table ::: columns])) results
1065+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
948 -> Manipulation schema params results
1066 -> Manipulation schema params results
949updateReturning table updates wh results = UnsafeManipulation $ mconcat
1067updateReturning table updates wh results = UnsafeManipulation $ mconcat
950 [ "UPDATE "
1068 [ "UPDATE "
@@ -965,9 +1083,9 @@ updateReturning table updates wh results = UnsafeManipulation $ mconcat
965upsertInto
1083upsertInto
966 :: (SListI columns, HasTable table schema columns)
1084 :: (SListI columns, HasTable table schema columns)
967 => Alias table
1085 => Alias table
968− -> NP (Aliased (Expression params '[])) columns
1086+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
969 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1087 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
970− -> Condition params '[table ::: columns]
1088+ -> Condition params '[table ::: columns] 'Ungrouped
971 -> Manipulation schema params '[]
1089 -> Manipulation schema params '[]
972upsertInto table inserts updates wh = UnsafeManipulation . mconcat $
1090upsertInto table inserts updates wh = UnsafeManipulation . mconcat $
973 [ "INSERT INTO "
1091 [ "INSERT INTO "
@@ -992,10 +1110,10 @@ upsertInto table inserts updates wh = UnsafeManipulation . mconcat $
992upsertIntoReturning
1110upsertIntoReturning
993 :: (SListI columns, SListI results, HasTable table schema columns)
1111 :: (SListI columns, SListI results, HasTable table schema columns)
994 => Alias table
1112 => Alias table
995− -> NP (Aliased (Expression params '[])) columns
1113+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
996 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1114 -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
997− -> Condition params '[table ::: columns]
1115+ -> Condition params '[table ::: columns] 'Ungrouped
998− -> NP (Aliased (Expression params '[table ::: columns])) results
1116+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
999 -> Manipulation schema params results
1117 -> Manipulation schema params results
1000upsertIntoReturning table inserts updates wh results =
1118upsertIntoReturning table inserts updates wh results =
1001 UnsafeManipulation . mconcat $
1119 UnsafeManipulation . mconcat $
@@ -1031,7 +1149,7 @@ DELETE statements
1031deleteFrom
1149deleteFrom
1032 :: HasTable table schema columns
1150 :: HasTable table schema columns
1033 => Alias table
1151 => Alias table
1034− -> Condition params '[table ::: columns]
1152+ -> Condition params '[table ::: columns] 'Ungrouped
1035 -> Manipulation schema params '[]
1153 -> Manipulation schema params '[]
1036deleteFrom table wh = UnsafeManipulation $ mconcat
1154deleteFrom table wh = UnsafeManipulation $ mconcat
1037 [ "DELETE FROM "
1155 [ "DELETE FROM "