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