@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Query
3+Description: Squeal expressions
4+Copyright: (c) Eitan Chatav, 2017
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Squeal expressions are the atoms used to build statements.
9+-}
10+
111{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
212{-# LANGUAGE
313 AllowAmbiguousTypes
@@ -24,7 +34,7 @@
2434#-}
2535
2636module Squeal.PostgreSQL.Expression
27− ( -- * Column Expressions
37+ ( -- * Expression
2838 Expression (UnsafeExpression, renderExpression)
2939 , HasParameter (param)
3040 , HasColumn (getColumn)
@@ -49,8 +59,8 @@ module Squeal.PostgreSQL.Expression
4959 , unsafeFunction
5060 , atan2_
5161 , cast
52− , div_
53− , mod_
62+ , quot_
63+ , rem_
5464 , trunc
5565 , round_
5666 , ceiling_
@@ -83,25 +93,15 @@ module Squeal.PostgreSQL.Expression
8393 , charLength
8494 , like
8595 -- ** Aggregation
86− , unsafeAggregate
87− , unsafeAggregateDistinct
88− , sum_
89− , sumDistinct
96+ , unsafeAggregate, unsafeAggregateDistinct
97+ , sum_, sumDistinct
9098 , PGAvg (avg, avgDistinct)
91− , bitAnd
92− , bitOr
93− , boolAnd
94− , boolOr
99+ , bitAnd, bitOr, boolAnd, boolOr
100+ , bitAndDistinct, bitOrDistinct, boolAndDistinct, boolOrDistinct
95101 , countStar
96− , countDistinctStar
97− , count
98− , every
99− , jsonAgg
100− , jsonbAgg
101− , jsonObjectAgg
102− , jsonbObjectAgg
103− , max_
104− , min_
102+ , count, countDistinct
103+ , every, everyDistinct
104+ , max_, maxDistinct, min_, minDistinct
105105 -- * Tables
106106 , Table (UnsafeTable, renderTable)
107107 , HasTable (getTable)
@@ -140,6 +140,7 @@ module Squeal.PostgreSQL.Expression
140140 , timeWithTimeZone
141141 , interval
142142 , uuid
143+ , inet
143144 , json
144145 , jsonb
145146 , notNull
@@ -233,6 +234,10 @@ instance (HasTable table tables columns, HasColumn column columns ty)
233234 table ! column = UnsafeExpression $
234235 renderAlias table <> "." <> renderAlias column
235236
237+-- | A `Column` is a witness to a `HasColumn` constraint. It's used
238+-- in `Squeel.PostgreSQL.Definition.unique` and other
239+-- `Squeel.PostgreSQL.Definition.TableConstraint`s to witness a
240+-- subcolumns relationship.
236241data Column
237242 (columns :: ColumnsType)
238243 (columnty :: (Symbol,ColumnType))
@@ -245,9 +250,14 @@ deriving instance Show (Column columns columnty)
245250deriving instance Eq (Column columns columnty)
246251deriving instance Ord (Column columns columnty)
247252
253+-- | Render a `Column`.
248254renderColumn :: Column columns columnty -> ByteString
249255renderColumn (Column column) = renderAlias column
250256
257+{- | A `GroupedBy` constraint indicates that a table qualified column is
258+a member of the auxiliary namespace created by @GROUP BY@ clauses and thus,
259+may be called in an output `Expression` without aggregating.
260+-}
251261class (KnownSymbol table, KnownSymbol column)
252262 => GroupedBy table column bys where
253263 getGroup1
@@ -294,6 +304,7 @@ def = UnsafeExpression "DEFAULT"
294304-- "FALSE"
295305unDef
296306 :: Expression '[] 'Ungrouped params ('Required (nullity ty))
307+ -- ^ not @DEFAULT@
297308 -> Expression '[] 'Ungrouped params ('Optional (nullity ty))
298309unDef = UnsafeExpression . renderExpression
299310
@@ -310,6 +321,7 @@ null_ = UnsafeExpression "NULL"
310321-- "TRUE"
311322unNull
312323 :: Expression tables grouping params (optionality ('NotNull ty))
324+ -- ^ not @NULL@
313325 -> Expression tables grouping params (optionality ('Null ty))
314326unNull = UnsafeExpression . renderExpression
315327
@@ -319,7 +331,9 @@ unNull = UnsafeExpression . renderExpression
319331-- "COALESCE(NULL, TRUE, FALSE)"
320332coalesce
321333 :: [Expression tables grouping params ('Required ('Null ty))]
334+ -- ^ @NULL@s may be present
322335 -> Expression tables grouping params ('Required ('NotNull ty))
336+ -- ^ @NULL@ is absent
323337 -> Expression tables grouping params ('Required ('NotNull ty))
324338coalesce nullxs notNullx = UnsafeExpression $
325339 "COALESCE" <> parenthesized (commaSeparated
@@ -331,6 +345,7 @@ coalesce nullxs notNullx = UnsafeExpression $
331345-- "COALESCE(NULL, TRUE)"
332346fromNull
333347 :: Expression tables grouping params ('Required ('NotNull ty))
348+ -- ^ what to convert @NULL@ to
334349 -> Expression tables grouping params ('Required ('Null ty))
335350 -> Expression tables grouping params ('Required ('NotNull ty))
336351fromNull notNullx nullx = coalesce [nullx] notNullx
@@ -339,6 +354,7 @@ fromNull notNullx nullx = coalesce [nullx] notNullx
339354-- "NULL IS NULL"
340355isNull
341356 :: Expression tables grouping params ('Required ('Null ty))
357+ -- ^ possibly @NULL@
342358 -> Condition tables grouping params
343359isNull x = UnsafeExpression $ renderExpression x <+> "IS NULL"
344360
@@ -346,6 +362,7 @@ isNull x = UnsafeExpression $ renderExpression x <+> "IS NULL"
346362-- "NULL IS NOT NULL"
347363isn'tNull
348364 :: Expression tables grouping params ('Required ('Null ty))
365+ -- ^ possibly @NULL@
349366 -> Condition tables grouping params
350367isn'tNull x = UnsafeExpression $ renderExpression x <+> "IS NOT NULL"
351368
@@ -355,21 +372,26 @@ isn'tNull x = UnsafeExpression $ renderExpression x <+> "IS NOT NULL"
355372-- "CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END"
356373matchNull
357374 :: Expression tables grouping params ('Required nullty)
375+ -- ^ what to convert @NULL@ to
358376 -> ( Expression tables grouping params ('Required ('NotNull ty))
359377 -> Expression tables grouping params ('Required nullty) )
378+ -- ^ function to perform when @NULL@ is absent
360379 -> Expression tables grouping params ('Required ('Null ty))
361380 -> Expression tables grouping params ('Required nullty)
362381matchNull y f x = ifThenElse (isNull x) y
363382 (f (UnsafeExpression (renderExpression x)))
364383
365−-- | right inverse to `fromNull`
384+-- | right inverse to `fromNull`, if its arguments are equal then
385+-- `nullIf` gives @NULL@.
366386--
367387-- >>> :set -XTypeApplications -XDataKinds
368388-- >>> renderExpression @_ @_ @'[_] $ fromNull false (nullIf false (param @1))
369389-- "COALESCE(NULL IF (FALSE, ($1 :: bool)), FALSE)"
370390nullIf
371391 :: Expression tables grouping params ('Required ('NotNull ty))
392+ -- ^ @NULL@ is absent
372393 -> Expression tables grouping params ('Required ('NotNull ty))
394+ -- ^ @NULL@ is absent
373395 -> Expression tables grouping params ('Required ('Null ty))
374396nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
375397 (renderExpression x <> ", " <> renderExpression y)
@@ -378,7 +400,9 @@ nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
378400-- "GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))"
379401greatest
380402 :: Expression tables grouping params ('Required nullty)
403+ -- ^ needs at least 1 argument
381404 -> [Expression tables grouping params ('Required nullty)]
405+ -- ^ or more
382406 -> Expression tables grouping params ('Required nullty)
383407greatest x xs = UnsafeExpression $ "GREATEST("
384408 <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
@@ -387,28 +411,39 @@ greatest x xs = UnsafeExpression $ "GREATEST("
387411-- "LEAST(CURRENT_TIMESTAMP, NULL)"
388412least
389413 :: Expression tables grouping params ('Required nullty)
414+ -- ^ needs at least 1 argument
390415 -> [Expression tables grouping params ('Required nullty)]
416+ -- ^ or more
391417 -> Expression tables grouping params ('Required nullty)
392418least x xs = UnsafeExpression $ "LEAST("
393419 <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
394420
421+-- | >>> renderExpression $ unsafeBinaryOp "OR" true false
422+-- "(TRUE OR FALSE)"
395423unsafeBinaryOp
396424 :: ByteString
425+ -- ^ operator
397426 -> Expression tables grouping params ('Required ty0)
398427 -> Expression tables grouping params ('Required ty1)
399428 -> Expression tables grouping params ('Required ty2)
400429unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
401430 renderExpression x <+> op <+> renderExpression y
402431
432+-- | >>> renderExpression $ unsafeUnaryOp "NOT" true
433+-- "(NOT TRUE)"
403434unsafeUnaryOp
404435 :: ByteString
436+ -- ^ operator
405437 -> Expression tables grouping params ('Required ty0)
406438 -> Expression tables grouping params ('Required ty1)
407439unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
408440 op <+> renderExpression x
409441
442+-- | >>> renderExpression $ unsafeFunction "f" true
443+-- "f(TRUE)"
410444unsafeFunction
411445 :: ByteString
446+ -- ^ function
412447 -> Expression tables grouping params ('Required xty)
413448 -> Expression tables grouping params ('Required yty)
414449unsafeFunction fun x = UnsafeExpression $
@@ -453,79 +488,128 @@ instance (PGNum ty, PGFloating ty) => Floating
453488 acosh x = log (x + sqrt (x*x - 1))
454489 atanh x = log ((1 + x) / (1 - x)) / 2
455490
491+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ atan2_ pi 2
492+-- "atan2(pi(), 2)"
456493atan2_
457494 :: PGFloating float
458495 => Expression tables grouping params ('Required (nullity float))
496+ -- ^ numerator
459497 -> Expression tables grouping params ('Required (nullity float))
498+ -- ^ denominator
460499 -> Expression tables grouping params ('Required (nullity float))
461500atan2_ y x = UnsafeExpression $
462501 "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
463502
503+-- When a `cast` is applied to an `Expression` of a known type, it
504+-- represents a run-time type conversion. The cast will succeed only if a
505+-- suitable type conversion operation has been defined.
506+--
507+-- | >>> renderExpression $ true & cast int4
508+-- "(TRUE :: int4)"
464509cast
465510 :: TypeExpression ('Required ('Null ty1))
511+ -- ^ type to cast as
466512 -> Expression tables grouping params ('Required (nullity ty0))
513+ -- ^ value to convert
467514 -> Expression tables grouping params ('Required (nullity ty1))
468515cast ty x = UnsafeExpression $ parenthesized $
469516 renderExpression x <+> "::" <+> renderTypeExpression ty
470517
471−div_
518+-- | integer division, truncates the result
519+--
520+-- >>> renderExpression @_ @_ @_ @(_(_ 'PGint2)) $ 5 `quot_` 2
521+-- "(5 / 2)"
522+quot_
472523 :: PGIntegral int
473524 => Expression tables grouping params ('Required (nullity int))
525+ -- ^ numerator
474526 -> Expression tables grouping params ('Required (nullity int))
527+ -- ^ denominator
475528 -> Expression tables grouping params ('Required (nullity int))
476−div_ = unsafeBinaryOp "/"
529+quot_ = unsafeBinaryOp "/"
477530
478−mod_
531+-- | remainder upon integer division
532+--
533+-- >>> renderExpression @_ @_ @_ @(_ (_ 'PGint2)) $ 5 `rem_` 2
534+-- "(5 % 2)"
535+rem_
479536 :: PGIntegral int
480537 => Expression tables grouping params ('Required (nullity int))
538+ -- ^ numerator
481539 -> Expression tables grouping params ('Required (nullity int))
540+ -- ^ denominator
482541 -> Expression tables grouping params ('Required (nullity int))
483−mod_ = unsafeBinaryOp "%"
542+rem_ = unsafeBinaryOp "%"
484543
544+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ trunc pi
545+-- "trunc(pi())"
485546trunc
486547 :: PGFloating frac
487548 => Expression tables grouping params ('Required (nullity frac))
549+ -- ^ fractional number
488550 -> Expression tables grouping params ('Required (nullity frac))
489551trunc = unsafeFunction "trunc"
490552
553+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ round_ pi
554+-- "round(pi())"
491555round_
492556 :: PGFloating frac
493557 => Expression tables grouping params ('Required (nullity frac))
558+ -- ^ fractional number
494559 -> Expression tables grouping params ('Required (nullity frac))
495560round_ = unsafeFunction "round"
496561
562+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ ceiling_ pi
563+-- "ceiling(pi())"
497564ceiling_
498565 :: PGFloating frac
499566 => Expression tables grouping params ('Required (nullity frac))
567+ -- ^ fractional number
500568 -> Expression tables grouping params ('Required (nullity frac))
501569ceiling_ = unsafeFunction "ceiling"
502570
571+-- | A `Condition` is a boolean valued `Expression`. While SQL allows
572+-- conditions to have @NULL@, squeal instead chooses to disallow @NULL@,
573+-- forcing one to handle the case of @NULL@ explicitly to produce
574+-- a `Condition`.
503575type Condition tables grouping params =
504576 Expression tables grouping params ('Required ('NotNull 'PGbool))
505577
578+-- | >>> renderExpression true
579+-- "TRUE"
506580true :: Condition tables grouping params
507581true = UnsafeExpression "TRUE"
508582
583+-- | >>> renderExpression false
584+-- "FALSE"
509585false :: Condition tables grouping params
510586false = UnsafeExpression "FALSE"
511587
588+-- | >>> renderExpression $ not_ true
589+-- "(NOT TRUE)"
512590not_
513591 :: Condition tables grouping params
514592 -> Condition tables grouping params
515593not_ = unsafeUnaryOp "NOT"
516594
595+-- | >>> renderExpression $ true .&& false
596+-- "(TRUE AND FALSE)"
517597(.&&)
518598 :: Condition tables grouping params
519599 -> Condition tables grouping params
520600 -> Condition tables grouping params
521601(.&&) = unsafeBinaryOp "AND"
522602
603+-- | >>> renderExpression $ true .|| false
604+-- "(TRUE OR FALSE)"
523605(.||)
524606 :: Condition tables grouping params
525607 -> Condition tables grouping params
526608 -> Condition tables grouping params
527609(.||) = unsafeBinaryOp "OR"
528610
611+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGint2)) $ caseWhenThenElse [(true, 1), (false, 2)] 3
612+-- "CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END"
529613caseWhenThenElse
530614 :: [ ( Condition tables grouping params
531615 , Expression tables grouping params ('Required ty)
@@ -545,6 +629,8 @@ caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
545629 , " END"
546630 ]
547631
632+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGint2)) $ ifThenElse true 1 0
633+-- "CASE WHEN TRUE THEN 1 ELSE 0 END"
548634ifThenElse
549635 :: Condition tables grouping params
550636 -> Expression tables grouping params ('Required ty)
@@ -552,64 +638,89 @@ ifThenElse
552638 -> Expression tables grouping params ('Required ty)
553639ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
554640
641+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
642+-- will produce @NULL@s if one of their arguments is @NULL@.
643+--
644+-- >>> renderExpression $ unNull true .== null_
645+-- "(TRUE = NULL)"
555646(.==)
556− :: Expression tables grouping params ('Required (nullity ty))
557− -> Expression tables grouping params ('Required (nullity ty))
647+ :: Expression tables grouping params ('Required (nullity ty)) -- ^ lhs
648+ -> Expression tables grouping params ('Required (nullity ty)) -- ^ rhs
558649 -> Expression tables grouping params ('Required (nullity 'PGbool))
559650(.==) = unsafeBinaryOp "="
560651infix 4 .==
561652
653+-- | >>> renderExpression $ unNull true ./= null_
654+-- "(TRUE <> NULL)"
562655(./=)
563− :: Expression tables grouping params ('Required (nullity ty))
564− -> Expression tables grouping params ('Required (nullity ty))
656+ :: Expression tables grouping params ('Required (nullity ty)) -- ^ lhs
657+ -> Expression tables grouping params ('Required (nullity ty)) -- ^ rhs
565658 -> Expression tables grouping params ('Required (nullity 'PGbool))
566659(./=) = unsafeBinaryOp "<>"
567660infix 4 ./=
568661
662+-- | >>> renderExpression $ unNull true .>= null_
663+-- "(TRUE >= NULL)"
569664(.>=)
570− :: Expression tables grouping params ('Required (nullity ty))
571− -> Expression tables grouping params ('Required (nullity ty))
665+ :: Expression tables grouping params ('Required (nullity ty)) -- ^ lhs
666+ -> Expression tables grouping params ('Required (nullity ty)) -- ^ rhs
572667 -> Expression tables grouping params ('Required (nullity 'PGbool))
573668(.>=) = unsafeBinaryOp ">="
574669infix 4 .>=
575670
671+-- | >>> renderExpression $ unNull true .< null_
672+-- "(TRUE < NULL)"
576673(.<)
577− :: Expression tables grouping params ('Required (nullity ty))
578− -> Expression tables grouping params ('Required (nullity ty))
674+ :: Expression tables grouping params ('Required (nullity ty)) -- ^ lhs
675+ -> Expression tables grouping params ('Required (nullity ty)) -- ^ rhs
579676 -> Expression tables grouping params ('Required (nullity 'PGbool))
580677(.<) = unsafeBinaryOp "<"
581678infix 4 .<
582679
680+-- | >>> renderExpression $ unNull true .<= null_
681+-- "(TRUE <= NULL)"
583682(.<=)
584− :: Expression tables grouping params ('Required (nullity ty))
585− -> Expression tables grouping params ('Required (nullity ty))
683+ :: Expression tables grouping params ('Required (nullity ty)) -- ^ lhs
684+ -> Expression tables grouping params ('Required (nullity ty)) -- ^ rhs
586685 -> Expression tables grouping params ('Required (nullity 'PGbool))
587686(.<=) = unsafeBinaryOp "<="
588687infix 4 .<=
589688
689+-- | >>> renderExpression $ unNull true .> null_
690+-- "(TRUE > NULL)"
590691(.>)
591− :: Expression tables grouping params ('Required (nullity ty))
592− -> Expression tables grouping params ('Required (nullity ty))
692+ :: Expression tables grouping params ('Required (nullity ty)) -- ^ lhs
693+ -> Expression tables grouping params ('Required (nullity ty)) -- ^ rhs
593694 -> Expression tables grouping params ('Required (nullity 'PGbool))
594695(.>) = unsafeBinaryOp ">"
595696infix 4 .>
596697
698+-- | >>> renderExpression $ currentDate
699+-- "CURRENT_DATE"
597700currentDate
598701 :: Expression tables grouping params ('Required (nullity 'PGdate))
599702currentDate = UnsafeExpression "CURRENT_DATE"
600703
704+-- | >>> renderExpression $ currentTime
705+-- "CURRENT_TIME"
601706currentTime
602707 :: Expression tables grouping params ('Required (nullity 'PGtimetz))
603708currentTime = UnsafeExpression "CURRENT_TIME"
604709
710+-- | >>> renderExpression $ currentTimestamp
711+-- "CURRENT_TIMESTAMP"
605712currentTimestamp
606713 :: Expression tables grouping params ('Required (nullity 'PGtimestamptz))
607714currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
608715
716+-- | >>> renderExpression $ localTime
717+-- "LOCALTIME"
609718localTime
610719 :: Expression tables grouping params ('Required (nullity 'PGtime))
611720localTime = UnsafeExpression "LOCALTIME"
612721
722+-- | >>> renderExpression $ localTimestamp
723+-- "LOCALTIMESTAMP"
613724localTimestamp
614725 :: Expression tables grouping params ('Required (nullity 'PGtimestamp))
615726localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
@@ -639,24 +750,44 @@ instance Monoid
639750 mempty = fromString ""
640751 mappend = unsafeBinaryOp "||"
641752
753+-- | >>> renderExpression $ lower "ARRRGGG"
754+-- "lower(E'ARRRGGG')"
642755lower
643756 :: Expression tables grouping params ('Required (nullity 'PGtext))
757+ -- ^ string to lower case
644758 -> Expression tables grouping params ('Required (nullity 'PGtext))
645759lower = unsafeFunction "lower"
646760
761+-- | >>> renderExpression $ upper "eeee"
762+-- "upper(E'eeee')"
647763upper
648764 :: Expression tables grouping params ('Required (nullity 'PGtext))
765+ -- ^ string to upper case
649766 -> Expression tables grouping params ('Required (nullity 'PGtext))
650767upper = unsafeFunction "upper"
651768
769+-- | >>> renderExpression $ charLength "four"
770+-- "char_length(E'four')"
652771charLength
653772 :: Expression tables grouping params ('Required (nullity 'PGtext))
773+ -- ^ string to measure
654774 -> Expression tables grouping params ('Required (nullity 'PGint4))
655775charLength = unsafeFunction "char_length"
656776
777+-- | The `like` expression returns true if the @string@ matches
778+-- the supplied @pattern@. If @pattern@ does not contain percent signs
779+-- or underscores, then the pattern only represents the string itself;
780+-- in that case `like` acts like the equals operator. An underscore (_)
781+-- in pattern stands for (matches) any single character; a percent sign (%)
782+-- matches any sequence of zero or more characters.
783+--
784+-- >>> renderExpression $ "abc" `like` "a%"
785+-- "(E'abc' LIKE E'a%')"
657786like
658787 :: Expression tables grouping params ('Required (nullity 'PGtext))
788+ -- ^ string
659789 -> Expression tables grouping params ('Required (nullity 'PGtext))
790+ -- ^ pattern
660791 -> Expression tables grouping params ('Required (nullity 'PGbool))
661792like = unsafeBinaryOp "LIKE"
662793
@@ -664,25 +795,46 @@ like = unsafeBinaryOp "LIKE"
664795aggregation
665796-----------------------------------------}
666797
667−unsafeAggregate, unsafeAggregateDistinct
668− :: ByteString
798+-- | escape hatch to define aggregate functions
799+unsafeAggregate
800+ :: ByteString -- ^ aggregate function
669801 -> Expression tables 'Ungrouped params ('Required xty)
670802 -> Expression tables ('Grouped bys) params ('Required yty)
671803unsafeAggregate fun x = UnsafeExpression $ mconcat
672804 [fun, "(", renderExpression x, ")"]
805+
806+-- | escape hatch to define aggregate functions over distinct values
807+unsafeAggregateDistinct
808+ :: ByteString -- ^ aggregate function
809+ -> Expression tables 'Ungrouped params ('Required xty)
810+ -> Expression tables ('Grouped bys) params ('Required yty)
673811unsafeAggregateDistinct fun x = UnsafeExpression $ mconcat
674812 [fun, "(DISTINCT ", renderExpression x, ")"]
675813
676−sum_, sumDistinct
814+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGnumeric)]] $ sum_ #col
815+-- "sum(col)"
816+sum_
677817 :: PGNum ty
678818 => Expression tables 'Ungrouped params ('Required (nullity ty))
819+ -- ^ what to sum
679820 -> Expression tables ('Grouped bys) params ('Required (nullity ty))
680821sum_ = unsafeAggregate "sum"
822+
823+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGnumeric)]] $ sumDistinct #col
824+-- "sum(DISTINCT col)"
825+sumDistinct
826+ :: PGNum ty
827+ => Expression tables 'Ungrouped params ('Required (nullity ty))
828+ -- ^ what to sum
829+ -> Expression tables ('Grouped bys) params ('Required (nullity ty))
681830sumDistinct = unsafeAggregateDistinct "sum"
682831
832+-- | A constraint for `PGType`s that you can take averages of and the resulting
833+-- `PGType`.
683834class PGAvg ty avg | ty -> avg where
684835 avg, avgDistinct
685836 :: Expression tables 'Ungrouped params ('Required (nullity ty))
837+ -- ^ what to average
686838 -> Expression tables ('Grouped bys) params ('Required (nullity avg))
687839 avg = unsafeAggregate "avg"
688840 avgDistinct = unsafeAggregateDistinct "avg"
@@ -694,76 +846,141 @@ instance PGAvg 'PGfloat4 'PGfloat8
694846instance PGAvg 'PGfloat8 'PGfloat8
695847instance PGAvg 'PGinterval 'PGinterval
696848
697−bitAnd, bitOr
849+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGint4)]] $ bitAnd #col
850+-- "bit_and(col)"
851+bitAnd
698852 :: PGIntegral int
699853 => Expression tables 'Ungrouped params ('Required (nullity int))
854+ -- ^ what to aggregate
700855 -> Expression tables ('Grouped bys) params ('Required (nullity int))
701856bitAnd = unsafeAggregate "bit_and"
857+
858+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGint4)]] $ bitOr #col
859+-- "bit_or(col)"
860+bitOr
861+ :: PGIntegral int
862+ => Expression tables 'Ungrouped params ('Required (nullity int))
863+ -- ^ what to aggregate
864+ -> Expression tables ('Grouped bys) params ('Required (nullity int))
702865bitOr = unsafeAggregate "bit_or"
703866
704−boolAnd, boolOr
867+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGint4)]] $ bitAndDistinct #col
868+-- "bit_and(DISTINCT col)"
869+bitAndDistinct
870+ :: PGIntegral int
871+ => Expression tables 'Ungrouped params ('Required (nullity int))
872+ -- ^ what to aggregate
873+ -> Expression tables ('Grouped bys) params ('Required (nullity int))
874+bitAndDistinct = unsafeAggregateDistinct "bit_and"
875+
876+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGint4)]] $ bitOrDistinct #col
877+-- "bit_or(DISTINCT col)"
878+bitOrDistinct
879+ :: PGIntegral int
880+ => Expression tables 'Ungrouped params ('Required (nullity int))
881+ -- ^ what to aggregate
882+ -> Expression tables ('Grouped bys) params ('Required (nullity int))
883+bitOrDistinct = unsafeAggregateDistinct "bit_or"
884+
885+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ boolAnd #col
886+-- "bool_and(col)"
887+boolAnd
705888 :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
889+ -- ^ what to aggregate
706890 -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
707891boolAnd = unsafeAggregate "bool_and"
892+
893+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ boolOr #col
894+-- "bool_or(col)"
895+boolOr
896+ :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
897+ -- ^ what to aggregate
898+ -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
708899boolOr = unsafeAggregate "bool_or"
709900
710−countStar, countDistinctStar
901+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ boolAndDistinct #col
902+-- "bool_and(DISTINCT col)"
903+boolAndDistinct
904+ :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
905+ -- ^ what to aggregate
906+ -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
907+boolAndDistinct = unsafeAggregateDistinct "bool_and"
908+
909+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ boolOrDistinct #col
910+-- "bool_or(DISTINCT col)"
911+boolOrDistinct
912+ :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
913+ -- ^ what to aggregate
914+ -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
915+boolOrDistinct = unsafeAggregateDistinct "bool_or"
916+
917+-- | A special aggregation that does not require an input
918+--
919+-- >>> renderExpression countStar
920+-- "count(*)"
921+countStar
711922 :: Expression tables ('Grouped bys) params ('Required ('NotNull 'PGint8))
712923countStar = UnsafeExpression $ "count(*)"
713−countDistinctStar = UnsafeExpression $ "count(DISTINCT *)"
714924
925+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Optional _]] $ count #col
926+-- "count(col)"
715927count
716928 :: Expression tables 'Ungrouped params ('Required ty)
929+ -- ^ what to count
717930 -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGint8))
718931count = unsafeAggregate "count"
719−
932+
933+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required _]] $ countDistinct #col
934+-- "count(DISTINCT col)"
935+countDistinct
936+ :: Expression tables 'Ungrouped params ('Required ty)
937+ -- ^ what to count
938+ -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGint8))
939+countDistinct = unsafeAggregateDistinct "count"
940+
941+-- | synonym for `boolAnd`
942+--
943+-- >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ every #col
944+-- "every(col)"
720945every
721946 :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
947+ -- ^ what to aggregate
722948 -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
723949every = unsafeAggregate "every"
724950
725−jsonAgg
726− :: Expression tables 'Ungrouped params ('Required ty)
727− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjson))
728−jsonAgg = unsafeAggregate "json_agg"
951+-- | synonym for `boolAndDistinct`
952+--
953+-- >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ everyDistinct #col
954+-- "every(DISTINCT col)"
955+everyDistinct
956+ :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
957+ -- ^ what to aggregate
958+ -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
959+everyDistinct = unsafeAggregateDistinct "every"
729960
730−jsonbAgg
731− :: Expression tables 'Ungrouped params ('Required ty)
732− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjsonb))
733−jsonbAgg = unsafeAggregate "jsonb_agg"
734−
735−jsonObjectAgg
736− :: Expression tables 'Ungrouped params ('Required ('NotNull keyty))
737− -> Expression tables 'Ungrouped params ('Required valty)
738− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjson))
739−jsonObjectAgg k v = UnsafeExpression $
740− "json_object_agg(" <> renderExpression k
741− <> ", " <> renderExpression v <> ")"
742−
743−jsonbObjectAgg
744− :: Expression tables 'Ungrouped params ('Required ('NotNull keyty))
745− -> Expression tables 'Ungrouped params ('Required valty)
746− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjsonb))
747−jsonbObjectAgg k v = UnsafeExpression $
748− "jsonb_object_agg("
749− <> renderExpression k <> ", " <> renderExpression v <> ")"
750−
751−max_, min_
961+-- | minimum and maximum aggregation
962+max_, min_, maxDistinct, minDistinct
752963 :: Expression tables 'Ungrouped params ('Required (nullity ty))
964+ -- ^ what to aggregate
753965 -> Expression tables ('Grouped bys) params ('Required (nullity ty))
754966max_ = unsafeAggregate "max"
755967min_ = unsafeAggregate "min"
968+maxDistinct = unsafeAggregateDistinct "max"
969+minDistinct = unsafeAggregateDistinct "min"
756970
757971{-----------------------------------------
758972tables
759973-----------------------------------------}
760974
975+-- | A `Table` from a schema without its alias with an `IsLabel` instance
976+-- to call a table reference by its alias.
761977newtype Table
762978 (schema :: TablesType)
763979 (columns :: ColumnsType)
764980 = UnsafeTable { renderTable :: ByteString }
765981 deriving (GHC.Generic,Show,Eq,Ord,NFData)
766982
983+-- | A `HasTable` constraint indicates a table reference.
767984class KnownSymbol table => HasTable table tables columns
768985 | table tables -> columns where
769986 getTable :: Alias table -> Table tables columns
@@ -782,96 +999,113 @@ instance HasTable table schema columns
782999type expressions
7831000-----------------------------------------}
7841001
1002+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
7851003newtype TypeExpression (ty :: ColumnType)
7861004 = UnsafeTypeExpression { renderTypeExpression :: ByteString }
7871005 deriving (GHC.Generic,Show,Eq,Ord,NFData)
7881006
1007+-- | logical Boolean (true/false)
7891008bool :: TypeExpression ('Required ('Null 'PGbool))
7901009bool = UnsafeTypeExpression "bool"
791−int2 :: TypeExpression ('Required ('Null 'PGint2))
1010+-- | signed two-byte integer
1011+int2, smallint :: TypeExpression ('Required ('Null 'PGint2))
7921012int2 = UnsafeTypeExpression "int2"
793−smallint :: TypeExpression ('Required ('Null 'PGint2))
7941013smallint = UnsafeTypeExpression "smallint"
795−int4 :: TypeExpression ('Required ('Null 'PGint4))
1014+-- | signed four-byte integer
1015+int4, int, integer :: TypeExpression ('Required ('Null 'PGint4))
7961016int4 = UnsafeTypeExpression "int4"
797−int :: TypeExpression ('Required ('Null 'PGint4))
7981017int = UnsafeTypeExpression "int"
799−integer :: TypeExpression ('Required ('Null 'PGint4))
8001018integer = UnsafeTypeExpression "integer"
801−int8 :: TypeExpression ('Required ('Null 'PGint8))
1019+-- | signed eight-byte integer
1020+int8, bigint :: TypeExpression ('Required ('Null 'PGint8))
8021021int8 = UnsafeTypeExpression "int8"
803−bigint :: TypeExpression ('Required ('Null 'PGint8))
8041022bigint = UnsafeTypeExpression "bigint"
1023+-- | arbitrary precision numeric type
8051024numeric :: TypeExpression ('Required ('Null 'PGnumeric))
8061025numeric = UnsafeTypeExpression "numeric"
807−float4 :: TypeExpression ('Required ('Null 'PGfloat4))
1026+-- | single precision floating-point number (4 bytes)
1027+float4, real :: TypeExpression ('Required ('Null 'PGfloat4))
8081028float4 = UnsafeTypeExpression "float4"
809−real :: TypeExpression ('Required ('Null 'PGfloat4))
8101029real = UnsafeTypeExpression "real"
811−float8 :: TypeExpression ('Required ('Null 'PGfloat8))
1030+-- | double precision floating-point number (8 bytes)
1031+float8, doublePrecision :: TypeExpression ('Required ('Null 'PGfloat8))
8121032float8 = UnsafeTypeExpression "float8"
813−doublePrecision :: TypeExpression ('Required ('Null 'PGfloat8))
8141033doublePrecision = UnsafeTypeExpression "double precision"
815−serial2 :: TypeExpression ('Optional ('NotNull 'PGint2))
1034+-- | not a true type, but merely a notational convenience for creating
1035+-- unique identifier columns with type `'PGint2`
1036+serial2, smallserial :: TypeExpression ('Optional ('NotNull 'PGint2))
8161037serial2 = UnsafeTypeExpression "serial2"
817−smallserial :: TypeExpression ('Optional ('NotNull 'PGint2))
8181038smallserial = UnsafeTypeExpression "smallserial"
819−serial4 :: TypeExpression ('Optional ('NotNull 'PGint4))
1039+-- | not a true type, but merely a notational convenience for creating
1040+-- unique identifier columns with type `'PGint4`
1041+serial4, serial :: TypeExpression ('Optional ('NotNull 'PGint4))
8201042serial4 = UnsafeTypeExpression "serial4"
821−serial :: TypeExpression ('Optional ('NotNull 'PGint4))
8221043serial = UnsafeTypeExpression "serial"
823−serial8 :: TypeExpression ('Optional ('NotNull 'PGint8))
1044+-- | not a true type, but merely a notational convenience for creating
1045+-- unique identifier columns with type `'PGint8`
1046+serial8, bigserial :: TypeExpression ('Optional ('NotNull 'PGint8))
8241047serial8 = UnsafeTypeExpression "serial8"
825−bigserial :: TypeExpression ('Optional ('NotNull 'PGint8))
8261048bigserial = UnsafeTypeExpression "bigserial"
1049+-- | variable-length character string
8271050text :: TypeExpression ('Required ('Null 'PGtext))
8281051text = UnsafeTypeExpression "text"
829−char
1052+-- | fixed-length character string
1053+char, character
8301054 :: (KnownNat n, 1 <= n)
8311055 => proxy n
8321056 -> TypeExpression ('Required ('Null ('PGchar n)))
8331057char p = UnsafeTypeExpression $ "char(" <> renderNat p <> ")"
834−character
835− :: (KnownNat n, 1 <= n)
836− => proxy n
837− -> TypeExpression ('Required ('Null ('PGchar n)))
8381058character p = UnsafeTypeExpression $ "character(" <> renderNat p <> ")"
839−varchar
1059+-- | variable-length character string
1060+varchar, characterVarying
8401061 :: (KnownNat n, 1 <= n)
8411062 => proxy n
8421063 -> TypeExpression ('Required ('Null ('PGvarchar n)))
8431064varchar p = UnsafeTypeExpression $ "varchar(" <> renderNat p <> ")"
844−characterVarying
845− :: (KnownNat n, 1 <= n)
846− => proxy n
847− -> TypeExpression ('Required ('Null ('PGvarchar n)))
8481065characterVarying p = UnsafeTypeExpression $
8491066 "character varying(" <> renderNat p <> ")"
850−bytea :: TypeExpression ('Required ('Null ('PGbytea)))
1067+-- | binary data ("byte array")
1068+bytea :: TypeExpression ('Required ('Null 'PGbytea))
8511069bytea = UnsafeTypeExpression "bytea"
852−timestamp :: TypeExpression ('Required ('Null ('PGtimestamp)))
1070+-- | date and time (no time zone)
1071+timestamp :: TypeExpression ('Required ('Null 'PGtimestamp))
8531072timestamp = UnsafeTypeExpression "timestamp"
854−timestampWithTimeZone :: TypeExpression ('Required ('Null ('PGtimestamptz)))
1073+-- | date and time, including time zone
1074+timestampWithTimeZone :: TypeExpression ('Required ('Null 'PGtimestamptz))
8551075timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
856−date :: TypeExpression ('Required ('Null ('PGdate)))
1076+-- | calendar date (year, month, day)
1077+date :: TypeExpression ('Required ('Null 'PGdate))
8571078date = UnsafeTypeExpression "date"
858−time :: TypeExpression ('Required ('Null ('PGtime)))
1079+-- | time of day (no time zone)
1080+time :: TypeExpression ('Required ('Null 'PGtime))
8591081time = UnsafeTypeExpression "time"
860−timeWithTimeZone :: TypeExpression ('Required ('Null ('PGtimetz)))
1082+-- | time of day, including time zone
1083+timeWithTimeZone :: TypeExpression ('Required ('Null 'PGtimetz))
8611084timeWithTimeZone = UnsafeTypeExpression "time with time zone"
862−interval :: TypeExpression ('Required ('Null ('PGinterval)))
1085+-- | time span
1086+interval :: TypeExpression ('Required ('Null 'PGinterval))
8631087interval = UnsafeTypeExpression "interval"
864−uuid :: TypeExpression ('Required ('Null ('PGuuid)))
1088+-- | universally unique identifier
1089+uuid :: TypeExpression ('Required ('Null 'PGuuid))
8651090uuid = UnsafeTypeExpression "uuid"
866−json :: TypeExpression ('Required ('Null ('PGjson)))
1091+-- | IPv4 or IPv6 host address
1092+inet :: TypeExpression ('Required ('Null 'PGinet))
1093+inet = UnsafeTypeExpression "inet"
1094+-- | textual JSON data
1095+json :: TypeExpression ('Required ('Null 'PGjson))
8671096json = UnsafeTypeExpression "json"
868−jsonb :: TypeExpression ('Required ('Null ('PGjsonb)))
1097+-- | binary JSON data, decomposed
1098+jsonb :: TypeExpression ('Required ('Null 'PGjsonb))
8691099jsonb = UnsafeTypeExpression "jsonb"
8701100
1101+-- | used in `createTable` commands as a column constraint to ensure
1102+-- @NULL@ is not present
8711103notNull
8721104 :: TypeExpression (optionality ('Null ty))
8731105 -> TypeExpression (optionality ('NotNull ty))
8741106notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <+> "NOT NULL"
1107+
1108+-- | used in `createTable` commands as a column constraint to give a default
8751109default_
8761110 :: Expression '[] 'Ungrouped '[] ('Required ty)
8771111 -> TypeExpression ('Required ty)
@@ -879,6 +1113,7 @@ default_
8791113default_ x ty = UnsafeTypeExpression $
8801114 renderTypeExpression ty <+> "DEFAULT" <+> renderExpression x
8811115
1116+-- | `pgtype` is a demoted version of a `PGType`
8821117class PGTyped (ty :: PGType) where
8831118 pgtype :: TypeExpression ('Required ('Null ty))
8841119instance PGTyped 'PGbool where pgtype = bool