@@ -1,1143 +0,0 @@
1−{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
2−{-# LANGUAGE
3− DataKinds
4− , FlexibleContexts
5− , FlexibleInstances
6− , FunctionalDependencies
7− , GADTs
8− , LambdaCase
9− , MagicHash
10− , OverloadedStrings
11− , PolyKinds
12− , RankNTypes
13− , ScopedTypeVariables
14− , TypeApplications
15− , TypeFamilies
16− , TypeOperators
17− , UndecidableInstances
18−#-}
19−
20−module Squeel.PostgreSQL.Statement where
21−
22−import Control.Category
23−import Data.ByteString (ByteString)
24−import Data.Foldable
25−import Data.Maybe
26−import Data.Monoid
27−import Data.Ratio
28−import Data.String
29−import Data.Word
30−import Generics.SOP
31−import GHC.Exts
32−import GHC.OverloadedLabels
33−import GHC.TypeLits
34−import Prelude hiding (RealFrac(..), id, (.))
35−
36−import qualified Data.ByteString as ByteString
37−
38−import Squeel.PostgreSQL.Schema
39−
40−{-----------------------------------------
41−column expressions
42−-----------------------------------------}
43−
44−newtype Expression
45− (params :: [ColumnType])
46− (tables :: [(Symbol,[(Symbol,ColumnType)])])
47− (grouping :: Grouping)
48− (ty :: ColumnType)
49− = UnsafeExpression { renderExpression :: ByteString }
50− deriving (Show,Eq)
51−
52−class KnownNat n => HasParameter (n :: Nat) params ty | n params -> ty where
53− param :: Proxy# n -> Expression params tables grouping ty
54− param p = UnsafeExpression $ ("$" <>) $ fromString $ show $ natVal' p
55−instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
56−instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
57− => HasParameter n (ty' : params) ty
58−
59−param1 :: Expression (ty1:tys) tables grouping ty1
60−param1 = param (proxy# :: Proxy# 1)
61−param2 :: Expression (ty1:ty2:tys) tables grouping ty2
62−param2 = param (proxy# :: Proxy# 2)
63−param3 :: Expression (ty1:ty2:ty3:tys) tables grouping ty3
64−param3 = param (proxy# :: Proxy# 3)
65−param4 :: Expression (ty1:ty2:ty3:ty4:tys) tables grouping ty4
66−param4 = param (proxy# :: Proxy# 4)
67−param5 :: Expression (ty1:ty2:ty3:ty4:ty5:tys) tables grouping ty5
68−param5 = param (proxy# :: Proxy# 5)
69−
70−class KnownSymbol column => HasColumn column columns ty
71− | column columns -> ty where
72− getColumn
73− :: Proxy# column
74− -> Expression params '[table ::: columns] 'Ungrouped ty
75− getColumn column = UnsafeExpression $ renderSymbol column
76−instance {-# OVERLAPPING #-} KnownSymbol column
77− => HasColumn column ((column ::: optionality ty) ': tys) ('Required ty)
78−instance {-# OVERLAPPABLE #-} (KnownSymbol column, HasColumn column table ty)
79− => HasColumn column (ty' ': table) ty
80−
81−instance (HasColumn column columns ty, tables ~ '[table ::: columns])
82− => IsLabel column (Expression params tables 'Ungrouped ty) where
83− fromLabel = getColumn
84−
85−instance (HasTable table tables columns, HasColumn column columns ty)
86− => IsTableColumn table column (Expression params tables 'Ungrouped ty) where
87− table &. column = UnsafeExpression $
88− renderAlias table <> "." <> renderAlias column
89−
90−def :: Expression params '[] grouping ('Optional (nullity ty))
91−def = UnsafeExpression "DEFAULT"
92−
93−unDef
94− :: Expression params '[] grouping ('Required (nullity ty))
95− -> Expression params '[] grouping ('Optional (nullity ty))
96−unDef = UnsafeExpression . renderExpression
97−
98−null :: Expression params tables grouping (optionality ('Null ty))
99−null = UnsafeExpression "NULL"
100−
101−unNull
102− :: Expression params tables grouping (optionality ('NotNull ty))
103− -> Expression params tables grouping (optionality ('Null ty))
104−unNull = UnsafeExpression . renderExpression
105−
106−coalesce
107− :: [Expression params tables grouping ('Required ('Null x))]
108− -> Expression params tables grouping ('Required ('NotNull x))
109− -> Expression params tables grouping ('Required ('NotNull x))
110−coalesce nulls isn'tNull = UnsafeExpression $
111− "COALESCE"
112− <> parenthesized (commaSeparated (renderExpression <$> nulls))
113− <> ", " <> renderExpression isn'tNull
114−
115−unsafeBinaryOp
116− :: ByteString
117− -> Expression params tables grouping ty0
118− -> Expression params tables grouping ty1
119− -> Expression params tables grouping ty2
120−unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
121− renderExpression x <+> op <+> renderExpression y
122−
123−unsafeUnaryOp
124− :: ByteString
125− -> Expression params tables grouping ty0
126− -> Expression params tables grouping ty1
127−unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
128− op <+> renderExpression x
129−
130−unsafeFunction
131− :: ByteString
132− -> Expression params tables grouping xty
133− -> Expression params tables grouping yty
134−unsafeFunction fun x = UnsafeExpression $
135− fun <> parenthesized (renderExpression x)
136−
137−instance PGNum ty
138− => Num (Expression params tables grouping ('Required (nullity ty))) where
139− (+) = unsafeBinaryOp "+"
140− (-) = unsafeBinaryOp "-"
141− (*) = unsafeBinaryOp "*"
142− abs = unsafeFunction "abs"
143− signum = unsafeFunction "sign"
144− fromInteger
145− = UnsafeExpression
146− . (<> if decimal (Proxy :: Proxy ty) then "." else "")
147− . fromString
148− . show
149−
150−instance PGFractional ty => Fractional
151− (Expression params tables grouping ('Required (nullity ty))) where
152− (/) = unsafeBinaryOp "/"
153− fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
154−
155−instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty) => Floating
156− (Expression params tables grouping ('Required (nullity ty))) where
157− pi = UnsafeExpression "pi()"
158− exp = unsafeFunction "exp"
159− log = unsafeFunction "ln"
160− sqrt = unsafeFunction "sqrt"
161− b ** x = UnsafeExpression $
162− "power(" <> renderExpression b <> ", " <> renderExpression x <> ")"
163− logBase b y = cast pgtype $ logBaseNumeric b y
164− where
165− logBaseNumeric
166− :: Expression params tables grouping ('Required (nullity ty))
167− -> Expression params tables grouping ('Required (nullity ty))
168− -> Expression params tables grouping ('Required (nullity 'PGNumeric))
169− logBaseNumeric b' y' = UnsafeExpression $ mconcat
170− [ "log("
171− , renderExpression b' <> "::numeric"
172− , ", "
173− , renderExpression y' <> "::numeric"
174− , ")"
175− ]
176− sin = unsafeFunction "sin"
177− cos = unsafeFunction "cos"
178− tan = unsafeFunction "tan"
179− asin = unsafeFunction "asin"
180− acos = unsafeFunction "acos"
181− atan = unsafeFunction "atan"
182− sinh x = (exp x - exp (-x)) / 2
183− cosh x = (exp x + exp (-x)) / 2
184− tanh x = sinh x / cosh x
185− asinh x = log (x + sqrt (x*x + 1))
186− acosh x = log (x + sqrt (x*x - 1))
187− atanh x = log ((1 + x) / (1 - x)) / 2
188−
189−atan2
190− :: PGFloating float
191− => Expression params tables grouping ('Required (nullity float))
192− -> Expression params tables grouping ('Required (nullity float))
193− -> Expression params tables grouping ('Required (nullity float))
194−atan2 y x = UnsafeExpression $
195− "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
196−
197−class PGCast (ty0 :: PGType) (ty1 :: PGType) where
198− cast
199− :: TypeExpression ('Required ('Null ty1))
200− -> Expression params tables grouping ('Required (nullity ty0))
201− -> Expression params tables grouping ('Required (nullity ty1))
202− cast ty x = UnsafeExpression $
203− "(" <> renderExpression x <> "::" <> renderTypeExpression ty <> ")"
204−instance PGCast 'PGInt2 'PGInt2
205−instance PGCast 'PGInt2 'PGInt4
206−instance PGCast 'PGInt2 'PGInt8
207−instance PGCast 'PGInt4 'PGInt2
208−instance PGCast 'PGInt4 'PGInt4
209−instance PGCast 'PGInt4 'PGInt8
210−instance PGCast 'PGInt8 'PGInt2
211−instance PGCast 'PGInt8 'PGInt4
212−instance PGCast 'PGInt8 'PGInt8
213−instance PGCast 'PGInt8 'PGFloat4
214−instance PGCast 'PGInt8 'PGFloat8
215−instance PGCast 'PGInt8 'PGNumeric
216−
217−div
218− :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
219− => Expression params tables grouping ('Required (nullity ty))
220− -> Expression params tables grouping ('Required (nullity ty))
221− -> Expression params tables grouping ('Required (nullity ty))
222−div = unsafeBinaryOp "/"
223−
224−mod
225− :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
226− => Expression params tables grouping ('Required (nullity ty))
227− -> Expression params tables grouping ('Required (nullity ty))
228− -> Expression params tables grouping ('Required (nullity ty))
229−mod = unsafeBinaryOp "%"
230−
231−truncate
232− :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
233− => Expression params tables grouping ('Required (nullity frac))
234− -> Expression params tables grouping ('Required (nullity int))
235−truncate = cast pgtype . truncate'
236− where
237− truncate'
238− :: Expression params tables grouping ('Required (nullity frac))
239− -> Expression params tables grouping ('Required (nullity 'PGInt4))
240− truncate' = unsafeFunction "trunc"
241−
242−round
243− :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
244− => Expression params tables grouping ('Required (nullity frac))
245− -> Expression params tables grouping ('Required (nullity int))
246−round = cast pgtype . round'
247− where
248− round'
249− :: Expression params tables grouping ('Required (nullity frac))
250− -> Expression params tables grouping ('Required (nullity 'PGInt4))
251− round' = unsafeFunction "round"
252−
253−ceiling
254− :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
255− => Expression params tables grouping ('Required (nullity frac))
256− -> Expression params tables grouping ('Required (nullity int))
257−ceiling = cast pgtype . ceiling'
258− where
259− ceiling'
260− :: Expression params tables grouping ('Required (nullity frac))
261− -> Expression params tables grouping ('Required (nullity 'PGInt4))
262− ceiling' = unsafeFunction "ceiling"
263−
264−instance IsString
265− (Expression params tables grouping ('Required (nullity 'PGText))) where
266− fromString str = UnsafeExpression $
267− "E\'" <> fromString (escape =<< str) <> "\'"
268− where
269− escape = \case
270− '\NUL' -> "\\0"
271− '\'' -> "''"
272− '"' -> "\\\""
273− '\b' -> "\\b"
274− '\n' -> "\\n"
275− '\r' -> "\\r"
276− '\t' -> "\\t"
277− '\\' -> "\\\\"
278− c -> [c]
279−
280−type Condition params tables grouping =
281− Expression params tables grouping ('Required ('NotNull 'PGBool))
282−
283−true :: Condition params tables grouping
284−true = UnsafeExpression "TRUE"
285−
286−false :: Condition params tables grouping
287−false = UnsafeExpression "FALSE"
288−
289−not_
290− :: Condition params tables grouping
291− -> Condition params tables grouping
292−not_ = unsafeUnaryOp "NOT"
293−
294−(&&*)
295− :: Condition params tables grouping
296− -> Condition params tables grouping
297− -> Condition params tables grouping
298−(&&*) = unsafeBinaryOp "AND"
299−
300−(||*)
301− :: Condition params tables grouping
302− -> Condition params tables grouping
303− -> Condition params tables grouping
304−(||*) = unsafeBinaryOp "OR"
305−
306−caseWhenThenElse
307− :: [(Condition params tables grouping, Expression params tables grouping ty)]
308− -> Expression params tables grouping ty
309− -> Expression params tables grouping ty
310−caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
311− [ "CASE"
312− , mconcat
313− [ mconcat
314− [ " WHEN ", renderExpression when_
315− , " THEN ", renderExpression then_
316− ]
317− | (when_,then_) <- whenThens
318− ]
319− , " ELSE ", renderExpression else_
320− , " END"
321− ]
322−
323−ifThenElse
324− :: Condition params tables grouping
325− -> Expression params tables grouping ty
326− -> Expression params tables grouping ty
327− -> Expression params tables grouping ty
328−ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
329−
330−(==*)
331− :: Expression params tables grouping ('Required (nullity ty))
332− -> Expression params tables grouping ('Required (nullity ty))
333− -> Expression params tables grouping ('Required (nullity 'PGBool))
334−(==*) = unsafeBinaryOp "="
335−
336−(/=*)
337− :: Expression params tables grouping ('Required (nullity ty))
338− -> Expression params tables grouping ('Required (nullity ty))
339− -> Expression params tables grouping ('Required (nullity 'PGBool))
340−(/=*) = unsafeBinaryOp "<>"
341−
342−(>=*)
343− :: Expression params tables grouping ('Required (nullity ty))
344− -> Expression params tables grouping ('Required (nullity ty))
345− -> Expression params tables grouping ('Required (nullity 'PGBool))
346−(>=*) = unsafeBinaryOp ">="
347−
348−(<*)
349− :: Expression params tables grouping ('Required (nullity ty))
350− -> Expression params tables grouping ('Required (nullity ty))
351− -> Expression params tables grouping ('Required (nullity 'PGBool))
352−(<*) = unsafeBinaryOp "<"
353−
354−(<=*)
355− :: Expression params tables grouping ('Required (nullity ty))
356− -> Expression params tables grouping ('Required (nullity ty))
357− -> Expression params tables grouping ('Required (nullity 'PGBool))
358−(<=*) = unsafeBinaryOp "<="
359−
360−(>*)
361− :: Expression params tables grouping ('Required (nullity ty))
362− -> Expression params tables grouping ('Required (nullity ty))
363− -> Expression params tables grouping ('Required (nullity 'PGBool))
364−(>*) = unsafeBinaryOp ">"
365−
366−data SortExpression params tables grouping where
367− Asc
368− :: Expression params tables grouping ty
369− -> SortExpression params tables grouping
370− Desc
371− :: Expression params tables grouping ty
372− -> SortExpression params tables grouping
373−
374−renderSortExpression :: SortExpression params tables grouping -> ByteString
375−renderSortExpression = \case
376− Asc expression -> renderExpression expression <+> "ASC"
377− Desc expression -> renderExpression expression <+> "DESC"
378−
379−{-----------------------------------------
380−aggregation
381−-----------------------------------------}
382−
383−data By
384− (tables :: [(Symbol,[(Symbol,ColumnType)])])
385− (tabcol :: (Symbol,Symbol)) where
386− By
387− :: (HasTable table tables columns, HasColumn column columns ty)
388− => (Alias table, Alias column)
389− -> By tables '(table, column)
390−
391−renderBy :: By tables tabcolty -> ByteString
392−renderBy (By (table, column)) = renderAlias table <> "." <> renderAlias column
393−
394−data GroupByClause tables grouping where
395− NoGroups :: GroupByClause tables 'Ungrouped
396− Group
397− :: SListI bys
398− => NP (By tables) bys
399− -> GroupByClause tables ('Grouped bys)
400−
401−renderGroupByClause :: GroupByClause tables grouping -> ByteString
402−renderGroupByClause = \case
403− NoGroups -> ""
404− Group Nil -> ""
405− Group bys -> " GROUP BY" <+> renderCommaSeparated renderBy bys
406−
407−data HavingClause params tables grouping where
408− NoHaving :: HavingClause params tables 'Ungrouped
409− Having
410− :: [Condition params tables ('Grouped bys)]
411− -> HavingClause params tables ('Grouped bys)
412−
413−renderHavingClause :: HavingClause params tables grouping -> ByteString
414−renderHavingClause = \case
415− NoHaving -> ""
416− Having [] -> ""
417− Having conditions ->
418− " HAVING" <+> commaSeparated (renderExpression <$> conditions)
419−
420−class (KnownSymbol table, KnownSymbol column)
421− => GroupedBy table column bys where
422− getGroup1
423− :: (tables ~ '[table ::: columns], HasColumn column columns ty)
424− => Proxy# column
425− -> Expression params tables ('Grouped bys) ty
426− getGroup1 column = UnsafeExpression $ fromString (symbolVal' column)
427− getGroup2
428− :: (HasTable table tables columns, HasColumn column columns ty)
429− => Alias table
430− -> Alias column
431− -> Expression params tables ('Grouped bys) ty
432− getGroup2 table column = UnsafeExpression $
433− renderAlias table <> "." <> renderAlias column
434−instance {-# OVERLAPPING #-} (KnownSymbol table, KnownSymbol column)
435− => GroupedBy table column ('(table,column) ': bys)
436−instance {-# OVERLAPPABLE #-}
437− ( KnownSymbol table
438− , KnownSymbol column
439− , GroupedBy table column bys
440− ) => GroupedBy table column (tabcol ': bys)
441−
442−instance
443− ( tables ~ '[table ::: columns]
444− , HasColumn column columns ty
445− , GroupedBy table column bys
446− ) => IsLabel column
447− (Expression params tables ('Grouped bys) ty) where fromLabel = getGroup1
448−
449−instance
450− ( HasTable table tables columns
451− , HasColumn column columns ty
452− , GroupedBy table column bys
453− ) => IsTableColumn table column
454− (Expression params tables ('Grouped bys) ty) where (&.) = getGroup2
455−
456−unsafeAggregate
457− :: ByteString
458− -> Expression params tables 'Ungrouped xty
459− -> Expression params tables ('Grouped bys) yty
460−unsafeAggregate fun x = UnsafeExpression $ mconcat
461− [fun, "(", renderExpression x, ")"]
462−
463−sum_
464− :: PGNum ty
465− => Expression params tables 'Ungrouped ('Required (nullity ty))
466− -> Expression params tables ('Grouped bys) ('Required (nullity ty))
467−sum_ = unsafeAggregate "sum"
468−
469−{-----------------------------------------
470−tables
471−-----------------------------------------}
472−
473−newtype Table
474− (schema :: [(Symbol,[(Symbol,ColumnType)])])
475− (columns :: [(Symbol,ColumnType)])
476− = UnsafeTable { renderTable :: ByteString }
477− deriving (Show,Eq)
478−
479−class KnownSymbol table => HasTable table tables columns
480− | table tables -> columns where
481− getTable :: Proxy# table -> Table tables columns
482− getTable table = UnsafeTable $ fromString $ symbolVal' table
483−instance {-# OVERLAPPING #-} KnownSymbol table
484− => HasTable table ((table ::: columns) ': tables) columns
485−instance {-# OVERLAPPABLE #-}
486− (KnownSymbol table, HasTable table schema columns)
487− => HasTable table (table' ': schema) columns
488−
489−instance HasTable table schema columns
490− => IsLabel table (Table schema columns) where
491− fromLabel = getTable
492−
493−data TableReference params schema tables where
494− Table
495− :: Aliased (Table schema) table
496− -> TableReference params schema '[table]
497− Subquery
498− :: Aliased (Query schema params) table
499− -> TableReference params schema '[table]
500− CrossJoin
501− :: TableReference params schema right
502− -> TableReference params schema left
503− -> TableReference params schema (Join left right)
504− InnerJoin
505− :: TableReference params schema right
506− -> Condition params (Join left right) 'Ungrouped
507− -> TableReference params schema left
508− -> TableReference params schema (Join left right)
509− LeftOuterJoin
510− :: TableReference params schema right
511− -> Condition params (Join left right) 'Ungrouped
512− -> TableReference params schema left
513− -> TableReference params schema (Join left (NullifyTables right))
514− RightOuterJoin
515− :: TableReference params schema right
516− -> Condition params (Join left right) 'Ungrouped
517− -> TableReference params schema left
518− -> TableReference params schema (Join (NullifyTables left) right)
519− FullOuterJoin
520− :: TableReference params schema right
521− -> Condition params (Join left right) 'Ungrouped
522− -> TableReference params schema left
523− -> TableReference params schema
524− (Join (NullifyTables left) (NullifyTables right))
525−
526−renderTableReference :: TableReference params schema tables -> ByteString
527−renderTableReference = \case
528− Table table -> renderAliased renderTable table
529− Subquery selection -> renderAliased renderQuery selection
530− CrossJoin right left ->
531− renderTableReference left <+> "CROSS JOIN" <+> renderTableReference right
532− InnerJoin right on left -> renderJoin "INNER JOIN" right on left
533− LeftOuterJoin right on left -> renderJoin "LEFT OUTER JOIN" right on left
534− RightOuterJoin right on left -> renderJoin "RIGHT OUTER JOIN" right on left
535− FullOuterJoin right on left -> renderJoin "FULL OUTER JOIN" right on left
536− where
537− renderJoin op right on left =
538− renderTableReference left <+> op <+> renderTableReference right
539− <+> "ON" <+> renderExpression on
540−
541−data TableExpression
542− (params :: [ColumnType])
543− (schema :: [(Symbol,[(Symbol,ColumnType)])])
544− (tables :: [(Symbol,[(Symbol,ColumnType)])])
545− (grouping :: Grouping)
546− = TableExpression
547− { fromClause :: TableReference params schema tables
548− , whereClause :: [Condition params tables 'Ungrouped]
549− , groupByClause :: GroupByClause tables grouping
550− , havingClause :: HavingClause params tables grouping
551− , orderByClause :: [SortExpression params tables grouping]
552− , limitClause :: [Word64]
553− , offsetClause :: [Word64]
554− }
555−
556−renderTableExpression
557− :: TableExpression params schema tables grouping
558− -> ByteString
559−renderTableExpression
560− (TableExpression tables whs' grps' hvs' srts' lims' offs') = mconcat
561− [ "FROM ", renderTableReference tables
562− , renderWheres whs'
563− , renderGroupByClause grps'
564− , renderHavingClause hvs'
565− , renderSorts srts'
566− , renderLimits lims'
567− , renderOffsets offs'
568− ]
569− where
570− renderWheres = \case
571− [] -> ""
572− wh:[] -> " WHERE" <+> renderExpression wh
573− wh:whs -> " WHERE" <+> renderExpression (foldr (&&*) wh whs)
574− renderSorts = \case
575− [] -> ""
576− srts -> " SORT BY"
577− <+> commaSeparated (renderSortExpression <$> srts)
578− renderLimits = \case
579− [] -> ""
580− lims -> " LIMIT" <+> fromString (show (minimum lims))
581− renderOffsets = \case
582− [] -> ""
583− offs -> " OFFSET" <+> fromString (show (sum offs))
584−
585−from
586− :: TableReference params schema tables
587− -> TableExpression params schema tables 'Ungrouped
588−from tables = TableExpression tables [] NoGroups NoHaving [] [] []
589−
590−where_
591− :: Condition params tables 'Ungrouped
592− -> TableExpression params schema tables grouping
593− -> TableExpression params schema tables grouping
594−where_ wh tables = tables {whereClause = wh : whereClause tables}
595−
596−group
597− :: SListI bys
598− => NP (By tables) bys
599− -> TableExpression params schema tables 'Ungrouped
600− -> TableExpression params schema tables ('Grouped bys)
601−group bys tables = TableExpression
602− { fromClause = fromClause tables
603− , whereClause = whereClause tables
604− , groupByClause = Group bys
605− , havingClause = Having []
606− , orderByClause = []
607− , limitClause = limitClause tables
608− , offsetClause = offsetClause tables
609− }
610−
611−having
612− :: Condition params tables ('Grouped bys)
613− -> TableExpression params schema tables ('Grouped bys)
614− -> TableExpression params schema tables ('Grouped bys)
615−having hv tables = tables
616− { havingClause = case havingClause tables of Having hvs -> Having (hv:hvs) }
617−
618−orderBy
619− :: [SortExpression params tables grouping]
620− -> TableExpression params schema tables grouping
621− -> TableExpression params schema tables grouping
622−orderBy srts tables = tables {orderByClause = orderByClause tables ++ srts}
623−
624−limit
625− :: Word64
626− -> TableExpression params schema tables grouping
627− -> TableExpression params schema tables grouping
628−limit lim tables = tables {limitClause = lim : limitClause tables}
629−
630−offset
631− :: Word64
632− -> TableExpression params schema tables grouping
633− -> TableExpression params schema tables grouping
634−offset off tables = tables {offsetClause = off : offsetClause tables}
635−
636−{-----------------------------------------
637−type expressions
638−-----------------------------------------}
639−
640−newtype TypeExpression (ty :: ColumnType)
641− = UnsafeTypeExpression { renderTypeExpression :: ByteString }
642− deriving (Show,Eq)
643−
644−bool :: TypeExpression ('Required ('Null 'PGBool))
645−bool = UnsafeTypeExpression "bool"
646−int2 :: TypeExpression ('Required ('Null 'PGInt2))
647−int2 = UnsafeTypeExpression "int2"
648−smallint :: TypeExpression ('Required ('Null 'PGInt2))
649−smallint = UnsafeTypeExpression "smallint"
650−int4 :: TypeExpression ('Required ('Null 'PGInt4))
651−int4 = UnsafeTypeExpression "int4"
652−int :: TypeExpression ('Required ('Null 'PGInt4))
653−int = UnsafeTypeExpression "int"
654−integer :: TypeExpression ('Required ('Null 'PGInt4))
655−integer = UnsafeTypeExpression "integer"
656−int8 :: TypeExpression ('Required ('Null 'PGInt8))
657−int8 = UnsafeTypeExpression "int8"
658−bigint :: TypeExpression ('Required ('Null 'PGInt8))
659−bigint = UnsafeTypeExpression "bigint"
660−numeric :: TypeExpression ('Required ('Null 'PGNumeric))
661−numeric = UnsafeTypeExpression "numeric"
662−float4 :: TypeExpression ('Required ('Null 'PGFloat4))
663−float4 = UnsafeTypeExpression "float4"
664−real :: TypeExpression ('Required ('Null 'PGFloat4))
665−real = UnsafeTypeExpression "real"
666−float8 :: TypeExpression ('Required ('Null 'PGFloat8))
667−float8 = UnsafeTypeExpression "float8"
668−doublePrecision :: TypeExpression ('Required ('Null 'PGFloat8))
669−doublePrecision = UnsafeTypeExpression "double precision"
670−serial2 :: TypeExpression ('Optional ('NotNull 'PGInt2))
671−serial2 = UnsafeTypeExpression "serial2"
672−smallserial :: TypeExpression ('Optional ('NotNull 'PGInt2))
673−smallserial = UnsafeTypeExpression "smallserial"
674−serial4 :: TypeExpression ('Optional ('NotNull 'PGInt4))
675−serial4 = UnsafeTypeExpression "serial4"
676−serial :: TypeExpression ('Optional ('NotNull 'PGInt4))
677−serial = UnsafeTypeExpression "serial"
678−serial8 :: TypeExpression ('Optional ('NotNull 'PGInt8))
679−serial8 = UnsafeTypeExpression "serial8"
680−bigserial :: TypeExpression ('Optional ('NotNull 'PGInt8))
681−bigserial = UnsafeTypeExpression "bigserial"
682−money :: TypeExpression ('Required ('Null 'PGMoney))
683−money = UnsafeTypeExpression "money"
684−text :: TypeExpression ('Required ('Null 'PGText))
685−text = UnsafeTypeExpression "text"
686−char
687− :: KnownNat n
688− => proxy n
689− -> TypeExpression ('Required ('Null ('PGChar n)))
690−char (_ :: proxy n) = UnsafeTypeExpression $
691− "char(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
692−character
693− :: KnownNat n
694− => proxy n
695− -> TypeExpression ('Required ('Null ('PGChar n)))
696−character (_ :: proxy n) = UnsafeTypeExpression $
697− "character(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
698−varchar
699− :: KnownNat n
700− => proxy n
701− -> TypeExpression ('Required ('Null ('PGVarChar n)))
702−varchar (_ :: proxy n) = UnsafeTypeExpression $
703− "varchar(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
704−characterVarying
705− :: KnownNat n
706− => proxy n
707− -> TypeExpression ('Required ('Null ('PGVarChar n)))
708−characterVarying (_ :: proxy n) = UnsafeTypeExpression $
709− "character varying(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
710−bytea :: TypeExpression ('Required ('Null ('PGBytea)))
711−bytea = UnsafeTypeExpression "bytea"
712−timestamp :: TypeExpression ('Required ('Null ('PGTimestamp)))
713−timestamp = UnsafeTypeExpression "timestamp"
714−timestampWithTimeZone :: TypeExpression ('Required ('Null ('PGTimestampTZ)))
715−timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
716−date :: TypeExpression ('Required ('Null ('PGDate)))
717−date = UnsafeTypeExpression "date"
718−time :: TypeExpression ('Required ('Null ('PGTime)))
719−time = UnsafeTypeExpression "time"
720−timeWithTimeZone :: TypeExpression ('Required ('Null ('PGTimeTZ)))
721−timeWithTimeZone = UnsafeTypeExpression "time with time zone"
722−interval :: TypeExpression ('Required ('Null ('PGInterval)))
723−interval = UnsafeTypeExpression "interval"
724−uuid :: TypeExpression ('Required ('Null ('PGUuid)))
725−uuid = UnsafeTypeExpression "uuid"
726−json :: TypeExpression ('Required ('Null ('PGJson)))
727−json = UnsafeTypeExpression "json"
728−jsonb :: TypeExpression ('Required ('Null ('PGJsonb)))
729−jsonb = UnsafeTypeExpression "jsonb"
730−
731−notNull
732− :: TypeExpression (optionality ('Null ty))
733− -> TypeExpression (optionality ('NotNull ty))
734−notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <+> "NOT NULL"
735−default_
736− :: Expression '[] '[] 'Ungrouped ('Required ty)
737− -> TypeExpression ('Required ty)
738− -> TypeExpression ('Optional ty)
739−default_ x ty = UnsafeTypeExpression $
740− renderTypeExpression ty <+> "DEFAULT" <+> renderExpression x
741−
742−class PGTyped (ty :: PGType) where
743− pgtype :: TypeExpression ('Required ('Null ty))
744−instance PGTyped 'PGBool where pgtype = bool
745−instance PGTyped 'PGInt2 where pgtype = int2
746−instance PGTyped 'PGInt4 where pgtype = int4
747−instance PGTyped 'PGInt8 where pgtype = int8
748−instance PGTyped 'PGNumeric where pgtype = numeric
749−instance PGTyped 'PGFloat4 where pgtype = float4
750−instance PGTyped 'PGFloat8 where pgtype = float8
751−instance PGTyped 'PGMoney where pgtype = money
752−instance PGTyped 'PGText where pgtype = text
753−instance KnownNat n => PGTyped ('PGChar n) where pgtype = char (Proxy @n)
754−instance KnownNat n => PGTyped ('PGVarChar n) where pgtype = varchar (Proxy @n)
755−instance PGTyped 'PGBytea where pgtype = bytea
756−instance PGTyped 'PGTimestamp where pgtype = timestamp
757−instance PGTyped 'PGTimestampTZ where pgtype = timestampWithTimeZone
758−instance PGTyped 'PGDate where pgtype = date
759−instance PGTyped 'PGTime where pgtype = time
760−instance PGTyped 'PGTimeTZ where pgtype = timeWithTimeZone
761−instance PGTyped 'PGInterval where pgtype = interval
762−instance PGTyped 'PGUuid where pgtype = uuid
763−instance PGTyped 'PGJson where pgtype = json
764−instance PGTyped 'PGJsonb where pgtype = jsonb
765−
766−{-----------------------------------------
767−statements
768−-----------------------------------------}
769−
770−newtype Definition
771− (schema0 :: [(Symbol,[(Symbol,ColumnType)])])
772− (schema1 :: [(Symbol,[(Symbol,ColumnType)])])
773− = UnsafeDefinition { renderDefinition :: ByteString }
774−
775−instance Category Definition where
776− id = UnsafeDefinition ";"
777− ddl1 . ddl0 = UnsafeDefinition $
778− renderDefinition ddl0 <+> renderDefinition ddl1
779−
780−newtype Manipulation
781− (schema :: [(Symbol,[(Symbol,ColumnType)])])
782− (params :: [ColumnType])
783− (columns :: [(Symbol,ColumnType)])
784− = UnsafeManipulation { renderManipulation :: ByteString }
785−
786−newtype Query
787− (schema :: [(Symbol,[(Symbol,ColumnType)])])
788− (params :: [ColumnType])
789− (columns :: [(Symbol,ColumnType)])
790− = UnsafeQuery { renderQuery :: ByteString }
791−
792−query
793− :: Query schema params columns
794− -> Manipulation schema params columns
795−query q = UnsafeManipulation $ renderQuery q <> ";"
796−
797−union, unionAll, intersect, intersectAll, except, exceptAll
798− :: Query schema params columns
799− -> Query schema params columns
800− -> Query schema params columns
801−q1 `union` q2 = UnsafeQuery $
802− parenthesized (renderQuery q1)
803− <+> "UNION"
804− <+> parenthesized (renderQuery q2)
805−q1 `unionAll` q2 = UnsafeQuery $
806− parenthesized (renderQuery q1)
807− <+> "UNION" <+> "ALL"
808− <+> parenthesized (renderQuery q2)
809−q1 `intersect` q2 = UnsafeQuery $
810− parenthesized (renderQuery q1)
811− <+> "INTERSECT"
812− <+> parenthesized (renderQuery q2)
813−q1 `intersectAll` q2 = UnsafeQuery $
814− parenthesized (renderQuery q1)
815− <+> "INTERSECT" <+> "ALL"
816− <+> parenthesized (renderQuery q2)
817−q1 `except` q2 = UnsafeQuery $
818− parenthesized (renderQuery q1)
819− <+> "EXCEPT"
820− <+> parenthesized (renderQuery q2)
821−q1 `exceptAll` q2 = UnsafeQuery $
822− parenthesized (renderQuery q1)
823− <+> "EXCEPT" <+> "ALL"
824− <+> parenthesized (renderQuery q2)
825−
826−{-----------------------------------------
827−SELECT statements
828−-----------------------------------------}
829−
830−select
831− :: SListI columns
832− => NP (Aliased (Expression params tables grouping)) columns
833− -> TableExpression params schema tables grouping
834− -> Query schema params columns
835−select list tabs = UnsafeQuery $
836− "SELECT"
837− <+> renderCommaSeparated (renderAliased renderExpression) list
838− <+> renderTableExpression tabs
839−
840−selectStar
841− :: (tables ~ '[table ::: columns])
842− => TableExpression params schema tables 'Ungrouped
843− -> Query schema params columns
844−selectStar tabs = UnsafeQuery $ "SELECT" <+> "*" <+> renderTableExpression tabs
845−
846−selectDotStar
847− :: HasTable table tables columns
848− => Alias table
849− -> TableExpression params schema tables 'Ungrouped
850− -> Query schema params columns
851−selectDotStar table tables = UnsafeQuery $
852− "SELECT" <+> renderAlias table <> ".*" <+> renderTableExpression tables
853−
854−selectRow
855− :: SListI columns
856− => NP (Aliased (Expression params '[] 'Ungrouped)) columns
857− -> Query schema params columns
858−selectRow row = UnsafeQuery $
859− "SELECT" <+> renderCommaSeparated (renderAliased renderExpression) row
860−
861−{-----------------------------------------
862−CREATE statements
863−-----------------------------------------}
864−
865−createTable
866− :: (KnownSymbol table, SListI columns)
867− => Alias table
868− -> NP (Aliased TypeExpression) columns
869− -> Definition schema (Create table columns schema)
870−createTable table columns = UnsafeDefinition $
871− "CREATE TABLE" <+> renderAlias table
872− <+> parenthesized (renderCommaSeparated renderColumn columns) <> ";"
873− where
874− renderColumn :: Aliased TypeExpression x -> ByteString
875− renderColumn (ty `As` column) =
876− renderAlias column <+> renderTypeExpression ty
877−
878−{-----------------------------------------
879−DROP statements
880−-----------------------------------------}
881−
882−dropTable
883− :: KnownSymbol table
884− => Alias table
885− -> Definition schema (Drop table schema)
886−dropTable table = UnsafeDefinition $ "DROP TABLE" <+> renderAlias table <> ";"
887−
888−{-----------------------------------------
889−ALTER statements
890−-----------------------------------------}
891−
892−alterTable
893− :: HasTable table schema columns0
894− => Alias table
895− -> AlterTable columns0 columns1
896− -> Definition schema (Alter table schema columns1)
897−alterTable table alteration = UnsafeDefinition $
898− "ALTER TABLE"
899− <+> renderAlias table
900− <+> renderAlterTable alteration
901− <> ";"
902−
903−alterTableRename
904− :: (KnownSymbol table0, KnownSymbol table1)
905− => Alias table0
906− -> Alias table1
907− -> Definition schema (Rename table0 table1 schema)
908−alterTableRename table0 table1 = UnsafeDefinition $
909− "ALTER TABLE" <+> renderAlias table0
910− <+> "RENAME TO" <+> renderAlias table1 <> ";"
911−
912−data AlterTable
913− (columns0 :: [(Symbol, ColumnType)])
914− (columns1 :: [(Symbol, ColumnType)]) =
915− UnsafeAlterTable {renderAlterTable :: ByteString}
916−
917−addColumnDefault
918− :: KnownSymbol column
919− => Alias column
920− -> TypeExpression ('Optional ty)
921− -> AlterTable columns (Create column ('Optional ty) columns)
922−addColumnDefault column ty = UnsafeAlterTable $
923− "ADD COLUMN" <+> renderAlias column <+> renderTypeExpression ty
924−
925−addColumnNull
926− :: KnownSymbol column
927− => Alias column
928− -> TypeExpression ('Required ('Null ty))
929− -> AlterTable columns ((column ::: 'Required ('Null ty)) ': columns)
930−addColumnNull column ty = UnsafeAlterTable $
931− "ADD COLUMN" <+> renderAlias column <+> renderTypeExpression ty
932−
933−dropColumn
934− :: KnownSymbol column
935− => Alias column
936− -> AlterTable columns (Drop column columns)
937−dropColumn column = UnsafeAlterTable $
938− "DROP COLUMN" <+> renderAlias column
939−
940−renameColumn
941− :: (KnownSymbol column0, KnownSymbol column1)
942− => Alias column0
943− -> Alias column1
944− -> AlterTable columns (Rename column0 column1 columns)
945−renameColumn column0 column1 = UnsafeAlterTable $
946− "RENAME COLUMN" <+> renderAlias column0 <+> "TO" <+> renderAlias column1
947−
948−alterColumn
949− :: (KnownSymbol column, HasColumn column columns ty0)
950− => Alias column
951− -> AlterColumn ty0 ty1
952− -> AlterTable columns (Alter column columns ty1)
953−alterColumn column alteration = UnsafeAlterTable $
954− "ALTER COLUMN" <+> renderAlias column <+> renderAlterColumn alteration
955−
956−data AlterColumn (ty0 :: ColumnType) (ty1 :: ColumnType) =
957− UnsafeAlterColumn {renderAlterColumn :: ByteString}
958−
959−setDefault
960− :: Expression '[] '[] 'Ungrouped ('Required ty)
961− -> AlterColumn ('Required ty) ('Optional ty)
962−setDefault expression = UnsafeAlterColumn $
963− "SET DEFAULT" <+> renderExpression expression
964−
965−dropDefault :: AlterColumn ('Optional ty) ('Required ty)
966−dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
967−
968−setNotNull
969− :: AlterColumn (optionality ('Null ty)) (optionality ('NotNull ty))
970−setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
971−
972−dropNotNull
973− :: AlterColumn (optionality ('NotNull ty)) (optionality ('Null ty))
974−dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
975−
976−alterType
977− :: PGCast ty0 ty1
978− => TypeExpression (optionality (nullity ty1))
979− -> AlterColumn (optionality (nullity ty0)) (optionality (nullity ty1))
980−alterType ty = UnsafeAlterColumn $ "TYPE " <> renderTypeExpression ty
981−
982−{-----------------------------------------
983−INSERT statements
984−-----------------------------------------}
985−
986−insertInto
987− :: (SListI columns, SListI results, HasTable table schema columns)
988− => Alias table
989− -> ValuesClause schema params columns
990− -> ConflictClause params columns
991− -> ReturningClause params columns results
992− -> Manipulation schema params results
993−insertInto table insert conflict returning = UnsafeManipulation $
994− "INSERT" <+> "INTO" <+> renderAlias table
995− <+> renderValuesClause insert
996− <> renderConflictClause conflict
997− <> renderReturningClause returning
998−
999−data ValuesClause
1000− (schema :: [(Symbol,[(Symbol,ColumnType)])])
1001− (params :: [ColumnType])
1002− (columns :: [(Symbol,ColumnType)])
1003− = Values
1004− (NP (Aliased (Expression params '[] 'Ungrouped)) columns)
1005− [NP (Aliased (Expression params '[] 'Ungrouped)) columns]
1006− | ValuesQuery (Query schema params columns)
1007−
1008−renderValuesClause
1009− :: SListI columns
1010− => ValuesClause schema params columns
1011− -> ByteString
1012−renderValuesClause = \case
1013− Values row rows ->
1014− parenthesized (renderCommaSeparated renderAliasPart row)
1015− <+> "VALUES"
1016− <+> commaSeparated
1017− (parenthesized . renderCommaSeparated renderValuePart <$> row:rows)
1018− where
1019− renderAliasPart, renderValuePart
1020− :: Aliased (Expression params '[] 'Ungrouped) ty -> ByteString
1021− renderAliasPart (_ `As` name) = renderAlias name
1022− renderValuePart (value `As` _) = renderExpression value
1023− ValuesQuery q -> renderQuery q
1024−
1025−data ReturningClause
1026− (params :: [ColumnType])
1027− (columns :: [(Symbol,ColumnType)])
1028− (results :: [(Symbol,ColumnType)])
1029− where
1030− ReturningNil :: ReturningClause params columns '[]
1031− ReturningStar :: ReturningClause params columns columns
1032− Returning
1033− :: NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1034− -> ReturningClause params columns results
1035−
1036−renderReturningClause
1037− :: SListI results
1038− => ReturningClause params columns results
1039− -> ByteString
1040−renderReturningClause = \case
1041− ReturningNil -> ";"
1042− ReturningStar -> " RETURNING *;"
1043− Returning results -> " RETURNING"
1044− <+> renderCommaSeparated (renderAliased renderExpression) results <> ";"
1045−
1046−data ConflictClause params columns where
1047− Conflict :: ConflictClause params columns
1048− OnConflictDoNothing :: ConflictClause params columns
1049− OnConflictDoUpdate
1050− :: NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1051− -> Condition params '[table ::: columns] 'Ungrouped
1052− -> ConflictClause params columns
1053−
1054−renderConflictClause
1055− :: SListI columns
1056− => ConflictClause params columns
1057− -> ByteString
1058−renderConflictClause = \case
1059− Conflict -> ""
1060− OnConflictDoNothing -> " ON CONFLICT DO NOTHING"
1061− OnConflictDoUpdate updates wh
1062− -> " ON CONFLICT DO UPDATE SET"
1063− <+> renderCommaSeparatedMaybe renderUpdateExpression updates
1064− <+> "WHERE" <+> renderExpression wh
1065−
1066−{-----------------------------------------
1067−UPDATE statements
1068−-----------------------------------------}
1069−
1070−data UpdateExpression params table ty
1071− = Same
1072− | Set (Expression params table 'Ungrouped ty)
1073−
1074−renderUpdateExpression
1075− :: Aliased (UpdateExpression params '[table ::: columns]) column
1076− -> Maybe ByteString
1077−renderUpdateExpression = \case
1078− Same `As` _ -> Nothing
1079− Set expression `As` column -> Just $
1080− renderAlias column <+> "=" <+> renderExpression expression
1081−
1082−update
1083− :: (HasTable table schema columns, SListI columns, SListI results)
1084− => Alias table
1085− -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1086− -> Condition params '[table ::: columns] 'Ungrouped
1087− -> ReturningClause params columns results
1088− -> Manipulation schema params results
1089−update table columns wh returning = UnsafeManipulation $
1090− "UPDATE"
1091− <+> renderAlias table
1092− <+> "SET"
1093− <+> renderCommaSeparatedMaybe renderUpdateExpression columns
1094− <+> "WHERE" <+> renderExpression wh
1095− <> renderReturningClause returning
1096−
1097−{-----------------------------------------
1098−DELETE statements
1099−-----------------------------------------}
1100−
1101−deleteFrom
1102− :: HasTable table schema columns
1103− => Alias table
1104− -> Condition params '[table ::: columns] 'Ungrouped
1105− -> Manipulation schema params '[]
1106−deleteFrom table wh = UnsafeManipulation $
1107− "DELETE FROM" <+> renderAlias table
1108− <+> "WHERE" <+> renderExpression wh <> ";"
1109−
1110−{-----------------------------------------
1111−render helper functions
1112−-----------------------------------------}
1113−
1114−parenthesized :: ByteString -> ByteString
1115−parenthesized str = "(" <> str <> ")"
1116−
1117−(<+>) :: ByteString -> ByteString -> ByteString
1118−str1 <+> str2 = str1 <> " " <> str2
1119−
1120−commaSeparated :: [ByteString] -> ByteString
1121−commaSeparated = ByteString.intercalate ", "
1122−
1123−renderCommaSeparated
1124− :: SListI xs
1125− => (forall x. expression x -> ByteString)
1126− -> NP expression xs -> ByteString
1127−renderCommaSeparated render
1128− = commaSeparated
1129− . hcollapse
1130− . hmap (K . render)
1131−
1132−renderCommaSeparatedMaybe
1133− :: SListI xs
1134− => (forall x. expression x -> Maybe ByteString)
1135− -> NP expression xs -> ByteString
1136−renderCommaSeparatedMaybe render
1137− = commaSeparated
1138− . catMaybes
1139− . hcollapse
1140− . hmap (K . render)
1141−
1142−renderSymbol :: KnownSymbol str => Proxy# str -> ByteString
1143−renderSymbol p = fromString $ symbolVal' p