@@ -0,0 +1,1176 @@
1+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
6+ , FunctionalDependencies
11+ , ScopedTypeVariables
15+ , UndecidableInstances
18+module Squeel.PostgreSQL.Statement where
20+import Control.Category
21+import Data.ByteString (ByteString)
30+import GHC.OverloadedLabels
32+import Prelude hiding (RealFrac(..), id, (.))
34+import qualified Data.ByteString as ByteString
36+import Squeel.PostgreSQL.Schema
38+{-----------------------------------------
40+-----------------------------------------}
43+ (params :: [ColumnType])
44+ (tables :: [(Symbol,[(Symbol,ColumnType)])])
45+ (grouping :: Grouping)
47+ = UnsafeExpression { renderExpression :: ByteString }
50+class KnownNat n => HasParameter (n :: Nat) params ty | n params -> ty where
51+ param :: Proxy# n -> Expression params tables grouping ty
52+ param p = UnsafeExpression $ ("$" <>) $ fromString $ show $ natVal' p
53+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
54+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
55+ => HasParameter n (ty' : params) ty
57+param1 :: Expression (ty1:tys) tables grouping ty1
58+param1 = param (proxy# :: Proxy# 1)
59+param2 :: Expression (ty1:ty2:tys) tables grouping ty2
60+param2 = param (proxy# :: Proxy# 2)
61+param3 :: Expression (ty1:ty2:ty3:tys) tables grouping ty3
62+param3 = param (proxy# :: Proxy# 3)
63+param4 :: Expression (ty1:ty2:ty3:ty4:tys) tables grouping ty4
64+param4 = param (proxy# :: Proxy# 4)
65+param5 :: Expression (ty1:ty2:ty3:ty4:ty5:tys) tables grouping ty5
66+param5 = param (proxy# :: Proxy# 5)
68+class KnownSymbol column => HasColumn column columns ty
69+ | column columns -> ty where
72+ -> Expression params '[table ::: columns] 'Ungrouped ty
73+ getColumn column = UnsafeExpression $ fromString $ symbolVal' column
74+instance {-# OVERLAPPING #-} KnownSymbol column
75+ => HasColumn column ((column ::: optionality ty) ': tys) ('Required ty)
76+instance {-# OVERLAPPABLE #-} (KnownSymbol column, HasColumn column table ty)
77+ => HasColumn column (ty' ': table) ty
79+instance (HasColumn column columns ty, tables ~ '[table ::: columns])
80+ => IsLabel column (Expression params tables 'Ungrouped ty) where
81+ fromLabel = getColumn
83+def :: Expression params '[] grouping ('Optional (nullity ty))
84+def = UnsafeExpression "DEFAULT"
87+ :: Expression params '[] grouping ('Required (nullity ty))
88+ -> Expression params '[] grouping ('Optional (nullity ty))
89+notDef = UnsafeExpression . renderExpression
91+null :: Expression params tables grouping (optionality ('Null ty))
92+null = UnsafeExpression "NULL"
95+ :: [Expression params tables grouping ('Required ('Null x))]
96+ -> Expression params tables grouping ('Required ('NotNull x))
97+ -> Expression params tables grouping ('Required ('NotNull x))
98+coalesce nulls isn'tNull = UnsafeExpression $ mconcat
100+ , ByteString.intercalate ", " $ map renderExpression nulls
101+ , ", ", renderExpression isn'tNull
107+ -> Expression params tables grouping ty0
108+ -> Expression params tables grouping ty1
109+ -> Expression params tables grouping ty2
110+unsafeBinaryOp op x y = UnsafeExpression $ mconcat
111+ ["(", renderExpression x, " ", op, " ", renderExpression y, ")"]
115+ -> Expression params tables grouping ty0
116+ -> Expression params tables grouping ty1
117+unsafeUnaryOp op x = UnsafeExpression $ mconcat
118+ ["(", op, " ", renderExpression x, ")"]
122+ -> Expression params tables grouping xty
123+ -> Expression params tables grouping yty
124+unsafeFunction fun x = UnsafeExpression $ mconcat
125+ [fun, "(", renderExpression x, ")"]
128+ => Num (Expression params tables grouping ('Required (nullity ty))) where
129+ (+) = unsafeBinaryOp "+"
130+ (-) = unsafeBinaryOp "-"
131+ (*) = unsafeBinaryOp "*"
132+ abs = unsafeFunction "abs"
133+ signum = unsafeFunction "sign"
136+ . (<> if decimal (Proxy :: Proxy ty) then "." else "")
140+instance PGFractional ty => Fractional
141+ (Expression params tables grouping ('Required (nullity ty))) where
142+ (/) = unsafeBinaryOp "/"
143+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
145+instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty) => Floating
146+ (Expression params tables grouping ('Required (nullity ty))) where
147+ pi = UnsafeExpression "pi()"
148+ exp = unsafeFunction "exp"
149+ log = unsafeFunction "ln"
150+ sqrt = unsafeFunction "sqrt"
151+ b ** x = UnsafeExpression $
152+ "power(" <> renderExpression b <> ", " <> renderExpression x <> ")"
153+ logBase b y = cast pgtype $ logBaseNumeric b y
156+ :: Expression params tables grouping ('Required (nullity ty))
157+ -> Expression params tables grouping ('Required (nullity ty))
158+ -> Expression params tables grouping ('Required (nullity 'PGNumeric))
159+ logBaseNumeric b' y' = UnsafeExpression $ mconcat
161+ , renderExpression b' <> "::numeric"
163+ , renderExpression y' <> "::numeric"
166+ sin = unsafeFunction "sin"
167+ cos = unsafeFunction "cos"
168+ tan = unsafeFunction "tan"
169+ asin = unsafeFunction "asin"
170+ acos = unsafeFunction "acos"
171+ atan = unsafeFunction "atan"
172+ sinh x = (exp x - exp (-x)) / 2
173+ cosh x = (exp x + exp (-x)) / 2
174+ tanh x = sinh x / cosh x
175+ asinh x = log (x + sqrt (x*x + 1))
176+ acosh x = log (x + sqrt (x*x - 1))
177+ atanh x = log ((1 + x) / (1 - x)) / 2
181+ => Expression params tables grouping ('Required (nullity float))
182+ -> Expression params tables grouping ('Required (nullity float))
183+ -> Expression params tables grouping ('Required (nullity float))
184+atan2 y x = UnsafeExpression $
185+ "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
187+class PGCast (ty0 :: PGType) (ty1 :: PGType) where
189+ :: TypeExpression ('Required ('Null ty1))
190+ -> Expression params tables grouping ('Required (nullity ty0))
191+ -> Expression params tables grouping ('Required (nullity ty1))
192+ cast ty x = UnsafeExpression $
193+ "(" <> renderExpression x <> "::" <> renderTypeExpression ty <> ")"
194+instance PGCast 'PGInt2 'PGInt2
195+instance PGCast 'PGInt2 'PGInt4
196+instance PGCast 'PGInt2 'PGInt8
197+instance PGCast 'PGInt4 'PGInt2
198+instance PGCast 'PGInt4 'PGInt4
199+instance PGCast 'PGInt4 'PGInt8
200+instance PGCast 'PGInt8 'PGInt2
201+instance PGCast 'PGInt8 'PGInt4
202+instance PGCast 'PGInt8 'PGInt8
203+instance PGCast 'PGInt8 'PGFloat4
204+instance PGCast 'PGInt8 'PGFloat8
205+instance PGCast 'PGInt8 'PGNumeric
208+ :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
209+ => Expression params tables grouping ('Required (nullity ty))
210+ -> Expression params tables grouping ('Required (nullity ty))
211+ -> Expression params tables grouping ('Required (nullity ty))
212+div = unsafeBinaryOp "/"
215+ :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
216+ => Expression params tables grouping ('Required (nullity ty))
217+ -> Expression params tables grouping ('Required (nullity ty))
218+ -> Expression params tables grouping ('Required (nullity ty))
219+mod = unsafeBinaryOp "%"
222+ :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
223+ => Expression params tables grouping ('Required (nullity frac))
224+ -> Expression params tables grouping ('Required (nullity int))
225+truncate = cast pgtype . truncate'
228+ :: Expression params tables grouping ('Required (nullity frac))
229+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
230+ truncate' = unsafeFunction "trunc"
233+ :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
234+ => Expression params tables grouping ('Required (nullity frac))
235+ -> Expression params tables grouping ('Required (nullity int))
236+round = cast pgtype . round'
239+ :: Expression params tables grouping ('Required (nullity frac))
240+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
241+ round' = unsafeFunction "round"
244+ :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
245+ => Expression params tables grouping ('Required (nullity frac))
246+ -> Expression params tables grouping ('Required (nullity int))
247+ceiling = cast pgtype . ceiling'
250+ :: Expression params tables grouping ('Required (nullity frac))
251+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
252+ ceiling' = unsafeFunction "ceiling"
255+ (Expression params tables grouping ('Required (nullity 'PGText))) where
256+ fromString str = UnsafeExpression $
257+ "E\'" <> fromString (escape =<< str) <> "\'"
270+type Condition params tables grouping =
271+ Expression params tables grouping ('Required ('NotNull 'PGBool))
273+true :: Condition params tables grouping
274+true = UnsafeExpression "TRUE"
276+false :: Condition params tables grouping
277+false = UnsafeExpression "FALSE"
280+ :: Condition params tables grouping
281+ -> Condition params tables grouping
282+not_ = unsafeUnaryOp "NOT"
285+ :: Condition params tables grouping
286+ -> Condition params tables grouping
287+ -> Condition params tables grouping
288+(&&*) = unsafeBinaryOp "AND"
291+ :: Condition params tables grouping
292+ -> Condition params tables grouping
293+ -> Condition params tables grouping
294+(||*) = unsafeBinaryOp "OR"
297+ :: [(Condition params tables grouping, Expression params tables grouping ty)]
298+ -> Expression params tables grouping ty
299+ -> Expression params tables grouping ty
300+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
304+ [ " WHEN ", renderExpression when_
305+ , " THEN ", renderExpression then_
307+ | (when_,then_) <- whenThens
309+ , " ELSE ", renderExpression else_
314+ :: Condition params tables grouping
315+ -> Expression params tables grouping ty
316+ -> Expression params tables grouping ty
317+ -> Expression params tables grouping ty
318+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
321+ :: Expression params tables grouping ('Required (nullity ty))
322+ -> Expression params tables grouping ('Required (nullity ty))
323+ -> Expression params tables grouping ('Required (nullity 'PGBool))
324+(==*) = unsafeBinaryOp "="
327+ :: Expression params tables grouping ('Required (nullity ty))
328+ -> Expression params tables grouping ('Required (nullity ty))
329+ -> Expression params tables grouping ('Required (nullity 'PGBool))
330+(/=*) = unsafeBinaryOp "<>"
333+ :: Expression params tables grouping ('Required (nullity ty))
334+ -> Expression params tables grouping ('Required (nullity ty))
335+ -> Expression params tables grouping ('Required (nullity 'PGBool))
336+(>=*) = unsafeBinaryOp ">="
339+ :: Expression params tables grouping ('Required (nullity ty))
340+ -> Expression params tables grouping ('Required (nullity ty))
341+ -> Expression params tables grouping ('Required (nullity 'PGBool))
342+(<*) = unsafeBinaryOp "<"
345+ :: Expression params tables grouping ('Required (nullity ty))
346+ -> Expression params tables grouping ('Required (nullity ty))
347+ -> Expression params tables grouping ('Required (nullity 'PGBool))
348+(<=*) = unsafeBinaryOp "<="
351+ :: Expression params tables grouping ('Required (nullity ty))
352+ -> Expression params tables grouping ('Required (nullity ty))
353+ -> Expression params tables grouping ('Required (nullity 'PGBool))
354+(>*) = unsafeBinaryOp ">"
356+data SortExpression params tables grouping where
358+ :: Expression params tables grouping ty
359+ -> SortExpression params tables grouping
361+ :: Expression params tables grouping ty
362+ -> SortExpression params tables grouping
364+renderSortExpression :: SortExpression params tables grouping -> ByteString
365+renderSortExpression = \case
366+ Asc expression -> renderExpression expression <> " ASC"
367+ Desc expression -> renderExpression expression <> " DESC"
369+data Aggregate (ty0 :: ColumnType) (ty1 :: ColumnType) =
370+ UnsafeAggregate { renderAggregate :: ByteString }
374+ => Aggregate ('Required (nullity ty)) ('Required (nullity ty))
375+sumAggregate = UnsafeAggregate "sum"
377+class (KnownSymbol table, KnownSymbol column)
378+ => GroupedBy table column distincts ty where
380+ :: (HasTable table tables columns, HasColumn column columns ty)
383+ -> Expression params tables ('Grouped distincts) ty
385+class (KnownSymbol table, KnownSymbol column)
386+ => Aggregated table column distincts ty where
388+ :: (HasTable table tables columns, HasColumn column columns ty0)
392+ -> Expression params tables ('Grouped distincts) ty
394+class TableColumn table column expression where
395+ (&.) :: Alias table -> Alias column -> expression
396+instance (HasTable table tables columns, HasColumn column columns ty)
397+ => TableColumn table column (Expression params tables 'Ungrouped ty) where
398+ table &. column = UnsafeExpression $
399+ renderAlias table <> "." <> renderAlias column
400+instance (HasTable table tables columns, HasColumn column columns ty)
401+ => TableColumn table column (By tables (table ::: (column ::: ty))) where
404+ ( HasTable table tables columns
405+ , HasColumn column columns ty
406+ , GroupedBy table column distincts ty
407+ ) => TableColumn table column
408+ (Expression params tables ('Grouped distincts) ty) where
411+ ( HasTable table tables columns
412+ , HasColumn column columns ty0
413+ , Aggregated table column distincts ty
414+ ) => TableColumn table column
415+ (Aggregate ty0 ty -> Expression params tables ('Grouped distincts) ty) where
418+{-----------------------------------------
420+-----------------------------------------}
423+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
424+ (columns :: [(Symbol,ColumnType)])
425+ = UnsafeTable { renderTable :: ByteString }
428+class KnownSymbol table => HasTable table tables columns
429+ | table tables -> columns where
430+ getTable :: Proxy# table -> Table tables columns
431+ getTable table = UnsafeTable $ fromString $ symbolVal' table
432+instance {-# OVERLAPPING #-} KnownSymbol table
433+ => HasTable table ((table ::: columns) ': tables) columns
434+instance {-# OVERLAPPABLE #-}
435+ (KnownSymbol table, HasTable table schema columns)
436+ => HasTable table (table' ': schema) columns
438+instance HasTable table schema columns
439+ => IsLabel table (Table schema columns) where
440+ fromLabel = getTable
442+data TableReference params schema tables where
444+ :: Aliased (Table schema) table
445+ -> TableReference params schema '[table]
447+ :: Aliased (Query schema params) table
448+ -> TableReference params schema '[table]
450+ :: TableReference params schema right
451+ -> TableReference params schema left
452+ -> TableReference params schema (Join left right)
454+ :: TableReference params schema right
455+ -> Condition params (Join left right) 'Ungrouped
456+ -> TableReference params schema left
457+ -> TableReference params schema (Join left right)
459+ :: TableReference params schema right
460+ -> Condition params (Join left right) 'Ungrouped
461+ -> TableReference params schema left
462+ -> TableReference params schema (Join left (NullifyTables right))
464+ :: TableReference params schema right
465+ -> Condition params (Join left right) 'Ungrouped
466+ -> TableReference params schema left
467+ -> TableReference params schema (Join (NullifyTables left) right)
469+ :: TableReference params schema right
470+ -> Condition params (Join left right) 'Ungrouped
471+ -> TableReference params schema left
472+ -> TableReference params schema
473+ (Join (NullifyTables left) (NullifyTables right))
475+renderTableReference :: TableReference params schema tables -> ByteString
476+renderTableReference = \case
477+ Table table -> renderAliased renderTable table
478+ Subquery selection -> renderAliased renderQuery selection
479+ CrossJoin right left -> mconcat
480+ [ renderTableReference left
482+ , renderTableReference right
484+ InnerJoin right on left -> mconcat
485+ [ renderTableReference left
487+ , renderTableReference right
489+ , renderExpression on
491+ LeftOuterJoin right on left -> mconcat
492+ [ renderTableReference left
493+ , " LEFT OUTER JOIN "
494+ , renderTableReference right
496+ , renderExpression on
498+ RightOuterJoin right on left -> mconcat
499+ [ renderTableReference left
500+ , " RIGHT OUTER JOIN "
501+ , renderTableReference right
503+ , renderExpression on
505+ FullOuterJoin right on left -> mconcat
506+ [ renderTableReference left
507+ , " FULL OUTER JOIN "
508+ , renderTableReference right
510+ , renderExpression on
513+data By tables tabcolty where
515+ :: (HasTable table tables columns, HasColumn column columns ty)
518+ -> By tables (table ::: (column ::: ty))
520+renderBy :: By tables tabcolty -> ByteString
521+renderBy (By table column) = renderAlias table <> "." <> renderAlias column
523+data GroupByClause tables grouping where
524+ NoGroups :: GroupByClause tables 'Ungrouped
527+ => NP (By tables) distincts
528+ -> GroupByClause tables ('Grouped distincts)
530+renderGroupByClause :: GroupByClause tables grouping -> ByteString
531+renderGroupByClause = \case
534+ Distinct distincts -> " GROUP BY " <> ByteString.intercalate ", "
535+ (hcollapse (hmap (K . renderBy) distincts))
537+data HavingClause params tables grouping where
538+ NoHaving :: HavingClause params tables 'Ungrouped
540+ :: [Condition params tables ('Grouped distincts)]
541+ -> HavingClause params tables ('Grouped distincts)
543+renderHavingClause :: HavingClause params tables grouping -> ByteString
544+renderHavingClause = \case
547+ Having conditions -> " HAVING " <> ByteString.intercalate ", "
548+ (renderExpression <$> conditions)
551+ (params :: [ColumnType])
552+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
553+ (tables :: [(Symbol,[(Symbol,ColumnType)])])
554+ (grouping :: Grouping)
556+ { fromClause :: TableReference params schema tables
557+ , whereClause :: [Condition params tables 'Ungrouped]
558+ , groupByClause :: GroupByClause tables grouping
559+ , havingClause :: HavingClause params tables grouping
560+ , orderByClause :: [SortExpression params tables grouping]
561+ , limitClause :: [Word64]
562+ , offsetClause :: [Word64]
565+renderTableExpression
566+ :: TableExpression params schema tables grouping
568+renderTableExpression
569+ (TableExpression tables whs' grps' hvs' srts' lims' offs') = mconcat
570+ [ "FROM ", renderTableReference tables
572+ , renderGroupByClause grps'
573+ , renderHavingClause hvs'
575+ , renderLimits lims'
576+ , renderOffsets offs'
579+ renderWheres = \case
581+ wh:[] -> " WHERE " <> renderExpression wh
582+ wh:whs -> " WHERE " <> renderExpression (foldr (&&*) wh whs)
586+ <> ByteString.intercalate ", " (renderSortExpression <$> srts)
587+ renderLimits = \case
589+ lims -> " LIMIT " <> fromString (show (minimum lims))
590+ renderOffsets = \case
592+ offs -> " OFFSET " <> fromString (show (sum offs))
595+ :: TableReference params schema tables
596+ -> TableExpression params schema tables 'Ungrouped
597+from tables = TableExpression tables [] NoGroups NoHaving [] [] []
600+ :: Condition params tables 'Ungrouped
601+ -> TableExpression params schema tables grouping
602+ -> TableExpression params schema tables grouping
603+where_ wh tables = tables {whereClause = wh : whereClause tables}
607+ => NP (By tables) distincts
608+ -> TableExpression params schema tables 'Ungrouped
609+ -> TableExpression params schema tables ('Grouped distincts)
610+group distincts tables = TableExpression
611+ { fromClause = fromClause tables
612+ , whereClause = whereClause tables
613+ , groupByClause = Distinct distincts
614+ , havingClause = Having []
615+ , orderByClause = []
616+ , limitClause = limitClause tables
617+ , offsetClause = offsetClause tables
621+ :: Condition params tables ('Grouped distincts)
622+ -> TableExpression params schema tables ('Grouped distincts)
623+ -> TableExpression params schema tables ('Grouped distincts)
624+having hv tables = tables
625+ { havingClause = case havingClause tables of Having hvs -> Having (hv:hvs) }
628+ :: [SortExpression params tables grouping]
629+ -> TableExpression params schema tables grouping
630+ -> TableExpression params schema tables grouping
631+orderBy srts tables = tables {orderByClause = orderByClause tables ++ srts}
635+ -> TableExpression params schema tables grouping
636+ -> TableExpression params schema tables grouping
637+limit lim tables = tables {limitClause = lim : limitClause tables}
641+ -> TableExpression params schema tables grouping
642+ -> TableExpression params schema tables grouping
643+offset off tables = tables {offsetClause = off : offsetClause tables}
645+{-----------------------------------------
647+-----------------------------------------}
649+newtype TypeExpression (ty :: ColumnType)
650+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
653+bool :: TypeExpression ('Required ('Null 'PGBool))
654+bool = UnsafeTypeExpression "bool"
655+int2 :: TypeExpression ('Required ('Null 'PGInt2))
656+int2 = UnsafeTypeExpression "int2"
657+smallint :: TypeExpression ('Required ('Null 'PGInt2))
658+smallint = UnsafeTypeExpression "smallint"
659+int4 :: TypeExpression ('Required ('Null 'PGInt4))
660+int4 = UnsafeTypeExpression "int4"
661+int :: TypeExpression ('Required ('Null 'PGInt4))
662+int = UnsafeTypeExpression "int"
663+integer :: TypeExpression ('Required ('Null 'PGInt4))
664+integer = UnsafeTypeExpression "integer"
665+int8 :: TypeExpression ('Required ('Null 'PGInt8))
666+int8 = UnsafeTypeExpression "int8"
667+bigint :: TypeExpression ('Required ('Null 'PGInt8))
668+bigint = UnsafeTypeExpression "bigint"
669+numeric :: TypeExpression ('Required ('Null 'PGNumeric))
670+numeric = UnsafeTypeExpression "numeric"
671+float4 :: TypeExpression ('Required ('Null 'PGFloat4))
672+float4 = UnsafeTypeExpression "float4"
673+real :: TypeExpression ('Required ('Null 'PGFloat4))
674+real = UnsafeTypeExpression "real"
675+float8 :: TypeExpression ('Required ('Null 'PGFloat8))
676+float8 = UnsafeTypeExpression "float8"
677+doublePrecision :: TypeExpression ('Required ('Null 'PGFloat8))
678+doublePrecision = UnsafeTypeExpression "double precision"
679+serial2 :: TypeExpression ('Optional ('NotNull 'PGInt2))
680+serial2 = UnsafeTypeExpression "serial2"
681+smallserial :: TypeExpression ('Optional ('NotNull 'PGInt2))
682+smallserial = UnsafeTypeExpression "smallserial"
683+serial4 :: TypeExpression ('Optional ('NotNull 'PGInt4))
684+serial4 = UnsafeTypeExpression "serial4"
685+serial :: TypeExpression ('Optional ('NotNull 'PGInt4))
686+serial = UnsafeTypeExpression "serial"
687+serial8 :: TypeExpression ('Optional ('NotNull 'PGInt8))
688+serial8 = UnsafeTypeExpression "serial8"
689+bigserial :: TypeExpression ('Optional ('NotNull 'PGInt8))
690+bigserial = UnsafeTypeExpression "bigserial"
691+money :: TypeExpression ('Required ('Null 'PGMoney))
692+money = UnsafeTypeExpression "money"
693+text :: TypeExpression ('Required ('Null 'PGText))
694+text = UnsafeTypeExpression "text"
698+ -> TypeExpression ('Required ('Null ('PGChar n)))
699+char (_ :: proxy n) = UnsafeTypeExpression $
700+ "char(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
704+ -> TypeExpression ('Required ('Null ('PGChar n)))
705+character (_ :: proxy n) = UnsafeTypeExpression $
706+ "character(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
710+ -> TypeExpression ('Required ('Null ('PGVarChar n)))
711+varchar (_ :: proxy n) = UnsafeTypeExpression $
712+ "varchar(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
716+ -> TypeExpression ('Required ('Null ('PGVarChar n)))
717+characterVarying (_ :: proxy n) = UnsafeTypeExpression $
718+ "character varying(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
719+bytea :: TypeExpression ('Required ('Null ('PGBytea)))
720+bytea = UnsafeTypeExpression "bytea"
721+timestamp :: TypeExpression ('Required ('Null ('PGTimestamp)))
722+timestamp = UnsafeTypeExpression "timestamp"
723+timestampWithTimeZone :: TypeExpression ('Required ('Null ('PGTimestampTZ)))
724+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
725+date :: TypeExpression ('Required ('Null ('PGDate)))
726+date = UnsafeTypeExpression "date"
727+time :: TypeExpression ('Required ('Null ('PGTime)))
728+time = UnsafeTypeExpression "time"
729+timeWithTimeZone :: TypeExpression ('Required ('Null ('PGTimeTZ)))
730+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
731+interval :: TypeExpression ('Required ('Null ('PGInterval)))
732+interval = UnsafeTypeExpression "interval"
733+uuid :: TypeExpression ('Required ('Null ('PGUuid)))
734+uuid = UnsafeTypeExpression "uuid"
735+json :: TypeExpression ('Required ('Null ('PGJson)))
736+json = UnsafeTypeExpression "json"
737+jsonb :: TypeExpression ('Required ('Null ('PGJsonb)))
738+jsonb = UnsafeTypeExpression "jsonb"
741+ :: TypeExpression ('Required ('Null ty))
742+ -> TypeExpression ('Required ('NotNull ty))
743+notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <> " NOT NULL"
745+ :: Expression '[] '[] 'Ungrouped ('Required ty)
746+ -> TypeExpression ('Required ty)
747+ -> TypeExpression ('Optional ty)
748+default_ x ty = UnsafeTypeExpression $
749+ renderTypeExpression ty <> " DEFAULT " <> renderExpression x
751+class PGTyped (ty :: PGType) where
752+ pgtype :: TypeExpression ('Required ('Null ty))
753+instance PGTyped 'PGBool where pgtype = bool
754+instance PGTyped 'PGInt2 where pgtype = int2
755+instance PGTyped 'PGInt4 where pgtype = int4
756+instance PGTyped 'PGInt8 where pgtype = int8
757+instance PGTyped 'PGNumeric where pgtype = numeric
758+instance PGTyped 'PGFloat4 where pgtype = float4
759+instance PGTyped 'PGFloat8 where pgtype = float8
760+instance PGTyped 'PGMoney where pgtype = money
761+instance PGTyped 'PGText where pgtype = text
762+instance KnownNat n => PGTyped ('PGChar n) where pgtype = char (Proxy @n)
763+instance KnownNat n => PGTyped ('PGVarChar n) where pgtype = varchar (Proxy @n)
764+instance PGTyped 'PGBytea where pgtype = bytea
765+instance PGTyped 'PGTimestamp where pgtype = timestamp
766+instance PGTyped 'PGTimestampTZ where pgtype = timestampWithTimeZone
767+instance PGTyped 'PGDate where pgtype = date
768+instance PGTyped 'PGTime where pgtype = time
769+instance PGTyped 'PGTimeTZ where pgtype = timeWithTimeZone
770+instance PGTyped 'PGInterval where pgtype = interval
771+instance PGTyped 'PGUuid where pgtype = uuid
772+instance PGTyped 'PGJson where pgtype = json
773+instance PGTyped 'PGJsonb where pgtype = jsonb
775+{-----------------------------------------
777+-----------------------------------------}
780+ (schema0 :: [(Symbol,[(Symbol,ColumnType)])])
781+ (schema1 :: [(Symbol,[(Symbol,ColumnType)])])
782+ = UnsafeDefinition { renderDefinition :: ByteString }
784+instance Category Definition where
785+ id = UnsafeDefinition ";"
786+ dd1 . dd0 = UnsafeDefinition $
787+ renderDefinition dd0 <> " " <> renderDefinition dd1
790+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
791+ (params :: [ColumnType])
792+ (columns :: [(Symbol,ColumnType)])
793+ = UnsafeManipulation { renderManipulation :: ByteString }
796+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
797+ (params :: [ColumnType])
798+ (columns :: [(Symbol,ColumnType)])
799+ = UnsafeQuery { renderQuery :: ByteString }
802+ :: Query schema params columns
803+ -> Manipulation schema params columns
804+query q = UnsafeManipulation $ renderQuery q <> ";"
806+union, unionAll, intersect, intersectAll, except, exceptAll
807+ :: Query schema params columns
808+ -> Query schema params columns
809+ -> Query schema params columns
810+q1 `union` q2 = UnsafeQuery $
811+ renderQuery q1 <> " UNION " <> renderQuery q2
812+q1 `unionAll` q2 = UnsafeQuery $
813+ renderQuery q1 <> " UNION ALL " <> renderQuery q2
814+q1 `intersect` q2 = UnsafeQuery $
815+ renderQuery q1 <> " INTERSECT " <> renderQuery q2
816+q1 `intersectAll` q2 = UnsafeQuery $
817+ renderQuery q1 <> " INTERSECT ALL " <> renderQuery q2
818+q1 `except` q2 = UnsafeQuery $
819+ renderQuery q1 <> " EXCEPT " <> renderQuery q2
820+q1 `exceptAll` q2 = UnsafeQuery $
821+ renderQuery q1 <> " EXCEPT ALL " <> renderQuery q2
823+{-----------------------------------------
825+-----------------------------------------}
829+ => NP (Aliased (Expression params tables grouping)) columns
830+ -> TableExpression params schema tables grouping
831+ -> Query schema params columns
832+select list tabs = UnsafeQuery $
833+ "SELECT " <> renderList list <> " " <> renderTableExpression tabs
836+ = ByteString.intercalate ", "
838+ . hmap (K . renderAliased renderExpression)
841+ :: (tables ~ '[table ::: columns])
842+ => TableExpression params schema tables 'Ungrouped
843+ -> Query schema params columns
844+selectStar tabs = UnsafeQuery $ "SELECT * " <> renderTableExpression tabs
847+ :: HasTable table tables columns
849+ -> TableExpression params schema tables 'Ungrouped
850+ -> Query schema params columns
851+selectDotStar table tables = UnsafeQuery $
852+ "SELECT " <> renderAlias table <> ".* " <> renderTableExpression tables
854+{-----------------------------------------
856+-----------------------------------------}
859+ :: (KnownSymbol table, SListI columns)
861+ -> NP (Aliased TypeExpression) columns
862+ -> Definition schema (Create table columns schema)
863+createTable table columns = UnsafeDefinition $ mconcat
867+ , ByteString.intercalate ", " . hcollapse $
868+ hmap (K . renderColumn) columns
872+ renderColumn :: Aliased TypeExpression x -> ByteString
873+ renderColumn (ty `As` column) =
874+ renderAlias column <> " " <> renderTypeExpression ty
876+{-----------------------------------------
878+-----------------------------------------}
881+ :: KnownSymbol table
883+ -> Definition schema (Drop table schema)
884+dropTable table = UnsafeDefinition $ "DROP TABLE " <> renderAlias table <> ";"
886+{-----------------------------------------
888+-----------------------------------------}
891+ :: HasTable table schema columns0
893+ -> AlterTable columns0 columns1
894+ -> Definition schema (Alter table schema columns1)
895+alterTable table alteration = UnsafeDefinition $
897+ <> renderAlias table
899+ <> renderAlterTable alteration
903+ :: (KnownSymbol table0, KnownSymbol table1)
906+ -> Definition schema (Rename table0 table1 schema)
907+alterTableRename table0 table1 = UnsafeDefinition $
909+ <> renderAlias table0
911+ <> renderAlias table1
915+ (columns0 :: [(Symbol, ColumnType)])
916+ (columns1 :: [(Symbol, ColumnType)]) =
917+ UnsafeAlterTable {renderAlterTable :: ByteString}
920+ :: KnownSymbol column
922+ -> TypeExpression ('Optional ty)
923+ -> AlterTable columns (Create column ('Optional ty) columns)
924+addColumnDefault column ty = UnsafeAlterTable $
926+ <> renderAlias column
928+ <> renderTypeExpression ty
931+ :: KnownSymbol column
933+ -> TypeExpression ('Required ('Null ty))
934+ -> AlterTable columns ((column ::: 'Required ('Null ty)) ': columns)
935+addColumnNull column ty = UnsafeAlterTable $
937+ <> renderAlias column
939+ <> renderTypeExpression ty
942+ :: KnownSymbol column
944+ -> AlterTable columns (Drop column columns)
945+dropColumn column = UnsafeAlterTable $
946+ "DROP COLUMN " <> renderAlias column
949+ :: (KnownSymbol column0, KnownSymbol column1)
952+ -> AlterTable columns (Rename column0 column1 columns)
953+renameColumn column0 column1 = UnsafeAlterTable $
954+ "RENAME COLUMN " <> renderAlias column0
955+ <> " TO " <> renderAlias column1
958+ :: (KnownSymbol column, HasColumn column columns ty0)
960+ -> AlterColumn ty0 ty1
961+ -> AlterTable columns (Alter column columns ty1)
962+alterColumn column alteration = UnsafeAlterTable $
963+ "ALTER COLUMN " <> renderAlias column
964+ <> " " <> renderAlterColumn alteration
966+data AlterColumn (ty0 :: ColumnType) (ty1 :: ColumnType) =
967+ UnsafeAlterColumn {renderAlterColumn :: ByteString}
970+ :: Expression '[] '[] 'Ungrouped ('Required ty)
971+ -> AlterColumn ('Required ty) ('Optional ty)
972+setDefault expression = UnsafeAlterColumn $
973+ "SET DEFAULT " <> renderExpression expression
975+dropDefault :: AlterColumn ('Optional ty) ('Required ty)
976+dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
979+ :: AlterColumn (optionality ('Null ty)) (optionality ('NotNull ty))
980+setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
983+ :: AlterColumn (optionality ('NotNull ty)) (optionality ('Null ty))
984+dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
988+ => TypeExpression (optionality (nullity ty1))
989+ -> AlterColumn (optionality (nullity ty0)) (optionality (nullity ty1))
990+alterType ty = UnsafeAlterColumn $ "TYPE " <> renderTypeExpression ty
992+{-----------------------------------------
994+-----------------------------------------}
997+ :: (SListI columns, HasTable table schema columns)
999+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1000+ -> Manipulation schema params '[]
1001+insertInto table expressions = UnsafeManipulation $ "INSERT INTO "
1002+ <> renderAlias table
1003+ <> " (" <> ByteString.intercalate ", " aliases
1005+ <> ByteString.intercalate ", " values
1008+ aliases = hcollapse $ hmap
1009+ (\ (_ `As` name) -> K (renderAlias name))
1011+ values = hcollapse $ hmap
1012+ (\ (expression `As` _) -> K (renderExpression expression))
1016+ :: (SListI columns, SListI results, HasTable table schema columns)
1018+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1019+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1020+ -> Manipulation schema params results
1021+insertIntoReturning table inserts results
1022+ = UnsafeManipulation . mconcat $
1024+ , renderAlias table
1025+ , " (" <> ByteString.intercalate ", " aliases
1027+ , ByteString.intercalate ", " values
1029+ , renderList results
1033+ aliases = hcollapse $ hmap
1034+ (\ (_ `As` name) -> K (renderAlias name))
1036+ values = hcollapse $ hmap
1037+ (\ (expression `As` _) -> K (renderExpression expression))
1040+ = ByteString.intercalate ", "
1042+ . hmap (K . renderAliased renderExpression)
1044+{-----------------------------------------
1046+-----------------------------------------}
1048+data UpdateExpression params table ty
1050+ | Set (Expression params table 'Ungrouped ty)
1052+renderUpdateExpression
1053+ :: Aliased (UpdateExpression params '[table ::: columns]) column
1054+ -> Maybe ByteString
1055+renderUpdateExpression = \case
1056+ Same `As` _ -> Nothing
1057+ Set expression `As` column -> Just $ mconcat
1058+ [ renderAlias column
1060+ , renderExpression expression
1064+ :: (HasTable table schema columns, SListI columns)
1066+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1067+ -> Condition params '[table ::: columns] 'Ungrouped
1068+ -> Manipulation schema params '[]
1069+update table columns wh = UnsafeManipulation $ mconcat
1071+ , renderAlias table
1073+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1074+ hmap (K . renderUpdateExpression) columns
1075+ , " WHERE ", renderExpression wh, ";"
1079+ :: (SListI columns, SListI results, HasTable table schema columns)
1081+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1082+ -> Condition params '[table ::: columns] 'Ungrouped
1083+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1084+ -> Manipulation schema params results
1085+updateReturning table updates wh results = UnsafeManipulation $ mconcat
1087+ , renderAlias table
1089+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1090+ hmap (K . renderUpdateExpression) updates
1091+ , " WHERE ", renderExpression wh
1092+ , " RETURNING ", renderList results
1097+ = ByteString.intercalate ", "
1099+ . hmap (K . renderAliased renderExpression)
1102+ :: (SListI columns, HasTable table schema columns)
1104+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1105+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1106+ -> Condition params '[table ::: columns] 'Ungrouped
1107+ -> Manipulation schema params '[]
1108+upsertInto table inserts updates wh = UnsafeManipulation . mconcat $
1110+ , renderAlias table
1111+ , " (" <> ByteString.intercalate ", " aliases
1113+ , ByteString.intercalate ", " values
1114+ , ") ON CONFLICT UPDATE "
1115+ , renderAlias table
1117+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1118+ hmap (K . renderUpdateExpression) updates
1119+ , " WHERE ", renderExpression wh, ";"
1121+ aliases = hcollapse $ hmap
1122+ (\ (_ `As` name) -> K (renderAlias name))
1124+ values = hcollapse $ hmap
1125+ (\ (expression `As` _) -> K (renderExpression expression))
1129+ :: (SListI columns, SListI results, HasTable table schema columns)
1131+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1132+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1133+ -> Condition params '[table ::: columns] 'Ungrouped
1134+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1135+ -> Manipulation schema params results
1136+upsertIntoReturning table inserts updates wh results =
1137+ UnsafeManipulation . mconcat $
1139+ , renderAlias table
1140+ , " (" <> ByteString.intercalate ", " aliases
1142+ , ByteString.intercalate ", " values
1143+ , ") ON CONFLICT UPDATE "
1144+ , renderAlias table
1146+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1147+ hmap (K . renderUpdateExpression) updates
1148+ , " WHERE ", renderExpression wh
1149+ , " RETURNING ", renderList results
1152+ aliases = hcollapse $ hmap
1153+ (\ (_ `As` name) -> K (renderAlias name))
1155+ values = hcollapse $ hmap
1156+ (\ (expression `As` _) -> K (renderExpression expression))
1159+ = ByteString.intercalate ", "
1161+ . hmap (K . renderAliased renderExpression)
1163+{-----------------------------------------
1165+-----------------------------------------}
1168+ :: HasTable table schema columns
1170+ -> Condition params '[table ::: columns] 'Ungrouped
1171+ -> Manipulation schema params '[]
1172+deleteFrom table wh = UnsafeManipulation $ mconcat
1174+ , renderAlias table
1175+ , " WHERE ", renderExpression wh, ";"