@@ -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
@@ -34,213 +35,365 @@ module Squeal.PostgreSQL.Expression
34 ( -- * Expression
35 ( -- * Expression
35 Expression (..)
36 Expression (..)
45 , Operator
38 , Operator
46− , OperatorDB
39+ , (:-->)
47− , unsafeBinaryOp
40+ , HasParameter (parameter)
48− , binaryOp
41+ , param
49− , FunctionVar
42+ -- ** Null
50− , unsafeFunctionVar
43+ , null_
51− , type (--->)
44+ , notNull
52− , FunctionNDB
45+ , coalesce
53− , unsafeFunctionN
46+ , fromNull
54− , functionN
47+ , isNull
55 , PGSubset (..)
57 , PGSubset (..)
56− , PGIntersect (..)
58+ -- ** Functions
62+ , unsafeVariadicFunction
91+ , notBetweenSymmetric
118+ -- *** Json and Jsonb operators
123+ -- *** Jsonb operators
148+ , jsonExtractPathAsText
149+ , jsonbExtractPathAsText
168+ , websearchToTSquery
183+ -- * Window Functions
184+ , WindowDefinition (..)
186+ , WindowFunction (..)
199+ , SortExpression (..)
202+ , TypeExpression (..)
228+ , timestampWithTimeZone
57 -- * Re-export
241 -- * Re-export
63import Control.Category
248import Control.Category
64import Control.DeepSeq
249import Control.DeepSeq
65import Data.ByteString (ByteString)
250import Data.ByteString (ByteString)
251+import Data.ByteString.Lazy (toStrict)
66import Data.Function ((&))
252import Data.Function ((&))
67import Data.Semigroup hiding (All)
253import Data.Semigroup hiding (All)
254+import qualified Data.Aeson as JSON
68import Data.String
255import Data.String
69import Generics.SOP hiding (All, from)
257import Generics.SOP hiding (All, from)
258+import GHC.Generics ((:*:) (..))
70import GHC.OverloadedLabels
259import GHC.OverloadedLabels
71import GHC.TypeLits
260import GHC.TypeLits
72import Numeric
261import Numeric
73import Prelude hiding (id, (.))
262import Prelude hiding (id, (.))
264+import qualified Data.ByteString as ByteString
75import qualified GHC.Generics as GHC
265import qualified GHC.Generics as GHC
266+import qualified Generics.SOP as SOP
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79import Squeal.PostgreSQL.Render
268import Squeal.PostgreSQL.Render
80import Squeal.PostgreSQL.Schema
269import Squeal.PostgreSQL.Schema
83−-- >>> import Squeal.PostgreSQL
85{-----------------------------------------
271{-----------------------------------------
86column expressions
272column expressions
87-----------------------------------------}
273-----------------------------------------}
89{- | `Expression`s are used in a variety of contexts,
275{- | `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,
276+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
277as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93`Squeal.PostgreSQL.Manipulation.update`,
278`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
279+or in search `Condition`s in a number of commands.
96The expression syntax allows the calculation of
281The expression syntax allows the calculation of
97values from primitive expression using arithmetic, logical,
282values from primitive expression using arithmetic, logical,
98and other operations.
283and 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
285newtype Expression
115 (outer :: FromType)
286 (outer :: FromType)
116− (commons :: FromType)
117 (grp :: Grouping)
287 (grp :: Grouping)
288+ (commons :: FromType)
118 (schemas :: SchemasType)
289 (schemas :: SchemasType)
119 (params :: [NullityType])
290 (params :: [NullityType])
120 (from :: FromType)
291 (from :: FromType)
121 (ty :: NullityType)
292 (ty :: NullityType)
122 = UnsafeExpression { renderExpression :: ByteString }
293 = UnsafeExpression { renderExpression :: ByteString }
123 deriving (GHC.Generic,Show,Eq,Ord,NFData)
294 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
295+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125 renderSQL = renderExpression
296 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
298type Expr x
134− = forall outer commons grp schemas params from
299+ = forall outer grp commons schemas params from
135− . Expression outer commons grp schemas params from x
300+ . Expression outer grp commons schemas params from x
136− -- ^ cannot reference aliases
138−-- | A @RankNType@ for binary operators.
139type Operator x1 x2 y
302type Operator x1 x2 y
140− = forall outer commons grp schemas params from
303+ = forall outer grp commons schemas params from
141− . Expression outer commons grp schemas params from x1
304+ . Expression outer grp commons schemas params from x1
143− -> Expression outer commons grp schemas params from x2
305+ -> Expression outer grp commons schemas params from x2
145− -> Expression outer commons grp schemas params from y
306+ -> Expression outer grp commons schemas params from y
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
309+ = forall outer grp commons schemas params from
150− . Expression outer commons grp schemas params from x1
310+ . Expression outer grp commons schemas params from x
152− -> Expression outer commons grp schemas params from x2
311+ -> Expression outer grp commons schemas params from y
153− -- ^ right input
312+
313+type FunctionHet xs y
154− -> Expression outer commons grp schemas params from y
314+ = forall outer grp commons schemas params from
155− -- ^ output
315+ . NP (Expression outer grp commons schemas params from) xs
156−
316+ -> Expression outer grp commons schemas params from y
157−-- | A @RankNType@ for functions with a single argument.
317+
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
318+type FunctionHom x y
163− = forall outer commons grp schemas params from
319+ = forall outer grp commons schemas params from
164− . Expression outer commons grp schemas params from x
320+ . [Expression outer grp commons schemas params from x]
166− -> Expression outer commons grp schemas params from y
321+ -> 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
322+ -> Expression outer grp commons schemas params from y
175−
324+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
325+unsafeFunctionHom fun xs x = UnsafeExpression $ fun <> parenthesized
213 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
326 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
328+{- | A `HasParameter` constraint is used to indicate a value that is
329+supplied externally to a SQL statement.
330+`Squeal.PostgreSQL.PQ.manipulateParams`,
331+`Squeal.PostgreSQL.PQ.queryParams` and
332+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
333+separately from the SQL command string, in which case `param`s are used to
334+refer to the out-of-line data values.
336+class KnownNat n => HasParameter
338+ (params :: [NullityType])
340+ | n params -> ty where
341+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
343+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
344+ -- >>> printSQL expr
347+ :: TypeExpression schemas ty
348+ -> Expression outer grp commons schemas params from ty
349+ parameter ty = UnsafeExpression $ parenthesized $
350+ "$" <> renderNat @n <+> "::"
352+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
353+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
354+ => HasParameter n (ty' : params) ty
356+-- | `param` takes a `Nat` using type application and for basic types,
357+-- infers a `TypeExpression`.
359+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
363+ :: forall n outer commons schemas params from grp ty
364+ . (PGTyped schemas ty, HasParameter n params ty)
365+ => Expression outer grp commons schemas params from ty -- ^ param
366+param = parameter @n (pgtype @schemas)
215instance (HasUnique tab (Join outer from) row, Has col row ty)
368instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
369+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
370 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
371instance (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
372+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220 fromLabel = fromLabel @col :* Nil
373 fromLabel = fromLabel @col :* Nil
221instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
374instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222 => IsLabel col
375 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
376+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224 fromLabel = fromLabel @col `As` Alias
377 fromLabel = fromLabel @col `As` Alias
225instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
378instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226 => IsLabel col
379 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
380+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228 fromLabel = fromLabel @col :* Nil
381 fromLabel = fromLabel @col :* Nil
230instance (Has tab (Join outer from) row, Has col row ty)
383instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
384+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232 tab ! col = UnsafeExpression $
385 tab ! col = UnsafeExpression $
233 renderSQL tab <> "." <> renderSQL col
386 renderSQL tab <> "." <> renderSQL col
234instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])
387instance (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
388+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236 tab ! col = tab ! col :* Nil
389 tab ! col = tab ! col :* Nil
237instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
390instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238 => IsQualified tab col
391 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
392+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240 tab ! col = tab ! col `As` col
393 tab ! col = tab ! col `As` col
241instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
394instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242 => IsQualified tab col
395 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
396+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244 tab ! col = tab ! col :* Nil
397 tab ! col = tab ! col :* Nil
@@ -248,7 +401,7 @@ instance
248 , Has col row ty
401 , Has col row ty
249 , GroupedBy tab col bys
402 , GroupedBy tab col bys
250 ) => IsLabel col
403 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
404+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
405 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
254 ( HasUnique tab (Join outer from) row
407 ( HasUnique tab (Join outer from) row
@@ -256,7 +409,7 @@ instance
256 , GroupedBy tab col bys
409 , GroupedBy tab col bys
257 , tys ~ '[ty]
410 , tys ~ '[ty]
258 ) => IsLabel col
411 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
412+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260 fromLabel = fromLabel @col :* Nil
413 fromLabel = fromLabel @col :* Nil
262 ( HasUnique tab (Join outer from) row
415 ( HasUnique tab (Join outer from) row
@@ -264,7 +417,7 @@ instance
264 , GroupedBy tab col bys
417 , GroupedBy tab col bys
265 , column ~ (col ::: ty)
418 , column ~ (col ::: ty)
266 ) => IsLabel col
419 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
420+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268 fromLabel = fromLabel @col `As` Alias
421 fromLabel = fromLabel @col `As` Alias
270 ( HasUnique tab (Join outer from) row
423 ( HasUnique tab (Join outer from) row
@@ -272,7 +425,7 @@ instance
272 , GroupedBy tab col bys
425 , GroupedBy tab col bys
273 , columns ~ '[col ::: ty]
426 , columns ~ '[col ::: ty]
274 ) => IsLabel col
427 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
428+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276 fromLabel = fromLabel @col :* Nil
429 fromLabel = fromLabel @col :* Nil
@@ -280,7 +433,7 @@ instance
280 , Has col row ty
433 , Has col row ty
281 , GroupedBy tab col bys
434 , GroupedBy tab col bys
282 ) => IsQualified tab col
435 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
436+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284 tab ! col = UnsafeExpression $
437 tab ! col = UnsafeExpression $
285 renderSQL tab <> "." <> renderSQL col
438 renderSQL tab <> "." <> renderSQL col
@@ -289,7 +442,7 @@ instance
289 , GroupedBy tab col bys
442 , GroupedBy tab col bys
290 , tys ~ '[ty]
443 , tys ~ '[ty]
291 ) => IsQualified tab col
444 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
445+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293 tab ! col = tab ! col :* Nil
446 tab ! col = tab ! col :* Nil
295 ( Has tab (Join outer from) row
448 ( Has tab (Join outer from) row
@@ -297,7 +450,7 @@ instance
297 , GroupedBy tab col bys
450 , GroupedBy tab col bys
298 , column ~ (col ::: ty)
451 , column ~ (col ::: ty)
299 ) => IsQualified tab col
452 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
453+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301 tab ! col = tab ! col `As` col
454 tab ! col = tab ! col `As` col
303 ( Has tab (Join outer from) row
456 ( Has tab (Join outer from) row
@@ -305,78 +458,223 @@ instance
305 , GroupedBy tab col bys
458 , GroupedBy tab col bys
306 , columns ~ '[col ::: ty]
459 , columns ~ '[col ::: ty]
307 ) => IsQualified tab col
460 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
461+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309 tab ! col = tab ! col :* Nil
462 tab ! col = tab ! col :* Nil
464+-- | analagous to `Nothing`
466+-- >>> printSQL null_
468+null_ :: Expr ('Null ty)
469+null_ = UnsafeExpression "NULL"
471+-- | analagous to `Just`
473+-- >>> printSQL $ notNull true
475+notNull :: 'NotNull ty :--> 'Null ty
476+notNull = UnsafeExpression . renderSQL
478+-- | return the leftmost value which is not NULL
480+-- >>> printSQL $ coalesce [null_, true] false
481+-- COALESCE(NULL, TRUE, FALSE)
483+ :: [Expression outer grp commons schemas params from ('Null ty)]
484+ -- ^ @NULL@s may be present
485+ -> Expression outer grp commons schemas params from ('NotNull ty)
486+ -- ^ @NULL@ is absent
487+ -> Expression outer grp commons schemas params from ('NotNull ty)
488+coalesce nullxs notNullx = UnsafeExpression $
489+ "COALESCE" <> parenthesized (commaSeparated
490+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
492+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
494+-- >>> printSQL $ fromNull true null_
495+-- COALESCE(NULL, TRUE)
497+ :: Expression outer grp commons schemas params from ('NotNull ty)
498+ -- ^ what to convert @NULL@ to
499+ -> Expression outer grp commons schemas params from ('Null ty)
500+ -> Expression outer grp commons schemas params from ('NotNull ty)
501+fromNull notNullx nullx = coalesce [nullx] notNullx
503+-- | >>> printSQL $ null_ & isNull
506+ :: Expression outer grp commons schemas params from ('Null ty)
507+ -- ^ possibly @NULL@
508+ -> Condition outer grp commons schemas params from
509+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
511+-- | >>> printSQL $ null_ & isNotNull
514+ :: Expression outer grp commons schemas params from ('Null ty)
515+ -- ^ possibly @NULL@
516+ -> Condition outer grp commons schemas params from
517+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
519+-- | analagous to `maybe` using @IS NULL@
521+-- >>> printSQL $ matchNull true not_ null_
522+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
524+ :: Expression outer grp commons schemas params from (nullty)
525+ -- ^ what to convert @NULL@ to
526+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
527+ -> Expression outer grp commons schemas params from (nullty) )
528+ -- ^ function to perform when @NULL@ is absent
529+ -> Expression outer grp commons schemas params from ('Null ty)
530+ -> Expression outer grp commons schemas params from (nullty)
531+matchNull y f x = ifThenElse (isNull x) y
532+ (f (UnsafeExpression (renderSQL x)))
534+{-| right inverse to `fromNull`, if its arguments are equal then
535+`nullIf` gives @NULL@.
537+>>> :set -XTypeApplications -XDataKinds
538+>>> let expr = nullIf false (param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
540+NULL IF (FALSE, ($1 :: bool))
543+ :: Expression outer grp commons schemas params from ('NotNull ty)
544+ -- ^ @NULL@ is absent
545+ -> Expression outer grp commons schemas params from ('NotNull ty)
546+ -- ^ @NULL@ is absent
547+ -> Expression outer grp commons schemas params from ('Null ty)
548+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
549+ (renderSQL x <> ", " <> renderSQL y)
551+-- | >>> printSQL $ array [null_, false, true]
552+-- ARRAY[NULL, FALSE, TRUE]
554+ :: [Expression outer grp commons schemas params from ty]
556+ -> Expression outer grp commons schemas params from (null ('PGvararray ty))
557+array xs = UnsafeExpression $
558+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
560+-- | >>> printSQL $ cardinality (array [null_, false, true])
561+-- cardinality(ARRAY[NULL, FALSE, TRUE])
562+cardinality :: null ('PGvararray ty) :--> null 'PGint8
563+cardinality = unsafeFunction "cardinality"
565+-- | >>> printSQL $ array [null_, false, true] & index 2
566+-- (ARRAY[NULL, FALSE, TRUE])[2]
568+ :: Word64 -- ^ index
569+ -> null ('PGvararray ty) :--> NullifyType ty
570+index n expr = UnsafeExpression $
571+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
311instance (KnownSymbol label, label `In` labels) => IsPGlabel label
573instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
574+ (Expression outer grp commons schemas params from (null ('PGenum labels))) where
313 label = UnsafeExpression $ renderSQL (PGlabel @label)
575 label = UnsafeExpression $ renderSQL (PGlabel @label)
577+-- | A row constructor is an expression that builds a row value
578+-- (also called a composite value) using values for its member fields.
581+-- type Complex = 'PGcomposite
582+-- '[ "real" ::: 'NotNull 'PGfloat8
583+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
586+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
591+ => NP (Aliased (Expression outer grp commons schemas params from)) row
592+ -- ^ zero or more expressions for the row field values
593+ -> Expression outer grp commons schemas params from (null ('PGcomposite row))
594+row exprs = UnsafeExpression $ "ROW" <> parenthesized
595+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
598+-- type Complex = 'PGcomposite
599+-- '[ "real" ::: 'NotNull 'PGfloat8
600+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
601+-- type Schema = '["complex" ::: 'Typedef Complex]
604+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
605+-- >>> printSQL $ i & field #complex #imaginary
606+-- (ROW(0, 1)::"complex")."imaginary"
608+ :: ( Has sch schemas schema
609+ , Has tydef schema ('Typedef ('PGcomposite row))
611+ => QualifiedAlias sch tydef -- ^ row type
612+ -> Alias field -- ^ field name
613+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
614+ -> Expression outer grp commons schemas params from ty
615+field td fld expr = UnsafeExpression $
616+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
617+ <> "." <> renderSQL fld
620+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
621+ (<>) = unsafeBinaryOp "||"
624+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
628+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
630+-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
631+greatest :: FunctionHom ty ty
632+greatest = unsafeFunctionHom "GREATEST"
634+-- | >>> printSQL $ least [null_] currentTimestamp
635+-- LEAST(NULL, CURRENT_TIMESTAMP)
636+least :: FunctionHom ty ty
637+least = unsafeFunctionHom "LEAST"
315-- | >>> printSQL $ unsafeBinaryOp "OR" true false
639-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316-- (TRUE OR FALSE)
640-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
641+unsafeBinaryOp :: ByteString {- ^ operator -} -> Operator ty0 ty1 ty2
318unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
642unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319 renderSQL x <+> op <+> renderSQL y
643 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
645+-- | >>> printSQL $ unsafeUnaryOpL "NOT" true
329-- (NOT TRUE)
646-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
647+unsafeUnaryOpL :: ByteString {- ^ operator -} -> x :--> y
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
648+unsafeUnaryOpL op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
333−leftOp
650+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
651+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
653-- | >>> printSQL $ unsafeFunction "f" true
353-- f(TRUE)
654-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
655+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355unsafeFunction fun x = UnsafeExpression $
656unsafeFunction fun x = UnsafeExpression $
356 fun <> parenthesized (renderSQL x)
657 fun <> parenthesized (renderSQL x)
358−function
659+unsafeFunctionHet
359− :: (Has sch schemas schema, Has fun schema ('Function ('[x] :=> 'Returns y)))
660+ :: SListI xs
360− => QualifiedAlias sch fun
661+ => ByteString {- ^ function -}
361− -> FunctionDB schemas x y
662+ -> 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 $
663+unsafeFunctionHet fun xs = UnsafeExpression $
368 fun <> parenthesized (renderCommaSeparated renderSQL xs)
664 fun <> parenthesized (renderCommaSeparated renderSQL xs)
370−functionN
666+-- | Helper for defining variadic functions.
371− :: ( Has sch schemas schema
667+unsafeVariadicFunction
372− , Has fun schema ('Function (xs :=> 'Returns y))
373− , SListI xs )
668+ :: SListI elems
374− => QualifiedAlias sch fun
669+ => ByteString
375− -> FunctionNDB schemas xs y
670+ -- ^ function
376−functionN = unsafeFunctionN . renderSQL
671+ -> NP (Expression outer grp commons schemas params from) elems
672+ -> Expression outer grp commons schemas params from ret
673+unsafeVariadicFunction fun x = UnsafeExpression $
674+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
378instance ty `In` PGNum
676instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
677+ => Num (Expression outer grp commons schemas params from (null ty)) where
380 (+) = unsafeBinaryOp "+"
678 (+) = unsafeBinaryOp "+"
381 (-) = unsafeBinaryOp "-"
679 (-) = unsafeBinaryOp "-"
382 (*) = unsafeBinaryOp "*"
680 (*) = unsafeBinaryOp "*"
@@ -388,7 +686,7 @@ instance ty `In` PGNum
390instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
688instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
689+ (Expression outer grp commons schemas params from (null ty)) where
392 (/) = unsafeBinaryOp "/"
690 (/) = unsafeBinaryOp "/"
393 fromRational
691 fromRational
394 = UnsafeExpression
692 = UnsafeExpression
@@ -398,7 +696,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398 . fromRat @Double
696 . fromRat @Double
400instance (ty `In` PGNum, ty `In` PGFloating) => Floating
698instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
699+ (Expression outer grp commons schemas params from (null ty)) where
402 pi = UnsafeExpression "pi()"
700 pi = UnsafeExpression "pi()"
403 exp = unsafeFunction "exp"
701 exp = unsafeFunction "exp"
404 log = unsafeFunction "ln"
702 log = unsafeFunction "ln"
@@ -419,54 +717,1791 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419 acosh x = log (x + sqrt (x*x - 1))
717 acosh x = log (x + sqrt (x*x - 1))
420 atanh x = log ((1 + x) / (1 - x)) / 2
718 atanh x = log ((1 + x) / (1 - x)) / 2
422−-- | Contained by operators
720+-- | >>> :{
423−class PGSubset ty where
721+-- let
424− (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
722+-- expression :: Expr (null 'PGfloat4)
425− (@>) = unsafeBinaryOp "@>"
723+-- expression = atan2_ (pi *: 2)
426− (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
724+-- in printSQL expression
427− (<@) = unsafeBinaryOp "<@"
725+-- :}
428−instance PGSubset 'PGjsonb
726+-- atan2(pi(), 2)
429−instance PGSubset 'PGtsquery
727+atan2_
430−instance PGSubset ('PGvararray ty)
728+ :: float `In` PGFloating
431−instance PGSubset ('PGrange ty)
729+ => FunctionHet '[ null float, null float] (null float)
730+atan2_ = unsafeFunctionHet "atan2"
732+-- When a `cast` is applied to an `Expression` of a known type, it
733+-- represents a run-time type conversion. The cast will succeed only if a
734+-- suitable type conversion operation has been defined.
736+-- | >>> printSQL $ true & cast int4
739+ :: TypeExpression schemas ty1
740+ -- ^ type to cast as
741+ -> Expression outer grp commons schemas params from ty0
742+ -- ^ value to convert
743+ -> Expression outer grp commons schemas params from ty1
744+cast ty x = UnsafeExpression $ parenthesized $
745+ renderSQL x <+> "::" <+> renderSQL ty
747+-- | integer division, truncates the result
751+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
752+-- expression = 5 `quot_` 2
753+-- in printSQL expression
757+ :: int `In` PGIntegral
758+ => Operator (null int) (null int) (null int)
759+quot_ = unsafeBinaryOp "/"
761+-- | remainder upon integer division
765+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
766+-- expression = 5 `rem_` 2
767+-- in printSQL expression
771+ :: int `In` PGIntegral
772+ => Operator (null int) (null int) (null int)
773+rem_ = unsafeBinaryOp "%"
777+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
778+-- expression = trunc pi
779+-- in printSQL expression
782+trunc :: frac `In` PGFloating => null frac :--> null frac
783+trunc = unsafeFunction "trunc"
787+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
788+-- expression = round_ pi
789+-- in printSQL expression
792+round_ :: frac `In` PGFloating => null frac :--> null frac
793+round_ = unsafeFunction "round"
797+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
798+-- expression = ceiling_ pi
799+-- in printSQL expression
802+ceiling_ :: frac `In` PGFloating => null frac :--> null frac
803+ceiling_ = unsafeFunction "ceiling"
805+-- | A `Condition` is an `Expression`, which can evaluate
806+-- to `true`, `false` or `null_`. This is because SQL uses
807+-- a three valued logic.
808+type Condition outer grp commons schemas params from =
809+ Expression outer grp commons schemas params from ('Null 'PGbool)
811+-- | >>> printSQL true
813+true :: Expr (null 'PGbool)
814+true = UnsafeExpression "TRUE"
816+-- | >>> printSQL false
818+false :: Expr (null 'PGbool)
819+false = UnsafeExpression "FALSE"
821+-- | >>> printSQL $ not_ true
823+not_ :: null 'PGbool :--> null 'PGbool
824+not_ = unsafeUnaryOpL "NOT"
826+-- | >>> printSQL $ true .&& false
828+(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
830+(.&&) = unsafeBinaryOp "AND"
832+-- | >>> printSQL $ true .|| false
834+(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
836+(.||) = unsafeBinaryOp "OR"
840+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
841+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
842+-- in printSQL expression
844+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
846+ :: [ ( Condition outer grp commons schemas params from
847+ , Expression outer grp commons schemas params from ty
849+ -- ^ whens and thens
850+ -> Expression outer grp commons schemas params from ty
852+ -> Expression outer grp commons schemas params from ty
853+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
857+ [ " WHEN ", renderSQL when_
858+ , " THEN ", renderSQL then_
860+ | (when_,then_) <- whenThens
862+ , " ELSE ", renderSQL else_
868+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
869+-- expression = ifThenElse true 1 0
870+-- in printSQL expression
872+-- CASE WHEN TRUE THEN 1 ELSE 0 END
874+ :: Condition outer grp commons schemas params from
875+ -> Expression outer grp commons schemas params from ty -- ^ then
876+ -> Expression outer grp commons schemas params from ty -- ^ else
877+ -> Expression outer grp commons schemas params from ty
878+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
880+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
881+-- will produce @NULL@s if one of their arguments is @NULL@.
883+-- >>> printSQL $ true .== null_
885+(.==) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
886+(.==) = unsafeBinaryOp "="
889+-- | >>> printSQL $ true ./= null_
891+(./=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
892+(./=) = unsafeBinaryOp "<>"
895+-- | >>> printSQL $ true .>= null_
897+(.>=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
898+(.>=) = unsafeBinaryOp ">="
901+-- | >>> printSQL $ true .< null_
903+(.<) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
904+(.<) = unsafeBinaryOp "<"
907+-- | >>> printSQL $ true .<= null_
909+(.<=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
910+(.<=) = unsafeBinaryOp "<="
913+-- | >>> printSQL $ true .> null_
915+(.>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
916+(.>) = unsafeBinaryOp ">"
920+>>> printSQL $ true `between` (null_, false)
921+TRUE BETWEEN NULL AND FALSE
924+ :: Expression outer grp commons schemas params from (null ty)
925+ -> ( Expression outer grp commons schemas params from (null ty)
926+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
927+ -> Condition outer grp commons schemas params from
928+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
929+ <+> renderSQL x <+> "AND" <+> renderSQL y
932+>>> printSQL $ true `notBetween` (null_, false)
933+TRUE NOT BETWEEN NULL AND FALSE
936+ :: Expression outer grp commons schemas params from (null ty)
937+ -> ( Expression outer grp commons schemas params from (null ty)
938+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
939+ -> Condition outer grp commons schemas params from
940+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
941+ <+> renderSQL x <+> "AND" <+> renderSQL y
943+{- | between, after sorting the comparison values
944+>>> printSQL $ true `betweenSymmetric` (null_, false)
945+TRUE BETWEEN SYMMETRIC NULL AND FALSE
948+ :: Expression outer grp commons schemas params from (null ty)
949+ -> ( Expression outer grp commons schemas params from (null ty)
950+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
951+ -> Condition outer grp commons schemas params from
952+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
953+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
433−class PGIntersect ty where
955+{- | not between, after sorting the comparison values
956+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
957+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
960+ :: Expression outer grp commons schemas params from (null ty)
961+ -> ( Expression outer grp commons schemas params from (null ty)
962+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
963+ -> Condition outer grp commons schemas params from
964+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
965+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
967+{- | not equal, treating null like an ordinary value
968+>>> printSQL $ true `isDistinctFrom` null_
969+(TRUE IS DISTINCT FROM NULL)
434− (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
971+isDistinctFrom :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
972+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
974+{- | equal, treating null like an ordinary value
975+>>> printSQL $ true `isNotDistinctFrom` null_
976+(TRUE IS NOT DISTINCT FROM NULL)
978+isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ('NotNull 'PGbool)
435− (@&&) = unsafeBinaryOp "&&"
979+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
436−instance PGIntersect ('PGvararray ty)
980+
437−instance PGIntersect ('PGrange ty)
981+{- | is true
982+>>> printSQL $ true & isTrue
985+isTrue :: null 'PGbool :--> 'NotNull 'PGbool
986+isTrue = unsafeUnaryOpR "IS TRUE"
988+{- | is false or unknown
989+>>> printSQL $ true & isNotTrue
992+isNotTrue :: null 'PGbool :--> 'NotNull 'PGbool
993+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
996+>>> printSQL $ true & isFalse
999+isFalse :: null 'PGbool :--> 'NotNull 'PGbool
1000+isFalse = unsafeUnaryOpR "IS FALSE"
1002+{- | is true or unknown
1003+>>> printSQL $ true & isNotFalse
1006+isNotFalse :: null 'PGbool :--> 'NotNull 'PGbool
1007+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1010+>>> printSQL $ true & isUnknown
1013+isUnknown :: null 'PGbool :--> 'NotNull 'PGbool
1014+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1016+{- | is true or false
1017+>>> printSQL $ true & isNotUnknown
1018+(TRUE IS NOT UNKNOWN)
1020+isNotUnknown :: null 'PGbool :--> 'NotNull 'PGbool
1021+isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"
1023+-- | >>> printSQL currentDate
1025+currentDate :: Expr (null 'PGdate)
1026+currentDate = UnsafeExpression "CURRENT_DATE"
1028+-- | >>> printSQL currentTime
1030+currentTime :: Expr (null 'PGtimetz)
1031+currentTime = UnsafeExpression "CURRENT_TIME"
1033+-- | >>> printSQL currentTimestamp
1034+-- CURRENT_TIMESTAMP
1035+currentTimestamp :: Expr (null 'PGtimestamptz)
1036+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1038+-- | >>> printSQL localTime
1040+localTime :: Expr (null 'PGtime)
1041+localTime = UnsafeExpression "LOCALTIME"
1043+-- | >>> printSQL localTimestamp
1045+localTimestamp :: Expr (null 'PGtimestamp)
1046+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1048+{-----------------------------------------
1050+-----------------------------------------}
1052+escape :: Char -> String
439instance IsString
1064instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
1065+ (Expression outer grp commons schemas params from (null 'PGtext)) where
441 fromString str = UnsafeExpression $
1066 fromString str = UnsafeExpression $
442 "E\'" <> fromString (escape =<< str) <> "\'"
1067 "E\'" <> fromString (escape =<< str) <> "\'"
443instance IsString
1068instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1069+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1070+ fromString str = cast tsvector . UnsafeExpression $
446 "E\'" <> fromString (escape =<< str) <> "\'"
1071 "E\'" <> fromString (escape =<< str) <> "\'"
447instance IsString
1072instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
1073+ (Expression outer grp commons schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1074+ fromString str = cast tsquery . UnsafeExpression $
450 "E\'" <> fromString (escape =<< str) <> "\'"
1075 "E\'" <> fromString (escape =<< str) <> "\'"
452instance Semigroup
1077instance Semigroup
453− (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
454− (<>) = unsafeBinaryOp "||"
456− (Expression outer commons grp schemas params from (null 'PGjsonb)) where
457− (<>) = unsafeBinaryOp "||"
459− (Expression outer commons grp schemas params from (null 'PGtext)) where
1078+ (Expression outer grp commons schemas params from (null 'PGtext)) where
460 (<>) = unsafeBinaryOp "||"
1079 (<>) = unsafeBinaryOp "||"
461instance Semigroup
1080instance Semigroup
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1081+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
463 (<>) = unsafeBinaryOp "||"
1082 (<>) = unsafeBinaryOp "||"
465instance Monoid
1084instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
1085+ (Expression outer grp commons schemas params from (null 'PGtext)) where
467 mempty = fromString ""
1086 mempty = fromString ""
468 mappend = (<>)
1087 mappend = (<>)
469instance Monoid
1088instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1089+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
471 mempty = fromString ""
1090 mempty = fromString ""
472 mappend = (<>)
1091 mappend = (<>)
1093+-- | >>> printSQL $ lower "ARRRGGG"
1094+-- lower(E'ARRRGGG')
1095+lower :: null 'PGtext :--> null 'PGtext
1096+lower = unsafeFunction "lower"
1098+-- | >>> printSQL $ upper "eeee"
1100+upper :: null 'PGtext :--> null 'PGtext
1101+upper = unsafeFunction "upper"
1103+-- | >>> printSQL $ charLength "four"
1104+-- char_length(E'four')
1105+charLength :: null 'PGtext :--> null 'PGint4
1106+charLength = unsafeFunction "char_length"
1108+-- | The `like` expression returns true if the @string@ matches
1109+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1110+-- or underscores, then the pattern only represents the string itself;
1111+-- in that case `like` acts like the equals operator. An underscore (_)
1112+-- in pattern stands for (matches) any single character; a percent sign (%)
1113+-- matches any sequence of zero or more characters.
1115+-- >>> printSQL $ "abc" `like` "a%"
1116+-- (E'abc' LIKE E'a%')
1117+like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1118+like = unsafeBinaryOp "LIKE"
1120+-- | The key word ILIKE can be used instead of LIKE to make the
1121+-- match case-insensitive according to the active locale.
1123+-- >>> printSQL $ "abc" `ilike` "a%"
1124+-- (E'abc' ILIKE E'a%')
1125+ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1126+ilike = unsafeBinaryOp "ILIKE"
1128+{-----------------------------------------
1129+ -- json and jsonb support
1131+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1132+comments lifted directly from this page.
1134+Table 9.44: json and jsonb operators
1135+-----------------------------------------}
1137+-- | Get JSON value (object field or array element) at a key.
1139+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1140+ => Operator (null json) (null key) ('Null json)
1142+(.->) = unsafeBinaryOp "->"
1144+-- | Get JSON value (object field or array element) at a key, as text.
1146+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1147+ => Operator (null json) (null key) ('Null 'PGtext)
1149+(.->>) = unsafeBinaryOp "->>"
1151+-- | Get JSON value at a specified path.
1153+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1154+ => Operator (null json) (null path) ('Null json)
1156+(.#>) = unsafeBinaryOp "#>"
1158+-- | Get JSON value at a specified path as text.
1160+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1161+ => Operator (null json) (null path) ('Null 'PGtext)
1163+(.#>>) = unsafeBinaryOp "#>>"
1165+-- Additional jsonb operators
1167+class PGSubset container where
1168+ (@>) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1169+ (@>) = unsafeBinaryOp "@>"
1170+ (<@) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1171+ (<@) = unsafeBinaryOp "<@"
1172+instance PGSubset 'PGjsonb
1173+instance PGSubset 'PGtsquery
1174+instance PGSubset ('PGvararray ty)
1176+-- | Does the string exist as a top-level key within the JSON value?
1177+(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ('Null 'PGbool)
1179+(.?) = unsafeBinaryOp "?"
1181+-- | Do any of these array strings exist as top-level keys?
1184+ (null ('PGvararray ('NotNull 'PGtext)))
1187+(.?|) = unsafeBinaryOp "?|"
1189+-- | Do all of these array strings exist as top-level keys?
1192+ (null ('PGvararray ('NotNull 'PGtext)))
1195+(.?&) = unsafeBinaryOp "?&"
1197+-- | Concatenate two jsonb values into a new jsonb value.
1199+ (Expression outer grp commons schemas params from (null 'PGjsonb)) where
1200+ (<>) = unsafeBinaryOp "||"
1202+-- | Delete a key or keys from a JSON object, or remove an array element.
1204+-- If the right operand is..
1206+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1207+-- are matched based on their key value.
1209+-- @ text[] @: Delete multiple key/value pairs or string elements
1210+-- from left operand. Key/value pairs are matched based on their key value.
1212+-- @ integer @: Delete the array element with specified index (Negative integers
1213+-- count from the end). Throws an error if top level container is not an array.
1215+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1216+ => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
1218+(.-.) = unsafeBinaryOp "-"
1220+-- | Delete the field or element with specified path (for JSON arrays, negative
1221+-- integers count from the end)
1223+ :: PGTextArray "(#-.)" arrayty
1224+ => Operator (null 'PGjsonb) (null arrayty)(null 'PGjsonb)
1226+(#-.) = unsafeBinaryOp "#-"
1228+{-----------------------------------------
1229+Table 9.45: JSON creation functions
1230+-----------------------------------------}
1232+-- | Literal binary JSON
1233+jsonbLit :: JSON.ToJSON x => x -> Expr (null 'PGjsonb)
1234+jsonbLit = cast jsonb . UnsafeExpression
1235+ . singleQuotedUtf8 . toStrict . JSON.encode
1238+jsonLit :: JSON.ToJSON x => x -> Expr (null 'PGjson)
1239+jsonLit = cast json . UnsafeExpression
1240+ . singleQuotedUtf8 . toStrict . JSON.encode
1242+-- | Returns the value as json. Arrays and composites are converted
1243+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1244+-- type to json, the cast function will be used to perform the conversion;
1245+-- otherwise, a scalar value is produced. For any scalar type other than a
1246+-- number, a Boolean, or a null value, the text representation will be used, in
1247+-- such a fashion that it is a valid json value.
1248+toJson :: null ty :--> null 'PGjson
1249+toJson = unsafeFunction "to_json"
1251+-- | Returns the value as jsonb. Arrays and composites are converted
1252+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1253+-- type to json, the cast function will be used to perform the conversion;
1254+-- otherwise, a scalar value is produced. For any scalar type other than a
1255+-- number, a Boolean, or a null value, the text representation will be used, in
1256+-- such a fashion that it is a valid jsonb value.
1257+toJsonb :: null ty :--> null 'PGjsonb
1258+toJsonb = unsafeFunction "to_jsonb"
1260+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1261+-- becomes a JSON array of arrays.
1263+ :: PGArray "arrayToJson" arr
1264+ => null arr :--> null 'PGjson
1265+arrayToJson = unsafeFunction "array_to_json"
1267+-- | Returns the row as a JSON object.
1268+rowToJson :: null ('PGcomposite ty) :--> null 'PGjson
1269+rowToJson = unsafeFunction "row_to_json"
1271+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1275+ => NP (Expression outer grp commons schemas params from) elems
1276+ -> Expression outer grp commons schemas params from (null 'PGjson)
1277+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1279+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1280+-- variadic argument list.
1283+ => NP (Expression outer grp commons schemas params from) elems
1284+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1285+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1288+ :: SOP.SListI elems
1289+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1292+ (`appEndo` []) . hcfoldMap (Proxy :: SOP.Proxy SOP.Top)
1293+ (\(col `As` name) -> Endo $ \xs ->
1294+ renderAliasString name : renderSQL col : xs)
1296+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1297+ renderAliasString = singleQuotedText . fromString . symbolVal
1299+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1300+-- argument list. The elements of the argument list must alternate between text
1303+ :: SOP.SListI elems
1304+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1305+ -> Expression outer grp commons schemas params from (null 'PGjson)
1307+ = unsafeFunction "json_build_object"
1310+ . unsafeRowFunction
1312+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1313+-- variadic argument list. The elements of the argument list must alternate
1314+-- between text and values.
1316+ :: SOP.SListI elems
1317+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1318+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1320+ = unsafeFunction "jsonb_build_object"
1323+ . unsafeRowFunction
1325+-- | Builds a JSON object out of a text array. The array must have either
1326+-- exactly one dimension with an even number of members, in which case they are
1327+-- taken as alternating key/value pairs, or two dimensions such that each inner
1328+-- array has exactly two elements, which are taken as a key/value pair.
1330+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1331+ => null arr :--> null 'PGjson
1332+jsonObject = unsafeFunction "json_object"
1334+-- | Builds a binary JSON object out of a text array. The array must have either
1335+-- exactly one dimension with an even number of members, in which case they are
1336+-- taken as alternating key/value pairs, or two dimensions such that each inner
1337+-- array has exactly two elements, which are taken as a key/value pair.
1339+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1340+ => null arr :--> null 'PGjsonb
1341+jsonbObject = unsafeFunction "jsonb_object"
1343+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1344+-- keys and one for values, that are zipped pairwise to create a JSON object.
1346+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1347+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1348+ => Expression outer grp commons schemas params from (null keysArray)
1349+ -> Expression outer grp commons schemas params from (null valuesArray)
1350+ -> Expression outer grp commons schemas params from (null 'PGjson)
1351+jsonZipObject ks vs =
1352+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1354+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1355+-- keys and one for values, that are zipped pairwise to create a binary JSON
1358+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1359+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1360+ => Expression outer grp commons schemas params from (null keysArray)
1361+ -> Expression outer grp commons schemas params from (null valuesArray)
1362+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1363+jsonbZipObject ks vs =
1364+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1366+{-----------------------------------------
1367+Table 9.46: JSON processing functions
1368+-----------------------------------------}
1370+-- | Returns the number of elements in the outermost JSON array.
1371+jsonArrayLength :: null 'PGjson :--> null 'PGint4
1372+jsonArrayLength = unsafeFunction "json_array_length"
1374+-- | Returns the number of elements in the outermost binary JSON array.
1375+jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
1376+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1378+-- | Returns JSON value pointed to by the given path (equivalent to #>
1382+ => Expression outer grp commons schemas params from (null 'PGjson)
1383+ -> NP (Expression outer grp commons schemas params from) elems
1384+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1385+jsonExtractPath x xs =
1386+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1388+-- | Returns JSON value pointed to by the given path (equivalent to #>
1392+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1393+ -> NP (Expression outer grp commons schemas params from) elems
1394+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1395+jsonbExtractPath x xs =
1396+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1398+-- | Returns JSON value pointed to by the given path (equivalent to #>
1399+-- operator), as text.
1400+jsonExtractPathAsText
1402+ => Expression outer grp commons schemas params from (null 'PGjson)
1403+ -> NP (Expression outer grp commons schemas params from) elems
1404+ -> Expression outer grp commons schemas params from (null 'PGjson)
1405+jsonExtractPathAsText x xs =
1406+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1408+-- | Returns JSON value pointed to by the given path (equivalent to #>
1409+-- operator), as text.
1410+jsonbExtractPathAsText
1412+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1413+ -> NP (Expression outer grp commons schemas params from) elems
1414+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1415+jsonbExtractPathAsText x xs =
1416+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1418+-- | Returns the type of the outermost JSON value as a text string. Possible
1419+-- types are object, array, string, number, boolean, and null.
1420+jsonTypeof :: null 'PGjson :--> null 'PGtext
1421+jsonTypeof = unsafeFunction "json_typeof"
1423+-- | Returns the type of the outermost binary JSON value as a text string.
1424+-- Possible types are object, array, string, number, boolean, and null.
1425+jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
1426+jsonbTypeof = unsafeFunction "jsonb_typeof"
1428+-- | Returns its argument with all object fields that have null values omitted.
1429+-- Other null values are untouched.
1430+jsonStripNulls :: null 'PGjson :--> null 'PGjson
1431+jsonStripNulls = unsafeFunction "json_strip_nulls"
1433+-- | Returns its argument with all object fields that have null values omitted.
1434+-- Other null values are untouched.
1435+jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
1436+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1438+-- | @ jsonbSet target path new_value create_missing @
1440+-- Returns target with the section designated by path replaced by new_value,
1441+-- or with new_value added if create_missing is true ( default is true) and the
1442+-- item designated by path does not exist. As with the path orientated
1443+-- operators, negative integers that appear in path count from the end of JSON
1446+ :: PGTextArray "jsonbSet" arr
1447+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1448+ -> Expression outer grp commons schemas params from (null arr)
1449+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1450+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1451+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1452+jsonbSet tgt path val createMissing = case createMissing of
1453+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1454+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1456+-- | @ jsonbInsert target path new_value insert_after @
1458+-- Returns target with new_value inserted. If target section designated by
1459+-- path is in a JSONB array, new_value will be inserted before target or after
1460+-- if insert_after is true (default is false). If target section designated by
1461+-- path is in JSONB object, new_value will be inserted only if target does not
1462+-- exist. As with the path orientated operators, negative integers that appear
1463+-- in path count from the end of JSON arrays.
1465+ :: PGTextArray "jsonbInsert" arr
1466+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1467+ -> Expression outer grp commons schemas params from (null arr)
1468+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1469+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1470+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1471+jsonbInsert tgt path val insertAfter = case insertAfter of
1472+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1473+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1475+-- | Returns its argument as indented JSON text.
1476+jsonbPretty :: null 'PGjsonb :--> null 'PGtext
1477+jsonbPretty = unsafeFunction "jsonb_pretty"
1479+(@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)
1480+(@@) = unsafeBinaryOp "@@"
1482+(.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1483+(.&) = unsafeBinaryOp "&&"
1485+(.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1486+(.|) = unsafeBinaryOp "||"
1488+(.!) :: null 'PGtsquery :--> null 'PGtsquery
1489+(.!) = unsafeUnaryOpL "!!"
1491+(<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1492+(<->) = unsafeBinaryOp "<->"
1495+ :: null ('PGvararray ('NotNull 'PGtext))
1496+ :--> null 'PGtsvector
1497+arrayToTSvector = unsafeFunction "array_to_tsvector"
1499+tsvectorLength :: null 'PGtsvector :--> null 'PGint4
1500+tsvectorLength = unsafeFunction "length"
1502+numnode :: null 'PGtsquery :--> null 'PGint4
1503+numnode = unsafeFunction "numnode"
1505+plainToTSquery :: null 'PGtext :--> null 'PGtsquery
1506+plainToTSquery = unsafeFunction "plainto_tsquery"
1508+phraseToTSquery :: null 'PGtext :--> null 'PGtsquery
1509+phraseToTSquery = unsafeFunction "phraseto_tsquery"
1511+websearchToTSquery :: null 'PGtext :--> null 'PGtsquery
1512+websearchToTSquery = unsafeFunction "websearch_to_tsquery"
1514+queryTree :: null 'PGtsquery :--> null 'PGtext
1515+queryTree = unsafeFunction "query_tree"
1517+toTSquery :: null 'PGtext :--> null 'PGtsquery
1518+toTSquery = unsafeFunction "to_tsquery"
1521+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1522+ => null ty :--> null 'PGtsquery
1523+toTSvector = unsafeFunction "to_tsvector"
1526+ :: FunctionHet '[null 'PGtsvector, null ('PGchar 1)] (null 'PGtsvector)
1527+setWeight = unsafeFunctionHet "set_weight"
1529+litChar :: Char -> Expr (null ('PGchar 1))
1530+litChar chr = UnsafeExpression $
1531+ "E\'" <> fromString (escape =<< [chr]) <> "\'"
1533+strip :: null 'PGtsvector :--> null 'PGtsvector
1534+strip = unsafeFunction "strip"
1536+jsonToTSvector :: FunctionHet '[null 'PGjson, null 'PGjson] (null 'PGtsvector)
1537+jsonToTSvector = unsafeFunctionHet "json_to_tsvector"
1539+jsonbToTSvector :: FunctionHet '[null 'PGjsonb, null 'PGjsonb] (null 'PGtsvector)
1540+jsonbToTSvector = unsafeFunctionHet "jsonb_to_tsvector"
1542+tsDelete :: FunctionHet
1543+ '[null 'PGtsvector, null ('PGvararray ('NotNull 'PGtext))]
1545+tsDelete = unsafeFunctionHet "ts_delete"
1547+tsFilter :: FunctionHet
1548+ '[null 'PGtsvector, null ('PGvararray ('NotNull ('PGchar 1)))]
1550+tsFilter = unsafeFunctionHet "ts_filter"
1553+ :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1554+ => FunctionHet '[null document, null 'PGtsquery] (null 'PGtext)
1555+tsHeadline = unsafeFunctionHet "ts_headline"
1556+{-----------------------------------------
1558+-----------------------------------------}
1561+`Aggregate` functions compute a single result from a set of input values.
1562+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1563+as `WindowFunction`s.
1565+class Aggregate expr1 expr2 aggr
1566+ | aggr -> expr1, aggr -> expr2 where
1568+ -- | A special aggregation that does not require an input
1572+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1573+ -- expression = countStar
1574+ -- in printSQL expression
1577+ countStar :: aggr ('NotNull 'PGint8)
1581+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1582+ -- expression = count (All #col)
1583+ -- in printSQL expression
1585+ -- count(ALL "col")
1589+ -> aggr ('NotNull 'PGint8)
1593+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1594+ -- expression = sum_ (Distinct #col)
1595+ -- in printSQL expression
1597+ -- sum(DISTINCT "col")
1601+ -> aggr ('NotNull ty)
1603+ -- | input values, including nulls, concatenated into an array
1606+ -> aggr ('Null ('PGvararray ty))
1608+ -- | aggregates values as a JSON array
1611+ -> aggr ('Null 'PGjson)
1613+ -- | aggregates values as a JSON array
1616+ -> aggr ('Null 'PGjsonb)
1619+ the bitwise AND of all non-null input values, or null if none
1622+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1623+ expression = bitAnd (Distinct #col)
1624+ in printSQL expression
1626+ bit_and(DISTINCT "col")
1629+ :: int `In` PGIntegral
1630+ => expr1 (null int)
1631+ -- ^ what to aggregate
1632+ -> aggr ('Null int)
1635+ the bitwise OR of all non-null input values, or null if none
1639+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1640+ expression = bitOr (All #col)
1641+ in printSQL expression
1646+ :: int `In` PGIntegral
1647+ => expr1 (null int)
1648+ -- ^ what to aggregate
1649+ -> aggr ('Null int)
1652+ true if all input values are true, otherwise false
1656+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1657+ winFun = boolAnd #col
1663+ :: expr1 (null 'PGbool)
1664+ -- ^ what to aggregate
1665+ -> aggr ('Null 'PGbool)
1668+ true if at least one input value is true, otherwise false
1672+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1673+ expression = boolOr (All #col)
1674+ in printSQL expression
1679+ :: expr1(null 'PGbool)
1680+ -- ^ what to aggregate
1681+ -> aggr ('Null 'PGbool)
1684+ equivalent to `boolAnd`
1688+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1689+ expression = every (Distinct #col)
1690+ in printSQL expression
1692+ every(DISTINCT "col")
1695+ :: expr1 (null 'PGbool)
1696+ -- ^ what to aggregate
1697+ -> aggr ('Null 'PGbool)
1699+ {- |maximum value of expression across all input values-}
1702+ -- ^ what to maximize
1705+ -- | minimum value of expression across all input values
1708+ -- ^ what to minimize
1711+ -- | the average (arithmetic mean) of all input values
1714+ -- ^ what to average
1715+ -> aggr ('Null (PGAvg ty))
1717+ {- | correlation coefficient
1720+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1721+ expression = corr (All (#y :*: #x))
1722+ in printSQL expression
1727+ :: expr2 (null 'PGfloat8)
1728+ -> aggr ('Null 'PGfloat8)
1730+ {- | population covariance
1733+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1734+ expression = covarPop (All (#y :*: #x))
1735+ in printSQL expression
1737+ covar_pop(ALL "y", "x")
1740+ :: expr2 (null 'PGfloat8)
1741+ -> aggr ('Null 'PGfloat8)
1743+ {- | sample covariance
1746+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1747+ winFun = covarSamp (#y :*: #x)
1750+ covar_samp("y", "x")
1753+ :: expr2 (null 'PGfloat8)
1754+ -> aggr ('Null 'PGfloat8)
1756+ {- | average of the independent variable (sum(X)/N)
1759+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1760+ expression = regrAvgX (All (#y :*: #x))
1761+ in printSQL expression
1763+ regr_avgx(ALL "y", "x")
1766+ :: expr2 (null 'PGfloat8)
1767+ -> aggr ('Null 'PGfloat8)
1769+ {- | average of the dependent variable (sum(Y)/N)
1772+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1773+ winFun = regrAvgY (#y :*: #x)
1776+ regr_avgy("y", "x")
1779+ :: expr2 (null 'PGfloat8)
1780+ -> aggr ('Null 'PGfloat8)
1782+ {- | number of input rows in which both expressions are nonnull
1785+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1786+ winFun = regrCount (#y :*: #x)
1789+ regr_count("y", "x")
1792+ :: expr2 (null 'PGfloat8)
1793+ -> aggr ('Null 'PGint8)
1795+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1798+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1799+ expression = regrIntercept (All (#y :*: #x))
1800+ in printSQL expression
1802+ regr_intercept(ALL "y", "x")
1805+ :: expr2 (null 'PGfloat8)
1806+ -> aggr ('Null 'PGfloat8)
1808+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1810+ :: expr2 (null 'PGfloat8)
1811+ -> aggr ('Null 'PGfloat8)
1813+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1814+ -- determined by the (X, Y) pairs
1816+ :: expr2 (null 'PGfloat8)
1817+ -> aggr ('Null 'PGfloat8)
1819+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1820+ -- (“sum of squares” of the independent variable)
1822+ :: expr2 (null 'PGfloat8)
1823+ -> aggr ('Null 'PGfloat8)
1825+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1826+ -- (“sum of products” of independent times dependent variable)
1828+ :: expr2 (null 'PGfloat8)
1829+ -> aggr ('Null 'PGfloat8)
1831+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1832+ -- (“sum of squares” of the dependent variable)
1834+ :: expr2 (null 'PGfloat8)
1835+ -> aggr ('Null 'PGfloat8)
1837+ -- | historical alias for `stddevSamp`
1840+ -> aggr ('Null (PGAvg ty))
1842+ -- | population standard deviation of the input values
1845+ -> aggr ('Null (PGAvg ty))
1847+ -- | sample standard deviation of the input values
1850+ -> aggr ('Null (PGAvg ty))
1852+ -- | historical alias for `varSamp`
1855+ -> aggr ('Null (PGAvg ty))
1857+ -- | population variance of the input values
1858+ -- (square of the population standard deviation)
1861+ -> aggr ('Null (PGAvg ty))
1863+ -- | sample variance of the input values
1864+ -- (square of the sample standard deviation)
1867+ -> aggr ('Null (PGAvg ty))
1870+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1871+`All` invokes the aggregate once for each input row.
1872+`Distinct` invokes the aggregate once for each distinct value of the expression
1873+(or distinct set of values, for multiple expressions) found in the input
1875+data Distinction expr ty
1877+ | Distinct (expr ty)
1878+ deriving (GHC.Generic,Show,Eq,Ord)
1879+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1880+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1882+ All x -> "ALL" <+> renderSQL x
1883+ Distinct x -> "DISTINCT" <+> renderSQL x
1886+ ( Expression outer grp commons schemas params from
1888+ Expression outer grp commons schemas params from) xty ) where
1891+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1892+ Distinct (x :*: x') ->
1893+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1896+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1897+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1898+ (Expression outer ('Grouped bys) commons schemas params from) where
1899+ countStar = UnsafeExpression "count(*)"
1900+ count = unsafeAggregate1 "count"
1901+ sum_ = unsafeAggregate1 "sum"
1902+ arrayAgg = unsafeAggregate1 "array_agg"
1903+ jsonAgg = unsafeAggregate1 "json_agg"
1904+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1905+ bitAnd = unsafeAggregate1 "bit_and"
1906+ bitOr = unsafeAggregate1 "bit_or"
1907+ boolAnd = unsafeAggregate1 "bool_and"
1908+ boolOr = unsafeAggregate1 "bool_or"
1909+ every = unsafeAggregate1 "every"
1910+ max_ = unsafeAggregate1 "max"
1911+ min_ = unsafeAggregate1 "min"
1912+ avg = unsafeAggregate1 "avg"
1913+ corr = unsafeAggregate2 "corr"
1914+ covarPop = unsafeAggregate2 "covar_pop"
1915+ covarSamp = unsafeAggregate2 "covar_samp"
1916+ regrAvgX = unsafeAggregate2 "regr_avgx"
1917+ regrAvgY = unsafeAggregate2 "regr_avgy"
1918+ regrCount = unsafeAggregate2 "regr_count"
1919+ regrIntercept = unsafeAggregate2 "regr_intercept"
1920+ regrR2 = unsafeAggregate2 "regr_r2"
1921+ regrSlope = unsafeAggregate2 "regr_slope"
1922+ regrSxx = unsafeAggregate2 "regr_sxx"
1923+ regrSxy = unsafeAggregate2 "regr_sxy"
1924+ regrSyy = unsafeAggregate2 "regr_syy"
1925+ stddev = unsafeAggregate1 "stddev"
1926+ stddevPop = unsafeAggregate1 "stddev_pop"
1927+ stddevSamp = unsafeAggregate1 "stddev_samp"
1928+ variance = unsafeAggregate1 "variance"
1929+ varPop = unsafeAggregate1 "var_pop"
1930+ varSamp = unsafeAggregate1 "var_samp"
1932+ (Expression outer grp commons schemas params from)
1933+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1934+ (WindowFunction outer grp commons schemas params from) where
1935+ countStar = UnsafeWindowFunction "count(*)"
1936+ count = unsafeWindowFunction1 "count"
1937+ sum_ = unsafeWindowFunction1 "sum"
1938+ arrayAgg = unsafeWindowFunction1 "array_agg"
1939+ jsonAgg = unsafeWindowFunction1 "json_agg"
1940+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1941+ bitAnd = unsafeWindowFunction1 "bit_and"
1942+ bitOr = unsafeWindowFunction1 "bit_or"
1943+ boolAnd = unsafeWindowFunction1 "bool_and"
1944+ boolOr = unsafeWindowFunction1 "bool_or"
1945+ every = unsafeWindowFunction1 "every"
1946+ max_ = unsafeWindowFunction1 "max"
1947+ min_ = unsafeWindowFunction1 "min"
1948+ avg = unsafeWindowFunction1 "avg"
1949+ corr = unsafeWindowFunction2 "corr"
1950+ covarPop = unsafeWindowFunction2 "covar_pop"
1951+ covarSamp = unsafeWindowFunction2 "covar_samp"
1952+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1953+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1954+ regrCount = unsafeWindowFunction2 "regr_count"
1955+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1956+ regrR2 = unsafeWindowFunction2 "regr_r2"
1957+ regrSlope = unsafeWindowFunction2 "regr_slope"
1958+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1959+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1960+ regrSyy = unsafeWindowFunction2 "regr_syy"
1961+ stddev = unsafeWindowFunction1 "stddev"
1962+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1963+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1964+ variance = unsafeWindowFunction1 "variance"
1965+ varPop = unsafeWindowFunction1 "var_pop"
1966+ varSamp = unsafeWindowFunction1 "var_samp"
1968+-- | escape hatch to define aggregate functions
1970+ :: ByteString -- ^ aggregate function
1971+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1972+ -> Expression outer ('Grouped bys) commons schemas params from yty
1973+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1974+ [fun, "(", renderSQL x, ")"]
1976+-- | escape hatch to define aggregate binary functions
1978+ :: ByteString -- ^ aggregate function
1979+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1980+ -> Expression outer ('Grouped bys) commons schemas params from yty
1981+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1982+ [fun, "(", renderSQL xx, ")"]
1984+-- | A type family that calculates `PGAvg` type of a `PGType`.
1985+type family PGAvg ty where
1986+ PGAvg 'PGint2 = 'PGnumeric
1987+ PGAvg 'PGint4 = 'PGnumeric
1988+ PGAvg 'PGint8 = 'PGnumeric
1989+ PGAvg 'PGnumeric = 'PGnumeric
1990+ PGAvg 'PGfloat4 = 'PGfloat8
1991+ PGAvg 'PGfloat8 = 'PGfloat8
1992+ PGAvg 'PGinterval = 'PGinterval
1993+ PGAvg pg = TypeError
1994+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1996+{-----------------------------------------
1998+-----------------------------------------}
2000+-- | `TypeExpression`s are used in `cast`s and
2001+-- `Squeal.PostgreSQL.Definition.createTable` commands.
2002+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
2003+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
2004+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2005+instance RenderSQL (TypeExpression schemas ty) where
2006+ renderSQL = renderTypeExpression
2008+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
2010+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
2011+ => QualifiedAlias sch td
2012+ -> TypeExpression schemas (null ty)
2013+typedef = UnsafeTypeExpression . renderSQL
2015+-- | The composite type corresponding to a `Table` definition can be expressed
2018+ :: (Has sch schemas schema, Has tab schema ('Table table))
2019+ => QualifiedAlias sch tab
2020+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
2021+typetable = UnsafeTypeExpression . renderSQL
2023+-- | The composite type corresponding to a `View` definition can be expressed
2026+ :: (Has sch schemas schema, Has vw schema ('View view))
2027+ => QualifiedAlias sch vw
2028+ -> TypeExpression schemas (null ('PGcomposite view))
2029+typeview = UnsafeTypeExpression . renderSQL
2031+-- | logical Boolean (true/false)
2032+bool :: TypeExpression schemas (null 'PGbool)
2033+bool = UnsafeTypeExpression "bool"
2034+-- | signed two-byte integer
2035+int2, smallint :: TypeExpression schemas (null 'PGint2)
2036+int2 = UnsafeTypeExpression "int2"
2037+smallint = UnsafeTypeExpression "smallint"
2038+-- | signed four-byte integer
2039+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2040+int4 = UnsafeTypeExpression "int4"
2041+int = UnsafeTypeExpression "int"
2042+integer = UnsafeTypeExpression "integer"
2043+-- | signed eight-byte integer
2044+int8, bigint :: TypeExpression schemas (null 'PGint8)
2045+int8 = UnsafeTypeExpression "int8"
2046+bigint = UnsafeTypeExpression "bigint"
2047+-- | arbitrary precision numeric type
2048+numeric :: TypeExpression schemas (null 'PGnumeric)
2049+numeric = UnsafeTypeExpression "numeric"
2050+-- | single precision floating-point number (4 bytes)
2051+float4, real :: TypeExpression schemas (null 'PGfloat4)
2052+float4 = UnsafeTypeExpression "float4"
2053+real = UnsafeTypeExpression "real"
2054+-- | double precision floating-point number (8 bytes)
2055+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2056+float8 = UnsafeTypeExpression "float8"
2057+doublePrecision = UnsafeTypeExpression "double precision"
2058+-- | currency amount
2059+money :: TypeExpression schema (null 'PGmoney)
2060+money = UnsafeTypeExpression "money"
2061+-- | variable-length character string
2062+text :: TypeExpression schemas (null 'PGtext)
2063+text = UnsafeTypeExpression "text"
2064+-- | fixed-length character string
2066+ :: forall n schemas null. (KnownNat n, 1 <= n)
2067+ => TypeExpression schemas (null ('PGchar n))
2068+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2069+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2070+-- | variable-length character string
2071+varchar, characterVarying
2072+ :: forall n schemas null. (KnownNat n, 1 <= n)
2073+ => TypeExpression schemas (null ('PGvarchar n))
2074+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2075+characterVarying = UnsafeTypeExpression $
2076+ "character varying(" <> renderNat @n <> ")"
2077+-- | binary data ("byte array")
2078+bytea :: TypeExpression schemas (null 'PGbytea)
2079+bytea = UnsafeTypeExpression "bytea"
2080+-- | date and time (no time zone)
2081+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2082+timestamp = UnsafeTypeExpression "timestamp"
2083+-- | date and time, including time zone
2084+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2085+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2086+-- | calendar date (year, month, day)
2087+date :: TypeExpression schemas (null 'PGdate)
2088+date = UnsafeTypeExpression "date"
2089+-- | time of day (no time zone)
2090+time :: TypeExpression schemas (null 'PGtime)
2091+time = UnsafeTypeExpression "time"
2092+-- | time of day, including time zone
2093+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2094+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2096+interval :: TypeExpression schemas (null 'PGinterval)
2097+interval = UnsafeTypeExpression "interval"
2098+-- | universally unique identifier
2099+uuid :: TypeExpression schemas (null 'PGuuid)
2100+uuid = UnsafeTypeExpression "uuid"
2101+-- | IPv4 or IPv6 host address
2102+inet :: TypeExpression schemas (null 'PGinet)
2103+inet = UnsafeTypeExpression "inet"
2104+-- | textual JSON data
2105+json :: TypeExpression schemas (null 'PGjson)
2106+json = UnsafeTypeExpression "json"
2107+-- | binary JSON data, decomposed
2108+jsonb :: TypeExpression schemas (null 'PGjsonb)
2109+jsonb = UnsafeTypeExpression "jsonb"
2110+-- | variable length array
2112+ :: TypeExpression schemas pg
2113+ -> TypeExpression schemas (null ('PGvararray pg))
2114+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2115+-- | fixed length array
2117+-- >>> renderSQL (fixarray @'[2] json)
2120+ :: forall dims schemas null pg. SOP.All KnownNat dims
2121+ => TypeExpression schemas pg
2122+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2123+fixarray ty = UnsafeTypeExpression $
2124+ renderSQL ty <> renderDims @dims
2126+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2130+ . ByteString.intercalate "]["
2132+ $ hcmap (SOP.Proxy @KnownNat)
2133+ (K . fromString . show . natVal)
2134+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2135+tsvector :: TypeExpression schemas (null 'PGtsvector)
2136+tsvector = UnsafeTypeExpression "tsvector"
2137+tsquery :: TypeExpression schemas (null 'PGtsquery)
2138+tsquery = UnsafeTypeExpression "tsquery"
2140+-- | `pgtype` is a demoted version of a `PGType`
2141+class PGTyped schemas (ty :: NullityType) where
2142+ pgtype :: TypeExpression schemas ty
2143+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2144+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2145+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2146+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2147+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2148+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2149+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2150+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2151+instance PGTyped schemas (null 'PGtext) where pgtype = text
2152+instance (KnownNat n, 1 <= n)
2153+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2154+instance (KnownNat n, 1 <= n)
2155+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2156+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2157+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2158+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2159+instance PGTyped schemas (null 'PGdate) where pgtype = date
2160+instance PGTyped schemas (null 'PGtime) where pgtype = time
2161+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2162+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2163+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2164+instance PGTyped schemas (null 'PGjson) where pgtype = json
2165+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2166+instance PGTyped schemas ty
2167+ => PGTyped schemas (null ('PGvararray ty)) where
2168+ pgtype = vararray (pgtype @schemas @ty)
2169+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2170+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2171+ pgtype = fixarray @dims (pgtype @schemas @ty)
2172+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2173+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2175+{-----------------------------------------
2177+-----------------------------------------}
2179+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2180+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2181+-- set the sort direction of a `NotNull` result
2182+-- column to ascending or descending. Ascending order puts smaller values
2183+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2184+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2185+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2186+-- determine whether nulls appear before or after non-null values in the sort
2187+-- ordering of a `Null` result column.
2188+data SortExpression outer grp commons schemas params from where
2190+ :: Expression outer grp commons schemas params from ('NotNull ty)
2191+ -> SortExpression outer grp commons schemas params from
2193+ :: Expression outer grp commons schemas params from ('NotNull ty)
2194+ -> SortExpression outer grp commons schemas params from
2196+ :: Expression outer grp commons schemas params from ('Null ty)
2197+ -> SortExpression outer grp commons schemas params from
2199+ :: Expression outer grp commons schemas params from ('Null ty)
2200+ -> SortExpression outer grp commons schemas params from
2202+ :: Expression outer grp commons schemas params from ('Null ty)
2203+ -> SortExpression outer grp commons schemas params from
2205+ :: Expression outer grp commons schemas params from ('Null ty)
2206+ -> SortExpression outer grp commons schemas params from
2207+deriving instance Show (SortExpression outer grp commons schemas params from)
2210+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2211+to be sorted according to the specified `SortExpression`(s).
2212+If two rows are equal according to the leftmost expression,
2213+they are compared according to the next expression and so on.
2214+If they are equal according to all specified expressions,
2215+they are returned in an implementation-dependent order.
2217+You can also control the order in which rows are processed by window functions
2218+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2220+class OrderBy expr where
2222+ :: [SortExpression outer grp commons schemas params from]
2223+ -> expr outer grp commons schemas params from
2224+ -> expr outer grp commons schemas params from
2226+-- | Render a `SortExpression`.
2227+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2229+ Asc expression -> renderSQL expression <+> "ASC"
2230+ Desc expression -> renderSQL expression <+> "DESC"
2231+ AscNullsFirst expression -> renderSQL expression
2232+ <+> "ASC NULLS FIRST"
2233+ DescNullsFirst expression -> renderSQL expression
2234+ <+> "DESC NULLS FIRST"
2235+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2236+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2238+-- | A `WindowDefinition` is a set of table rows that are somehow related
2239+-- to the current row
2240+data WindowDefinition outer grp commons schemas params from where
2243+ => NP (Expression outer grp commons schemas params from) bys
2244+ -> [SortExpression outer grp commons schemas params from]
2245+ -> WindowDefinition outer grp commons schemas params from
2247+instance OrderBy WindowDefinition where
2248+ orderBy sortsR (WindowDefinition parts sortsL)
2249+ = WindowDefinition parts (sortsL ++ sortsR)
2251+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2252+ renderSQL (WindowDefinition part ord) =
2253+ renderPartitionByClause part <> renderOrderByClause ord
2255+ renderPartitionByClause = \case
2257+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2258+ renderOrderByClause = \case
2260+ srts -> " ORDER" <+> "BY"
2261+ <+> commaSeparated (renderSQL <$> srts)
2264+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2265+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2266+For each row, the window function is computed across the rows that fall into
2267+the same partition as the current row.
2271+ => NP (Expression outer grp commons schemas params from) bys
2272+ -> WindowDefinition outer grp commons schemas params from
2273+partitionBy bys = WindowDefinition bys []
2276+A window function performs a calculation across a set of table rows
2277+that are somehow related to the current row. This is comparable to the type
2278+of calculation that can be done with an aggregate function.
2279+However, window functions do not cause rows to become grouped into a single
2280+output row like non-window aggregate calls would.
2281+Instead, the rows retain their separate identities.
2282+Behind the scenes, the window function is able to access more than
2283+just the current row of the query result.
2285+newtype WindowFunction
2286+ (outer :: FromType)
2288+ (commons :: FromType)
2289+ (schemas :: SchemasType)
2290+ (params :: [NullityType])
2292+ (ty :: NullityType)
2293+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2294+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2296+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2297+ renderSQL = renderWindowFunction
2299+unsafeWindowFunction1
2301+ -> Expression outer grp commons schemas params from ty0
2302+ -> WindowFunction outer grp commons schemas params from ty1
2303+unsafeWindowFunction1 fun x
2304+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2306+unsafeWindowFunction2
2308+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2309+ -> WindowFunction outer grp commons schemas params from ty1
2310+unsafeWindowFunction2 fun (x :*: x')
2311+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2313+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2317+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2318+rank = UnsafeWindowFunction "rank()"
2320+{- | number of the current row within its partition, counting from 1
2321+>>> printSQL rowNumber
2324+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2325+rowNumber = UnsafeWindowFunction "row_number()"
2327+{- | rank of the current row without gaps; this function counts peer groups
2328+>>> printSQL denseRank
2331+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2332+denseRank = UnsafeWindowFunction "dense_rank()"
2334+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2335+>>> printSQL percentRank
2338+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2339+percentRank = UnsafeWindowFunction "percent_rank()"
2341+{- | cumulative distribution: (number of partition rows
2342+preceding or peer with current row) / total partition rows
2343+>>> printSQL cumeDist
2346+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2347+cumeDist = UnsafeWindowFunction "cume_dist()"
2349+{- | integer ranging from 1 to the argument value,
2350+dividing the partition as equally as possible
2353+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2355+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2356+ntile = unsafeWindowFunction1 "ntile"
2358+{- | returns value evaluated at the row that is offset rows before the current
2359+row within the partition; if there is no such row, instead return default
2360+(which must be of the same type as value). Both offset and default are
2361+evaluated with respect to the current row.
2364+ :: Expression outer grp commons schemas params from ty
2366+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2368+ -> Expression outer grp commons schemas params from ty
2370+ -> WindowFunction outer grp commons schemas params from ty
2371+lag value offset def = UnsafeWindowFunction $ "lag"
2373+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2375+{- | returns value evaluated at the row that is offset rows after the current
2376+row within the partition; if there is no such row, instead return default
2377+(which must be of the same type as value). Both offset and default are
2378+evaluated with respect to the current row.
2381+ :: Expression outer grp commons schemas params from ty
2383+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2385+ -> Expression outer grp commons schemas params from ty
2387+ -> WindowFunction outer grp commons schemas params from ty
2388+lead value offset def = UnsafeWindowFunction $ "lag"
2390+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2392+{- | returns value evaluated at the row that is the
2393+first row of the window frame
2396+ :: Expression outer grp commons schemas params from ty
2398+ -> WindowFunction outer grp commons schemas params from ty
2399+firstValue = unsafeWindowFunction1 "first_value"
2401+{- | returns value evaluated at the row that is the
2402+last row of the window frame
2405+ :: Expression outer grp commons schemas params from ty
2407+ -> WindowFunction outer grp commons schemas params from ty
2408+lastValue = unsafeWindowFunction1 "last_value"
2410+{- | returns value evaluated at the row that is the nth
2411+row of the window frame (counting from 1); null if no such row
2414+ :: Expression outer grp commons schemas params from (null ty)
2416+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2418+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2419+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2420+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])
2423+Create date from year, month and day fields
2425+>>> printSQL (makeDate (1984 :* 7 *: 3))
2426+make_date(1984, 7, 3)
2428+makeDate :: FunctionHet
2429+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2431+makeDate = unsafeFunctionHet "make_date"
2434+Create time from hour, minute and seconds fields
2436+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2437+make_time(8, 15, 23.5)
2439+makeTime :: FunctionHet
2440+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2442+makeTime = unsafeFunctionHet "make_time"
2445+Create timestamp from year, month, day, hour, minute and seconds fields
2447+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2448+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2450+makeTimestamp :: FunctionHet
2451+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2452+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2453+ ( null 'PGtimestamp )
2454+makeTimestamp = unsafeFunctionHet "make_timestamp"
2457+Create timestamp with time zone from
2458+year, month, day, hour, minute and seconds fields;
2459+the current time zone is used
2461+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2462+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2464+makeTimestamptz :: FunctionHet
2465+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2466+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2467+ ( null 'PGtimestamptz )
2468+makeTimestamptz = unsafeFunctionHet "make_timestamptz"
2471+Affine space operations on time types.
2473+class TimeOp time diff | time -> diff where
2475+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2476+ (make_date(1984, 7, 3) + 365)
2478+ (!+) :: Operator (null time) (null diff) (null time)
2479+ (!+) = unsafeBinaryOp "+"
2481+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2482+ (365 + make_date(1984, 7, 3))
2484+ (+!) :: Operator (null diff) (null time) (null time)
2485+ (+!) = unsafeBinaryOp "+"
2487+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2488+ (make_date(1984, 7, 3) - 365)
2490+ (!-) :: Operator (null time) (null diff) (null time)
2491+ (!-) = unsafeBinaryOp "-"
2493+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2494+ (make_date(1984, 7, 3) - CURRENT_DATE)
2496+ (!-!) :: Operator (null time) (null time) (null diff)
2497+ (!-!) = unsafeBinaryOp "-"
2498+instance TimeOp 'PGtimestamp 'PGinterval
2499+instance TimeOp 'PGtimestamptz 'PGinterval
2500+instance TimeOp 'PGtime 'PGinterval
2501+instance TimeOp 'PGtimetz 'PGinterval
2502+instance TimeOp 'PGinterval 'PGinterval
2503+instance TimeOp 'PGdate 'PGint4