@@ -0,0 +1,1158 @@
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
84+ :: (HasTable table tables columns, HasColumn column columns ty)
85+ => Alias table -> Alias column -> Expression params tables 'Ungrouped ty
86+table &. column = UnsafeExpression $
87+ renderAlias table <> "." <> renderAlias column
89+def :: Expression params '[] grouping ('Optional (nullity ty))
90+def = UnsafeExpression "DEFAULT"
93+ :: Expression params '[] grouping ('Required (nullity ty))
94+ -> Expression params '[] grouping ('Optional (nullity ty))
95+notDef = UnsafeExpression . renderExpression
97+null :: Expression params tables grouping (optionality ('Null ty))
98+null = UnsafeExpression "NULL"
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 $ mconcat
106+ , ByteString.intercalate ", " $ map renderExpression nulls
107+ , ", ", renderExpression isn'tNull
113+ -> Expression params tables grouping ty0
114+ -> Expression params tables grouping ty1
115+ -> Expression params tables grouping ty2
116+unsafeBinaryOp op x y = UnsafeExpression $ mconcat
117+ ["(", renderExpression x, " ", op, " ", renderExpression y, ")"]
121+ -> Expression params tables grouping ty0
122+ -> Expression params tables grouping ty1
123+unsafeUnaryOp op x = UnsafeExpression $ mconcat
124+ ["(", op, " ", renderExpression x, ")"]
128+ -> Expression params tables grouping xty
129+ -> Expression params tables grouping yty
130+unsafeFunction fun x = UnsafeExpression $ mconcat
131+ [fun, "(", renderExpression x, ")"]
134+ => Num (Expression params tables grouping ('Required (nullity ty))) where
135+ (+) = unsafeBinaryOp "+"
136+ (-) = unsafeBinaryOp "-"
137+ (*) = unsafeBinaryOp "*"
138+ abs = unsafeFunction "abs"
139+ signum = unsafeFunction "sign"
142+ . (<> if decimal (Proxy :: Proxy ty) then "." else "")
146+instance PGFractional ty => Fractional
147+ (Expression params tables grouping ('Required (nullity ty))) where
148+ (/) = unsafeBinaryOp "/"
149+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
151+instance (PGFloating ty, PGCast 'PGNumeric ty, PGTyped ty) => Floating
152+ (Expression params tables grouping ('Required (nullity ty))) where
153+ pi = UnsafeExpression "pi()"
154+ exp = unsafeFunction "exp"
155+ log = unsafeFunction "ln"
156+ sqrt = unsafeFunction "sqrt"
157+ b ** x = UnsafeExpression $
158+ "power(" <> renderExpression b <> ", " <> renderExpression x <> ")"
159+ logBase b y = cast pgtype $ logBaseNumeric b y
162+ :: Expression params tables grouping ('Required (nullity ty))
163+ -> Expression params tables grouping ('Required (nullity ty))
164+ -> Expression params tables grouping ('Required (nullity 'PGNumeric))
165+ logBaseNumeric b' y' = UnsafeExpression $ mconcat
167+ , renderExpression b' <> "::numeric"
169+ , renderExpression y' <> "::numeric"
172+ sin = unsafeFunction "sin"
173+ cos = unsafeFunction "cos"
174+ tan = unsafeFunction "tan"
175+ asin = unsafeFunction "asin"
176+ acos = unsafeFunction "acos"
177+ atan = unsafeFunction "atan"
178+ sinh x = (exp x - exp (-x)) / 2
179+ cosh x = (exp x + exp (-x)) / 2
180+ tanh x = sinh x / cosh x
181+ asinh x = log (x + sqrt (x*x + 1))
182+ acosh x = log (x + sqrt (x*x - 1))
183+ atanh x = log ((1 + x) / (1 - x)) / 2
187+ => Expression params tables grouping ('Required (nullity float))
188+ -> Expression params tables grouping ('Required (nullity float))
189+ -> Expression params tables grouping ('Required (nullity float))
190+atan2 y x = UnsafeExpression $
191+ "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
193+class PGCast (ty0 :: PGType) (ty1 :: PGType) where
195+ :: TypeExpression ('Required ('Null ty1))
196+ -> Expression params tables grouping ('Required (nullity ty0))
197+ -> Expression params tables grouping ('Required (nullity ty1))
198+ cast ty x = UnsafeExpression $
199+ "(" <> renderExpression x <> "::" <> renderTypeExpression ty <> ")"
200+instance PGCast 'PGInt2 'PGInt2
201+instance PGCast 'PGInt2 'PGInt4
202+instance PGCast 'PGInt2 'PGInt8
203+instance PGCast 'PGInt4 'PGInt2
204+instance PGCast 'PGInt4 'PGInt4
205+instance PGCast 'PGInt4 'PGInt8
206+instance PGCast 'PGInt8 'PGInt2
207+instance PGCast 'PGInt8 'PGInt4
208+instance PGCast 'PGInt8 'PGInt8
209+instance PGCast 'PGInt8 'PGFloat4
210+instance PGCast 'PGInt8 'PGFloat8
211+instance PGCast 'PGInt8 'PGNumeric
214+ :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
215+ => Expression params tables grouping ('Required (nullity ty))
216+ -> Expression params tables grouping ('Required (nullity ty))
217+ -> Expression params tables grouping ('Required (nullity ty))
218+div = unsafeBinaryOp "/"
221+ :: (PGNum ty, PGTyped ty, PGCast 'PGInt8 ty, PGCast ty 'PGInt8)
222+ => Expression params tables grouping ('Required (nullity ty))
223+ -> Expression params tables grouping ('Required (nullity ty))
224+ -> Expression params tables grouping ('Required (nullity ty))
225+mod = unsafeBinaryOp "%"
228+ :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
229+ => Expression params tables grouping ('Required (nullity frac))
230+ -> Expression params tables grouping ('Required (nullity int))
231+truncate = cast pgtype . truncate'
234+ :: Expression params tables grouping ('Required (nullity frac))
235+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
236+ truncate' = unsafeFunction "trunc"
239+ :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
240+ => Expression params tables grouping ('Required (nullity frac))
241+ -> Expression params tables grouping ('Required (nullity int))
242+round = cast pgtype . round'
245+ :: Expression params tables grouping ('Required (nullity frac))
246+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
247+ round' = unsafeFunction "round"
250+ :: (PGFractional frac, PGCast 'PGInt4 int, PGTyped int)
251+ => Expression params tables grouping ('Required (nullity frac))
252+ -> Expression params tables grouping ('Required (nullity int))
253+ceiling = cast pgtype . ceiling'
256+ :: Expression params tables grouping ('Required (nullity frac))
257+ -> Expression params tables grouping ('Required (nullity 'PGInt4))
258+ ceiling' = unsafeFunction "ceiling"
261+ (Expression params tables grouping ('Required (nullity 'PGText))) where
262+ fromString str = UnsafeExpression $
263+ "E\'" <> fromString (escape =<< str) <> "\'"
276+type Condition params tables grouping =
277+ Expression params tables grouping ('Required ('NotNull 'PGBool))
279+true :: Condition params tables grouping
280+true = UnsafeExpression "TRUE"
282+false :: Condition params tables grouping
283+false = UnsafeExpression "FALSE"
286+ :: Condition params tables grouping
287+ -> Condition params tables grouping
288+not_ = unsafeUnaryOp "NOT"
291+ :: Condition params tables grouping
292+ -> Condition params tables grouping
293+ -> Condition params tables grouping
294+(&&*) = unsafeBinaryOp "AND"
297+ :: Condition params tables grouping
298+ -> Condition params tables grouping
299+ -> Condition params tables grouping
300+(||*) = unsafeBinaryOp "OR"
303+ :: [(Condition params tables grouping, Expression params tables grouping ty)]
304+ -> Expression params tables grouping ty
305+ -> Expression params tables grouping ty
306+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
310+ [ " WHEN ", renderExpression when_
311+ , " THEN ", renderExpression then_
313+ | (when_,then_) <- whenThens
315+ , " ELSE ", renderExpression else_
320+ :: Condition params tables grouping
321+ -> Expression params tables grouping ty
322+ -> Expression params tables grouping ty
323+ -> Expression params tables grouping ty
324+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
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 "<="
357+ :: Expression params tables grouping ('Required (nullity ty))
358+ -> Expression params tables grouping ('Required (nullity ty))
359+ -> Expression params tables grouping ('Required (nullity 'PGBool))
360+(>*) = unsafeBinaryOp ">"
362+data SortExpression params tables grouping where
364+ :: Expression params tables grouping ty
365+ -> SortExpression params tables grouping
367+ :: Expression params tables grouping ty
368+ -> SortExpression params tables grouping
370+renderSortExpression :: SortExpression params tables grouping -> ByteString
371+renderSortExpression = \case
372+ Asc expression -> renderExpression expression <> " ASC"
373+ Desc expression -> renderExpression expression <> " DESC"
375+data Aggregate (ty0 :: ColumnType) (ty1 :: ColumnType) =
376+ UnsafeAggregate { renderAggregate :: ByteString }
380+ => Aggregate ('Required (nullity ty)) ('Required (nullity ty))
381+sumAggregate = UnsafeAggregate "sum"
383+class (KnownSymbol table, KnownSymbol column)
384+ => GroupedBy table column distincts ty where
386+ :: (HasTable table tables columns, HasColumn column columns ty)
389+ -> Expression params tables ('Grouped distincts) ty
391+class (KnownSymbol table, KnownSymbol column)
392+ => Aggregated table column distincts ty where
394+ :: (HasTable table tables columns, HasColumn column columns ty0)
398+ -> Expression params tables ('Grouped distincts) ty
400+{-----------------------------------------
402+-----------------------------------------}
405+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
406+ (columns :: [(Symbol,ColumnType)])
407+ = UnsafeTable { renderTable :: ByteString }
410+class KnownSymbol table => HasTable table tables columns
411+ | table tables -> columns where
412+ getTable :: Proxy# table -> Table tables columns
413+ getTable table = UnsafeTable $ fromString $ symbolVal' table
414+instance {-# OVERLAPPING #-} KnownSymbol table
415+ => HasTable table ((table ::: columns) ': tables) columns
416+instance {-# OVERLAPPABLE #-}
417+ (KnownSymbol table, HasTable table schema columns)
418+ => HasTable table (table' ': schema) columns
420+instance HasTable table schema columns
421+ => IsLabel table (Table schema columns) where
422+ fromLabel = getTable
424+data TableReference params schema tables where
426+ :: Aliased (Table schema) table
427+ -> TableReference params schema '[table]
429+ :: Aliased (Query schema params) table
430+ -> TableReference params schema '[table]
432+ :: TableReference params schema right
433+ -> TableReference params schema left
434+ -> TableReference params schema (Join left right)
436+ :: TableReference params schema right
437+ -> Condition params (Join left right) 'Ungrouped
438+ -> TableReference params schema left
439+ -> TableReference params schema (Join left right)
441+ :: TableReference params schema right
442+ -> Condition params (Join left right) 'Ungrouped
443+ -> TableReference params schema left
444+ -> TableReference params schema (Join left (NullifyTables right))
446+ :: TableReference params schema right
447+ -> Condition params (Join left right) 'Ungrouped
448+ -> TableReference params schema left
449+ -> TableReference params schema (Join (NullifyTables left) right)
451+ :: TableReference params schema right
452+ -> Condition params (Join left right) 'Ungrouped
453+ -> TableReference params schema left
454+ -> TableReference params schema
455+ (Join (NullifyTables left) (NullifyTables right))
457+renderTableReference :: TableReference params schema tables -> ByteString
458+renderTableReference = \case
459+ Table table -> renderAliased renderTable table
460+ Subquery selection -> renderAliased renderQuery selection
461+ CrossJoin right left -> mconcat
462+ [ renderTableReference left
464+ , renderTableReference right
466+ InnerJoin right on left -> mconcat
467+ [ renderTableReference left
469+ , renderTableReference right
471+ , renderExpression on
473+ LeftOuterJoin right on left -> mconcat
474+ [ renderTableReference left
475+ , " LEFT OUTER JOIN "
476+ , renderTableReference right
478+ , renderExpression on
480+ RightOuterJoin right on left -> mconcat
481+ [ renderTableReference left
482+ , " RIGHT OUTER JOIN "
483+ , renderTableReference right
485+ , renderExpression on
487+ FullOuterJoin right on left -> mconcat
488+ [ renderTableReference left
489+ , " FULL OUTER JOIN "
490+ , renderTableReference right
492+ , renderExpression on
495+data By tables tabcolty where
497+ :: (HasTable table tables columns, HasColumn column columns ty)
500+ -> By tables (table ::: (column ::: ty))
502+renderBy :: By tables tabcolty -> ByteString
503+renderBy (By table column) = renderAlias table <> "." <> renderAlias column
505+data GroupByClause tables grouping where
506+ NoGroups :: GroupByClause tables 'Ungrouped
509+ => NP (By tables) distincts
510+ -> GroupByClause tables ('Grouped distincts)
512+renderGroupByClause :: GroupByClause tables grouping -> ByteString
513+renderGroupByClause = \case
516+ Distinct distincts -> " GROUP BY " <> ByteString.intercalate ", "
517+ (hcollapse (hmap (K . renderBy) distincts))
519+data HavingClause params tables grouping where
520+ NoHaving :: HavingClause params tables 'Ungrouped
522+ :: [Condition params tables ('Grouped distincts)]
523+ -> HavingClause params tables ('Grouped distincts)
525+renderHavingClause :: HavingClause params tables grouping -> ByteString
526+renderHavingClause = \case
529+ Having conditions -> " HAVING " <> ByteString.intercalate ", "
530+ (renderExpression <$> conditions)
533+ (params :: [ColumnType])
534+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
535+ (tables :: [(Symbol,[(Symbol,ColumnType)])])
536+ (grouping :: Grouping)
538+ { fromClause :: TableReference params schema tables
539+ , whereClause :: [Condition params tables 'Ungrouped]
540+ , groupByClause :: GroupByClause tables grouping
541+ , havingClause :: HavingClause params tables grouping
542+ , orderByClause :: [SortExpression params tables grouping]
543+ , limitClause :: [Word64]
544+ , offsetClause :: [Word64]
547+renderTableExpression
548+ :: TableExpression params schema tables grouping
550+renderTableExpression
551+ (TableExpression tables whs' grps' hvs' srts' lims' offs') = mconcat
552+ [ "FROM ", renderTableReference tables
554+ , renderGroupByClause grps'
555+ , renderHavingClause hvs'
557+ , renderLimits lims'
558+ , renderOffsets offs'
561+ renderWheres = \case
563+ wh:[] -> " WHERE " <> renderExpression wh
564+ wh:whs -> " WHERE " <> renderExpression (foldr (&&*) wh whs)
568+ <> ByteString.intercalate ", " (renderSortExpression <$> srts)
569+ renderLimits = \case
571+ lims -> " LIMIT " <> fromString (show (minimum lims))
572+ renderOffsets = \case
574+ offs -> " OFFSET " <> fromString (show (sum offs))
577+ :: TableReference params schema tables
578+ -> TableExpression params schema tables 'Ungrouped
579+from tables = TableExpression tables [] NoGroups NoHaving [] [] []
582+ :: Condition params tables 'Ungrouped
583+ -> TableExpression params schema tables grouping
584+ -> TableExpression params schema tables grouping
585+where_ wh tables = tables {whereClause = wh : whereClause tables}
589+ => NP (By tables) distincts
590+ -> TableExpression params schema tables 'Ungrouped
591+ -> TableExpression params schema tables ('Grouped distincts)
592+group distincts tables = TableExpression
593+ { fromClause = fromClause tables
594+ , whereClause = whereClause tables
595+ , groupByClause = Distinct distincts
596+ , havingClause = Having []
597+ , orderByClause = []
598+ , limitClause = limitClause tables
599+ , offsetClause = offsetClause tables
603+ :: Condition params tables ('Grouped distincts)
604+ -> TableExpression params schema tables ('Grouped distincts)
605+ -> TableExpression params schema tables ('Grouped distincts)
606+having hv tables = tables
607+ { havingClause = case havingClause tables of Having hvs -> Having (hv:hvs) }
610+ :: [SortExpression params tables grouping]
611+ -> TableExpression params schema tables grouping
612+ -> TableExpression params schema tables grouping
613+orderBy srts tables = tables {orderByClause = orderByClause tables ++ srts}
617+ -> TableExpression params schema tables grouping
618+ -> TableExpression params schema tables grouping
619+limit lim tables = tables {limitClause = lim : limitClause tables}
623+ -> TableExpression params schema tables grouping
624+ -> TableExpression params schema tables grouping
625+offset off tables = tables {offsetClause = off : offsetClause tables}
627+{-----------------------------------------
629+-----------------------------------------}
631+newtype TypeExpression (ty :: ColumnType)
632+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
635+bool :: TypeExpression ('Required ('Null 'PGBool))
636+bool = UnsafeTypeExpression "bool"
637+int2 :: TypeExpression ('Required ('Null 'PGInt2))
638+int2 = UnsafeTypeExpression "int2"
639+smallint :: TypeExpression ('Required ('Null 'PGInt2))
640+smallint = UnsafeTypeExpression "smallint"
641+int4 :: TypeExpression ('Required ('Null 'PGInt4))
642+int4 = UnsafeTypeExpression "int4"
643+int :: TypeExpression ('Required ('Null 'PGInt4))
644+int = UnsafeTypeExpression "int"
645+integer :: TypeExpression ('Required ('Null 'PGInt4))
646+integer = UnsafeTypeExpression "integer"
647+int8 :: TypeExpression ('Required ('Null 'PGInt8))
648+int8 = UnsafeTypeExpression "int8"
649+bigint :: TypeExpression ('Required ('Null 'PGInt8))
650+bigint = UnsafeTypeExpression "bigint"
651+numeric :: TypeExpression ('Required ('Null 'PGNumeric))
652+numeric = UnsafeTypeExpression "numeric"
653+float4 :: TypeExpression ('Required ('Null 'PGFloat4))
654+float4 = UnsafeTypeExpression "float4"
655+real :: TypeExpression ('Required ('Null 'PGFloat4))
656+real = UnsafeTypeExpression "real"
657+float8 :: TypeExpression ('Required ('Null 'PGFloat8))
658+float8 = UnsafeTypeExpression "float8"
659+doublePrecision :: TypeExpression ('Required ('Null 'PGFloat8))
660+doublePrecision = UnsafeTypeExpression "double precision"
661+serial2 :: TypeExpression ('Optional ('NotNull 'PGInt2))
662+serial2 = UnsafeTypeExpression "serial2"
663+smallserial :: TypeExpression ('Optional ('NotNull 'PGInt2))
664+smallserial = UnsafeTypeExpression "smallserial"
665+serial4 :: TypeExpression ('Optional ('NotNull 'PGInt4))
666+serial4 = UnsafeTypeExpression "serial4"
667+serial :: TypeExpression ('Optional ('NotNull 'PGInt4))
668+serial = UnsafeTypeExpression "serial"
669+serial8 :: TypeExpression ('Optional ('NotNull 'PGInt8))
670+serial8 = UnsafeTypeExpression "serial8"
671+bigserial :: TypeExpression ('Optional ('NotNull 'PGInt8))
672+bigserial = UnsafeTypeExpression "bigserial"
673+money :: TypeExpression ('Required ('Null 'PGMoney))
674+money = UnsafeTypeExpression "money"
675+text :: TypeExpression ('Required ('Null 'PGText))
676+text = UnsafeTypeExpression "text"
680+ -> TypeExpression ('Required ('Null ('PGChar n)))
681+char (_ :: proxy n) = UnsafeTypeExpression $
682+ "char(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
686+ -> TypeExpression ('Required ('Null ('PGChar n)))
687+character (_ :: proxy n) = UnsafeTypeExpression $
688+ "character(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
692+ -> TypeExpression ('Required ('Null ('PGVarChar n)))
693+varchar (_ :: proxy n) = UnsafeTypeExpression $
694+ "varchar(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
698+ -> TypeExpression ('Required ('Null ('PGVarChar n)))
699+characterVarying (_ :: proxy n) = UnsafeTypeExpression $
700+ "character varying(" <> fromString (show (natVal' (proxy# :: Proxy# n))) <> ")"
701+bytea :: TypeExpression ('Required ('Null ('PGBytea)))
702+bytea = UnsafeTypeExpression "bytea"
703+timestamp :: TypeExpression ('Required ('Null ('PGTimestamp)))
704+timestamp = UnsafeTypeExpression "timestamp"
705+timestampWithTimeZone :: TypeExpression ('Required ('Null ('PGTimestampTZ)))
706+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
707+date :: TypeExpression ('Required ('Null ('PGDate)))
708+date = UnsafeTypeExpression "date"
709+time :: TypeExpression ('Required ('Null ('PGTime)))
710+time = UnsafeTypeExpression "time"
711+timeWithTimeZone :: TypeExpression ('Required ('Null ('PGTimeTZ)))
712+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
713+interval :: TypeExpression ('Required ('Null ('PGInterval)))
714+interval = UnsafeTypeExpression "interval"
715+uuid :: TypeExpression ('Required ('Null ('PGUuid)))
716+uuid = UnsafeTypeExpression "uuid"
717+json :: TypeExpression ('Required ('Null ('PGJson)))
718+json = UnsafeTypeExpression "json"
719+jsonb :: TypeExpression ('Required ('Null ('PGJsonb)))
720+jsonb = UnsafeTypeExpression "jsonb"
723+ :: TypeExpression ('Required ('Null ty))
724+ -> TypeExpression ('Required ('NotNull ty))
725+notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <> " NOT NULL"
727+ :: Expression '[] '[] 'Ungrouped ('Required ty)
728+ -> TypeExpression ('Required ty)
729+ -> TypeExpression ('Optional ty)
730+default_ x ty = UnsafeTypeExpression $
731+ renderTypeExpression ty <> " DEFAULT " <> renderExpression x
733+class PGTyped (ty :: PGType) where
734+ pgtype :: TypeExpression ('Required ('Null ty))
735+instance PGTyped 'PGBool where pgtype = bool
736+instance PGTyped 'PGInt2 where pgtype = int2
737+instance PGTyped 'PGInt4 where pgtype = int4
738+instance PGTyped 'PGInt8 where pgtype = int8
739+instance PGTyped 'PGNumeric where pgtype = numeric
740+instance PGTyped 'PGFloat4 where pgtype = float4
741+instance PGTyped 'PGFloat8 where pgtype = float8
742+instance PGTyped 'PGMoney where pgtype = money
743+instance PGTyped 'PGText where pgtype = text
744+instance KnownNat n => PGTyped ('PGChar n) where pgtype = char (Proxy @n)
745+instance KnownNat n => PGTyped ('PGVarChar n) where pgtype = varchar (Proxy @n)
746+instance PGTyped 'PGBytea where pgtype = bytea
747+instance PGTyped 'PGTimestamp where pgtype = timestamp
748+instance PGTyped 'PGTimestampTZ where pgtype = timestampWithTimeZone
749+instance PGTyped 'PGDate where pgtype = date
750+instance PGTyped 'PGTime where pgtype = time
751+instance PGTyped 'PGTimeTZ where pgtype = timeWithTimeZone
752+instance PGTyped 'PGInterval where pgtype = interval
753+instance PGTyped 'PGUuid where pgtype = uuid
754+instance PGTyped 'PGJson where pgtype = json
755+instance PGTyped 'PGJsonb where pgtype = jsonb
757+{-----------------------------------------
759+-----------------------------------------}
762+ (schema0 :: [(Symbol,[(Symbol,ColumnType)])])
763+ (schema1 :: [(Symbol,[(Symbol,ColumnType)])])
764+ = UnsafeDefinition { renderDefinition :: ByteString }
766+instance Category Definition where
767+ id = UnsafeDefinition ";"
768+ dd1 . dd0 = UnsafeDefinition $
769+ renderDefinition dd0 <> " " <> renderDefinition dd1
772+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
773+ (params :: [ColumnType])
774+ (columns :: [(Symbol,ColumnType)])
775+ = UnsafeManipulation { renderManipulation :: ByteString }
778+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
779+ (params :: [ColumnType])
780+ (columns :: [(Symbol,ColumnType)])
781+ = UnsafeQuery { renderQuery :: ByteString }
784+ :: Query schema params columns
785+ -> Manipulation schema params columns
786+query q = UnsafeManipulation $ renderQuery q <> ";"
788+union, unionAll, intersect, intersectAll, except, exceptAll
789+ :: Query schema params columns
790+ -> Query schema params columns
791+ -> Query schema params columns
792+q1 `union` q2 = UnsafeQuery $
793+ renderQuery q1 <> " UNION " <> renderQuery q2
794+q1 `unionAll` q2 = UnsafeQuery $
795+ renderQuery q1 <> " UNION ALL " <> renderQuery q2
796+q1 `intersect` q2 = UnsafeQuery $
797+ renderQuery q1 <> " INTERSECT " <> renderQuery q2
798+q1 `intersectAll` q2 = UnsafeQuery $
799+ renderQuery q1 <> " INTERSECT ALL " <> renderQuery q2
800+q1 `except` q2 = UnsafeQuery $
801+ renderQuery q1 <> " EXCEPT " <> renderQuery q2
802+q1 `exceptAll` q2 = UnsafeQuery $
803+ renderQuery q1 <> " EXCEPT ALL " <> renderQuery q2
805+{-----------------------------------------
807+-----------------------------------------}
811+ => NP (Aliased (Expression params tables grouping)) columns
812+ -> TableExpression params schema tables grouping
813+ -> Query schema params columns
814+select list tabs = UnsafeQuery $
815+ "SELECT " <> renderList list <> " " <> renderTableExpression tabs
818+ = ByteString.intercalate ", "
820+ . hmap (K . renderAliased renderExpression)
823+ :: (tables ~ '[table ::: columns])
824+ => TableExpression params schema tables 'Ungrouped
825+ -> Query schema params columns
826+selectStar tabs = UnsafeQuery $ "SELECT * " <> renderTableExpression tabs
829+ :: HasTable table tables columns
831+ -> TableExpression params schema tables 'Ungrouped
832+ -> Query schema params columns
833+selectDotStar table tables = UnsafeQuery $
834+ "SELECT " <> renderAlias table <> ".* " <> renderTableExpression tables
836+{-----------------------------------------
838+-----------------------------------------}
841+ :: (KnownSymbol table, SListI columns)
843+ -> NP (Aliased TypeExpression) columns
844+ -> Definition schema (Create table columns schema)
845+createTable table columns = UnsafeDefinition $ mconcat
849+ , ByteString.intercalate ", " . hcollapse $
850+ hmap (K . renderColumn) columns
854+ renderColumn :: Aliased TypeExpression x -> ByteString
855+ renderColumn (ty `As` column) =
856+ renderAlias column <> " " <> renderTypeExpression ty
858+{-----------------------------------------
860+-----------------------------------------}
863+ :: KnownSymbol table
865+ -> Definition schema (Drop table schema)
866+dropTable table = UnsafeDefinition $ "DROP TABLE " <> renderAlias table <> ";"
868+{-----------------------------------------
870+-----------------------------------------}
873+ :: HasTable table schema columns0
875+ -> AlterTable columns0 columns1
876+ -> Definition schema (Alter table schema columns1)
877+alterTable table alteration = UnsafeDefinition $
879+ <> renderAlias table
881+ <> renderAlterTable alteration
885+ :: (KnownSymbol table0, KnownSymbol table1)
888+ -> Definition schema (Rename table0 table1 schema)
889+alterTableRename table0 table1 = UnsafeDefinition $
891+ <> renderAlias table0
893+ <> renderAlias table1
897+ (columns0 :: [(Symbol, ColumnType)])
898+ (columns1 :: [(Symbol, ColumnType)]) =
899+ UnsafeAlterTable {renderAlterTable :: ByteString}
902+ :: KnownSymbol column
904+ -> TypeExpression ('Optional ty)
905+ -> AlterTable columns (Create column ('Optional ty) columns)
906+addColumnDefault column ty = UnsafeAlterTable $
908+ <> renderAlias column
910+ <> renderTypeExpression ty
913+ :: KnownSymbol column
915+ -> TypeExpression ('Required ('Null ty))
916+ -> AlterTable columns ((column ::: 'Required ('Null ty)) ': columns)
917+addColumnNull column ty = UnsafeAlterTable $
919+ <> renderAlias column
921+ <> renderTypeExpression ty
924+ :: KnownSymbol column
926+ -> AlterTable columns (Drop column columns)
927+dropColumn column = UnsafeAlterTable $
928+ "DROP COLUMN " <> renderAlias column
931+ :: (KnownSymbol column0, KnownSymbol column1)
934+ -> AlterTable columns (Rename column0 column1 columns)
935+renameColumn column0 column1 = UnsafeAlterTable $
936+ "RENAME COLUMN " <> renderAlias column0
937+ <> " TO " <> renderAlias column1
940+ :: (KnownSymbol column, HasColumn column columns ty0)
942+ -> AlterColumn ty0 ty1
943+ -> AlterTable columns (Alter column columns ty1)
944+alterColumn column alteration = UnsafeAlterTable $
945+ "ALTER COLUMN " <> renderAlias column
946+ <> " " <> renderAlterColumn alteration
948+data AlterColumn (ty0 :: ColumnType) (ty1 :: ColumnType) =
949+ UnsafeAlterColumn {renderAlterColumn :: ByteString}
952+ :: Expression '[] '[] 'Ungrouped ('Required ty)
953+ -> AlterColumn ('Required ty) ('Optional ty)
954+setDefault expression = UnsafeAlterColumn $
955+ "SET DEFAULT " <> renderExpression expression
957+dropDefault :: AlterColumn ('Optional ty) ('Required ty)
958+dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"
961+ :: AlterColumn (optionality ('Null ty)) (optionality ('NotNull ty))
962+setNotNull = UnsafeAlterColumn $ "SET NOT NULL"
965+ :: AlterColumn (optionality ('NotNull ty)) (optionality ('Null ty))
966+dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"
970+ => TypeExpression (optionality (nullity ty1))
971+ -> AlterColumn (optionality (nullity ty0)) (optionality (nullity ty1))
972+alterType ty = UnsafeAlterColumn $ "TYPE " <> renderTypeExpression ty
974+{-----------------------------------------
976+-----------------------------------------}
979+ :: (SListI columns, HasTable table schema columns)
981+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
982+ -> Manipulation schema params '[]
983+insertInto table expressions = UnsafeManipulation $ "INSERT INTO "
984+ <> renderAlias table
985+ <> " (" <> ByteString.intercalate ", " aliases
987+ <> ByteString.intercalate ", " values
990+ aliases = hcollapse $ hmap
991+ (\ (_ `As` name) -> K (renderAlias name))
993+ values = hcollapse $ hmap
994+ (\ (expression `As` _) -> K (renderExpression expression))
998+ :: (SListI columns, SListI results, HasTable table schema columns)
1000+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1001+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1002+ -> Manipulation schema params results
1003+insertIntoReturning table inserts results
1004+ = UnsafeManipulation . mconcat $
1006+ , renderAlias table
1007+ , " (" <> ByteString.intercalate ", " aliases
1009+ , ByteString.intercalate ", " values
1011+ , renderList results
1015+ aliases = hcollapse $ hmap
1016+ (\ (_ `As` name) -> K (renderAlias name))
1018+ values = hcollapse $ hmap
1019+ (\ (expression `As` _) -> K (renderExpression expression))
1022+ = ByteString.intercalate ", "
1024+ . hmap (K . renderAliased renderExpression)
1026+{-----------------------------------------
1028+-----------------------------------------}
1030+data UpdateExpression params table ty
1032+ | Set (Expression params table 'Ungrouped ty)
1034+renderUpdateExpression
1035+ :: Aliased (UpdateExpression params '[table ::: columns]) column
1036+ -> Maybe ByteString
1037+renderUpdateExpression = \case
1038+ Same `As` _ -> Nothing
1039+ Set expression `As` column -> Just $ mconcat
1040+ [ renderAlias column
1042+ , renderExpression expression
1046+ :: (HasTable table schema columns, SListI columns)
1048+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1049+ -> Condition params '[table ::: columns] 'Ungrouped
1050+ -> Manipulation schema params '[]
1051+update table columns wh = UnsafeManipulation $ mconcat
1053+ , renderAlias table
1055+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1056+ hmap (K . renderUpdateExpression) columns
1057+ , " WHERE ", renderExpression wh, ";"
1061+ :: (SListI columns, SListI results, HasTable table schema columns)
1063+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1064+ -> Condition params '[table ::: columns] 'Ungrouped
1065+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1066+ -> Manipulation schema params results
1067+updateReturning table updates wh results = UnsafeManipulation $ mconcat
1069+ , renderAlias table
1071+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1072+ hmap (K . renderUpdateExpression) updates
1073+ , " WHERE ", renderExpression wh
1074+ , " RETURNING ", renderList results
1079+ = ByteString.intercalate ", "
1081+ . hmap (K . renderAliased renderExpression)
1084+ :: (SListI columns, HasTable table schema columns)
1086+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1087+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1088+ -> Condition params '[table ::: columns] 'Ungrouped
1089+ -> Manipulation schema params '[]
1090+upsertInto table inserts updates wh = UnsafeManipulation . mconcat $
1092+ , renderAlias table
1093+ , " (" <> ByteString.intercalate ", " aliases
1095+ , ByteString.intercalate ", " values
1096+ , ") ON CONFLICT UPDATE "
1097+ , renderAlias table
1099+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1100+ hmap (K . renderUpdateExpression) updates
1101+ , " WHERE ", renderExpression wh, ";"
1103+ aliases = hcollapse $ hmap
1104+ (\ (_ `As` name) -> K (renderAlias name))
1106+ values = hcollapse $ hmap
1107+ (\ (expression `As` _) -> K (renderExpression expression))
1111+ :: (SListI columns, SListI results, HasTable table schema columns)
1113+ -> NP (Aliased (Expression params '[] 'Ungrouped)) columns
1114+ -> NP (Aliased (UpdateExpression params '[table ::: columns])) columns
1115+ -> Condition params '[table ::: columns] 'Ungrouped
1116+ -> NP (Aliased (Expression params '[table ::: columns] 'Ungrouped)) results
1117+ -> Manipulation schema params results
1118+upsertIntoReturning table inserts updates wh results =
1119+ UnsafeManipulation . mconcat $
1121+ , renderAlias table
1122+ , " (" <> ByteString.intercalate ", " aliases
1124+ , ByteString.intercalate ", " values
1125+ , ") ON CONFLICT UPDATE "
1126+ , renderAlias table
1128+ , ByteString.intercalate ", " . catMaybes . hcollapse $
1129+ hmap (K . renderUpdateExpression) updates
1130+ , " WHERE ", renderExpression wh
1131+ , " RETURNING ", renderList results
1134+ aliases = hcollapse $ hmap
1135+ (\ (_ `As` name) -> K (renderAlias name))
1137+ values = hcollapse $ hmap
1138+ (\ (expression `As` _) -> K (renderExpression expression))
1141+ = ByteString.intercalate ", "
1143+ . hmap (K . renderAliased renderExpression)
1145+{-----------------------------------------
1147+-----------------------------------------}
1150+ :: HasTable table schema columns
1152+ -> Condition params '[table ::: columns] 'Ungrouped
1153+ -> Manipulation schema params '[]
1154+deleteFrom table wh = UnsafeManipulation $ mconcat
1156+ , renderAlias table
1157+ , " WHERE ", renderExpression wh, ";"