on dev help sign in
expression docs
commite888092ae6e2ea18ac819f14d372c5db5581c0cb authorEitan Chatav <eitan.chatav@gmail.com> dateThu 24 Aug 2017, 13:57 (9 years ago) parentec5511f
3 files changed+337−101
squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+1−2 squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+334−97 squeal-postgresql/src/Squeal/PostgreSQL/Manipulation.hs+2−2
squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+1−2
@@ -78,8 +78,7 @@ statements
7878
7979-- | A `Definition` is a statement that changes the schema of the
8080-- database, like a `createTable`, `dropTable`, or `alterTable` command.
81−-- `Definition`s may be composed using the `>>>` operator from the
82−-- `Category` typeclass.
81+-- `Definition`s may be composed using the `>>>` operator.
8382newtype Definition
8483 (schema0 :: TablesType)
8584 (schema1 :: TablesType)
squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+334−97
@@ -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_
@@ -87,13 +97,10 @@ module Squeal.PostgreSQL.Expression
8797 , sum_, sumDistinct
8898 , PGAvg (avg, avgDistinct)
8999 , bitAnd, bitOr, boolAnd, boolOr
100+ , bitAndDistinct, bitOrDistinct, boolAndDistinct, boolOrDistinct
90101 , countStar
91102 , count, countDistinct
92103 , every, everyDistinct
93− , jsonAgg, jsonAggDistinct
94− , jsonbAgg, jsonbAggDistinct
95− , jsonObjectAgg
96− , jsonbObjectAgg
97104 , max_, maxDistinct, min_, minDistinct
98105 -- * Tables
99106 , Table (UnsafeTable, renderTable)
@@ -133,6 +140,7 @@ module Squeal.PostgreSQL.Expression
133140 , timeWithTimeZone
134141 , interval
135142 , uuid
143+ , inet
136144 , json
137145 , jsonb
138146 , notNull
@@ -226,6 +234,10 @@ instance (HasTable table tables columns, HasColumn column columns ty)
226234 table ! column = UnsafeExpression $
227235 renderAlias table <> "." <> renderAlias column
228236
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.
229241data Column
230242 (columns :: ColumnsType)
231243 (columnty :: (Symbol,ColumnType))
@@ -238,9 +250,14 @@ deriving instance Show (Column columns columnty)
238250deriving instance Eq (Column columns columnty)
239251deriving instance Ord (Column columns columnty)
240252
253+-- | Render a `Column`.
241254renderColumn :: Column columns columnty -> ByteString
242255renderColumn (Column column) = renderAlias column
243256
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+-}
244261class (KnownSymbol table, KnownSymbol column)
245262 => GroupedBy table column bys where
246263 getGroup1
@@ -287,6 +304,7 @@ def = UnsafeExpression "DEFAULT"
287304-- "FALSE"
288305unDef
289306 :: Expression '[] 'Ungrouped params ('Required (nullity ty))
307+ -- ^ not @DEFAULT@
290308 -> Expression '[] 'Ungrouped params ('Optional (nullity ty))
291309unDef = UnsafeExpression . renderExpression
292310
@@ -303,6 +321,7 @@ null_ = UnsafeExpression "NULL"
303321-- "TRUE"
304322unNull
305323 :: Expression tables grouping params (optionality ('NotNull ty))
324+ -- ^ not @NULL@
306325 -> Expression tables grouping params (optionality ('Null ty))
307326unNull = UnsafeExpression . renderExpression
308327
@@ -312,7 +331,9 @@ unNull = UnsafeExpression . renderExpression
312331-- "COALESCE(NULL, TRUE, FALSE)"
313332coalesce
314333 :: [Expression tables grouping params ('Required ('Null ty))]
334+ -- ^ @NULL@s may be present
315335 -> Expression tables grouping params ('Required ('NotNull ty))
336+ -- ^ @NULL@ is absent
316337 -> Expression tables grouping params ('Required ('NotNull ty))
317338coalesce nullxs notNullx = UnsafeExpression $
318339 "COALESCE" <> parenthesized (commaSeparated
@@ -324,6 +345,7 @@ coalesce nullxs notNullx = UnsafeExpression $
324345-- "COALESCE(NULL, TRUE)"
325346fromNull
326347 :: Expression tables grouping params ('Required ('NotNull ty))
348+ -- ^ what to convert @NULL@ to
327349 -> Expression tables grouping params ('Required ('Null ty))
328350 -> Expression tables grouping params ('Required ('NotNull ty))
329351fromNull notNullx nullx = coalesce [nullx] notNullx
@@ -332,6 +354,7 @@ fromNull notNullx nullx = coalesce [nullx] notNullx
332354-- "NULL IS NULL"
333355isNull
334356 :: Expression tables grouping params ('Required ('Null ty))
357+ -- ^ possibly @NULL@
335358 -> Condition tables grouping params
336359isNull x = UnsafeExpression $ renderExpression x <+> "IS NULL"
337360
@@ -339,6 +362,7 @@ isNull x = UnsafeExpression $ renderExpression x <+> "IS NULL"
339362-- "NULL IS NOT NULL"
340363isn'tNull
341364 :: Expression tables grouping params ('Required ('Null ty))
365+ -- ^ possibly @NULL@
342366 -> Condition tables grouping params
343367isn'tNull x = UnsafeExpression $ renderExpression x <+> "IS NOT NULL"
344368
@@ -348,21 +372,26 @@ isn'tNull x = UnsafeExpression $ renderExpression x <+> "IS NOT NULL"
348372-- "CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END"
349373matchNull
350374 :: Expression tables grouping params ('Required nullty)
375+ -- ^ what to convert @NULL@ to
351376 -> ( Expression tables grouping params ('Required ('NotNull ty))
352377 -> Expression tables grouping params ('Required nullty) )
378+ -- ^ function to perform when @NULL@ is absent
353379 -> Expression tables grouping params ('Required ('Null ty))
354380 -> Expression tables grouping params ('Required nullty)
355381matchNull y f x = ifThenElse (isNull x) y
356382 (f (UnsafeExpression (renderExpression x)))
357383
358−-- | right inverse to `fromNull`
384+-- | right inverse to `fromNull`, if its arguments are equal then
385+-- `nullIf` gives @NULL@.
359386--
360387-- >>> :set -XTypeApplications -XDataKinds
361388-- >>> renderExpression @_ @_ @'[_] $ fromNull false (nullIf false (param @1))
362389-- "COALESCE(NULL IF (FALSE, ($1 :: bool)), FALSE)"
363390nullIf
364391 :: Expression tables grouping params ('Required ('NotNull ty))
392+ -- ^ @NULL@ is absent
365393 -> Expression tables grouping params ('Required ('NotNull ty))
394+ -- ^ @NULL@ is absent
366395 -> Expression tables grouping params ('Required ('Null ty))
367396nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
368397 (renderExpression x <> ", " <> renderExpression y)
@@ -371,7 +400,9 @@ nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
371400-- "GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))"
372401greatest
373402 :: Expression tables grouping params ('Required nullty)
403+ -- ^ needs at least 1 argument
374404 -> [Expression tables grouping params ('Required nullty)]
405+ -- ^ or more
375406 -> Expression tables grouping params ('Required nullty)
376407greatest x xs = UnsafeExpression $ "GREATEST("
377408 <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
@@ -380,28 +411,39 @@ greatest x xs = UnsafeExpression $ "GREATEST("
380411-- "LEAST(CURRENT_TIMESTAMP, NULL)"
381412least
382413 :: Expression tables grouping params ('Required nullty)
414+ -- ^ needs at least 1 argument
383415 -> [Expression tables grouping params ('Required nullty)]
416+ -- ^ or more
384417 -> Expression tables grouping params ('Required nullty)
385418least x xs = UnsafeExpression $ "LEAST("
386419 <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
387420
421+-- | >>> renderExpression $ unsafeBinaryOp "OR" true false
422+-- "(TRUE OR FALSE)"
388423unsafeBinaryOp
389424 :: ByteString
425+ -- ^ operator
390426 -> Expression tables grouping params ('Required ty0)
391427 -> Expression tables grouping params ('Required ty1)
392428 -> Expression tables grouping params ('Required ty2)
393429unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
394430 renderExpression x <+> op <+> renderExpression y
395431
432+-- | >>> renderExpression $ unsafeUnaryOp "NOT" true
433+-- "(NOT TRUE)"
396434unsafeUnaryOp
397435 :: ByteString
436+ -- ^ operator
398437 -> Expression tables grouping params ('Required ty0)
399438 -> Expression tables grouping params ('Required ty1)
400439unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
401440 op <+> renderExpression x
402441
442+-- | >>> renderExpression $ unsafeFunction "f" true
443+-- "f(TRUE)"
403444unsafeFunction
404445 :: ByteString
446+ -- ^ function
405447 -> Expression tables grouping params ('Required xty)
406448 -> Expression tables grouping params ('Required yty)
407449unsafeFunction fun x = UnsafeExpression $
@@ -446,79 +488,128 @@ instance (PGNum ty, PGFloating ty) => Floating
446488 acosh x = log (x + sqrt (x*x - 1))
447489 atanh x = log ((1 + x) / (1 - x)) / 2
448490
491+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ atan2_ pi 2
492+-- "atan2(pi(), 2)"
449493atan2_
450494 :: PGFloating float
451495 => Expression tables grouping params ('Required (nullity float))
496+ -- ^ numerator
452497 -> Expression tables grouping params ('Required (nullity float))
498+ -- ^ denominator
453499 -> Expression tables grouping params ('Required (nullity float))
454500atan2_ y x = UnsafeExpression $
455501 "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
456502
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)"
457509cast
458510 :: TypeExpression ('Required ('Null ty1))
511+ -- ^ type to cast as
459512 -> Expression tables grouping params ('Required (nullity ty0))
513+ -- ^ value to convert
460514 -> Expression tables grouping params ('Required (nullity ty1))
461515cast ty x = UnsafeExpression $ parenthesized $
462516 renderExpression x <+> "::" <+> renderTypeExpression ty
463517
464−div_
518+-- | integer division, truncates the result
519+--
520+-- >>> renderExpression @_ @_ @_ @(_(_ 'PGint2)) $ 5 `quot_` 2
521+-- "(5 / 2)"
522+quot_
465523 :: PGIntegral int
466524 => Expression tables grouping params ('Required (nullity int))
525+ -- ^ numerator
467526 -> Expression tables grouping params ('Required (nullity int))
527+ -- ^ denominator
468528 -> Expression tables grouping params ('Required (nullity int))
469−div_ = unsafeBinaryOp "/"
529+quot_ = unsafeBinaryOp "/"
470530
471−mod_
531+-- | remainder upon integer division
532+--
533+-- >>> renderExpression @_ @_ @_ @(_ (_ 'PGint2)) $ 5 `rem_` 2
534+-- "(5 % 2)"
535+rem_
472536 :: PGIntegral int
473537 => Expression tables grouping params ('Required (nullity int))
538+ -- ^ numerator
474539 -> Expression tables grouping params ('Required (nullity int))
540+ -- ^ denominator
475541 -> Expression tables grouping params ('Required (nullity int))
476−mod_ = unsafeBinaryOp "%"
542+rem_ = unsafeBinaryOp "%"
477543
544+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ trunc pi
545+-- "trunc(pi())"
478546trunc
479547 :: PGFloating frac
480548 => Expression tables grouping params ('Required (nullity frac))
549+ -- ^ fractional number
481550 -> Expression tables grouping params ('Required (nullity frac))
482551trunc = unsafeFunction "trunc"
483552
553+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ round_ pi
554+-- "round(pi())"
484555round_
485556 :: PGFloating frac
486557 => Expression tables grouping params ('Required (nullity frac))
558+ -- ^ fractional number
487559 -> Expression tables grouping params ('Required (nullity frac))
488560round_ = unsafeFunction "round"
489561
562+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGfloat4)) $ ceiling_ pi
563+-- "ceiling(pi())"
490564ceiling_
491565 :: PGFloating frac
492566 => Expression tables grouping params ('Required (nullity frac))
567+ -- ^ fractional number
493568 -> Expression tables grouping params ('Required (nullity frac))
494569ceiling_ = unsafeFunction "ceiling"
495570
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`.
496575type Condition tables grouping params =
497576 Expression tables grouping params ('Required ('NotNull 'PGbool))
498577
578+-- | >>> renderExpression true
579+-- "TRUE"
499580true :: Condition tables grouping params
500581true = UnsafeExpression "TRUE"
501582
583+-- | >>> renderExpression false
584+-- "FALSE"
502585false :: Condition tables grouping params
503586false = UnsafeExpression "FALSE"
504587
588+-- | >>> renderExpression $ not_ true
589+-- "(NOT TRUE)"
505590not_
506591 :: Condition tables grouping params
507592 -> Condition tables grouping params
508593not_ = unsafeUnaryOp "NOT"
509594
595+-- | >>> renderExpression $ true .&& false
596+-- "(TRUE AND FALSE)"
510597(.&&)
511598 :: Condition tables grouping params
512599 -> Condition tables grouping params
513600 -> Condition tables grouping params
514601(.&&) = unsafeBinaryOp "AND"
515602
603+-- | >>> renderExpression $ true .|| false
604+-- "(TRUE OR FALSE)"
516605(.||)
517606 :: Condition tables grouping params
518607 -> Condition tables grouping params
519608 -> Condition tables grouping params
520609(.||) = unsafeBinaryOp "OR"
521610
611+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGint2)) $ caseWhenThenElse [(true, 1), (false, 2)] 3
612+-- "CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END"
522613caseWhenThenElse
523614 :: [ ( Condition tables grouping params
524615 , Expression tables grouping params ('Required ty)
@@ -538,6 +629,8 @@ caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
538629 , " END"
539630 ]
540631
632+-- | >>> renderExpression @_ @_ @_ @(_ (_ 'PGint2)) $ ifThenElse true 1 0
633+-- "CASE WHEN TRUE THEN 1 ELSE 0 END"
541634ifThenElse
542635 :: Condition tables grouping params
543636 -> Expression tables grouping params ('Required ty)
@@ -545,64 +638,89 @@ ifThenElse
545638 -> Expression tables grouping params ('Required ty)
546639ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
547640
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)"
548646(.==)
549− :: Expression tables grouping params ('Required (nullity ty))
550− -> 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
551649 -> Expression tables grouping params ('Required (nullity 'PGbool))
552650(.==) = unsafeBinaryOp "="
553651infix 4 .==
554652
653+-- | >>> renderExpression $ unNull true ./= null_
654+-- "(TRUE <> NULL)"
555655(./=)
556− :: Expression tables grouping params ('Required (nullity ty))
557− -> 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
558658 -> Expression tables grouping params ('Required (nullity 'PGbool))
559659(./=) = unsafeBinaryOp "<>"
560660infix 4 ./=
561661
662+-- | >>> renderExpression $ unNull true .>= null_
663+-- "(TRUE >= NULL)"
562664(.>=)
563− :: Expression tables grouping params ('Required (nullity ty))
564− -> 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
565667 -> Expression tables grouping params ('Required (nullity 'PGbool))
566668(.>=) = unsafeBinaryOp ">="
567669infix 4 .>=
568670
671+-- | >>> renderExpression $ unNull true .< null_
672+-- "(TRUE < NULL)"
569673(.<)
570− :: Expression tables grouping params ('Required (nullity ty))
571− -> 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
572676 -> Expression tables grouping params ('Required (nullity 'PGbool))
573677(.<) = unsafeBinaryOp "<"
574678infix 4 .<
575679
680+-- | >>> renderExpression $ unNull true .<= null_
681+-- "(TRUE <= NULL)"
576682(.<=)
577− :: Expression tables grouping params ('Required (nullity ty))
578− -> 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
579685 -> Expression tables grouping params ('Required (nullity 'PGbool))
580686(.<=) = unsafeBinaryOp "<="
581687infix 4 .<=
582688
689+-- | >>> renderExpression $ unNull true .> null_
690+-- "(TRUE > NULL)"
583691(.>)
584− :: Expression tables grouping params ('Required (nullity ty))
585− -> 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
586694 -> Expression tables grouping params ('Required (nullity 'PGbool))
587695(.>) = unsafeBinaryOp ">"
588696infix 4 .>
589697
698+-- | >>> renderExpression $ currentDate
699+-- "CURRENT_DATE"
590700currentDate
591701 :: Expression tables grouping params ('Required (nullity 'PGdate))
592702currentDate = UnsafeExpression "CURRENT_DATE"
593703
704+-- | >>> renderExpression $ currentTime
705+-- "CURRENT_TIME"
594706currentTime
595707 :: Expression tables grouping params ('Required (nullity 'PGtimetz))
596708currentTime = UnsafeExpression "CURRENT_TIME"
597709
710+-- | >>> renderExpression $ currentTimestamp
711+-- "CURRENT_TIMESTAMP"
598712currentTimestamp
599713 :: Expression tables grouping params ('Required (nullity 'PGtimestamptz))
600714currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
601715
716+-- | >>> renderExpression $ localTime
717+-- "LOCALTIME"
602718localTime
603719 :: Expression tables grouping params ('Required (nullity 'PGtime))
604720localTime = UnsafeExpression "LOCALTIME"
605721
722+-- | >>> renderExpression $ localTimestamp
723+-- "LOCALTIMESTAMP"
606724localTimestamp
607725 :: Expression tables grouping params ('Required (nullity 'PGtimestamp))
608726localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
@@ -632,24 +750,44 @@ instance Monoid
632750 mempty = fromString ""
633751 mappend = unsafeBinaryOp "||"
634752
753+-- | >>> renderExpression $ lower "ARRRGGG"
754+-- "lower(E'ARRRGGG')"
635755lower
636756 :: Expression tables grouping params ('Required (nullity 'PGtext))
757+ -- ^ string to lower case
637758 -> Expression tables grouping params ('Required (nullity 'PGtext))
638759lower = unsafeFunction "lower"
639760
761+-- | >>> renderExpression $ upper "eeee"
762+-- "upper(E'eeee')"
640763upper
641764 :: Expression tables grouping params ('Required (nullity 'PGtext))
765+ -- ^ string to upper case
642766 -> Expression tables grouping params ('Required (nullity 'PGtext))
643767upper = unsafeFunction "upper"
644768
769+-- | >>> renderExpression $ charLength "four"
770+-- "char_length(E'four')"
645771charLength
646772 :: Expression tables grouping params ('Required (nullity 'PGtext))
773+ -- ^ string to measure
647774 -> Expression tables grouping params ('Required (nullity 'PGint4))
648775charLength = unsafeFunction "char_length"
649776
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%')"
650786like
651787 :: Expression tables grouping params ('Required (nullity 'PGtext))
788+ -- ^ string
652789 -> Expression tables grouping params ('Required (nullity 'PGtext))
790+ -- ^ pattern
653791 -> Expression tables grouping params ('Required (nullity 'PGbool))
654792like = unsafeBinaryOp "LIKE"
655793
@@ -657,25 +795,46 @@ like = unsafeBinaryOp "LIKE"
657795aggregation
658796-----------------------------------------}
659797
660−unsafeAggregate, unsafeAggregateDistinct
661− :: ByteString
798+-- | escape hatch to define aggregate functions
799+unsafeAggregate
800+ :: ByteString -- ^ aggregate function
662801 -> Expression tables 'Ungrouped params ('Required xty)
663802 -> Expression tables ('Grouped bys) params ('Required yty)
664803unsafeAggregate fun x = UnsafeExpression $ mconcat
665804 [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)
666811unsafeAggregateDistinct fun x = UnsafeExpression $ mconcat
667812 [fun, "(DISTINCT ", renderExpression x, ")"]
668813
669−sum_, sumDistinct
814+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGnumeric)]] $ sum_ #col
815+-- "sum(col)"
816+sum_
670817 :: PGNum ty
671818 => Expression tables 'Ungrouped params ('Required (nullity ty))
819+ -- ^ what to sum
672820 -> Expression tables ('Grouped bys) params ('Required (nullity ty))
673821sum_ = 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))
674830sumDistinct = unsafeAggregateDistinct "sum"
675831
832+-- | A constraint for `PGType`s that you can take averages of and the resulting
833+-- `PGType`.
676834class PGAvg ty avg | ty -> avg where
677835 avg, avgDistinct
678836 :: Expression tables 'Ungrouped params ('Required (nullity ty))
837+ -- ^ what to average
679838 -> Expression tables ('Grouped bys) params ('Required (nullity avg))
680839 avg = unsafeAggregate "avg"
681840 avgDistinct = unsafeAggregateDistinct "avg"
@@ -687,65 +846,122 @@ instance PGAvg 'PGfloat4 'PGfloat8
687846instance PGAvg 'PGfloat8 'PGfloat8
688847instance PGAvg 'PGinterval 'PGinterval
689848
690−bitAnd, bitOr
849+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGint4)]] $ bitAnd #col
850+-- "bit_and(col)"
851+bitAnd
691852 :: PGIntegral int
692853 => Expression tables 'Ungrouped params ('Required (nullity int))
854+ -- ^ what to aggregate
693855 -> Expression tables ('Grouped bys) params ('Required (nullity int))
694856bitAnd = 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))
695865bitOr = unsafeAggregate "bit_or"
696866
697−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
698888 :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
889+ -- ^ what to aggregate
699890 -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
700891boolAnd = 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))
701899boolOr = unsafeAggregate "bool_or"
702900
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(*)"
703921countStar
704922 :: Expression tables ('Grouped bys) params ('Required ('NotNull 'PGint8))
705923countStar = UnsafeExpression $ "count(*)"
706924
707−count, countDistinct
925+-- | >>> renderExpression @'[_ ::: '["col" ::: 'Optional _]] $ count #col
926+-- "count(col)"
927+count
708928 :: Expression tables 'Ungrouped params ('Required ty)
929+ -- ^ what to count
709930 -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGint8))
710931count = unsafeAggregate "count"
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))
711939countDistinct = unsafeAggregateDistinct "count"
712−
713−every, everyDistinct
940+
941+-- | synonym for `boolAnd`
942+--
943+-- >>> renderExpression @'[_ ::: '["col" ::: 'Required (_ 'PGbool)]] $ every #col
944+-- "every(col)"
945+every
714946 :: Expression tables 'Ungrouped params ('Required (nullity 'PGbool))
947+ -- ^ what to aggregate
715948 -> Expression tables ('Grouped bys) params ('Required (nullity 'PGbool))
716949every = unsafeAggregate "every"
717−everyDistinct = unsafeAggregateDistinct "every"
718−
719−jsonAgg, jsonAggDistinct
720− :: Expression tables 'Ungrouped params ('Required ty)
721− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjson))
722−jsonAgg = unsafeAggregate "json_agg"
723−jsonAggDistinct = unsafeAggregateDistinct "json_agg"
724950
725−jsonbAgg, jsonbAggDistinct
726− :: Expression tables 'Ungrouped params ('Required ty)
727− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjsonb))
728−jsonbAgg = unsafeAggregate "jsonb_agg"
729−jsonbAggDistinct = unsafeAggregateDistinct "jsonb_agg"
730−
731−jsonObjectAgg
732− :: Expression tables 'Ungrouped params ('Required ('NotNull keyty))
733− -> Expression tables 'Ungrouped params ('Required valty)
734− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjson))
735−jsonObjectAgg k v = UnsafeExpression $
736− "json_object_agg(" <> renderExpression k
737− <> ", " <> renderExpression v <> ")"
738−
739−jsonbObjectAgg
740− :: Expression tables 'Ungrouped params ('Required ('NotNull keyty))
741− -> Expression tables 'Ungrouped params ('Required valty)
742− -> Expression tables ('Grouped bys) params ('Required ('NotNull 'PGjsonb))
743−jsonbObjectAgg k v = UnsafeExpression $
744− "jsonb_object_agg("
745− <> renderExpression k <> ", " <> renderExpression v <> ")"
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"
746960
961+-- | minimum and maximum aggregation
747962max_, min_, maxDistinct, minDistinct
748963 :: Expression tables 'Ungrouped params ('Required (nullity ty))
964+ -- ^ what to aggregate
749965 -> Expression tables ('Grouped bys) params ('Required (nullity ty))
750966max_ = unsafeAggregate "max"
751967min_ = unsafeAggregate "min"
@@ -756,12 +972,15 @@ minDistinct = unsafeAggregateDistinct "min"
756972tables
757973-----------------------------------------}
758974
975+-- | A `Table` from a schema without its alias with an `IsLabel` instance
976+-- to call a table reference by its alias.
759977newtype Table
760978 (schema :: TablesType)
761979 (columns :: ColumnsType)
762980 = UnsafeTable { renderTable :: ByteString }
763981 deriving (GHC.Generic,Show,Eq,Ord,NFData)
764982
983+-- | A `HasTable` constraint indicates a table reference.
765984class KnownSymbol table => HasTable table tables columns
766985 | table tables -> columns where
767986 getTable :: Alias table -> Table tables columns
@@ -780,96 +999,113 @@ instance HasTable table schema columns
780999type expressions
7811000-----------------------------------------}
7821001
1002+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
7831003newtype TypeExpression (ty :: ColumnType)
7841004 = UnsafeTypeExpression { renderTypeExpression :: ByteString }
7851005 deriving (GHC.Generic,Show,Eq,Ord,NFData)
7861006
1007+-- | logical Boolean (true/false)
7871008bool :: TypeExpression ('Required ('Null 'PGbool))
7881009bool = UnsafeTypeExpression "bool"
789−int2 :: TypeExpression ('Required ('Null 'PGint2))
1010+-- | signed two-byte integer
1011+int2, smallint :: TypeExpression ('Required ('Null 'PGint2))
7901012int2 = UnsafeTypeExpression "int2"
791−smallint :: TypeExpression ('Required ('Null 'PGint2))
7921013smallint = UnsafeTypeExpression "smallint"
793−int4 :: TypeExpression ('Required ('Null 'PGint4))
1014+-- | signed four-byte integer
1015+int4, int, integer :: TypeExpression ('Required ('Null 'PGint4))
7941016int4 = UnsafeTypeExpression "int4"
795−int :: TypeExpression ('Required ('Null 'PGint4))
7961017int = UnsafeTypeExpression "int"
797−integer :: TypeExpression ('Required ('Null 'PGint4))
7981018integer = UnsafeTypeExpression "integer"
799−int8 :: TypeExpression ('Required ('Null 'PGint8))
1019+-- | signed eight-byte integer
1020+int8, bigint :: TypeExpression ('Required ('Null 'PGint8))
8001021int8 = UnsafeTypeExpression "int8"
801−bigint :: TypeExpression ('Required ('Null 'PGint8))
8021022bigint = UnsafeTypeExpression "bigint"
1023+-- | arbitrary precision numeric type
8031024numeric :: TypeExpression ('Required ('Null 'PGnumeric))
8041025numeric = UnsafeTypeExpression "numeric"
805−float4 :: TypeExpression ('Required ('Null 'PGfloat4))
1026+-- | single precision floating-point number (4 bytes)
1027+float4, real :: TypeExpression ('Required ('Null 'PGfloat4))
8061028float4 = UnsafeTypeExpression "float4"
807−real :: TypeExpression ('Required ('Null 'PGfloat4))
8081029real = UnsafeTypeExpression "real"
809−float8 :: TypeExpression ('Required ('Null 'PGfloat8))
1030+-- | double precision floating-point number (8 bytes)
1031+float8, doublePrecision :: TypeExpression ('Required ('Null 'PGfloat8))
8101032float8 = UnsafeTypeExpression "float8"
811−doublePrecision :: TypeExpression ('Required ('Null 'PGfloat8))
8121033doublePrecision = UnsafeTypeExpression "double precision"
813−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))
8141037serial2 = UnsafeTypeExpression "serial2"
815−smallserial :: TypeExpression ('Optional ('NotNull 'PGint2))
8161038smallserial = UnsafeTypeExpression "smallserial"
817−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))
8181042serial4 = UnsafeTypeExpression "serial4"
819−serial :: TypeExpression ('Optional ('NotNull 'PGint4))
8201043serial = UnsafeTypeExpression "serial"
821−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))
8221047serial8 = UnsafeTypeExpression "serial8"
823−bigserial :: TypeExpression ('Optional ('NotNull 'PGint8))
8241048bigserial = UnsafeTypeExpression "bigserial"
1049+-- | variable-length character string
8251050text :: TypeExpression ('Required ('Null 'PGtext))
8261051text = UnsafeTypeExpression "text"
827−char
1052+-- | fixed-length character string
1053+char, character
8281054 :: (KnownNat n, 1 <= n)
8291055 => proxy n
8301056 -> TypeExpression ('Required ('Null ('PGchar n)))
8311057char p = UnsafeTypeExpression $ "char(" <> renderNat p <> ")"
832−character
833− :: (KnownNat n, 1 <= n)
834− => proxy n
835− -> TypeExpression ('Required ('Null ('PGchar n)))
8361058character p = UnsafeTypeExpression $ "character(" <> renderNat p <> ")"
837−varchar
1059+-- | variable-length character string
1060+varchar, characterVarying
8381061 :: (KnownNat n, 1 <= n)
8391062 => proxy n
8401063 -> TypeExpression ('Required ('Null ('PGvarchar n)))
8411064varchar p = UnsafeTypeExpression $ "varchar(" <> renderNat p <> ")"
842−characterVarying
843− :: (KnownNat n, 1 <= n)
844− => proxy n
845− -> TypeExpression ('Required ('Null ('PGvarchar n)))
8461065characterVarying p = UnsafeTypeExpression $
8471066 "character varying(" <> renderNat p <> ")"
848−bytea :: TypeExpression ('Required ('Null ('PGbytea)))
1067+-- | binary data ("byte array")
1068+bytea :: TypeExpression ('Required ('Null 'PGbytea))
8491069bytea = UnsafeTypeExpression "bytea"
850−timestamp :: TypeExpression ('Required ('Null ('PGtimestamp)))
1070+-- | date and time (no time zone)
1071+timestamp :: TypeExpression ('Required ('Null 'PGtimestamp))
8511072timestamp = UnsafeTypeExpression "timestamp"
852−timestampWithTimeZone :: TypeExpression ('Required ('Null ('PGtimestamptz)))
1073+-- | date and time, including time zone
1074+timestampWithTimeZone :: TypeExpression ('Required ('Null 'PGtimestamptz))
8531075timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
854−date :: TypeExpression ('Required ('Null ('PGdate)))
1076+-- | calendar date (year, month, day)
1077+date :: TypeExpression ('Required ('Null 'PGdate))
8551078date = UnsafeTypeExpression "date"
856−time :: TypeExpression ('Required ('Null ('PGtime)))
1079+-- | time of day (no time zone)
1080+time :: TypeExpression ('Required ('Null 'PGtime))
8571081time = UnsafeTypeExpression "time"
858−timeWithTimeZone :: TypeExpression ('Required ('Null ('PGtimetz)))
1082+-- | time of day, including time zone
1083+timeWithTimeZone :: TypeExpression ('Required ('Null 'PGtimetz))
8591084timeWithTimeZone = UnsafeTypeExpression "time with time zone"
860−interval :: TypeExpression ('Required ('Null ('PGinterval)))
1085+-- | time span
1086+interval :: TypeExpression ('Required ('Null 'PGinterval))
8611087interval = UnsafeTypeExpression "interval"
862−uuid :: TypeExpression ('Required ('Null ('PGuuid)))
1088+-- | universally unique identifier
1089+uuid :: TypeExpression ('Required ('Null 'PGuuid))
8631090uuid = UnsafeTypeExpression "uuid"
864−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))
8651096json = UnsafeTypeExpression "json"
866−jsonb :: TypeExpression ('Required ('Null ('PGjsonb)))
1097+-- | binary JSON data, decomposed
1098+jsonb :: TypeExpression ('Required ('Null 'PGjsonb))
8671099jsonb = UnsafeTypeExpression "jsonb"
8681100
1101+-- | used in `createTable` commands as a column constraint to ensure
1102+-- @NULL@ is not present
8691103notNull
8701104 :: TypeExpression (optionality ('Null ty))
8711105 -> TypeExpression (optionality ('NotNull ty))
8721106notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <+> "NOT NULL"
1107+
1108+-- | used in `createTable` commands as a column constraint to give a default
8731109default_
8741110 :: Expression '[] 'Ungrouped '[] ('Required ty)
8751111 -> TypeExpression ('Required ty)
@@ -877,6 +1113,7 @@ default_
8771113default_ x ty = UnsafeTypeExpression $
8781114 renderTypeExpression ty <+> "DEFAULT" <+> renderExpression x
8791115
1116+-- | `pgtype` is a demoted version of a `PGType`
8801117class PGTyped (ty :: PGType) where
8811118 pgtype :: TypeExpression ('Required ('Null ty))
8821119instance PGTyped 'PGbool where pgtype = bool
squeal-postgresql/src/Squeal/PostgreSQL/Manipulation.hs+2−2
@@ -54,9 +54,9 @@ import Squeal.PostgreSQL.Prettyprint
5454import Squeal.PostgreSQL.Query
5555import Squeal.PostgreSQL.Schema
5656
57−-- | A manipulation is a statement which may modify data in the database,
57+-- | A `Manipulation` is a statement which may modify data in the database,
5858-- but does not alter the schema. Examples are `insertInto`, `update` and
59−-- `deleteFrom`. A `Query` is also considered a manipulation even though
59+-- `deleteFrom`. A `Query` is also considered a `Manipulation` even though
6060-- it does not modify data.
6161newtype Manipulation
6262 (schema :: TablesType)