@@ -1,13 +1,14 @@
2Module: Squeal.PostgreSQL.Expression
2Module: Squeal.PostgreSQL.Expression
3Description: Squeal expressions
3Description: Squeal expressions
4−Copyright: (c) Eitan Chatav, 2019
4+Copyright: (c) Eitan Chatav, 2017
5Maintainer: eitan@morphism.tech
5Maintainer: eitan@morphism.tech
6Stability: experimental
6Stability: experimental
8Squeal expressions are the atoms used to build statements.
8Squeal expressions are the atoms used to build statements.
11+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
11{-# LANGUAGE
12{-# LANGUAGE
12 AllowAmbiguousTypes
13 AllowAmbiguousTypes
13 , ConstraintKinds
14 , ConstraintKinds
@@ -33,214 +34,358 @@ Squeal expressions are the atoms used to build statements.
33module Squeal.PostgreSQL.Expression
34module Squeal.PostgreSQL.Expression
34 ( -- * Expression
35 ( -- * Expression
35 Expression (..)
36 Expression (..)
45 , Operator
37 , Operator
46− , OperatorDB
38+ , (:-->)
39+ , HasParameter (parameter)
47 , unsafeBinaryOp
57 , unsafeBinaryOp
48− , binaryOp
58+ , unsafeUnaryOpL
49− , FunctionVar
59+ , unsafeFunction
50− , unsafeFunctionVar
60+ , unsafeVariadicFunction
51− , type (--->)
61+ , atan2_
52− , FunctionNDB
62+ , cast
53− , unsafeFunctionN
63+ , quot_
54− , functionN
64+ , rem_
55− , PGSubset (..)
65+ , trunc
56− , PGIntersect (..)
66+ , round_
88+ , notBetweenSymmetric
115+ -- *** Json and Jsonb operators
120+ -- *** Jsonb operators
147+ , jsonExtractPathAsText
148+ , jsonbExtractPathAsText
166+ -- * Window Functions
167+ , WindowDefinition (..)
169+ , WindowFunction (..)
182+ , SortExpression (..)
185+ , TypeExpression (..)
211+ , timestampWithTimeZone
229+ , websearchToTSquery
57 -- * Re-export
233 -- * Re-export
63import Control.Category
240import Control.Category
64import Control.DeepSeq
241import Control.DeepSeq
65import Data.ByteString (ByteString)
242import Data.ByteString (ByteString)
243+import Data.ByteString.Lazy (toStrict)
66import Data.Function ((&))
244import Data.Function ((&))
67import Data.Semigroup hiding (All)
245import Data.Semigroup hiding (All)
246+import qualified Data.Aeson as JSON
68import Data.String
247import Data.String
69import Generics.SOP hiding (All, from)
249import Generics.SOP hiding (All, from)
250+import GHC.Generics ((:*:) (..))
70import GHC.OverloadedLabels
251import GHC.OverloadedLabels
71import GHC.TypeLits
252import GHC.TypeLits
72import Numeric
253import Numeric
73import Prelude hiding (id, (.))
254import Prelude hiding (id, (.))
256+import qualified Data.ByteString as ByteString
75import qualified GHC.Generics as GHC
257import qualified GHC.Generics as GHC
258+import qualified Generics.SOP as SOP
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79import Squeal.PostgreSQL.Render
260import Squeal.PostgreSQL.Render
80import Squeal.PostgreSQL.Schema
261import Squeal.PostgreSQL.Schema
83−-- >>> import Squeal.PostgreSQL
85{-----------------------------------------
263{-----------------------------------------
86column expressions
264column expressions
87-----------------------------------------}
265-----------------------------------------}
89{- | `Expression`s are used in a variety of contexts,
267{- | `Expression`s are used in a variety of contexts,
90−such as in the target `Squeal.PostgreSQL.Query.List` of the
91−`Squeal.PostgreSQL.Query.select` command,
268+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
269as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93`Squeal.PostgreSQL.Manipulation.update`,
270`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
271+or in search `Condition`s in a number of commands.
96The expression syntax allows the calculation of
273The expression syntax allows the calculation of
97values from primitive expression using arithmetic, logical,
274values from primitive expression using arithmetic, logical,
98and other operations.
275and other operations.
100−The type parameters of `Expression` are
102−* @outer :: @ `FromType`, the @from@ clauses of any outer queries in which
103− the `Expression` is a correlated subquery expression;
104−* @commons :: @ `FromType`, the `Squeal.PostgreSQL.Query.CommonTableExpression`s
105− that are in scope for the `Expression`;
106−* @grp :: @ `Grouping`, the `Grouping` of the @from@ clause which may limit
107− which columns may be referenced by alias;
108−* @schemas :: @ `SchemasType`, the schemas of your database that are in
109− scope for the `Expression`;
110−* @from :: @ `FromType`, the @from@ clause which the `Expression` may use
111− to reference columns by alias;
112−* @ty :: @ `NullityType`, the type of the `Expression`.
114newtype Expression
277newtype Expression
115 (outer :: FromType)
278 (outer :: FromType)
116− (commons :: FromType)
117 (grp :: Grouping)
279 (grp :: Grouping)
280+ (commons :: FromType)
118 (schemas :: SchemasType)
281 (schemas :: SchemasType)
119 (params :: [NullityType])
282 (params :: [NullityType])
120 (from :: FromType)
283 (from :: FromType)
121 (ty :: NullityType)
284 (ty :: NullityType)
122 = UnsafeExpression { renderExpression :: ByteString }
285 = UnsafeExpression { renderExpression :: ByteString }
123 deriving (GHC.Generic,Show,Eq,Ord,NFData)
286 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
287+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125 renderSQL = renderExpression
288 renderSQL = renderExpression
127−-- | An `Expr` is a closed `Expression`.
128−-- It is a F@RankNType@ but don't be scared.
129−-- Think of it as an expression which sees no
130−-- namespaces, so you can't use parameters
131−-- or alias references. It can be used as
132−-- a simple piece of more complex `Expression`s.
133type Expr x
290type Expr x
134− = forall outer commons grp schemas params from
291+ = forall outer grp commons schemas params from
135− . Expression outer commons grp schemas params from x
292+ . Expression outer grp commons schemas params from x
136− -- ^ cannot reference aliases
138−-- | A @RankNType@ for binary operators.
139type Operator x1 x2 y
294type Operator x1 x2 y
140− = forall outer commons grp schemas params from
295+ = forall outer grp commons schemas params from
141− . Expression outer commons grp schemas params from x1
296+ . Expression outer grp commons schemas params from x1
143− -> Expression outer commons grp schemas params from x2
297+ -> Expression outer grp commons schemas params from x2
145− -> Expression outer commons grp schemas params from y
298+ -> Expression outer grp commons schemas params from y
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
301+ = forall outer grp commons schemas params from
150− . Expression outer commons grp schemas params from x1
302+ . Expression outer grp commons schemas params from x
152− -> Expression outer commons grp schemas params from x2
303+ -> Expression outer grp commons schemas params from y
153− -- ^ right input
304+
305+type FunctionHet xs y
154− -> Expression outer commons grp schemas params from y
306+ = forall outer grp commons schemas params from
155− -- ^ output
307+ . NP (Expression outer grp commons schemas params from) xs
156−
308+ -> Expression outer grp commons schemas params from y
157−-- | A @RankNType@ for functions with a single argument.
309+
158−-- These could be either function calls or unary operators.
159−-- This is a subtype of the usual Haskell function type `Prelude.->`,
160−-- indeed a subcategory as it is closed under the usual
161−-- `Prelude..` and `Prelude.id`.
162−type (-->) x y
310+type FunctionHom x y
163− = forall outer commons grp schemas params from
311+ = forall outer grp commons schemas params from
164− . Expression outer commons grp schemas params from x
312+ . [Expression outer grp commons schemas params from x]
166− -> Expression outer commons grp schemas params from y
313+ -> Expression outer grp commons schemas params from x
169−type FunctionDB schemas x y
170− = forall outer commons grp params from
171− . Expression outer commons grp schemas params from x
173− -> Expression outer commons grp schemas params from y
314+ -> Expression outer grp commons schemas params from y
175−
316+unsafeFunctionHom :: ByteString -> FunctionHom x y
176−{- | A @RankNType@ for functions with a fixed-length list of heterogeneous arguments.
177−Use the `*:` operator to end your argument lists, like so.
179−>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
180−fun(TRUE, FALSE, LOCALTIME, TRUE)
183− = forall outer commons grp schemas params from
184− . NP (Expression outer commons grp schemas params from) xs
186− -> Expression outer commons grp schemas params from y
189−type FunctionNDB schemas xs y
190− = forall outer commons grp params from
191− . NP (Expression outer commons grp schemas params from) xs
193− -> Expression outer commons grp schemas params from y
196−{- | A @RankNType@ for functions with a variable-length list of
197−homogeneous arguments and at least 1 more argument.
199−type FunctionVar x0 x1 y
200− = forall outer commons grp schemas params from
201− . [Expression outer commons grp schemas params from x0]
203− -> Expression outer commons grp schemas params from x1
204− -- ^ must have at least 1 input
205− -> Expression outer commons grp schemas params from y
208−{- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)
209−greatest(TRUE, NULL, FALSE)
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
317+unsafeFunctionHom fun xs x = UnsafeExpression $ fun <> parenthesized
213 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
318 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
320+{- | A `HasParameter` constraint is used to indicate a value that is
321+supplied externally to a SQL statement.
322+`Squeal.PostgreSQL.PQ.manipulateParams`,
323+`Squeal.PostgreSQL.PQ.queryParams` and
324+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
325+separately from the SQL command string, in which case `param`s are used to
326+refer to the out-of-line data values.
328+class KnownNat n => HasParameter
330+ (params :: [NullityType])
332+ | n params -> ty where
333+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
335+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
336+ -- >>> printSQL expr
339+ :: TypeExpression schemas ty
340+ -> Expression outer grp commons schemas params from ty
341+ parameter ty = UnsafeExpression $ parenthesized $
342+ "$" <> renderNat @n <+> "::"
344+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
345+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
346+ => HasParameter n (ty' : params) ty
348+-- | `param` takes a `Nat` using type application and for basic types,
349+-- infers a `TypeExpression`.
351+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
355+ :: forall n outer commons schemas params from grp ty
356+ . (PGTyped schemas ty, HasParameter n params ty)
357+ => Expression outer grp commons schemas params from ty -- ^ param
358+param = parameter @n (pgtype @schemas)
215instance (HasUnique tab (Join outer from) row, Has col row ty)
360instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
361+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
362 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
363instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
219− => IsLabel col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where
364+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220 fromLabel = fromLabel @col :* Nil
365 fromLabel = fromLabel @col :* Nil
221instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
366instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222 => IsLabel col
367 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
368+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224 fromLabel = fromLabel @col `As` Alias
369 fromLabel = fromLabel @col `As` Alias
225instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
370instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226 => IsLabel col
371 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
372+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228 fromLabel = fromLabel @col :* Nil
373 fromLabel = fromLabel @col :* Nil
230instance (Has tab (Join outer from) row, Has col row ty)
375instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
376+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232 tab ! col = UnsafeExpression $
377 tab ! col = UnsafeExpression $
233 renderSQL tab <> "." <> renderSQL col
378 renderSQL tab <> "." <> renderSQL col
234instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])
379instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])
235− => IsQualified tab col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where
380+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236 tab ! col = tab ! col :* Nil
381 tab ! col = tab ! col :* Nil
237instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
382instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238 => IsQualified tab col
383 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
384+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240 tab ! col = tab ! col `As` col
385 tab ! col = tab ! col `As` col
241instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
386instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242 => IsQualified tab col
387 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
388+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244 tab ! col = tab ! col :* Nil
389 tab ! col = tab ! col :* Nil
@@ -248,7 +393,7 @@ instance
248 , Has col row ty
393 , Has col row ty
249 , GroupedBy tab col bys
394 , GroupedBy tab col bys
250 ) => IsLabel col
395 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
396+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
397 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
254 ( HasUnique tab (Join outer from) row
399 ( HasUnique tab (Join outer from) row
@@ -256,7 +401,7 @@ instance
256 , GroupedBy tab col bys
401 , GroupedBy tab col bys
257 , tys ~ '[ty]
402 , tys ~ '[ty]
258 ) => IsLabel col
403 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
404+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260 fromLabel = fromLabel @col :* Nil
405 fromLabel = fromLabel @col :* Nil
262 ( HasUnique tab (Join outer from) row
407 ( HasUnique tab (Join outer from) row
@@ -264,7 +409,7 @@ instance
264 , GroupedBy tab col bys
409 , GroupedBy tab col bys
265 , column ~ (col ::: ty)
410 , column ~ (col ::: ty)
266 ) => IsLabel col
411 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
412+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268 fromLabel = fromLabel @col `As` Alias
413 fromLabel = fromLabel @col `As` Alias
270 ( HasUnique tab (Join outer from) row
415 ( HasUnique tab (Join outer from) row
@@ -272,7 +417,7 @@ instance
272 , GroupedBy tab col bys
417 , GroupedBy tab col bys
273 , columns ~ '[col ::: ty]
418 , columns ~ '[col ::: ty]
274 ) => IsLabel col
419 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
420+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276 fromLabel = fromLabel @col :* Nil
421 fromLabel = fromLabel @col :* Nil
@@ -280,7 +425,7 @@ instance
280 , Has col row ty
425 , Has col row ty
281 , GroupedBy tab col bys
426 , GroupedBy tab col bys
282 ) => IsQualified tab col
427 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
428+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284 tab ! col = UnsafeExpression $
429 tab ! col = UnsafeExpression $
285 renderSQL tab <> "." <> renderSQL col
430 renderSQL tab <> "." <> renderSQL col
@@ -289,7 +434,7 @@ instance
289 , GroupedBy tab col bys
434 , GroupedBy tab col bys
290 , tys ~ '[ty]
435 , tys ~ '[ty]
291 ) => IsQualified tab col
436 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
437+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293 tab ! col = tab ! col :* Nil
438 tab ! col = tab ! col :* Nil
295 ( Has tab (Join outer from) row
440 ( Has tab (Join outer from) row
@@ -297,7 +442,7 @@ instance
297 , GroupedBy tab col bys
442 , GroupedBy tab col bys
298 , column ~ (col ::: ty)
443 , column ~ (col ::: ty)
299 ) => IsQualified tab col
444 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
445+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301 tab ! col = tab ! col `As` col
446 tab ! col = tab ! col `As` col
303 ( Has tab (Join outer from) row
448 ( Has tab (Join outer from) row
@@ -305,78 +450,223 @@ instance
305 , GroupedBy tab col bys
450 , GroupedBy tab col bys
306 , columns ~ '[col ::: ty]
451 , columns ~ '[col ::: ty]
307 ) => IsQualified tab col
452 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
453+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309 tab ! col = tab ! col :* Nil
454 tab ! col = tab ! col :* Nil
456+-- | analagous to `Nothing`
458+-- >>> printSQL null_
460+null_ :: Expr ('Null ty)
461+null_ = UnsafeExpression "NULL"
463+-- | analagous to `Just`
465+-- >>> printSQL $ notNull true
467+notNull :: 'NotNull ty :--> 'Null ty
468+notNull = UnsafeExpression . renderSQL
470+-- | return the leftmost value which is not NULL
472+-- >>> printSQL $ coalesce [null_, true] false
473+-- COALESCE(NULL, TRUE, FALSE)
475+ :: [Expression outer grp commons schemas params from ('Null ty)]
476+ -- ^ @NULL@s may be present
477+ -> Expression outer grp commons schemas params from ('NotNull ty)
478+ -- ^ @NULL@ is absent
479+ -> Expression outer grp commons schemas params from ('NotNull ty)
480+coalesce nullxs notNullx = UnsafeExpression $
481+ "COALESCE" <> parenthesized (commaSeparated
482+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
484+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
486+-- >>> printSQL $ fromNull true null_
487+-- COALESCE(NULL, TRUE)
489+ :: Expression outer grp commons schemas params from ('NotNull ty)
490+ -- ^ what to convert @NULL@ to
491+ -> Expression outer grp commons schemas params from ('Null ty)
492+ -> Expression outer grp commons schemas params from ('NotNull ty)
493+fromNull notNullx nullx = coalesce [nullx] notNullx
495+-- | >>> printSQL $ null_ & isNull
498+ :: Expression outer grp commons schemas params from ('Null ty)
499+ -- ^ possibly @NULL@
500+ -> Condition outer grp commons schemas params from
501+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
503+-- | >>> printSQL $ null_ & isNotNull
506+ :: Expression outer grp commons schemas params from ('Null ty)
507+ -- ^ possibly @NULL@
508+ -> Condition outer grp commons schemas params from
509+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
511+-- | analagous to `maybe` using @IS NULL@
513+-- >>> printSQL $ matchNull true not_ null_
514+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
516+ :: Expression outer grp commons schemas params from (nullty)
517+ -- ^ what to convert @NULL@ to
518+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
519+ -> Expression outer grp commons schemas params from (nullty) )
520+ -- ^ function to perform when @NULL@ is absent
521+ -> Expression outer grp commons schemas params from ('Null ty)
522+ -> Expression outer grp commons schemas params from (nullty)
523+matchNull y f x = ifThenElse (isNull x) y
524+ (f (UnsafeExpression (renderSQL x)))
526+{-| right inverse to `fromNull`, if its arguments are equal then
527+`nullIf` gives @NULL@.
529+>>> :set -XTypeApplications -XDataKinds
530+>>> let expr = nullIf false (param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
532+NULL IF (FALSE, ($1 :: bool))
535+ :: Expression outer grp commons schemas params from ('NotNull ty)
536+ -- ^ @NULL@ is absent
537+ -> Expression outer grp commons schemas params from ('NotNull ty)
538+ -- ^ @NULL@ is absent
539+ -> Expression outer grp commons schemas params from ('Null ty)
540+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
541+ (renderSQL x <> ", " <> renderSQL y)
543+-- | >>> printSQL $ array [null_, false, true]
544+-- ARRAY[NULL, FALSE, TRUE]
546+ :: [Expression outer grp commons schemas params from ty]
548+ -> Expression outer grp commons schemas params from (null ('PGvararray ty))
549+array xs = UnsafeExpression $
550+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
552+-- | >>> printSQL $ cardinality (array [null_, false, true])
553+-- cardinality(ARRAY[NULL, FALSE, TRUE])
554+cardinality :: null ('PGvararray ty) :--> null 'PGint8
555+cardinality = unsafeFunction "cardinality"
557+-- | >>> printSQL $ array [null_, false, true] & index 2
558+-- (ARRAY[NULL, FALSE, TRUE])[2]
560+ :: Word64 -- ^ index
561+ -> null ('PGvararray ty) :--> NullifyType ty
562+index n expr = UnsafeExpression $
563+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
311instance (KnownSymbol label, label `In` labels) => IsPGlabel label
565instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
566+ (Expression outer grp commons schemas params from (null ('PGenum labels))) where
313 label = UnsafeExpression $ renderSQL (PGlabel @label)
567 label = UnsafeExpression $ renderSQL (PGlabel @label)
569+-- | A row constructor is an expression that builds a row value
570+-- (also called a composite value) using values for its member fields.
573+-- type Complex = 'PGcomposite
574+-- '[ "real" ::: 'NotNull 'PGfloat8
575+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
578+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
583+ => NP (Aliased (Expression outer grp commons schemas params from)) row
584+ -- ^ zero or more expressions for the row field values
585+ -> Expression outer grp commons schemas params from (null ('PGcomposite row))
586+row exprs = UnsafeExpression $ "ROW" <> parenthesized
587+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
590+-- type Complex = 'PGcomposite
591+-- '[ "real" ::: 'NotNull 'PGfloat8
592+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
593+-- type Schema = '["complex" ::: 'Typedef Complex]
596+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
597+-- >>> printSQL $ i & field #complex #imaginary
598+-- (ROW(0, 1)::"complex")."imaginary"
600+ :: ( Has sch schemas schema
601+ , Has tydef schema ('Typedef ('PGcomposite row))
603+ => QualifiedAlias sch tydef -- ^ row type
604+ -> Alias field -- ^ field name
605+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
606+ -> Expression outer grp commons schemas params from ty
607+field td fld expr = UnsafeExpression $
608+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
609+ <> "." <> renderSQL fld
612+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
613+ (<>) = unsafeBinaryOp "||"
616+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
620+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
622+-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
623+greatest :: FunctionHom ty ty
624+greatest = unsafeFunctionHom "GREATEST"
626+-- | >>> printSQL $ least [null_] currentTimestamp
627+-- LEAST(NULL, CURRENT_TIMESTAMP)
628+least :: FunctionHom ty ty
629+least = unsafeFunctionHom "LEAST"
315-- | >>> printSQL $ unsafeBinaryOp "OR" true false
631-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316-- (TRUE OR FALSE)
632-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
633+unsafeBinaryOp :: ByteString {- ^ operator -} -> Operator ty0 ty1 ty2
318unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
634unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319 renderSQL x <+> op <+> renderSQL y
635 renderSQL x <+> op <+> renderSQL y
322− :: forall op sch schemas schema x y z.
323− ( Has sch schemas schema
324− , Has op schema ('Operator ('BinaryOp x y z)) )
325− => OperatorDB schemas x y z
326−binaryOp = unsafeBinaryOp $ renderSymbol @op
328−-- | >>> printSQL $ unsafeLeftOp "NOT" true
637+-- | >>> printSQL $ unsafeUnaryOpL "NOT" true
329-- (NOT TRUE)
638-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
639+unsafeUnaryOpL :: ByteString {- ^ operator -} -> x :--> y
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
640+unsafeUnaryOpL op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
333−leftOp
642+unsafeUnaryOpR :: ByteString {- ^ operator -} -> x :--> y
334− :: forall op sch schemas schema x y.
335− ( Has sch schemas schema
336− , Has op schema ('Operator ('LeftOp x y)) )
337− => FunctionDB schemas x y
338−leftOp = unsafeLeftOp $ renderSymbol @op
340−-- | >>> printSQL $ true & unsafeRightOp "IS NOT TRUE"
341−-- (TRUE IS NOT TRUE)
342−unsafeRightOp :: ByteString -> x --> y
343−unsafeRightOp op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
643+unsafeUnaryOpR op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
346− :: forall op sch schemas schema x y.
347− ( Has sch schemas schema
348− , Has op schema ('Operator ('RightOp x y)) )
349− => FunctionDB schemas x y
350−rightOp = unsafeRightOp $ renderSymbol @op
352-- | >>> printSQL $ unsafeFunction "f" true
645-- | >>> printSQL $ unsafeFunction "f" true
353-- f(TRUE)
646-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
647+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355unsafeFunction fun x = UnsafeExpression $
648unsafeFunction fun x = UnsafeExpression $
356 fun <> parenthesized (renderSQL x)
649 fun <> parenthesized (renderSQL x)
358−function
651+unsafeFunctionHet
359− :: (Has sch schemas schema, Has fun schema ('Function ('[x] :=> 'Returns y)))
652+ :: SListI xs
360− => QualifiedAlias sch fun
653+ => ByteString {- ^ function -}
361− -> FunctionDB schemas x y
654+ -> FunctionHet xs y
362−function = unsafeFunction . renderSQL
364−-- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a')
365−-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
366−unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
367−unsafeFunctionN fun xs = UnsafeExpression $
655+unsafeFunctionHet fun xs = UnsafeExpression $
368 fun <> parenthesized (renderCommaSeparated renderSQL xs)
656 fun <> parenthesized (renderCommaSeparated renderSQL xs)
370−functionN
658+-- | Helper for defining variadic functions.
371− :: ( Has sch schemas schema
659+unsafeVariadicFunction
372− , Has fun schema ('Function (xs :=> 'Returns y))
373− , SListI xs )
660+ :: SListI elems
374− => QualifiedAlias sch fun
661+ => ByteString
375− -> FunctionNDB schemas xs y
662+ -- ^ function
376−functionN = unsafeFunctionN . renderSQL
663+ -> NP (Expression outer grp commons schemas params from) elems
664+ -> Expression outer grp commons schemas params from ret
665+unsafeVariadicFunction fun x = UnsafeExpression $
666+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
378instance ty `In` PGNum
668instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
669+ => Num (Expression outer grp commons schemas params from (null ty)) where
380 (+) = unsafeBinaryOp "+"
670 (+) = unsafeBinaryOp "+"
381 (-) = unsafeBinaryOp "-"
671 (-) = unsafeBinaryOp "-"
382 (*) = unsafeBinaryOp "*"
672 (*) = unsafeBinaryOp "*"
@@ -388,7 +678,7 @@ instance ty `In` PGNum
390instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
680instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
681+ (Expression outer grp commons schemas params from (null ty)) where
392 (/) = unsafeBinaryOp "/"
682 (/) = unsafeBinaryOp "/"
393 fromRational
683 fromRational
394 = UnsafeExpression
684 = UnsafeExpression
@@ -398,7 +688,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398 . fromRat @Double
688 . fromRat @Double
400instance (ty `In` PGNum, ty `In` PGFloating) => Floating
690instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
691+ (Expression outer grp commons schemas params from (null ty)) where
402 pi = UnsafeExpression "pi()"
692 pi = UnsafeExpression "pi()"
403 exp = unsafeFunction "exp"
693 exp = unsafeFunction "exp"
404 log = unsafeFunction "ln"
694 log = unsafeFunction "ln"
@@ -419,54 +709,1768 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419 acosh x = log (x + sqrt (x*x - 1))
709 acosh x = log (x + sqrt (x*x - 1))
420 atanh x = log ((1 + x) / (1 - x)) / 2
710 atanh x = log ((1 + x) / (1 - x)) / 2
422−-- | Contained by operators
712+-- | >>> :{
423−class PGSubset ty where
713+-- let
424− (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
714+-- expression :: Expr (null 'PGfloat4)
425− (@>) = unsafeBinaryOp "@>"
715+-- expression = atan2_ (pi *: 2)
426− (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
716+-- in printSQL expression
427− (<@) = unsafeBinaryOp "<@"
717+-- :}
428−instance PGSubset 'PGjsonb
718+-- atan2(pi(), 2)
429−instance PGSubset 'PGtsquery
719+atan2_
430−instance PGSubset ('PGvararray ty)
720+ :: float `In` PGFloating
431−instance PGSubset ('PGrange ty)
721+ => FunctionHet '[ null float, null float] (null float)
432−
722+atan2_ = unsafeFunctionHet "atan2"
433−class PGIntersect ty where
723+
434− (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
724+-- When a `cast` is applied to an `Expression` of a known type, it
435− (@&&) = unsafeBinaryOp "&&"
725+-- represents a run-time type conversion. The cast will succeed only if a
436−instance PGIntersect ('PGvararray ty)
726+-- suitable type conversion operation has been defined.
437−instance PGIntersect ('PGrange ty)
727+--
728+-- | >>> printSQL $ true & cast int4
731+ :: TypeExpression schemas ty1
732+ -- ^ type to cast as
733+ -> Expression outer grp commons schemas params from ty0
734+ -- ^ value to convert
735+ -> Expression outer grp commons schemas params from ty1
736+cast ty x = UnsafeExpression $ parenthesized $
737+ renderSQL x <+> "::" <+> renderSQL ty
739+-- | integer division, truncates the result
743+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
744+-- expression = 5 `quot_` 2
745+-- in printSQL expression
749+ :: int `In` PGIntegral
750+ => Operator (null int) (null int) (null int)
751+quot_ = unsafeBinaryOp "/"
753+-- | remainder upon integer division
757+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
758+-- expression = 5 `rem_` 2
759+-- in printSQL expression
763+ :: int `In` PGIntegral
764+ => Operator (null int) (null int) (null int)
765+rem_ = unsafeBinaryOp "%"
769+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
770+-- expression = trunc pi
771+-- in printSQL expression
774+trunc :: frac `In` PGFloating => null frac :--> null frac
775+trunc = unsafeFunction "trunc"
779+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
780+-- expression = round_ pi
781+-- in printSQL expression
784+round_ :: frac `In` PGFloating => null frac :--> null frac
785+round_ = unsafeFunction "round"
789+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
790+-- expression = ceiling_ pi
791+-- in printSQL expression
794+ceiling_ :: frac `In` PGFloating => null frac :--> null frac
795+ceiling_ = unsafeFunction "ceiling"
797+-- | A `Condition` is an `Expression`, which can evaluate
798+-- to `true`, `false` or `null_`. This is because SQL uses
799+-- a three valued logic.
800+type Condition outer grp commons schemas params from =
801+ Expression outer grp commons schemas params from ('Null 'PGbool)
803+-- | >>> printSQL true
805+true :: Expr (null 'PGbool)
806+true = UnsafeExpression "TRUE"
808+-- | >>> printSQL false
810+false :: Expr (null 'PGbool)
811+false = UnsafeExpression "FALSE"
813+-- | >>> printSQL $ not_ true
815+not_ :: null 'PGbool :--> null 'PGbool
816+not_ = unsafeUnaryOpL "NOT"
818+-- | >>> printSQL $ true .&& false
820+(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
822+(.&&) = unsafeBinaryOp "AND"
824+-- | >>> printSQL $ true .|| false
826+(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
828+(.||) = unsafeBinaryOp "OR"
832+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
833+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
834+-- in printSQL expression
836+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
838+ :: [ ( Condition outer grp commons schemas params from
839+ , Expression outer grp commons schemas params from ty
841+ -- ^ whens and thens
842+ -> Expression outer grp commons schemas params from ty
844+ -> Expression outer grp commons schemas params from ty
845+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
849+ [ " WHEN ", renderSQL when_
850+ , " THEN ", renderSQL then_
852+ | (when_,then_) <- whenThens
854+ , " ELSE ", renderSQL else_
860+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
861+-- expression = ifThenElse true 1 0
862+-- in printSQL expression
864+-- CASE WHEN TRUE THEN 1 ELSE 0 END
866+ :: Condition outer grp commons schemas params from
867+ -> Expression outer grp commons schemas params from ty -- ^ then
868+ -> Expression outer grp commons schemas params from ty -- ^ else
869+ -> Expression outer grp commons schemas params from ty
870+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
872+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
873+-- will produce @NULL@s if one of their arguments is @NULL@.
875+-- >>> printSQL $ true .== null_
877+(.==) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
878+(.==) = unsafeBinaryOp "="
881+-- | >>> printSQL $ true ./= null_
883+(./=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
884+(./=) = unsafeBinaryOp "<>"
887+-- | >>> printSQL $ true .>= null_
889+(.>=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
890+(.>=) = unsafeBinaryOp ">="
893+-- | >>> printSQL $ true .< null_
895+(.<) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
896+(.<) = unsafeBinaryOp "<"
899+-- | >>> printSQL $ true .<= null_
901+(.<=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
902+(.<=) = unsafeBinaryOp "<="
905+-- | >>> printSQL $ true .> null_
907+(.>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
908+(.>) = unsafeBinaryOp ">"
912+>>> printSQL $ true `between` (null_, false)
913+TRUE BETWEEN NULL AND FALSE
916+ :: Expression outer grp commons schemas params from (null ty)
917+ -> ( Expression outer grp commons schemas params from (null ty)
918+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
919+ -> Condition outer grp commons schemas params from
920+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
921+ <+> renderSQL x <+> "AND" <+> renderSQL y
924+>>> printSQL $ true `notBetween` (null_, false)
925+TRUE NOT BETWEEN NULL AND FALSE
928+ :: Expression outer grp commons schemas params from (null ty)
929+ -> ( Expression outer grp commons schemas params from (null ty)
930+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
931+ -> Condition outer grp commons schemas params from
932+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
933+ <+> renderSQL x <+> "AND" <+> renderSQL y
935+{- | between, after sorting the comparison values
936+>>> printSQL $ true `betweenSymmetric` (null_, false)
937+TRUE BETWEEN SYMMETRIC NULL AND FALSE
940+ :: Expression outer grp commons schemas params from (null ty)
941+ -> ( Expression outer grp commons schemas params from (null ty)
942+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
943+ -> Condition outer grp commons schemas params from
944+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
945+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
947+{- | not between, after sorting the comparison values
948+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
949+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
952+ :: Expression outer grp commons schemas params from (null ty)
953+ -> ( Expression outer grp commons schemas params from (null ty)
954+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
955+ -> Condition outer grp commons schemas params from
956+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
957+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
959+{- | not equal, treating null like an ordinary value
960+>>> printSQL $ true `isDistinctFrom` null_
961+(TRUE IS DISTINCT FROM NULL)
963+isDistinctFrom :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
964+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
966+{- | equal, treating null like an ordinary value
967+>>> printSQL $ true `isNotDistinctFrom` null_
968+(TRUE IS NOT DISTINCT FROM NULL)
970+isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ('NotNull 'PGbool)
971+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
974+>>> printSQL $ true & isTrue
977+isTrue :: null 'PGbool :--> 'NotNull 'PGbool
978+isTrue = unsafeUnaryOpR "IS TRUE"
980+{- | is false or unknown
981+>>> printSQL $ true & isNotTrue
984+isNotTrue :: null 'PGbool :--> 'NotNull 'PGbool
985+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
988+>>> printSQL $ true & isFalse
991+isFalse :: null 'PGbool :--> 'NotNull 'PGbool
992+isFalse = unsafeUnaryOpR "IS FALSE"
994+{- | is true or unknown
995+>>> printSQL $ true & isNotFalse
998+isNotFalse :: null 'PGbool :--> 'NotNull 'PGbool
999+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1002+>>> printSQL $ true & isUnknown
1005+isUnknown :: null 'PGbool :--> 'NotNull 'PGbool
1006+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1008+{- | is true or false
1009+>>> printSQL $ true & isNotUnknown
1010+(TRUE IS NOT UNKNOWN)
1012+isNotUnknown :: null 'PGbool :--> 'NotNull 'PGbool
1013+isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"
1015+-- | >>> printSQL currentDate
1017+currentDate :: Expr (null 'PGdate)
1018+currentDate = UnsafeExpression "CURRENT_DATE"
1020+-- | >>> printSQL currentTime
1022+currentTime :: Expr (null 'PGtimetz)
1023+currentTime = UnsafeExpression "CURRENT_TIME"
1025+-- | >>> printSQL currentTimestamp
1026+-- CURRENT_TIMESTAMP
1027+currentTimestamp :: Expr (null 'PGtimestamptz)
1028+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1030+-- | >>> printSQL localTime
1032+localTime :: Expr (null 'PGtime)
1033+localTime = UnsafeExpression "LOCALTIME"
1035+-- | >>> printSQL localTimestamp
1037+localTimestamp :: Expr (null 'PGtimestamp)
1038+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1040+{-----------------------------------------
1042+-----------------------------------------}
1044+escape :: Char -> String
439instance IsString
1056instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
1057+ (Expression outer grp commons schemas params from (null 'PGtext)) where
441 fromString str = UnsafeExpression $
1058 fromString str = UnsafeExpression $
442 "E\'" <> fromString (escape =<< str) <> "\'"
1059 "E\'" <> fromString (escape =<< str) <> "\'"
443instance IsString
1060instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1061+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1062+ fromString str = cast tsvector . UnsafeExpression $
446 "E\'" <> fromString (escape =<< str) <> "\'"
1063 "E\'" <> fromString (escape =<< str) <> "\'"
447instance IsString
1064instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
1065+ (Expression outer grp commons schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1066+ fromString str = cast tsquery . UnsafeExpression $
450 "E\'" <> fromString (escape =<< str) <> "\'"
1067 "E\'" <> fromString (escape =<< str) <> "\'"
452instance Semigroup
1069instance Semigroup
453− (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
1070+ (Expression outer grp commons schemas params from (null 'PGtext)) where
454 (<>) = unsafeBinaryOp "||"
1071 (<>) = unsafeBinaryOp "||"
455instance Semigroup
1072instance Semigroup
456− (Expression outer commons grp schemas params from (null 'PGjsonb)) where
457− (<>) = unsafeBinaryOp "||"
459− (Expression outer commons grp schemas params from (null 'PGtext)) where
460− (<>) = unsafeBinaryOp "||"
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1073+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
463 (<>) = unsafeBinaryOp "||"
1074 (<>) = unsafeBinaryOp "||"
465instance Monoid
1076instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
1077+ (Expression outer grp commons schemas params from (null 'PGtext)) where
467 mempty = fromString ""
1078 mempty = fromString ""
468 mappend = (<>)
1079 mappend = (<>)
469instance Monoid
1080instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1081+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
471 mempty = fromString ""
1082 mempty = fromString ""
472 mappend = (<>)
1083 mappend = (<>)
1085+-- | >>> printSQL $ lower "ARRRGGG"
1086+-- lower(E'ARRRGGG')
1087+lower :: null 'PGtext :--> null 'PGtext
1088+lower = unsafeFunction "lower"
1090+-- | >>> printSQL $ upper "eeee"
1092+upper :: null 'PGtext :--> null 'PGtext
1093+upper = unsafeFunction "upper"
1095+-- | >>> printSQL $ charLength "four"
1096+-- char_length(E'four')
1097+charLength :: null 'PGtext :--> null 'PGint4
1098+charLength = unsafeFunction "char_length"
1100+-- | The `like` expression returns true if the @string@ matches
1101+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1102+-- or underscores, then the pattern only represents the string itself;
1103+-- in that case `like` acts like the equals operator. An underscore (_)
1104+-- in pattern stands for (matches) any single character; a percent sign (%)
1105+-- matches any sequence of zero or more characters.
1107+-- >>> printSQL $ "abc" `like` "a%"
1108+-- (E'abc' LIKE E'a%')
1109+like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1110+like = unsafeBinaryOp "LIKE"
1112+-- | The key word ILIKE can be used instead of LIKE to make the
1113+-- match case-insensitive according to the active locale.
1115+-- >>> printSQL $ "abc" `ilike` "a%"
1116+-- (E'abc' ILIKE E'a%')
1117+ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1118+ilike = unsafeBinaryOp "ILIKE"
1120+{-----------------------------------------
1121+ -- json and jsonb support
1123+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1124+comments lifted directly from this page.
1126+Table 9.44: json and jsonb operators
1127+-----------------------------------------}
1129+-- | Get JSON value (object field or array element) at a key.
1131+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1132+ => Operator (null json) (null key) ('Null json)
1134+(.->) = unsafeBinaryOp "->"
1136+-- | Get JSON value (object field or array element) at a key, as text.
1138+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1139+ => Operator (null json) (null key) ('Null 'PGtext)
1141+(.->>) = unsafeBinaryOp "->>"
1143+-- | Get JSON value at a specified path.
1145+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1146+ => Operator (null json) (null path) ('Null json)
1148+(.#>) = unsafeBinaryOp "#>"
1150+-- | Get JSON value at a specified path as text.
1152+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1153+ => Operator (null json) (null path) ('Null 'PGtext)
1155+(.#>>) = unsafeBinaryOp "#>>"
1157+-- Additional jsonb operators
1159+-- | Does the left JSON value contain the right JSON path/value entries at the
1162+ :: Operator (null 'PGjsonb) (null 'PGjsonb) ('Null 'PGbool)
1164+(.@>) = unsafeBinaryOp "@>"
1166+-- | Are the left JSON path/value entries contained at the top level within the
1167+-- right JSON value?
1168+(.<@) :: Operator (null 'PGjsonb) (null 'PGjsonb) ('Null 'PGbool)
1170+(.<@) = unsafeBinaryOp "<@"
1172+-- | Does the string exist as a top-level key within the JSON value?
1173+(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ('Null 'PGbool)
1175+(.?) = unsafeBinaryOp "?"
1177+-- | Do any of these array strings exist as top-level keys?
1180+ (null ('PGvararray ('NotNull 'PGtext)))
1183+(.?|) = unsafeBinaryOp "?|"
1185+-- | Do all of these array strings exist as top-level keys?
1188+ (null ('PGvararray ('NotNull 'PGtext)))
1191+(.?&) = unsafeBinaryOp "?&"
1193+-- | Concatenate two jsonb values into a new jsonb value.
1195+ (Expression outer grp commons schemas params from (null 'PGjsonb)) where
1196+ (<>) = unsafeBinaryOp "||"
1198+-- | Delete a key or keys from a JSON object, or remove an array element.
1200+-- If the right operand is..
1202+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1203+-- are matched based on their key value.
1205+-- @ text[] @: Delete multiple key/value pairs or string elements
1206+-- from left operand. Key/value pairs are matched based on their key value.
1208+-- @ integer @: Delete the array element with specified index (Negative integers
1209+-- count from the end). Throws an error if top level container is not an array.
1211+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1212+ => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
1214+(.-.) = unsafeBinaryOp "-"
1216+-- | Delete the field or element with specified path (for JSON arrays, negative
1217+-- integers count from the end)
1219+ :: PGTextArray "(#-.)" arrayty
1220+ => Operator (null 'PGjsonb) (null arrayty)(null 'PGjsonb)
1222+(#-.) = unsafeBinaryOp "#-"
1224+{-----------------------------------------
1225+Table 9.45: JSON creation functions
1226+-----------------------------------------}
1228+-- | Literal binary JSON
1229+jsonbLit :: JSON.ToJSON x => x -> Expr (null 'PGjsonb)
1230+jsonbLit = cast jsonb . UnsafeExpression
1231+ . singleQuotedUtf8 . toStrict . JSON.encode
1234+jsonLit :: JSON.ToJSON x => x -> Expr (null 'PGjson)
1235+jsonLit = cast json . UnsafeExpression
1236+ . singleQuotedUtf8 . toStrict . JSON.encode
1238+-- | Returns the value as json. Arrays and composites are converted
1239+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1240+-- type to json, the cast function will be used to perform the conversion;
1241+-- otherwise, a scalar value is produced. For any scalar type other than a
1242+-- number, a Boolean, or a null value, the text representation will be used, in
1243+-- such a fashion that it is a valid json value.
1244+toJson :: null ty :--> null 'PGjson
1245+toJson = unsafeFunction "to_json"
1247+-- | Returns the value as jsonb. Arrays and composites are converted
1248+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1249+-- type to json, the cast function will be used to perform the conversion;
1250+-- otherwise, a scalar value is produced. For any scalar type other than a
1251+-- number, a Boolean, or a null value, the text representation will be used, in
1252+-- such a fashion that it is a valid jsonb value.
1253+toJsonb :: null ty :--> null 'PGjsonb
1254+toJsonb = unsafeFunction "to_jsonb"
1256+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1257+-- becomes a JSON array of arrays.
1259+ :: PGArray "arrayToJson" arr
1260+ => null arr :--> null 'PGjson
1261+arrayToJson = unsafeFunction "array_to_json"
1263+-- | Returns the row as a JSON object.
1264+rowToJson :: null ('PGcomposite ty) :--> null 'PGjson
1265+rowToJson = unsafeFunction "row_to_json"
1267+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1271+ => NP (Expression outer grp commons schemas params from) elems
1272+ -> Expression outer grp commons schemas params from (null 'PGjson)
1273+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1275+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1276+-- variadic argument list.
1279+ => NP (Expression outer grp commons schemas params from) elems
1280+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1281+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1284+ :: SOP.SListI elems
1285+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1288+ (`appEndo` []) . hcfoldMap (Proxy :: SOP.Proxy SOP.Top)
1289+ (\(col `As` name) -> Endo $ \xs ->
1290+ renderAliasString name : renderSQL col : xs)
1292+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1293+ renderAliasString = singleQuotedText . fromString . symbolVal
1295+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1296+-- argument list. The elements of the argument list must alternate between text
1299+ :: SOP.SListI elems
1300+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1301+ -> Expression outer grp commons schemas params from (null 'PGjson)
1303+ = unsafeFunction "json_build_object"
1306+ . unsafeRowFunction
1308+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1309+-- variadic argument list. The elements of the argument list must alternate
1310+-- between text and values.
1312+ :: SOP.SListI elems
1313+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1314+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1316+ = unsafeFunction "jsonb_build_object"
1319+ . unsafeRowFunction
1321+-- | Builds a JSON object out of a text array. The array must have either
1322+-- exactly one dimension with an even number of members, in which case they are
1323+-- taken as alternating key/value pairs, or two dimensions such that each inner
1324+-- array has exactly two elements, which are taken as a key/value pair.
1326+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1327+ => null arr :--> null 'PGjson
1328+jsonObject = unsafeFunction "json_object"
1330+-- | Builds a binary JSON object out of a text array. The array must have either
1331+-- exactly one dimension with an even number of members, in which case they are
1332+-- taken as alternating key/value pairs, or two dimensions such that each inner
1333+-- array has exactly two elements, which are taken as a key/value pair.
1335+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1336+ => null arr :--> null 'PGjsonb
1337+jsonbObject = unsafeFunction "jsonb_object"
1339+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1340+-- keys and one for values, that are zipped pairwise to create a JSON object.
1342+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1343+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1344+ => Expression outer grp commons schemas params from (null keysArray)
1345+ -> Expression outer grp commons schemas params from (null valuesArray)
1346+ -> Expression outer grp commons schemas params from (null 'PGjson)
1347+jsonZipObject ks vs =
1348+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1350+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1351+-- keys and one for values, that are zipped pairwise to create a binary JSON
1354+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1355+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1356+ => Expression outer grp commons schemas params from (null keysArray)
1357+ -> Expression outer grp commons schemas params from (null valuesArray)
1358+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1359+jsonbZipObject ks vs =
1360+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1362+{-----------------------------------------
1363+Table 9.46: JSON processing functions
1364+-----------------------------------------}
1366+-- | Returns the number of elements in the outermost JSON array.
1367+jsonArrayLength :: null 'PGjson :--> null 'PGint4
1368+jsonArrayLength = unsafeFunction "json_array_length"
1370+-- | Returns the number of elements in the outermost binary JSON array.
1371+jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
1372+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1374+-- | Returns JSON value pointed to by the given path (equivalent to #>
1378+ => Expression outer grp commons schemas params from (null 'PGjson)
1379+ -> NP (Expression outer grp commons schemas params from) elems
1380+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1381+jsonExtractPath x xs =
1382+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1384+-- | Returns JSON value pointed to by the given path (equivalent to #>
1388+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1389+ -> NP (Expression outer grp commons schemas params from) elems
1390+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1391+jsonbExtractPath x xs =
1392+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1394+-- | Returns JSON value pointed to by the given path (equivalent to #>
1395+-- operator), as text.
1396+jsonExtractPathAsText
1398+ => Expression outer grp commons schemas params from (null 'PGjson)
1399+ -> NP (Expression outer grp commons schemas params from) elems
1400+ -> Expression outer grp commons schemas params from (null 'PGjson)
1401+jsonExtractPathAsText x xs =
1402+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1404+-- | Returns JSON value pointed to by the given path (equivalent to #>
1405+-- operator), as text.
1406+jsonbExtractPathAsText
1408+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1409+ -> NP (Expression outer grp commons schemas params from) elems
1410+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1411+jsonbExtractPathAsText x xs =
1412+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1414+-- | Returns the type of the outermost JSON value as a text string. Possible
1415+-- types are object, array, string, number, boolean, and null.
1416+jsonTypeof :: null 'PGjson :--> null 'PGtext
1417+jsonTypeof = unsafeFunction "json_typeof"
1419+-- | Returns the type of the outermost binary JSON value as a text string.
1420+-- Possible types are object, array, string, number, boolean, and null.
1421+jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
1422+jsonbTypeof = unsafeFunction "jsonb_typeof"
1424+-- | Returns its argument with all object fields that have null values omitted.
1425+-- Other null values are untouched.
1426+jsonStripNulls :: null 'PGjson :--> null 'PGjson
1427+jsonStripNulls = unsafeFunction "json_strip_nulls"
1429+-- | Returns its argument with all object fields that have null values omitted.
1430+-- Other null values are untouched.
1431+jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
1432+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1434+-- | @ jsonbSet target path new_value create_missing @
1436+-- Returns target with the section designated by path replaced by new_value,
1437+-- or with new_value added if create_missing is true ( default is true) and the
1438+-- item designated by path does not exist. As with the path orientated
1439+-- operators, negative integers that appear in path count from the end of JSON
1442+ :: PGTextArray "jsonbSet" arr
1443+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1444+ -> Expression outer grp commons schemas params from (null arr)
1445+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1446+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1447+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1448+jsonbSet tgt path val createMissing = case createMissing of
1449+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1450+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1452+-- | @ jsonbInsert target path new_value insert_after @
1454+-- Returns target with new_value inserted. If target section designated by
1455+-- path is in a JSONB array, new_value will be inserted before target or after
1456+-- if insert_after is true (default is false). If target section designated by
1457+-- path is in JSONB object, new_value will be inserted only if target does not
1458+-- exist. As with the path orientated operators, negative integers that appear
1459+-- in path count from the end of JSON arrays.
1461+ :: PGTextArray "jsonbInsert" arr
1462+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1463+ -> Expression outer grp commons schemas params from (null arr)
1464+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1465+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1466+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1467+jsonbInsert tgt path val insertAfter = case insertAfter of
1468+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1469+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1471+-- | Returns its argument as indented JSON text.
1472+jsonbPretty :: null 'PGjsonb :--> null 'PGtext
1473+jsonbPretty = unsafeFunction "jsonb_pretty"
1475+(@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)
1476+(@@) = unsafeBinaryOp "@@"
1478+(.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1479+(.&) = unsafeBinaryOp "&&"
1481+(.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1482+(.|) = unsafeBinaryOp "||"
1484+(.!) :: null 'PGtsquery :--> null 'PGtsquery
1485+(.!) = unsafeUnaryOpL "!!"
1487+(<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1488+(<->) = unsafeBinaryOp "<->"
1491+ :: null ('PGvararray ('NotNull 'PGtext))
1492+ :--> null 'PGtsvector
1493+arrayToTSvector = unsafeFunction "array_to_tsvector"
1495+tsvectorLength :: null 'PGtsvector :--> null 'PGint4
1496+tsvectorLength = unsafeFunction "length"
1498+numnode :: null 'PGtsquery :--> null 'PGint4
1499+numnode = unsafeFunction "numnode"
1502+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1503+plainToTSquery = unsafeFunctionHet "plainto_tsquery"
1506+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1507+phraseToTSquery = unsafeFunctionHet "phraseto_tsquery"
1510+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1511+websearchToTSquery = unsafeFunctionHet "websearch_to_tsquery"
1513+queryTree :: null 'PGtsquery :--> null 'PGtext
1514+queryTree = unsafeFunction "query_tree"
1517+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1518+toTSquery = unsafeFunctionHet "to_tsquery"
1521+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1522+ => FunctionHet '[null 'PGtext, null ty] (null 'PGtsquery)
1523+toTSvector = unsafeFunctionHet "to_tsvector"
1525+{-----------------------------------------
1527+-----------------------------------------}
1530+`Aggregate` functions compute a single result from a set of input values.
1531+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1532+as `WindowFunction`s.
1534+class Aggregate expr1 expr2 aggr
1535+ | aggr -> expr1, aggr -> expr2 where
1537+ -- | A special aggregation that does not require an input
1541+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1542+ -- expression = countStar
1543+ -- in printSQL expression
1546+ countStar :: aggr ('NotNull 'PGint8)
1550+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1551+ -- expression = count (All #col)
1552+ -- in printSQL expression
1554+ -- count(ALL "col")
1558+ -> aggr ('NotNull 'PGint8)
1562+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1563+ -- expression = sum_ (Distinct #col)
1564+ -- in printSQL expression
1566+ -- sum(DISTINCT "col")
1570+ -> aggr ('NotNull ty)
1572+ -- | input values, including nulls, concatenated into an array
1575+ -> aggr ('Null ('PGvararray ty))
1577+ -- | aggregates values as a JSON array
1580+ -> aggr ('Null 'PGjson)
1582+ -- | aggregates values as a JSON array
1585+ -> aggr ('Null 'PGjsonb)
1588+ the bitwise AND of all non-null input values, or null if none
1591+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1592+ expression = bitAnd (Distinct #col)
1593+ in printSQL expression
1595+ bit_and(DISTINCT "col")
1598+ :: int `In` PGIntegral
1599+ => expr1 (null int)
1600+ -- ^ what to aggregate
1601+ -> aggr ('Null int)
1604+ the bitwise OR of all non-null input values, or null if none
1608+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1609+ expression = bitOr (All #col)
1610+ in printSQL expression
1615+ :: int `In` PGIntegral
1616+ => expr1 (null int)
1617+ -- ^ what to aggregate
1618+ -> aggr ('Null int)
1621+ true if all input values are true, otherwise false
1625+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1626+ winFun = boolAnd #col
1632+ :: expr1 (null 'PGbool)
1633+ -- ^ what to aggregate
1634+ -> aggr ('Null 'PGbool)
1637+ true if at least one input value is true, otherwise false
1641+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1642+ expression = boolOr (All #col)
1643+ in printSQL expression
1648+ :: expr1(null 'PGbool)
1649+ -- ^ what to aggregate
1650+ -> aggr ('Null 'PGbool)
1653+ equivalent to `boolAnd`
1657+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1658+ expression = every (Distinct #col)
1659+ in printSQL expression
1661+ every(DISTINCT "col")
1664+ :: expr1 (null 'PGbool)
1665+ -- ^ what to aggregate
1666+ -> aggr ('Null 'PGbool)
1668+ {- |maximum value of expression across all input values-}
1671+ -- ^ what to maximize
1674+ -- | minimum value of expression across all input values
1677+ -- ^ what to minimize
1680+ -- | the average (arithmetic mean) of all input values
1683+ -- ^ what to average
1684+ -> aggr ('Null (PGAvg ty))
1686+ {- | correlation coefficient
1689+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1690+ expression = corr (All (#y :*: #x))
1691+ in printSQL expression
1696+ :: expr2 (null 'PGfloat8)
1697+ -> aggr ('Null 'PGfloat8)
1699+ {- | population covariance
1702+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1703+ expression = covarPop (All (#y :*: #x))
1704+ in printSQL expression
1706+ covar_pop(ALL "y", "x")
1709+ :: expr2 (null 'PGfloat8)
1710+ -> aggr ('Null 'PGfloat8)
1712+ {- | sample covariance
1715+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1716+ winFun = covarSamp (#y :*: #x)
1719+ covar_samp("y", "x")
1722+ :: expr2 (null 'PGfloat8)
1723+ -> aggr ('Null 'PGfloat8)
1725+ {- | average of the independent variable (sum(X)/N)
1728+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1729+ expression = regrAvgX (All (#y :*: #x))
1730+ in printSQL expression
1732+ regr_avgx(ALL "y", "x")
1735+ :: expr2 (null 'PGfloat8)
1736+ -> aggr ('Null 'PGfloat8)
1738+ {- | average of the dependent variable (sum(Y)/N)
1741+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1742+ winFun = regrAvgY (#y :*: #x)
1745+ regr_avgy("y", "x")
1748+ :: expr2 (null 'PGfloat8)
1749+ -> aggr ('Null 'PGfloat8)
1751+ {- | number of input rows in which both expressions are nonnull
1754+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1755+ winFun = regrCount (#y :*: #x)
1758+ regr_count("y", "x")
1761+ :: expr2 (null 'PGfloat8)
1762+ -> aggr ('Null 'PGint8)
1764+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1767+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1768+ expression = regrIntercept (All (#y :*: #x))
1769+ in printSQL expression
1771+ regr_intercept(ALL "y", "x")
1774+ :: expr2 (null 'PGfloat8)
1775+ -> aggr ('Null 'PGfloat8)
1777+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1779+ :: expr2 (null 'PGfloat8)
1780+ -> aggr ('Null 'PGfloat8)
1782+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1783+ -- determined by the (X, Y) pairs
1785+ :: expr2 (null 'PGfloat8)
1786+ -> aggr ('Null 'PGfloat8)
1788+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1789+ -- (“sum of squares” of the independent variable)
1791+ :: expr2 (null 'PGfloat8)
1792+ -> aggr ('Null 'PGfloat8)
1794+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1795+ -- (“sum of products” of independent times dependent variable)
1797+ :: expr2 (null 'PGfloat8)
1798+ -> aggr ('Null 'PGfloat8)
1800+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1801+ -- (“sum of squares” of the dependent variable)
1803+ :: expr2 (null 'PGfloat8)
1804+ -> aggr ('Null 'PGfloat8)
1806+ -- | historical alias for `stddevSamp`
1809+ -> aggr ('Null (PGAvg ty))
1811+ -- | population standard deviation of the input values
1814+ -> aggr ('Null (PGAvg ty))
1816+ -- | sample standard deviation of the input values
1819+ -> aggr ('Null (PGAvg ty))
1821+ -- | historical alias for `varSamp`
1824+ -> aggr ('Null (PGAvg ty))
1826+ -- | population variance of the input values
1827+ -- (square of the population standard deviation)
1830+ -> aggr ('Null (PGAvg ty))
1832+ -- | sample variance of the input values
1833+ -- (square of the sample standard deviation)
1836+ -> aggr ('Null (PGAvg ty))
1839+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1840+`All` invokes the aggregate once for each input row.
1841+`Distinct` invokes the aggregate once for each distinct value of the expression
1842+(or distinct set of values, for multiple expressions) found in the input
1844+data Distinction expr ty
1846+ | Distinct (expr ty)
1847+ deriving (GHC.Generic,Show,Eq,Ord)
1848+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1849+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1851+ All x -> "ALL" <+> renderSQL x
1852+ Distinct x -> "DISTINCT" <+> renderSQL x
1855+ ( Expression outer grp commons schemas params from
1857+ Expression outer grp commons schemas params from) xty ) where
1860+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1861+ Distinct (x :*: x') ->
1862+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1865+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1866+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1867+ (Expression outer ('Grouped bys) commons schemas params from) where
1868+ countStar = UnsafeExpression "count(*)"
1869+ count = unsafeAggregate1 "count"
1870+ sum_ = unsafeAggregate1 "sum"
1871+ arrayAgg = unsafeAggregate1 "array_agg"
1872+ jsonAgg = unsafeAggregate1 "json_agg"
1873+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1874+ bitAnd = unsafeAggregate1 "bit_and"
1875+ bitOr = unsafeAggregate1 "bit_or"
1876+ boolAnd = unsafeAggregate1 "bool_and"
1877+ boolOr = unsafeAggregate1 "bool_or"
1878+ every = unsafeAggregate1 "every"
1879+ max_ = unsafeAggregate1 "max"
1880+ min_ = unsafeAggregate1 "min"
1881+ avg = unsafeAggregate1 "avg"
1882+ corr = unsafeAggregate2 "corr"
1883+ covarPop = unsafeAggregate2 "covar_pop"
1884+ covarSamp = unsafeAggregate2 "covar_samp"
1885+ regrAvgX = unsafeAggregate2 "regr_avgx"
1886+ regrAvgY = unsafeAggregate2 "regr_avgy"
1887+ regrCount = unsafeAggregate2 "regr_count"
1888+ regrIntercept = unsafeAggregate2 "regr_intercept"
1889+ regrR2 = unsafeAggregate2 "regr_r2"
1890+ regrSlope = unsafeAggregate2 "regr_slope"
1891+ regrSxx = unsafeAggregate2 "regr_sxx"
1892+ regrSxy = unsafeAggregate2 "regr_sxy"
1893+ regrSyy = unsafeAggregate2 "regr_syy"
1894+ stddev = unsafeAggregate1 "stddev"
1895+ stddevPop = unsafeAggregate1 "stddev_pop"
1896+ stddevSamp = unsafeAggregate1 "stddev_samp"
1897+ variance = unsafeAggregate1 "variance"
1898+ varPop = unsafeAggregate1 "var_pop"
1899+ varSamp = unsafeAggregate1 "var_samp"
1901+ (Expression outer grp commons schemas params from)
1902+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1903+ (WindowFunction outer grp commons schemas params from) where
1904+ countStar = UnsafeWindowFunction "count(*)"
1905+ count = unsafeWindowFunction1 "count"
1906+ sum_ = unsafeWindowFunction1 "sum"
1907+ arrayAgg = unsafeWindowFunction1 "array_agg"
1908+ jsonAgg = unsafeWindowFunction1 "json_agg"
1909+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1910+ bitAnd = unsafeWindowFunction1 "bit_and"
1911+ bitOr = unsafeWindowFunction1 "bit_or"
1912+ boolAnd = unsafeWindowFunction1 "bool_and"
1913+ boolOr = unsafeWindowFunction1 "bool_or"
1914+ every = unsafeWindowFunction1 "every"
1915+ max_ = unsafeWindowFunction1 "max"
1916+ min_ = unsafeWindowFunction1 "min"
1917+ avg = unsafeWindowFunction1 "avg"
1918+ corr = unsafeWindowFunction2 "corr"
1919+ covarPop = unsafeWindowFunction2 "covar_pop"
1920+ covarSamp = unsafeWindowFunction2 "covar_samp"
1921+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1922+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1923+ regrCount = unsafeWindowFunction2 "regr_count"
1924+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1925+ regrR2 = unsafeWindowFunction2 "regr_r2"
1926+ regrSlope = unsafeWindowFunction2 "regr_slope"
1927+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1928+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1929+ regrSyy = unsafeWindowFunction2 "regr_syy"
1930+ stddev = unsafeWindowFunction1 "stddev"
1931+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1932+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1933+ variance = unsafeWindowFunction1 "variance"
1934+ varPop = unsafeWindowFunction1 "var_pop"
1935+ varSamp = unsafeWindowFunction1 "var_samp"
1937+-- | escape hatch to define aggregate functions
1939+ :: ByteString -- ^ aggregate function
1940+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1941+ -> Expression outer ('Grouped bys) commons schemas params from yty
1942+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1943+ [fun, "(", renderSQL x, ")"]
1945+-- | escape hatch to define aggregate binary functions
1947+ :: ByteString -- ^ aggregate function
1948+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1949+ -> Expression outer ('Grouped bys) commons schemas params from yty
1950+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1951+ [fun, "(", renderSQL xx, ")"]
1953+-- | A type family that calculates `PGAvg` type of a `PGType`.
1954+type family PGAvg ty where
1955+ PGAvg 'PGint2 = 'PGnumeric
1956+ PGAvg 'PGint4 = 'PGnumeric
1957+ PGAvg 'PGint8 = 'PGnumeric
1958+ PGAvg 'PGnumeric = 'PGnumeric
1959+ PGAvg 'PGfloat4 = 'PGfloat8
1960+ PGAvg 'PGfloat8 = 'PGfloat8
1961+ PGAvg 'PGinterval = 'PGinterval
1962+ PGAvg pg = TypeError
1963+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1965+{-----------------------------------------
1967+-----------------------------------------}
1969+-- | `TypeExpression`s are used in `cast`s and
1970+-- `Squeal.PostgreSQL.Definition.createTable` commands.
1971+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1972+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1973+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1974+instance RenderSQL (TypeExpression schemas ty) where
1975+ renderSQL = renderTypeExpression
1977+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1979+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1980+ => QualifiedAlias sch td
1981+ -> TypeExpression schemas (null ty)
1982+typedef = UnsafeTypeExpression . renderSQL
1984+-- | The composite type corresponding to a `Table` definition can be expressed
1987+ :: (Has sch schemas schema, Has tab schema ('Table table))
1988+ => QualifiedAlias sch tab
1989+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
1990+typetable = UnsafeTypeExpression . renderSQL
1992+-- | The composite type corresponding to a `View` definition can be expressed
1995+ :: (Has sch schemas schema, Has vw schema ('View view))
1996+ => QualifiedAlias sch vw
1997+ -> TypeExpression schemas (null ('PGcomposite view))
1998+typeview = UnsafeTypeExpression . renderSQL
2000+-- | logical Boolean (true/false)
2001+bool :: TypeExpression schemas (null 'PGbool)
2002+bool = UnsafeTypeExpression "bool"
2003+-- | signed two-byte integer
2004+int2, smallint :: TypeExpression schemas (null 'PGint2)
2005+int2 = UnsafeTypeExpression "int2"
2006+smallint = UnsafeTypeExpression "smallint"
2007+-- | signed four-byte integer
2008+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2009+int4 = UnsafeTypeExpression "int4"
2010+int = UnsafeTypeExpression "int"
2011+integer = UnsafeTypeExpression "integer"
2012+-- | signed eight-byte integer
2013+int8, bigint :: TypeExpression schemas (null 'PGint8)
2014+int8 = UnsafeTypeExpression "int8"
2015+bigint = UnsafeTypeExpression "bigint"
2016+-- | arbitrary precision numeric type
2017+numeric :: TypeExpression schemas (null 'PGnumeric)
2018+numeric = UnsafeTypeExpression "numeric"
2019+-- | single precision floating-point number (4 bytes)
2020+float4, real :: TypeExpression schemas (null 'PGfloat4)
2021+float4 = UnsafeTypeExpression "float4"
2022+real = UnsafeTypeExpression "real"
2023+-- | double precision floating-point number (8 bytes)
2024+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2025+float8 = UnsafeTypeExpression "float8"
2026+doublePrecision = UnsafeTypeExpression "double precision"
2027+-- | currency amount
2028+money :: TypeExpression schema (null 'PGmoney)
2029+money = UnsafeTypeExpression "money"
2030+-- | variable-length character string
2031+text :: TypeExpression schemas (null 'PGtext)
2032+text = UnsafeTypeExpression "text"
2033+-- | fixed-length character string
2035+ :: forall n schemas null. (KnownNat n, 1 <= n)
2036+ => TypeExpression schemas (null ('PGchar n))
2037+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2038+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2039+-- | variable-length character string
2040+varchar, characterVarying
2041+ :: forall n schemas null. (KnownNat n, 1 <= n)
2042+ => TypeExpression schemas (null ('PGvarchar n))
2043+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2044+characterVarying = UnsafeTypeExpression $
2045+ "character varying(" <> renderNat @n <> ")"
2046+-- | binary data ("byte array")
2047+bytea :: TypeExpression schemas (null 'PGbytea)
2048+bytea = UnsafeTypeExpression "bytea"
2049+-- | date and time (no time zone)
2050+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2051+timestamp = UnsafeTypeExpression "timestamp"
2052+-- | date and time, including time zone
2053+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2054+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2055+-- | calendar date (year, month, day)
2056+date :: TypeExpression schemas (null 'PGdate)
2057+date = UnsafeTypeExpression "date"
2058+-- | time of day (no time zone)
2059+time :: TypeExpression schemas (null 'PGtime)
2060+time = UnsafeTypeExpression "time"
2061+-- | time of day, including time zone
2062+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2063+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2065+interval :: TypeExpression schemas (null 'PGinterval)
2066+interval = UnsafeTypeExpression "interval"
2067+-- | universally unique identifier
2068+uuid :: TypeExpression schemas (null 'PGuuid)
2069+uuid = UnsafeTypeExpression "uuid"
2070+-- | IPv4 or IPv6 host address
2071+inet :: TypeExpression schemas (null 'PGinet)
2072+inet = UnsafeTypeExpression "inet"
2073+-- | textual JSON data
2074+json :: TypeExpression schemas (null 'PGjson)
2075+json = UnsafeTypeExpression "json"
2076+-- | binary JSON data, decomposed
2077+jsonb :: TypeExpression schemas (null 'PGjsonb)
2078+jsonb = UnsafeTypeExpression "jsonb"
2079+-- | variable length array
2081+ :: TypeExpression schemas pg
2082+ -> TypeExpression schemas (null ('PGvararray pg))
2083+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2084+-- | fixed length array
2086+-- >>> renderSQL (fixarray @'[2] json)
2089+ :: forall dims schemas null pg. SOP.All KnownNat dims
2090+ => TypeExpression schemas pg
2091+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2092+fixarray ty = UnsafeTypeExpression $
2093+ renderSQL ty <> renderDims @dims
2095+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2099+ . ByteString.intercalate "]["
2101+ $ hcmap (SOP.Proxy @KnownNat)
2102+ (K . fromString . show . natVal)
2103+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2104+tsvector :: TypeExpression schemas (null 'PGtsvector)
2105+tsvector = UnsafeTypeExpression "tsvector"
2106+tsquery :: TypeExpression schemas (null 'PGtsquery)
2107+tsquery = UnsafeTypeExpression "tsquery"
2109+-- | `pgtype` is a demoted version of a `PGType`
2110+class PGTyped schemas (ty :: NullityType) where
2111+ pgtype :: TypeExpression schemas ty
2112+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2113+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2114+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2115+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2116+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2117+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2118+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2119+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2120+instance PGTyped schemas (null 'PGtext) where pgtype = text
2121+instance (KnownNat n, 1 <= n)
2122+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2123+instance (KnownNat n, 1 <= n)
2124+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2125+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2126+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2127+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2128+instance PGTyped schemas (null 'PGdate) where pgtype = date
2129+instance PGTyped schemas (null 'PGtime) where pgtype = time
2130+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2131+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2132+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2133+instance PGTyped schemas (null 'PGjson) where pgtype = json
2134+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2135+instance PGTyped schemas ty
2136+ => PGTyped schemas (null ('PGvararray ty)) where
2137+ pgtype = vararray (pgtype @schemas @ty)
2138+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2139+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2140+ pgtype = fixarray @dims (pgtype @schemas @ty)
2141+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2142+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2144+{-----------------------------------------
2146+-----------------------------------------}
2148+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2149+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2150+-- set the sort direction of a `NotNull` result
2151+-- column to ascending or descending. Ascending order puts smaller values
2152+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2153+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2154+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2155+-- determine whether nulls appear before or after non-null values in the sort
2156+-- ordering of a `Null` result column.
2157+data SortExpression outer grp commons schemas params from where
2159+ :: Expression outer grp commons schemas params from ('NotNull ty)
2160+ -> SortExpression outer grp commons schemas params from
2162+ :: Expression outer grp commons schemas params from ('NotNull ty)
2163+ -> SortExpression outer grp commons schemas params from
2165+ :: Expression outer grp commons schemas params from ('Null ty)
2166+ -> SortExpression outer grp commons schemas params from
2168+ :: Expression outer grp commons schemas params from ('Null ty)
2169+ -> SortExpression outer grp commons schemas params from
2171+ :: Expression outer grp commons schemas params from ('Null ty)
2172+ -> SortExpression outer grp commons schemas params from
2174+ :: Expression outer grp commons schemas params from ('Null ty)
2175+ -> SortExpression outer grp commons schemas params from
2176+deriving instance Show (SortExpression outer grp commons schemas params from)
2179+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2180+to be sorted according to the specified `SortExpression`(s).
2181+If two rows are equal according to the leftmost expression,
2182+they are compared according to the next expression and so on.
2183+If they are equal according to all specified expressions,
2184+they are returned in an implementation-dependent order.
2186+You can also control the order in which rows are processed by window functions
2187+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2189+class OrderBy expr where
2191+ :: [SortExpression outer grp commons schemas params from]
2192+ -> expr outer grp commons schemas params from
2193+ -> expr outer grp commons schemas params from
2195+-- | Render a `SortExpression`.
2196+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2198+ Asc expression -> renderSQL expression <+> "ASC"
2199+ Desc expression -> renderSQL expression <+> "DESC"
2200+ AscNullsFirst expression -> renderSQL expression
2201+ <+> "ASC NULLS FIRST"
2202+ DescNullsFirst expression -> renderSQL expression
2203+ <+> "DESC NULLS FIRST"
2204+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2205+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2207+-- | A `WindowDefinition` is a set of table rows that are somehow related
2208+-- to the current row
2209+data WindowDefinition outer grp commons schemas params from where
2212+ => NP (Expression outer grp commons schemas params from) bys
2213+ -> [SortExpression outer grp commons schemas params from]
2214+ -> WindowDefinition outer grp commons schemas params from
2216+instance OrderBy WindowDefinition where
2217+ orderBy sortsR (WindowDefinition parts sortsL)
2218+ = WindowDefinition parts (sortsL ++ sortsR)
2220+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2221+ renderSQL (WindowDefinition part ord) =
2222+ renderPartitionByClause part <> renderOrderByClause ord
2224+ renderPartitionByClause = \case
2226+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2227+ renderOrderByClause = \case
2229+ srts -> " ORDER" <+> "BY"
2230+ <+> commaSeparated (renderSQL <$> srts)
2233+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2234+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2235+For each row, the window function is computed across the rows that fall into
2236+the same partition as the current row.
2240+ => NP (Expression outer grp commons schemas params from) bys
2241+ -> WindowDefinition outer grp commons schemas params from
2242+partitionBy bys = WindowDefinition bys []
2245+A window function performs a calculation across a set of table rows
2246+that are somehow related to the current row. This is comparable to the type
2247+of calculation that can be done with an aggregate function.
2248+However, window functions do not cause rows to become grouped into a single
2249+output row like non-window aggregate calls would.
2250+Instead, the rows retain their separate identities.
2251+Behind the scenes, the window function is able to access more than
2252+just the current row of the query result.
2254+newtype WindowFunction
2255+ (outer :: FromType)
2257+ (commons :: FromType)
2258+ (schemas :: SchemasType)
2259+ (params :: [NullityType])
2261+ (ty :: NullityType)
2262+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2263+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2265+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2266+ renderSQL = renderWindowFunction
2268+unsafeWindowFunction1
2270+ -> Expression outer grp commons schemas params from ty0
2271+ -> WindowFunction outer grp commons schemas params from ty1
2272+unsafeWindowFunction1 fun x
2273+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2275+unsafeWindowFunction2
2277+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2278+ -> WindowFunction outer grp commons schemas params from ty1
2279+unsafeWindowFunction2 fun (x :*: x')
2280+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2282+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2286+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2287+rank = UnsafeWindowFunction "rank()"
2289+{- | number of the current row within its partition, counting from 1
2290+>>> printSQL rowNumber
2293+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2294+rowNumber = UnsafeWindowFunction "row_number()"
2296+{- | rank of the current row without gaps; this function counts peer groups
2297+>>> printSQL denseRank
2300+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2301+denseRank = UnsafeWindowFunction "dense_rank()"
2303+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2304+>>> printSQL percentRank
2307+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2308+percentRank = UnsafeWindowFunction "percent_rank()"
2310+{- | cumulative distribution: (number of partition rows
2311+preceding or peer with current row) / total partition rows
2312+>>> printSQL cumeDist
2315+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2316+cumeDist = UnsafeWindowFunction "cume_dist()"
2318+{- | integer ranging from 1 to the argument value,
2319+dividing the partition as equally as possible
2322+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2324+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2325+ntile = unsafeWindowFunction1 "ntile"
2327+{- | returns value evaluated at the row that is offset rows before the current
2328+row within the partition; if there is no such row, instead return default
2329+(which must be of the same type as value). Both offset and default are
2330+evaluated with respect to the current row.
2333+ :: Expression outer grp commons schemas params from ty
2335+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2337+ -> Expression outer grp commons schemas params from ty
2339+ -> WindowFunction outer grp commons schemas params from ty
2340+lag value offset def = UnsafeWindowFunction $ "lag"
2342+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2344+{- | returns value evaluated at the row that is offset rows after the current
2345+row within the partition; if there is no such row, instead return default
2346+(which must be of the same type as value). Both offset and default are
2347+evaluated with respect to the current row.
2350+ :: Expression outer grp commons schemas params from ty
2352+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2354+ -> Expression outer grp commons schemas params from ty
2356+ -> WindowFunction outer grp commons schemas params from ty
2357+lead value offset def = UnsafeWindowFunction $ "lag"
2359+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2361+{- | returns value evaluated at the row that is the
2362+first row of the window frame
2365+ :: Expression outer grp commons schemas params from ty
2367+ -> WindowFunction outer grp commons schemas params from ty
2368+firstValue = unsafeWindowFunction1 "first_value"
2370+{- | returns value evaluated at the row that is the
2371+last row of the window frame
2374+ :: Expression outer grp commons schemas params from ty
2376+ -> WindowFunction outer grp commons schemas params from ty
2377+lastValue = unsafeWindowFunction1 "last_value"
2379+{- | returns value evaluated at the row that is the nth
2380+row of the window frame (counting from 1); null if no such row
2383+ :: Expression outer grp commons schemas params from (null ty)
2385+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2387+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2388+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2389+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])
2392+Create date from year, month and day fields
2394+>>> printSQL (makeDate (1984 :* 7 *: 3))
2395+make_date(1984, 7, 3)
2397+makeDate :: FunctionHet
2398+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2400+makeDate = unsafeFunctionHet "make_date"
2403+Create time from hour, minute and seconds fields
2405+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2406+make_time(8, 15, 23.5)
2408+makeTime :: FunctionHet
2409+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2411+makeTime = unsafeFunctionHet "make_time"
2414+Create timestamp from year, month, day, hour, minute and seconds fields
2416+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2417+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2419+makeTimestamp :: FunctionHet
2420+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2421+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2422+ ( null 'PGtimestamp )
2423+makeTimestamp = unsafeFunctionHet "make_timestamp"
2426+Create timestamp with time zone from
2427+year, month, day, hour, minute and seconds fields;
2428+the current time zone is used
2430+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2431+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2433+makeTimestamptz :: FunctionHet
2434+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2435+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2436+ ( null 'PGtimestamptz )
2437+makeTimestamptz = unsafeFunctionHet "make_timestamptz"
2440+Affine space operations on time types.
2442+class TimeOp time diff | time -> diff where
2444+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2445+ (make_date(1984, 7, 3) + 365)
2447+ (!+) :: Operator (null time) (null diff) (null time)
2448+ (!+) = unsafeBinaryOp "+"
2450+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2451+ (365 + make_date(1984, 7, 3))
2453+ (+!) :: Operator (null diff) (null time) (null time)
2454+ (+!) = unsafeBinaryOp "+"
2456+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2457+ (make_date(1984, 7, 3) - 365)
2459+ (!-) :: Operator (null time) (null diff) (null time)
2460+ (!-) = unsafeBinaryOp "-"
2462+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2463+ (make_date(1984, 7, 3) - CURRENT_DATE)
2465+ (!-!) :: Operator (null time) (null time) (null diff)
2466+ (!-!) = unsafeBinaryOp "-"
2467+instance TimeOp 'PGtimestamp 'PGinterval
2468+instance TimeOp 'PGtimestamptz 'PGinterval
2469+instance TimeOp 'PGtime 'PGinterval
2470+instance TimeOp 'PGtimetz 'PGinterval
2471+instance TimeOp 'PGinterval 'PGinterval
2472+instance TimeOp 'PGdate 'PGint4