@@ -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,404 @@ module Squeal.PostgreSQL.Expression
34 ( -- * Expression
35 ( -- * Expression
35 Expression (..)
36 Expression (..)
45 , Operator
38 , Operator
47 , unsafeBinaryOp
39 , unsafeBinaryOp
48− , binaryOp
40+ , (:-->)
49− , FunctionVar
41+ , unsafeUnaryOpL
50− , unsafeFunctionVar
42+ , unsafeUnaryOpR
51− , type (--->)
43+ , unsafeFunction
52− , FunctionNDB
44+ , FunctionHom
53− , unsafeFunctionN
45+ , unsafeFunctionHom
54− , functionN
46+ , FunctionHet
48+ , HasParameter (parameter)
55 , PGSubset (..)
65 , PGSubset (..)
56− , PGIntersect (..)
66+ -- ** Functions
95+ , notBetweenSymmetric
122+ -- *** Json and Jsonb operators
127+ -- *** Jsonb operators
153+ , jsonExtractPathAsText
154+ , jsonbExtractPathAsText
173+ , websearchToTSquery
188+ -- * Window Functions
189+ , WindowDefinition (..)
191+ , WindowFunction (..)
204+ , SortExpression (..)
207+ , TypeExpression (..)
233+ , timestampWithTimeZone
57 -- * Re-export
246 -- * Re-export
63import Control.Category
252import Control.Category
64import Control.DeepSeq
253import Control.DeepSeq
65import Data.ByteString (ByteString)
254import Data.ByteString (ByteString)
255+import Data.ByteString.Lazy (toStrict)
66import Data.Function ((&))
256import Data.Function ((&))
67import Data.Semigroup hiding (All)
258import Data.Semigroup hiding (All)
259+import qualified Data.Aeson as JSON
68import Data.String
260import Data.String
69import Generics.SOP hiding (All, from)
262import Generics.SOP hiding (All, from)
70import GHC.OverloadedLabels
263import GHC.OverloadedLabels
71import GHC.TypeLits
264import GHC.TypeLits
72import Numeric
265import Numeric
73import Prelude hiding (id, (.))
266import Prelude hiding (id, (.))
268+import qualified Data.ByteString as ByteString
75import qualified GHC.Generics as GHC
269import qualified GHC.Generics as GHC
270+import qualified Generics.SOP as SOP
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79import Squeal.PostgreSQL.Render
272import Squeal.PostgreSQL.Render
80import Squeal.PostgreSQL.Schema
273import Squeal.PostgreSQL.Schema
83−-- >>> import Squeal.PostgreSQL
85{-----------------------------------------
275{-----------------------------------------
86column expressions
276column expressions
87-----------------------------------------}
277-----------------------------------------}
89{- | `Expression`s are used in a variety of contexts,
279{- | `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,
280+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
281as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93`Squeal.PostgreSQL.Manipulation.update`,
282`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
283+or in search `Condition`s in a number of commands.
96The expression syntax allows the calculation of
285The expression syntax allows the calculation of
97values from primitive expression using arithmetic, logical,
286values from primitive expression using arithmetic, logical,
98and other operations.
287and 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
289newtype Expression
115 (outer :: FromType)
290 (outer :: FromType)
116− (commons :: FromType)
117 (grp :: Grouping)
291 (grp :: Grouping)
292+ (commons :: FromType)
118 (schemas :: SchemasType)
293 (schemas :: SchemasType)
119 (params :: [NullityType])
294 (params :: [NullityType])
120 (from :: FromType)
295 (from :: FromType)
121 (ty :: NullityType)
296 (ty :: NullityType)
122 = UnsafeExpression { renderExpression :: ByteString }
297 = UnsafeExpression { renderExpression :: ByteString }
123 deriving (GHC.Generic,Show,Eq,Ord,NFData)
298 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
299+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125 renderSQL = renderExpression
300 renderSQL = renderExpression
127-- | An `Expr` is a closed `Expression`.
302-- | An `Expr` is a closed `Expression`.
128−-- It is a F@RankNType@ but don't be scared.
303+-- It is a F`RankNType` but don't be scared.
129-- Think of it as an expression which sees no
304-- Think of it as an expression which sees no
130-- namespaces, so you can't use parameters
305-- namespaces, so you can't use parameters
131-- or alias references. It can be used as
306-- or alias references. It can be used as
132-- a simple piece of more complex `Expression`s.
307-- a simple piece of more complex `Expression`s.
133type Expr x
308type Expr x
134− = forall outer commons grp schemas params from
309+ = forall outer grp commons schemas params from
135− . Expression outer commons grp schemas params from x
310+ . Expression outer grp commons schemas params from x
136 -- ^ cannot reference aliases
311 -- ^ cannot reference aliases
138−-- | A @RankNType@ for binary operators.
313+-- | A `RankNType` for binary operators.
139type Operator x1 x2 y
314type Operator x1 x2 y
140− = forall outer commons grp schemas params from
141− . Expression outer commons grp schemas params from x1
315+ = forall outer grp commons schemas params from
143− -> Expression outer commons grp schemas params from x2
145− -> Expression outer commons grp schemas params from y
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
150− . Expression outer commons grp schemas params from x1
316+ . Expression outer grp commons schemas params from x1
151 -- ^ left input
317 -- ^ left input
152− -> Expression outer commons grp schemas params from x2
318+ -> Expression outer grp commons schemas params from x2
153 -- ^ right input
319 -- ^ right input
154− -> Expression outer commons grp schemas params from y
320+ -> Expression outer grp commons schemas params from y
155 -- ^ output
321 -- ^ output
157−-- | A @RankNType@ for functions with a single argument.
323+-- | A `RankNType` for functions with a single argument.
158-- These could be either function calls or unary operators.
324-- These could be either function calls or unary operators.
159-- This is a subtype of the usual Haskell function type `Prelude.->`,
325-- This is a subtype of the usual Haskell function type `Prelude.->`,
160-- indeed a subcategory as it is closed under the usual
326-- indeed a subcategory as it is closed under the usual
161-- `Prelude..` and `Prelude.id`.
327-- `Prelude..` and `Prelude.id`.
162−type (-->) x y
328+type (:-->) x y
163− = forall outer commons grp schemas params from
329+ = forall outer grp commons schemas params from
164− . Expression outer commons grp schemas params from x
330+ . Expression outer grp commons schemas params from x
165 -- ^ input
331 -- ^ input
166− -> Expression outer commons grp schemas params from y
332+ -> Expression outer grp commons schemas params from y
167 -- ^ output
333 -- ^ output
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
176−{- | A @RankNType@ for functions with a fixed-length list of heterogeneous arguments.
335+{- | A `RankNType` for functions with a fixed-length list of heterogeneous arguments.
177Use the `*:` operator to end your argument lists, like so.
336Use the `*:` operator to end your argument lists, like so.
179−>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
338+>>> printSQL (unsafeFunctionHet "fun" (true :* false :* localTime *: true))
180fun(TRUE, FALSE, LOCALTIME, TRUE)
339fun(TRUE, FALSE, LOCALTIME, TRUE)
182−type (--->) xs y
341+type FunctionHet xs y
183− = forall outer commons grp schemas params from
342+ = forall outer grp commons 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
343+ . NP (Expression outer grp commons schemas params from) xs
192 -- ^ inputs
344 -- ^ inputs
193− -> Expression outer commons grp schemas params from y
345+ -> Expression outer grp commons schemas params from y
194 -- ^ output
346 -- ^ output
196−{- | A @RankNType@ for functions with a variable-length list of
348+{- | A `RankNType` for functions with a variable-length list of
197homogeneous arguments and at least 1 more argument.
349homogeneous arguments and at least 1 more argument.
199−type FunctionVar x0 x1 y
351+type FunctionHom x0 x1 y
200− = forall outer commons grp schemas params from
352+ = forall outer grp commons schemas params from
201− . [Expression outer commons grp schemas params from x0]
353+ . [Expression outer grp commons schemas params from x0]
202 -- ^ inputs
354 -- ^ inputs
203− -> Expression outer commons grp schemas params from x1
355+ -> Expression outer grp commons schemas params from x1
204 -- ^ must have at least 1 input
356 -- ^ must have at least 1 input
205− -> Expression outer commons grp schemas params from y
357+ -> Expression outer grp commons schemas params from y
206 -- ^ output
358 -- ^ output
208−{- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)
360+{- | >>> printSQL (unsafeFunctionHom "greatest" [true, null_] false)
209greatest(TRUE, NULL, FALSE)
361greatest(TRUE, NULL, FALSE)
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
363+unsafeFunctionHom :: ByteString -> FunctionHom x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
364+unsafeFunctionHom fun xs x = UnsafeExpression $ fun <> parenthesized
213 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
365 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
367+{- | A `HasParameter` constraint is used to indicate a value that is
368+supplied externally to a SQL statement.
369+`Squeal.PostgreSQL.PQ.manipulateParams`,
370+`Squeal.PostgreSQL.PQ.queryParams` and
371+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
372+separately from the SQL command string, in which case `param`s are used to
373+refer to the out-of-line data values.
375+class KnownNat n => HasParameter
377+ (params :: [NullityType])
379+ | n params -> ty where
380+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
382+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
383+ -- >>> printSQL expr
386+ :: TypeExpression schemas ty
387+ -> Expression outer grp commons schemas params from ty
388+ parameter ty = UnsafeExpression $ parenthesized $
389+ "$" <> renderNat @n <+> "::"
391+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
392+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
393+ => HasParameter n (ty' : params) ty
395+-- | `param` takes a `Nat` using type application and for basic types,
396+-- infers a `TypeExpression`.
398+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
402+ :: forall n outer commons schemas params from grp ty
403+ . (PGTyped schemas ty, HasParameter n params ty)
404+ => Expression outer grp commons schemas params from ty -- ^ param
405+param = parameter @n (pgtype @schemas)
215instance (HasUnique tab (Join outer from) row, Has col row ty)
407instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
408+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
409 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
410instance (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
411+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220 fromLabel = fromLabel @col :* Nil
412 fromLabel = fromLabel @col :* Nil
221instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
413instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222 => IsLabel col
414 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
415+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224 fromLabel = fromLabel @col `As` Alias
416 fromLabel = fromLabel @col `As` Alias
225instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
417instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226 => IsLabel col
418 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
419+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228 fromLabel = fromLabel @col :* Nil
420 fromLabel = fromLabel @col :* Nil
230instance (Has tab (Join outer from) row, Has col row ty)
422instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
423+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232 tab ! col = UnsafeExpression $
424 tab ! col = UnsafeExpression $
233 renderSQL tab <> "." <> renderSQL col
425 renderSQL tab <> "." <> renderSQL col
234instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])
426instance (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
427+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236 tab ! col = tab ! col :* Nil
428 tab ! col = tab ! col :* Nil
237instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
429instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238 => IsQualified tab col
430 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
431+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240 tab ! col = tab ! col `As` col
432 tab ! col = tab ! col `As` col
241instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
433instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242 => IsQualified tab col
434 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
435+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244 tab ! col = tab ! col :* Nil
436 tab ! col = tab ! col :* Nil
@@ -248,7 +440,7 @@ instance
248 , Has col row ty
440 , Has col row ty
249 , GroupedBy tab col bys
441 , GroupedBy tab col bys
250 ) => IsLabel col
442 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
443+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
444 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
254 ( HasUnique tab (Join outer from) row
446 ( HasUnique tab (Join outer from) row
@@ -256,7 +448,7 @@ instance
256 , GroupedBy tab col bys
448 , GroupedBy tab col bys
257 , tys ~ '[ty]
449 , tys ~ '[ty]
258 ) => IsLabel col
450 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
451+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260 fromLabel = fromLabel @col :* Nil
452 fromLabel = fromLabel @col :* Nil
262 ( HasUnique tab (Join outer from) row
454 ( HasUnique tab (Join outer from) row
@@ -264,7 +456,7 @@ instance
264 , GroupedBy tab col bys
456 , GroupedBy tab col bys
265 , column ~ (col ::: ty)
457 , column ~ (col ::: ty)
266 ) => IsLabel col
458 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
459+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268 fromLabel = fromLabel @col `As` Alias
460 fromLabel = fromLabel @col `As` Alias
270 ( HasUnique tab (Join outer from) row
462 ( HasUnique tab (Join outer from) row
@@ -272,7 +464,7 @@ instance
272 , GroupedBy tab col bys
464 , GroupedBy tab col bys
273 , columns ~ '[col ::: ty]
465 , columns ~ '[col ::: ty]
274 ) => IsLabel col
466 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
467+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276 fromLabel = fromLabel @col :* Nil
468 fromLabel = fromLabel @col :* Nil
@@ -280,7 +472,7 @@ instance
280 , Has col row ty
472 , Has col row ty
281 , GroupedBy tab col bys
473 , GroupedBy tab col bys
282 ) => IsQualified tab col
474 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
475+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284 tab ! col = UnsafeExpression $
476 tab ! col = UnsafeExpression $
285 renderSQL tab <> "." <> renderSQL col
477 renderSQL tab <> "." <> renderSQL col
@@ -289,7 +481,7 @@ instance
289 , GroupedBy tab col bys
481 , GroupedBy tab col bys
290 , tys ~ '[ty]
482 , tys ~ '[ty]
291 ) => IsQualified tab col
483 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
484+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293 tab ! col = tab ! col :* Nil
485 tab ! col = tab ! col :* Nil
295 ( Has tab (Join outer from) row
487 ( Has tab (Join outer from) row
@@ -297,7 +489,7 @@ instance
297 , GroupedBy tab col bys
489 , GroupedBy tab col bys
298 , column ~ (col ::: ty)
490 , column ~ (col ::: ty)
299 ) => IsQualified tab col
491 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
492+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301 tab ! col = tab ! col `As` col
493 tab ! col = tab ! col `As` col
303 ( Has tab (Join outer from) row
495 ( Has tab (Join outer from) row
@@ -305,78 +497,200 @@ instance
305 , GroupedBy tab col bys
497 , GroupedBy tab col bys
306 , columns ~ '[col ::: ty]
498 , columns ~ '[col ::: ty]
307 ) => IsQualified tab col
499 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
500+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309 tab ! col = tab ! col :* Nil
501 tab ! col = tab ! col :* Nil
503+-- | analagous to `Nothing`
505+-- >>> printSQL null_
507+null_ :: Expr ('Null ty)
508+null_ = UnsafeExpression "NULL"
510+-- | analagous to `Just`
512+-- >>> printSQL $ notNull true
514+notNull :: 'NotNull ty :--> 'Null ty
515+notNull = UnsafeExpression . renderSQL
517+-- | return the leftmost value which is not NULL
519+-- >>> printSQL $ coalesce [null_, true] false
520+-- COALESCE(NULL, TRUE, FALSE)
521+coalesce :: FunctionHom ('Null ty) ('NotNull ty) ('NotNull ty)
522+coalesce nullxs notNullx = UnsafeExpression $
523+ "COALESCE" <> parenthesized (commaSeparated
524+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
526+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
528+-- >>> printSQL $ fromNull true null_
529+-- COALESCE(NULL, TRUE)
531+ :: Expression outer grp commons schemas params from ('NotNull ty)
532+ -- ^ what to convert @NULL@ to
533+ -> Expression outer grp commons schemas params from ('Null ty)
534+ -> Expression outer grp commons schemas params from ('NotNull ty)
535+fromNull notNullx nullx = coalesce [nullx] notNullx
537+-- | >>> printSQL $ null_ & isNull
539+isNull :: 'Null ty :--> null 'PGbool
540+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
542+-- | >>> printSQL $ null_ & isNotNull
544+isNotNull :: 'Null ty :--> null 'PGbool
545+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
547+-- | analagous to `maybe` using @IS NULL@
549+-- >>> printSQL $ matchNull true not_ null_
550+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
552+ :: Expression outer grp commons schemas params from (nullty)
553+ -- ^ what to convert @NULL@ to
554+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
555+ -> Expression outer grp commons schemas params from (nullty) )
556+ -- ^ function to perform when @NULL@ is absent
557+ -> Expression outer grp commons schemas params from ('Null ty)
558+ -> Expression outer grp commons schemas params from (nullty)
559+matchNull y f x = ifThenElse (isNull x) y
560+ (f (UnsafeExpression (renderSQL x)))
562+{-| right inverse to `fromNull`, if its arguments are equal then
563+`nullIf` gives @NULL@.
565+>>> :set -XTypeApplications -XDataKinds
566+>>> let expr = nullIf (false *: param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
568+NULLIF(FALSE, ($1 :: bool))
570+nullIf :: FunctionHet '[ 'NotNull ty, 'NotNull ty] ('Null ty)
571+nullIf = unsafeFunctionHet "NULLIF"
573+-- | >>> printSQL $ array [null_, false, true]
574+-- ARRAY[NULL, FALSE, TRUE]
576+ :: [Expression outer grp commons schemas params from ty]
578+ -> Expression outer grp commons schemas params from (null ('PGvararray ty))
579+array xs = UnsafeExpression $
580+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
582+-- | >>> printSQL $ cardinality (array [null_, false, true])
583+-- cardinality(ARRAY[NULL, FALSE, TRUE])
584+cardinality :: null ('PGvararray ty) :--> null 'PGint8
585+cardinality = unsafeFunction "cardinality"
587+-- | >>> printSQL $ array [null_, false, true] & index 2
588+-- (ARRAY[NULL, FALSE, TRUE])[2]
590+ :: Word64 -- ^ index
591+ -> null ('PGvararray ty) :--> NullifyType ty
592+index n expr = UnsafeExpression $
593+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
311instance (KnownSymbol label, label `In` labels) => IsPGlabel label
595instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
596+ (Expression outer grp commons schemas params from (null ('PGenum labels))) where
313 label = UnsafeExpression $ renderSQL (PGlabel @label)
597 label = UnsafeExpression $ renderSQL (PGlabel @label)
599+-- | A row constructor is an expression that builds a row value
600+-- (also called a composite value) using values for its member fields.
603+-- type Complex = 'PGcomposite
604+-- '[ "real" ::: 'NotNull 'PGfloat8
605+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
608+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
613+ => NP (Aliased (Expression outer grp commons schemas params from)) row
614+ -- ^ zero or more expressions for the row field values
615+ -> Expression outer grp commons schemas params from (null ('PGcomposite row))
616+row exprs = UnsafeExpression $ "ROW" <> parenthesized
617+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
620+-- type Complex = 'PGcomposite
621+-- '[ "real" ::: 'NotNull 'PGfloat8
622+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
623+-- type Schema = '["complex" ::: 'Typedef Complex]
626+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
627+-- >>> printSQL $ i & field #complex #imaginary
628+-- (ROW(0, 1)::"complex")."imaginary"
630+ :: ( Has sch schemas schema
631+ , Has tydef schema ('Typedef ('PGcomposite row))
633+ => QualifiedAlias sch tydef -- ^ row type
634+ -> Alias field -- ^ field name
635+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
636+ -> Expression outer grp commons schemas params from ty
637+field td fld expr = UnsafeExpression $
638+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
639+ <> "." <> renderSQL fld
642+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
643+ (<>) = unsafeBinaryOp "||"
646+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
650+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
652+-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
653+greatest :: FunctionHom ty ty ty
654+greatest = unsafeFunctionHom "GREATEST"
656+-- | >>> printSQL $ least [null_] currentTimestamp
657+-- LEAST(NULL, CURRENT_TIMESTAMP)
658+least :: FunctionHom ty ty ty
659+least = unsafeFunctionHom "LEAST"
315-- | >>> printSQL $ unsafeBinaryOp "OR" true false
661-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316-- (TRUE OR FALSE)
662-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
663+unsafeBinaryOp :: ByteString {- ^ operator -} -> Operator ty0 ty1 ty2
318unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
664unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319 renderSQL x <+> op <+> renderSQL y
665 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
667+-- | >>> printSQL $ unsafeUnaryOpL "NOT" true
329-- (NOT TRUE)
668-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
669+unsafeUnaryOpL :: ByteString {- ^ operator -} -> x :--> y
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
670+unsafeUnaryOpL op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
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"
672+-- | >>> printSQL $ true & unsafeUnaryOpR "IS NOT TRUE"
341-- (TRUE IS NOT TRUE)
673-- (TRUE IS NOT TRUE)
342−unsafeRightOp :: ByteString -> x --> y
674+unsafeUnaryOpR :: ByteString {- ^ operator -} -> x :--> y
343−unsafeRightOp op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
675+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
677-- | >>> printSQL $ unsafeFunction "f" true
353-- f(TRUE)
678-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
679+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355unsafeFunction fun x = UnsafeExpression $
680unsafeFunction fun x = UnsafeExpression $
356 fun <> parenthesized (renderSQL x)
681 fun <> parenthesized (renderSQL x)
359− :: (Has sch schemas schema, Has fun schema ('Function ('[x] :=> 'Returns y)))
360− => QualifiedAlias sch fun
361− -> FunctionDB schemas x y
362−function = unsafeFunction . renderSQL
364−-- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a')
683+-- | >>> printSQL $ unsafeFunctionHet "f" (currentTime :* localTimestamp :* false *: litChar 'a')
365-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
684-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
366−unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
685+unsafeFunctionHet
687+ => ByteString {- ^ function -}
367−unsafeFunctionN fun xs = UnsafeExpression $
689+unsafeFunctionHet fun xs = UnsafeExpression $
368 fun <> parenthesized (renderCommaSeparated renderSQL xs)
690 fun <> parenthesized (renderCommaSeparated renderSQL xs)
371− :: ( Has sch schemas schema
372− , Has fun schema ('Function (xs :=> 'Returns y))
374− => QualifiedAlias sch fun
375− -> FunctionNDB schemas xs y
376−functionN = unsafeFunctionN . renderSQL
378instance ty `In` PGNum
692instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
693+ => Num (Expression outer grp commons schemas params from (null ty)) where
380 (+) = unsafeBinaryOp "+"
694 (+) = unsafeBinaryOp "+"
381 (-) = unsafeBinaryOp "-"
695 (-) = unsafeBinaryOp "-"
382 (*) = unsafeBinaryOp "*"
696 (*) = unsafeBinaryOp "*"
@@ -388,7 +702,7 @@ instance ty `In` PGNum
390instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
704instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
705+ (Expression outer grp commons schemas params from (null ty)) where
392 (/) = unsafeBinaryOp "/"
706 (/) = unsafeBinaryOp "/"
393 fromRational
707 fromRational
394 = UnsafeExpression
708 = UnsafeExpression
@@ -398,7 +712,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398 . fromRat @Double
712 . fromRat @Double
400instance (ty `In` PGNum, ty `In` PGFloating) => Floating
714instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
715+ (Expression outer grp commons schemas params from (null ty)) where
402 pi = UnsafeExpression "pi()"
716 pi = UnsafeExpression "pi()"
403 exp = unsafeFunction "exp"
717 exp = unsafeFunction "exp"
404 log = unsafeFunction "ln"
718 log = unsafeFunction "ln"
@@ -419,54 +733,1748 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419 acosh x = log (x + sqrt (x*x - 1))
733 acosh x = log (x + sqrt (x*x - 1))
420 atanh x = log ((1 + x) / (1 - x)) / 2
734 atanh x = log ((1 + x) / (1 - x)) / 2
422−-- | Contained by operators
736+-- | >>> :{
423−class PGSubset ty where
737+-- let
424− (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
738+-- expression :: Expr (null 'PGfloat4)
425− (@>) = unsafeBinaryOp "@>"
739+-- expression = atan2_ (pi *: 2)
426− (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
740+-- in printSQL expression
744+ :: float `In` PGFloating
745+ => FunctionHet '[ null float, null float] (null float)
746+atan2_ = unsafeFunctionHet "atan2"
748+-- When a `cast` is applied to an `Expression` of a known type, it
749+-- represents a run-time type conversion. The cast will succeed only if a
750+-- suitable type conversion operation has been defined.
752+-- | >>> printSQL $ true & cast int4
755+ :: TypeExpression schemas ty1
756+ -- ^ type to cast as
757+ -> Expression outer grp commons schemas params from ty0
758+ -- ^ value to convert
759+ -> Expression outer grp commons schemas params from ty1
760+cast ty x = UnsafeExpression $ parenthesized $
761+ renderSQL x <+> "::" <+> renderSQL ty
763+-- | integer division, truncates the result
767+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
768+-- expression = 5 `quot_` 2
769+-- in printSQL expression
773+ :: int `In` PGIntegral
774+ => Operator (null int) (null int) (null int)
775+quot_ = unsafeBinaryOp "/"
777+-- | remainder upon integer division
781+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
782+-- expression = 5 `rem_` 2
783+-- in printSQL expression
787+ :: int `In` PGIntegral
788+ => Operator (null int) (null int) (null int)
427− (<@) = unsafeBinaryOp "<@"
789+rem_ = unsafeBinaryOp "%"
428−instance PGSubset 'PGjsonb
790+
429−instance PGSubset 'PGtsquery
791+-- | >>> :{
430−instance PGSubset ('PGvararray ty)
792+-- let
431−instance PGSubset ('PGrange ty)
793+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
794+-- expression = trunc pi
795+-- in printSQL expression
798+trunc :: frac `In` PGFloating => null frac :--> null frac
799+trunc = unsafeFunction "trunc"
433−class PGIntersect ty where
801+-- | >>> :{
434− (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
802+-- let
435− (@&&) = unsafeBinaryOp "&&"
803+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
436−instance PGIntersect ('PGvararray ty)
804+-- expression = round_ pi
437−instance PGIntersect ('PGrange ty)
805+-- in printSQL expression
808+round_ :: frac `In` PGFloating => null frac :--> null frac
809+round_ = unsafeFunction "round"
813+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
814+-- expression = ceiling_ pi
815+-- in printSQL expression
818+ceiling_ :: frac `In` PGFloating => null frac :--> null frac
819+ceiling_ = unsafeFunction "ceiling"
821+-- | A `Condition` is an `Expression`, which can evaluate
822+-- to `true`, `false` or `null_`. This is because SQL uses
823+-- a three valued logic.
824+type Condition outer grp commons schemas params from =
825+ Expression outer grp commons schemas params from ('Null 'PGbool)
827+-- | >>> printSQL true
829+true :: Expr (null 'PGbool)
830+true = UnsafeExpression "TRUE"
832+-- | >>> printSQL false
834+false :: Expr (null 'PGbool)
835+false = UnsafeExpression "FALSE"
837+-- | >>> printSQL $ not_ true
839+not_ :: null 'PGbool :--> null 'PGbool
840+not_ = unsafeUnaryOpL "NOT"
842+-- | >>> printSQL $ true .&& false
844+(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
846+(.&&) = unsafeBinaryOp "AND"
848+-- | >>> printSQL $ true .|| false
850+(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
852+(.||) = unsafeBinaryOp "OR"
856+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
857+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
858+-- in printSQL expression
860+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
862+ :: [ ( Condition outer grp commons schemas params from
863+ , Expression outer grp commons schemas params from ty
865+ -- ^ whens and thens
866+ -> Expression outer grp commons schemas params from ty
868+ -> Expression outer grp commons schemas params from ty
869+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
873+ [ " WHEN ", renderSQL when_
874+ , " THEN ", renderSQL then_
876+ | (when_,then_) <- whenThens
878+ , " ELSE ", renderSQL else_
884+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
885+-- expression = ifThenElse true 1 0
886+-- in printSQL expression
888+-- CASE WHEN TRUE THEN 1 ELSE 0 END
890+ :: Condition outer grp commons schemas params from
891+ -> Expression outer grp commons schemas params from ty -- ^ then
892+ -> Expression outer grp commons schemas params from ty -- ^ else
893+ -> Expression outer grp commons schemas params from ty
894+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
896+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
897+-- will produce @NULL@s if one of their arguments is @NULL@.
899+-- >>> printSQL $ true .== null_
901+(.==) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
902+(.==) = unsafeBinaryOp "="
905+-- | >>> printSQL $ true ./= null_
907+(./=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
908+(./=) = unsafeBinaryOp "<>"
911+-- | >>> printSQL $ true .>= null_
913+(.>=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
914+(.>=) = unsafeBinaryOp ">="
917+-- | >>> printSQL $ true .< null_
919+(.<) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
920+(.<) = unsafeBinaryOp "<"
923+-- | >>> printSQL $ true .<= null_
925+(.<=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
926+(.<=) = unsafeBinaryOp "<="
929+-- | >>> printSQL $ true .> null_
931+(.>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
932+(.>) = unsafeBinaryOp ">"
935+{- | >>> printSQL $ true `between` (null_, false)
936+TRUE BETWEEN NULL AND FALSE
939+ :: Expression outer grp commons schemas params from (null ty)
940+ -> ( Expression outer grp commons schemas params from (null ty)
941+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
942+ -> Condition outer grp commons schemas params from
943+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
944+ <+> renderSQL x <+> "AND" <+> renderSQL y
946+{- | >>> printSQL $ true `notBetween` (null_, false)
947+TRUE NOT BETWEEN NULL AND FALSE
950+ :: Expression outer grp commons schemas params from (null ty)
951+ -> ( Expression outer grp commons schemas params from (null ty)
952+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
953+ -> Condition outer grp commons schemas params from
954+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
955+ <+> renderSQL x <+> "AND" <+> renderSQL y
957+{- | between, after sorting the comparison values
959+>>> printSQL $ true `betweenSymmetric` (null_, false)
960+TRUE BETWEEN SYMMETRIC NULL AND FALSE
963+ :: Expression outer grp commons schemas params from (null ty)
964+ -> ( Expression outer grp commons schemas params from (null ty)
965+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
966+ -> Condition outer grp commons schemas params from
967+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
968+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
970+{- | not between, after sorting the comparison values
972+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
973+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
976+ :: Expression outer grp commons schemas params from (null ty)
977+ -> ( Expression outer grp commons schemas params from (null ty)
978+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
979+ -> Condition outer grp commons schemas params from
980+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
981+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
983+{- | not equal, treating null like an ordinary value
985+>>> printSQL $ true `isDistinctFrom` null_
986+(TRUE IS DISTINCT FROM NULL)
988+isDistinctFrom :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
989+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
991+{- | equal, treating null like an ordinary value
993+>>> printSQL $ true `isNotDistinctFrom` null_
994+(TRUE IS NOT DISTINCT FROM NULL)
996+isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ('NotNull 'PGbool)
997+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
1001+>>> printSQL $ true & isTrue
1004+isTrue :: null0 'PGbool :--> null1 'PGbool
1005+isTrue = unsafeUnaryOpR "IS TRUE"
1007+{- | is false or unknown
1009+>>> printSQL $ true & isNotTrue
1012+isNotTrue :: null0 'PGbool :--> null1 'PGbool
1013+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
1017+>>> printSQL $ true & isFalse
1020+isFalse :: null0 'PGbool :--> null1 'PGbool
1021+isFalse = unsafeUnaryOpR "IS FALSE"
1023+{- | is true or unknown
1025+>>> printSQL $ true & isNotFalse
1028+isNotFalse :: null0 'PGbool :--> null1 'PGbool
1029+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1033+>>> printSQL $ true & isUnknown
1036+isUnknown :: null0 'PGbool :--> null1 'PGbool
1037+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1039+{- | is true or false
1041+>>> printSQL $ true & isNotUnknown
1042+(TRUE IS NOT UNKNOWN)
1044+isNotUnknown :: null0 'PGbool :--> null1 'PGbool
1045+isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"
1047+-- | >>> printSQL currentDate
1049+currentDate :: Expr (null 'PGdate)
1050+currentDate = UnsafeExpression "CURRENT_DATE"
1052+-- | >>> printSQL currentTime
1054+currentTime :: Expr (null 'PGtimetz)
1055+currentTime = UnsafeExpression "CURRENT_TIME"
1057+-- | >>> printSQL currentTimestamp
1058+-- CURRENT_TIMESTAMP
1059+currentTimestamp :: Expr (null 'PGtimestamptz)
1060+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1062+-- | >>> printSQL localTime
1064+localTime :: Expr (null 'PGtime)
1065+localTime = UnsafeExpression "LOCALTIME"
1067+-- | >>> printSQL localTimestamp
1069+localTimestamp :: Expr (null 'PGtimestamp)
1070+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1072+{-----------------------------------------
1074+-----------------------------------------}
1076+escape :: Char -> String
439instance IsString
1088instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
1089+ (Expression outer grp commons schemas params from (null 'PGtext)) where
441 fromString str = UnsafeExpression $
1090 fromString str = UnsafeExpression $
442 "E\'" <> fromString (escape =<< str) <> "\'"
1091 "E\'" <> fromString (escape =<< str) <> "\'"
443instance IsString
1092instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1093+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1094+ fromString str = cast tsvector . UnsafeExpression $
446 "E\'" <> fromString (escape =<< str) <> "\'"
1095 "E\'" <> fromString (escape =<< str) <> "\'"
447instance IsString
1096instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
1097+ (Expression outer grp commons schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1098+ fromString str = cast tsquery . UnsafeExpression $
450 "E\'" <> fromString (escape =<< str) <> "\'"
1099 "E\'" <> fromString (escape =<< str) <> "\'"
452instance Semigroup
1101instance 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
1102+ (Expression outer grp commons schemas params from (null 'PGtext)) where
460 (<>) = unsafeBinaryOp "||"
1103 (<>) = unsafeBinaryOp "||"
461instance Semigroup
1104instance Semigroup
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1105+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
463 (<>) = unsafeBinaryOp "||"
1106 (<>) = unsafeBinaryOp "||"
465instance Monoid
1108instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
1109+ (Expression outer grp commons schemas params from (null 'PGtext)) where
467 mempty = fromString ""
1110 mempty = fromString ""
468 mappend = (<>)
1111 mappend = (<>)
469instance Monoid
1112instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1113+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
471 mempty = fromString ""
1114 mempty = fromString ""
472 mappend = (<>)
1115 mappend = (<>)
1117+-- | >>> printSQL $ lower "ARRRGGG"
1118+-- lower(E'ARRRGGG')
1119+lower :: null 'PGtext :--> null 'PGtext
1120+lower = unsafeFunction "lower"
1122+-- | >>> printSQL $ upper "eeee"
1124+upper :: null 'PGtext :--> null 'PGtext
1125+upper = unsafeFunction "upper"
1127+-- | >>> printSQL $ charLength "four"
1128+-- char_length(E'four')
1129+charLength :: null 'PGtext :--> null 'PGint4
1130+charLength = unsafeFunction "char_length"
1132+-- | The `like` expression returns true if the @string@ matches
1133+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1134+-- or underscores, then the pattern only represents the string itself;
1135+-- in that case `like` acts like the equals operator. An underscore (_)
1136+-- in pattern stands for (matches) any single character; a percent sign (%)
1137+-- matches any sequence of zero or more characters.
1139+-- >>> printSQL $ "abc" `like` "a%"
1140+-- (E'abc' LIKE E'a%')
1141+like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1142+like = unsafeBinaryOp "LIKE"
1144+-- | The key word ILIKE can be used instead of LIKE to make the
1145+-- match case-insensitive according to the active locale.
1147+-- >>> printSQL $ "abc" `ilike` "a%"
1148+-- (E'abc' ILIKE E'a%')
1149+ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1150+ilike = unsafeBinaryOp "ILIKE"
1152+{-----------------------------------------
1153+ -- json and jsonb support
1155+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1156+comments lifted directly from this page.
1158+Table 9.44: json and jsonb operators
1159+-----------------------------------------}
1161+-- | Get JSON value (object field or array element) at a key.
1163+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1164+ => Operator (null json) (null key) ('Null json)
1166+(.->) = unsafeBinaryOp "->"
1168+-- | Get JSON value (object field or array element) at a key, as text.
1170+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1171+ => Operator (null json) (null key) ('Null 'PGtext)
1173+(.->>) = unsafeBinaryOp "->>"
1175+-- | Get JSON value at a specified path.
1177+ :: json `In` PGJsonType
1178+ => Operator (null json) (null ('PGvararray ('NotNull 'PGtext))) ('Null json)
1180+(.#>) = unsafeBinaryOp "#>"
1182+-- | Get JSON value at a specified path as text.
1184+ :: json `In` PGJsonType
1185+ => Operator (null json) (null ('PGvararray ('NotNull 'PGtext))) ('Null 'PGtext)
1187+(.#>>) = unsafeBinaryOp "#>>"
1189+-- Additional jsonb operators
1191+class PGSubset container where
1192+ (@>) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1193+ (@>) = unsafeBinaryOp "@>"
1194+ (<@) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1195+ (<@) = unsafeBinaryOp "<@"
1196+instance PGSubset 'PGjsonb
1197+instance PGSubset 'PGtsquery
1198+instance PGSubset ('PGvararray ty)
1200+-- | Does the string exist as a top-level key within the JSON value?
1201+(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ('Null 'PGbool)
1203+(.?) = unsafeBinaryOp "?"
1205+-- | Do any of these array strings exist as top-level keys?
1208+ (null ('PGvararray ('NotNull 'PGtext)))
1211+(.?|) = unsafeBinaryOp "?|"
1213+-- | Do all of these array strings exist as top-level keys?
1216+ (null ('PGvararray ('NotNull 'PGtext)))
1219+(.?&) = unsafeBinaryOp "?&"
1221+-- | Concatenate two jsonb values into a new jsonb value.
1223+ (Expression outer grp commons schemas params from (null 'PGjsonb)) where
1224+ (<>) = unsafeBinaryOp "||"
1226+-- | Delete a key or keys from a JSON object, or remove an array element.
1228+-- If the right operand is..
1230+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1231+-- are matched based on their key value.
1233+-- @ text[] @: Delete multiple key/value pairs or string elements
1234+-- from left operand. Key/value pairs are matched based on their key value.
1236+-- @ integer @: Delete the array element with specified index (Negative integers
1237+-- count from the end). Throws an error if top level container is not an array.
1239+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1240+ => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
1242+(.-.) = unsafeBinaryOp "-"
1244+-- | Delete the field or element with specified path (for JSON arrays, negative
1245+-- integers count from the end)
1246+(#-.) :: Operator (null 'PGjsonb) (null ('PGvararray ('NotNull 'PGtext))) (null 'PGjsonb)
1248+(#-.) = unsafeBinaryOp "#-"
1250+{-----------------------------------------
1251+Table 9.45: JSON creation functions
1252+-----------------------------------------}
1254+-- | Literal binary JSON
1255+jsonbLit :: JSON.ToJSON x => x -> Expr (null 'PGjsonb)
1256+jsonbLit = cast jsonb . UnsafeExpression
1257+ . singleQuotedUtf8 . toStrict . JSON.encode
1260+jsonLit :: JSON.ToJSON x => x -> Expr (null 'PGjson)
1261+jsonLit = cast json . UnsafeExpression
1262+ . singleQuotedUtf8 . toStrict . JSON.encode
1264+-- | Returns the value as json. Arrays and composites are converted
1265+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1266+-- type to json, the cast function will be used to perform the conversion;
1267+-- otherwise, a scalar value is produced. For any scalar type other than a
1268+-- number, a Boolean, or a null value, the text representation will be used, in
1269+-- such a fashion that it is a valid json value.
1270+toJson :: null ty :--> null 'PGjson
1271+toJson = unsafeFunction "to_json"
1273+-- | Returns the value as jsonb. Arrays and composites are converted
1274+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1275+-- type to json, the cast function will be used to perform the conversion;
1276+-- otherwise, a scalar value is produced. For any scalar type other than a
1277+-- number, a Boolean, or a null value, the text representation will be used, in
1278+-- such a fashion that it is a valid jsonb value.
1279+toJsonb :: null ty :--> null 'PGjsonb
1280+toJsonb = unsafeFunction "to_jsonb"
1282+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1283+-- becomes a JSON array of arrays.
1284+arrayToJson :: null ('PGvararray ty) :--> null 'PGjson
1285+arrayToJson = unsafeFunction "array_to_json"
1287+-- | Returns the row as a JSON object.
1288+rowToJson :: null ('PGcomposite ty) :--> null 'PGjson
1289+rowToJson = unsafeFunction "row_to_json"
1291+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1293+jsonBuildArray :: SListI tuple => FunctionHet tuple (null 'PGjson)
1294+jsonBuildArray = unsafeFunctionHet "json_build_array"
1296+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1297+-- variadic argument list.
1298+jsonbBuildArray :: SListI tuple => FunctionHet tuple (null 'PGjsonb)
1299+jsonbBuildArray = unsafeFunctionHet "jsonb_build_array"
1301+class PGBuildObject tys where
1302+instance PGBuildObject '[]
1303+instance (PGBuildObject tys, key `In` PGJsonKey)
1304+ => PGBuildObject ('NotNull key ': value ': tys)
1306+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1307+-- argument list. The elements of the argument list must alternate between text
1310+ :: (SListI elems, PGBuildObject elems)
1311+ => FunctionHet elems (null 'PGjson)
1312+jsonBuildObject = unsafeFunctionHet "json_build_object"
1314+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1315+-- variadic argument list. The elements of the argument list must alternate
1316+-- between keys and values.
1318+ :: (SListI elems, PGBuildObject elems)
1319+ => FunctionHet elems (null 'PGjsonb)
1320+jsonbBuildObject = unsafeFunctionHet "jsonb_build_object"
1322+-- | Builds a JSON object out of a text array.
1323+-- The array must have two dimensions
1324+-- such that each inner array has exactly two elements,
1325+-- which are taken as a key/value pair.
1327+ :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))
1329+jsonObject = unsafeFunction "json_object"
1331+-- | Builds a binary JSON object out of a text array.
1332+-- The array must have two dimensions
1333+-- such that each inner array has exactly two elements,
1334+-- which are taken as a key/value pair.
1336+ :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))
1338+jsonbObject = unsafeFunction "jsonb_object"
1340+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1341+-- keys and one for values, that are zipped pairwise to create a JSON object.
1342+jsonZipObject :: FunctionHet
1343+ '[ null ('PGvararray ('NotNull 'PGtext))
1344+ , null ('PGvararray ('NotNull 'PGtext)) ]
1346+jsonZipObject = unsafeFunctionHet "json_object"
1348+-- | This is an alternate form of 'jsonbObject' that takes two arrays; one for
1349+-- keys and one for values, that are zipped pairwise to create a binary JSON
1351+jsonbZipObject :: FunctionHet
1352+ '[ null ('PGvararray ('NotNull 'PGtext))
1353+ , null ('PGvararray ('NotNull 'PGtext)) ]
1355+jsonbZipObject = unsafeFunctionHet "jsonb_object"
1357+{-----------------------------------------
1358+Table 9.46: JSON processing functions
1359+-----------------------------------------}
1361+-- | Returns the number of elements in the outermost JSON array.
1362+jsonArrayLength :: null 'PGjson :--> null 'PGint4
1363+jsonArrayLength = unsafeFunction "json_array_length"
1365+-- | Returns the number of elements in the outermost binary JSON array.
1366+jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
1367+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1369+-- | Returns JSON value pointed to by the given path (equivalent to #>
1373+ => Expression outer grp commons schemas params from (null 'PGjson)
1374+ -> NP (Expression outer grp commons schemas params from) elems
1375+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1376+jsonExtractPath x xs =
1377+ unsafeFunctionHet "json_extract_path" (x :* xs)
1379+-- | Returns JSON value pointed to by the given path (equivalent to #>
1383+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1384+ -> NP (Expression outer grp commons schemas params from) elems
1385+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1386+jsonbExtractPath x xs =
1387+ unsafeFunctionHet "jsonb_extract_path" (x :* xs)
1389+-- | Returns JSON value pointed to by the given path (equivalent to #>
1390+-- operator), as text.
1391+jsonExtractPathAsText
1393+ => Expression outer grp commons schemas params from (null 'PGjson)
1394+ -> NP (Expression outer grp commons schemas params from) elems
1395+ -> Expression outer grp commons schemas params from (null 'PGjson)
1396+jsonExtractPathAsText x xs =
1397+ unsafeFunctionHet "json_extract_path_text" (x :* xs)
1399+-- | Returns JSON value pointed to by the given path (equivalent to #>
1400+-- operator), as text.
1401+jsonbExtractPathAsText
1403+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1404+ -> NP (Expression outer grp commons schemas params from) elems
1405+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1406+jsonbExtractPathAsText x xs =
1407+ unsafeFunctionHet "jsonb_extract_path_text" (x :* xs)
1409+-- | Returns the type of the outermost JSON value as a text string. Possible
1410+-- types are object, array, string, number, boolean, and null.
1411+jsonTypeof :: null 'PGjson :--> null 'PGtext
1412+jsonTypeof = unsafeFunction "json_typeof"
1414+-- | Returns the type of the outermost binary JSON value as a text string.
1415+-- Possible types are object, array, string, number, boolean, and null.
1416+jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
1417+jsonbTypeof = unsafeFunction "jsonb_typeof"
1419+-- | Returns its argument with all object fields that have null values omitted.
1420+-- Other null values are untouched.
1421+jsonStripNulls :: null 'PGjson :--> null 'PGjson
1422+jsonStripNulls = unsafeFunction "json_strip_nulls"
1424+-- | Returns its argument with all object fields that have null values omitted.
1425+-- Other null values are untouched.
1426+jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
1427+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1429+-- | @ jsonbSet target path new_value create_missing @
1431+-- Returns target with the section designated by path replaced by new_value,
1432+-- or with new_value added if create_missing is true ( default is true) and the
1433+-- item designated by path does not exist. As with the path orientated
1434+-- operators, negative integers that appear in path count from the end of JSON
1437+ :: Expression outer grp commons schemas params from (null 'PGjsonb)
1438+ -> Expression outer grp commons schemas params from (null ('PGvararray ('NotNull 'PGtext)))
1439+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1440+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1441+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1442+jsonbSet tgt path val createMissing = case createMissing of
1443+ Just m -> unsafeFunctionHet "jsonb_set" (tgt :* path :* val :* m :* Nil)
1444+ Nothing -> unsafeFunctionHet "jsonb_set" (tgt :* path :* val :* Nil)
1446+-- | @ jsonbInsert target path new_value insert_after @
1448+-- Returns target with new_value inserted. If target section designated by
1449+-- path is in a JSONB array, new_value will be inserted before target or after
1450+-- if insert_after is true (default is false). If target section designated by
1451+-- path is in JSONB object, new_value will be inserted only if target does not
1452+-- exist. As with the path orientated operators, negative integers that appear
1453+-- in path count from the end of JSON arrays.
1455+ :: Expression outer grp commons schemas params from (null 'PGjsonb)
1456+ -> Expression outer grp commons schemas params from (null ('PGvararray ('NotNull 'PGtext)))
1457+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1458+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1459+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1460+jsonbInsert tgt path val insertAfter = case insertAfter of
1461+ Just i -> unsafeFunctionHet "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1462+ Nothing -> unsafeFunctionHet "jsonb_insert" (tgt :* path :* val :* Nil)
1464+-- | Returns its argument as indented JSON text.
1465+jsonbPretty :: null 'PGjsonb :--> null 'PGtext
1466+jsonbPretty = unsafeFunction "jsonb_pretty"
1468+(@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)
1469+(@@) = unsafeBinaryOp "@@"
1471+(.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1472+(.&) = unsafeBinaryOp "&&"
1474+(.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1475+(.|) = unsafeBinaryOp "||"
1477+(.!) :: null 'PGtsquery :--> null 'PGtsquery
1478+(.!) = unsafeUnaryOpL "!!"
1480+(<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1481+(<->) = unsafeBinaryOp "<->"
1484+ :: null ('PGvararray ('NotNull 'PGtext))
1485+ :--> null 'PGtsvector
1486+arrayToTSvector = unsafeFunction "array_to_tsvector"
1488+tsvectorLength :: null 'PGtsvector :--> null 'PGint4
1489+tsvectorLength = unsafeFunction "length"
1491+numnode :: null 'PGtsquery :--> null 'PGint4
1492+numnode = unsafeFunction "numnode"
1494+plainToTSquery :: null 'PGtext :--> null 'PGtsquery
1495+plainToTSquery = unsafeFunction "plainto_tsquery"
1497+phraseToTSquery :: null 'PGtext :--> null 'PGtsquery
1498+phraseToTSquery = unsafeFunction "phraseto_tsquery"
1500+websearchToTSquery :: null 'PGtext :--> null 'PGtsquery
1501+websearchToTSquery = unsafeFunction "websearch_to_tsquery"
1503+queryTree :: null 'PGtsquery :--> null 'PGtext
1504+queryTree = unsafeFunction "query_tree"
1506+toTSquery :: null 'PGtext :--> null 'PGtsquery
1507+toTSquery = unsafeFunction "to_tsquery"
1510+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1511+ => null ty :--> null 'PGtsquery
1512+toTSvector = unsafeFunction "to_tsvector"
1515+ :: FunctionHet '[null 'PGtsvector, null ('PGchar 1)] (null 'PGtsvector)
1516+setWeight = unsafeFunctionHet "set_weight"
1518+litChar :: Char -> Expr (null ('PGchar 1))
1519+litChar chr = UnsafeExpression $
1520+ "E\'" <> fromString (escape =<< [chr]) <> "\'"
1522+strip :: null 'PGtsvector :--> null 'PGtsvector
1523+strip = unsafeFunction "strip"
1525+jsonToTSvector :: FunctionHet '[null 'PGjson, null 'PGjson] (null 'PGtsvector)
1526+jsonToTSvector = unsafeFunctionHet "json_to_tsvector"
1528+jsonbToTSvector :: FunctionHet '[null 'PGjsonb, null 'PGjsonb] (null 'PGtsvector)
1529+jsonbToTSvector = unsafeFunctionHet "jsonb_to_tsvector"
1531+tsDelete :: FunctionHet
1532+ '[null 'PGtsvector, null ('PGvararray ('NotNull 'PGtext))]
1534+tsDelete = unsafeFunctionHet "ts_delete"
1536+tsFilter :: FunctionHet
1537+ '[null 'PGtsvector, null ('PGvararray ('NotNull ('PGchar 1)))]
1539+tsFilter = unsafeFunctionHet "ts_filter"
1542+ :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1543+ => FunctionHet '[null document, null 'PGtsquery] (null 'PGtext)
1544+tsHeadline = unsafeFunctionHet "ts_headline"
1545+{-----------------------------------------
1547+-----------------------------------------}
1550+ = forall outer bys commons schemas params from
1551+ . Distinction (Expression outer 'Ungrouped commons schemas params from) x
1553+ -> Expression outer ('Grouped bys) commons schemas params from y
1557+ = forall outer bys commons schemas params from
1558+ . Distinction (NP (Expression outer 'Ungrouped commons schemas params from)) xs
1560+ -> Expression outer ('Grouped bys) commons schemas params from y
1563+unsafeAggregateHet :: SOP.SListI xs => ByteString -> AggrHet xs y
1564+unsafeAggregateHet fun xs = UnsafeExpression $ mconcat
1565+ [fun, "(", renderSQL xs, ")"]
1568+`Aggregate` functions compute a single result from a set of input values.
1569+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1570+as `WindowFunction`s.
1572+class Aggregate expr1 exprHet aggr
1573+ | aggr -> expr1, aggr -> exprHet where
1575+ -- | A special aggregation that does not require an input
1579+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1580+ -- expression = countStar
1581+ -- in printSQL expression
1584+ countStar :: aggr ('NotNull 'PGint8)
1588+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1589+ -- expression = count (All #col)
1590+ -- in printSQL expression
1592+ -- count(ALL "col")
1596+ -> aggr ('NotNull 'PGint8)
1600+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1601+ -- expression = sum_ (Distinct #col)
1602+ -- in printSQL expression
1604+ -- sum(DISTINCT "col")
1608+ -> aggr ('NotNull ty)
1610+ -- | input values, including nulls, concatenated into an array
1613+ -> aggr ('Null ('PGvararray ty))
1615+ -- | aggregates values as a JSON array
1618+ -> aggr ('Null 'PGjson)
1620+ -- | aggregates values as a JSON array
1623+ -> aggr ('Null 'PGjsonb)
1626+ the bitwise AND of all non-null input values, or null if none
1629+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1630+ expression = bitAnd (Distinct #col)
1631+ in printSQL expression
1633+ bit_and(DISTINCT "col")
1636+ :: int `In` PGIntegral
1637+ => expr1 (null int)
1638+ -- ^ what to aggregate
1639+ -> aggr ('Null int)
1642+ the bitwise OR of all non-null input values, or null if none
1646+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1647+ expression = bitOr (All #col)
1648+ in printSQL expression
1653+ :: int `In` PGIntegral
1654+ => expr1 (null int)
1655+ -- ^ what to aggregate
1656+ -> aggr ('Null int)
1659+ true if all input values are true, otherwise false
1663+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1664+ winFun = boolAnd #col
1670+ :: expr1 (null 'PGbool)
1671+ -- ^ what to aggregate
1672+ -> aggr ('Null 'PGbool)
1675+ true if at least one input value is true, otherwise false
1679+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1680+ expression = boolOr (All #col)
1681+ in printSQL expression
1686+ :: expr1 (null 'PGbool)
1687+ -- ^ what to aggregate
1688+ -> aggr ('Null 'PGbool)
1691+ equivalent to `boolAnd`
1695+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1696+ expression = every (Distinct #col)
1697+ in printSQL expression
1699+ every(DISTINCT "col")
1702+ :: expr1 (null 'PGbool)
1703+ -- ^ what to aggregate
1704+ -> aggr ('Null 'PGbool)
1706+ {- |maximum value of expression across all input values-}
1709+ -- ^ what to maximize
1712+ -- | minimum value of expression across all input values
1715+ -- ^ what to minimize
1718+ -- | the average (arithmetic mean) of all input values
1721+ -- ^ what to average
1722+ -> aggr ('Null (PGAvg ty))
1724+ {- | correlation coefficient
1727+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1728+ expression = corr (All (#y *: #x))
1729+ in printSQL expression
1734+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1735+ -> aggr ('Null 'PGfloat8)
1737+ {- | population covariance
1740+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1741+ expression = covarPop (All (#y *: #x))
1742+ in printSQL expression
1744+ covar_pop(ALL "y", "x")
1747+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1748+ -> aggr ('Null 'PGfloat8)
1750+ {- | sample covariance
1753+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1754+ winFun = covarSamp (#y *: #x)
1757+ covar_samp("y", "x")
1760+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1761+ -> aggr ('Null 'PGfloat8)
1763+ {- | average of the independent variable (sum(X)/N)
1766+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1767+ expression = regrAvgX (All (#y *: #x))
1768+ in printSQL expression
1770+ regr_avgx(ALL "y", "x")
1773+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1774+ -> aggr ('Null 'PGfloat8)
1776+ {- | average of the dependent variable (sum(Y)/N)
1779+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1780+ winFun = regrAvgY (#y *: #x)
1783+ regr_avgy("y", "x")
1786+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1787+ -> aggr ('Null 'PGfloat8)
1789+ {- | number of input rows in which both expressions are nonnull
1792+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1793+ winFun = regrCount (#y *: #x)
1796+ regr_count("y", "x")
1799+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1800+ -> aggr ('Null 'PGint8)
1802+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1805+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1806+ expression = regrIntercept (All (#y *: #x))
1807+ in printSQL expression
1809+ regr_intercept(ALL "y", "x")
1812+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1813+ -> aggr ('Null 'PGfloat8)
1815+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1817+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1818+ -> aggr ('Null 'PGfloat8)
1820+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1821+ -- determined by the (X, Y) pairs
1823+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1824+ -> aggr ('Null 'PGfloat8)
1826+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1827+ -- (“sum of squares” of the independent variable)
1829+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1830+ -> aggr ('Null 'PGfloat8)
1832+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1833+ -- (“sum of products” of independent times dependent variable)
1835+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1836+ -> aggr ('Null 'PGfloat8)
1838+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1839+ -- (“sum of squares” of the dependent variable)
1841+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1842+ -> aggr ('Null 'PGfloat8)
1844+ -- | historical alias for `stddevSamp`
1847+ -> aggr ('Null (PGAvg ty))
1849+ -- | population standard deviation of the input values
1852+ -> aggr ('Null (PGAvg ty))
1854+ -- | sample standard deviation of the input values
1857+ -> aggr ('Null (PGAvg ty))
1859+ -- | historical alias for `varSamp`
1862+ -> aggr ('Null (PGAvg ty))
1864+ -- | population variance of the input values
1865+ -- (square of the population standard deviation)
1868+ -> aggr ('Null (PGAvg ty))
1870+ -- | sample variance of the input values
1871+ -- (square of the sample standard deviation)
1874+ -> aggr ('Null (PGAvg ty))
1877+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1878+`All` invokes the aggregate once for each input row.
1879+`Distinct` invokes the aggregate once for each distinct value of the expression
1880+(or distinct set of values, for multiple expressions) found in the input
1882+data Distinction (expr :: kind -> Type) (ty :: kind)
1884+ | Distinct (expr ty)
1885+ deriving (GHC.Generic,Show,Eq,Ord)
1886+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1887+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1889+ All x -> "ALL" <+> renderSQL x
1890+ Distinct x -> "DISTINCT" <+> renderSQL x
1891+instance SOP.SListI tys => RenderSQL
1892+ (Distinction (NP (Expression outer grp commons schemas params from)) tys) where
1894+ All xs -> "ALL" <+> renderCommaSeparated renderSQL xs
1895+ Distinct xs -> "DISTINCT" <+> renderCommaSeparated renderSQL xs
1898+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1899+ (Distinction (NP (Expression outer 'Ungrouped commons schemas params from)))
1900+ (Expression outer ('Grouped bys) commons schemas params from) where
1901+ countStar = UnsafeExpression "count(*)"
1902+ count = unsafeAggregate1 "count"
1903+ sum_ = unsafeAggregate1 "sum"
1904+ arrayAgg = unsafeAggregate1 "array_agg"
1905+ jsonAgg = unsafeAggregate1 "json_agg"
1906+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1907+ bitAnd = unsafeAggregate1 "bit_and"
1908+ bitOr = unsafeAggregate1 "bit_or"
1909+ boolAnd = unsafeAggregate1 "bool_and"
1910+ boolOr = unsafeAggregate1 "bool_or"
1911+ every = unsafeAggregate1 "every"
1912+ max_ = unsafeAggregate1 "max"
1913+ min_ = unsafeAggregate1 "min"
1914+ avg = unsafeAggregate1 "avg"
1915+ corr = unsafeAggregateHet "corr"
1916+ covarPop = unsafeAggregateHet "covar_pop"
1917+ covarSamp = unsafeAggregateHet "covar_samp"
1918+ regrAvgX = unsafeAggregateHet "regr_avgx"
1919+ regrAvgY = unsafeAggregateHet "regr_avgy"
1920+ regrCount = unsafeAggregateHet "regr_count"
1921+ regrIntercept = unsafeAggregateHet "regr_intercept"
1922+ regrR2 = unsafeAggregateHet "regr_r2"
1923+ regrSlope = unsafeAggregateHet "regr_slope"
1924+ regrSxx = unsafeAggregateHet "regr_sxx"
1925+ regrSxy = unsafeAggregateHet "regr_sxy"
1926+ regrSyy = unsafeAggregateHet "regr_syy"
1927+ stddev = unsafeAggregate1 "stddev"
1928+ stddevPop = unsafeAggregate1 "stddev_pop"
1929+ stddevSamp = unsafeAggregate1 "stddev_samp"
1930+ variance = unsafeAggregate1 "variance"
1931+ varPop = unsafeAggregate1 "var_pop"
1932+ varSamp = unsafeAggregate1 "var_samp"
1934+ (Expression outer grp commons schemas params from)
1935+ (NP (Expression outer grp commons schemas params from))
1936+ (WindowFunction outer grp commons schemas params from) where
1937+ countStar = UnsafeWindowFunction "count(*)"
1938+ count = unsafeWindowFunction1 "count"
1939+ sum_ = unsafeWindowFunction1 "sum"
1940+ arrayAgg = unsafeWindowFunction1 "array_agg"
1941+ jsonAgg = unsafeWindowFunction1 "json_agg"
1942+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1943+ bitAnd = unsafeWindowFunction1 "bit_and"
1944+ bitOr = unsafeWindowFunction1 "bit_or"
1945+ boolAnd = unsafeWindowFunction1 "bool_and"
1946+ boolOr = unsafeWindowFunction1 "bool_or"
1947+ every = unsafeWindowFunction1 "every"
1948+ max_ = unsafeWindowFunction1 "max"
1949+ min_ = unsafeWindowFunction1 "min"
1950+ avg = unsafeWindowFunction1 "avg"
1951+ corr = unsafeWindowFunctionHet "corr"
1952+ covarPop = unsafeWindowFunctionHet "covar_pop"
1953+ covarSamp = unsafeWindowFunctionHet "covar_samp"
1954+ regrAvgX = unsafeWindowFunctionHet "regr_avgx"
1955+ regrAvgY = unsafeWindowFunctionHet "regr_avgy"
1956+ regrCount = unsafeWindowFunctionHet "regr_count"
1957+ regrIntercept = unsafeWindowFunctionHet "regr_intercept"
1958+ regrR2 = unsafeWindowFunctionHet "regr_r2"
1959+ regrSlope = unsafeWindowFunctionHet "regr_slope"
1960+ regrSxx = unsafeWindowFunctionHet "regr_sxx"
1961+ regrSxy = unsafeWindowFunctionHet "regr_sxy"
1962+ regrSyy = unsafeWindowFunctionHet "regr_syy"
1963+ stddev = unsafeWindowFunction1 "stddev"
1964+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1965+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1966+ variance = unsafeWindowFunction1 "variance"
1967+ varPop = unsafeWindowFunction1 "var_pop"
1968+ varSamp = unsafeWindowFunction1 "var_samp"
1970+-- | escape hatch to define aggregate functions
1972+ :: ByteString -- ^ aggregate function
1974+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1975+ [fun, "(", renderSQL x, ")"]
1977+-- | A type family that calculates `PGAvg` type of a `PGType`.
1978+type family PGAvg ty where
1979+ PGAvg 'PGint2 = 'PGnumeric
1980+ PGAvg 'PGint4 = 'PGnumeric
1981+ PGAvg 'PGint8 = 'PGnumeric
1982+ PGAvg 'PGnumeric = 'PGnumeric
1983+ PGAvg 'PGfloat4 = 'PGfloat8
1984+ PGAvg 'PGfloat8 = 'PGfloat8
1985+ PGAvg 'PGinterval = 'PGinterval
1986+ PGAvg pg = TypeError
1987+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1989+{-----------------------------------------
1991+-----------------------------------------}
1993+-- | `TypeExpression`s are used in `cast`s and
1994+-- `Squeal.PostgreSQL.Definition.createTable` commands.
1995+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1996+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1997+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1998+instance RenderSQL (TypeExpression schemas ty) where
1999+ renderSQL = renderTypeExpression
2001+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
2003+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
2004+ => QualifiedAlias sch td
2005+ -> TypeExpression schemas (null ty)
2006+typedef = UnsafeTypeExpression . renderSQL
2008+-- | The composite type corresponding to a `Table` definition can be expressed
2011+ :: (Has sch schemas schema, Has tab schema ('Table table))
2012+ => QualifiedAlias sch tab
2013+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
2014+typetable = UnsafeTypeExpression . renderSQL
2016+-- | The composite type corresponding to a `View` definition can be expressed
2019+ :: (Has sch schemas schema, Has vw schema ('View view))
2020+ => QualifiedAlias sch vw
2021+ -> TypeExpression schemas (null ('PGcomposite view))
2022+typeview = UnsafeTypeExpression . renderSQL
2024+-- | logical Boolean (true/false)
2025+bool :: TypeExpression schemas (null 'PGbool)
2026+bool = UnsafeTypeExpression "bool"
2027+-- | signed two-byte integer
2028+int2, smallint :: TypeExpression schemas (null 'PGint2)
2029+int2 = UnsafeTypeExpression "int2"
2030+smallint = UnsafeTypeExpression "smallint"
2031+-- | signed four-byte integer
2032+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2033+int4 = UnsafeTypeExpression "int4"
2034+int = UnsafeTypeExpression "int"
2035+integer = UnsafeTypeExpression "integer"
2036+-- | signed eight-byte integer
2037+int8, bigint :: TypeExpression schemas (null 'PGint8)
2038+int8 = UnsafeTypeExpression "int8"
2039+bigint = UnsafeTypeExpression "bigint"
2040+-- | arbitrary precision numeric type
2041+numeric :: TypeExpression schemas (null 'PGnumeric)
2042+numeric = UnsafeTypeExpression "numeric"
2043+-- | single precision floating-point number (4 bytes)
2044+float4, real :: TypeExpression schemas (null 'PGfloat4)
2045+float4 = UnsafeTypeExpression "float4"
2046+real = UnsafeTypeExpression "real"
2047+-- | double precision floating-point number (8 bytes)
2048+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2049+float8 = UnsafeTypeExpression "float8"
2050+doublePrecision = UnsafeTypeExpression "double precision"
2051+-- | currency amount
2052+money :: TypeExpression schema (null 'PGmoney)
2053+money = UnsafeTypeExpression "money"
2054+-- | variable-length character string
2055+text :: TypeExpression schemas (null 'PGtext)
2056+text = UnsafeTypeExpression "text"
2057+-- | fixed-length character string
2059+ :: forall n schemas null. (KnownNat n, 1 <= n)
2060+ => TypeExpression schemas (null ('PGchar n))
2061+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2062+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2063+-- | variable-length character string
2064+varchar, characterVarying
2065+ :: forall n schemas null. (KnownNat n, 1 <= n)
2066+ => TypeExpression schemas (null ('PGvarchar n))
2067+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2068+characterVarying = UnsafeTypeExpression $
2069+ "character varying(" <> renderNat @n <> ")"
2070+-- | binary data ("byte array")
2071+bytea :: TypeExpression schemas (null 'PGbytea)
2072+bytea = UnsafeTypeExpression "bytea"
2073+-- | date and time (no time zone)
2074+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2075+timestamp = UnsafeTypeExpression "timestamp"
2076+-- | date and time, including time zone
2077+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2078+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2079+-- | calendar date (year, month, day)
2080+date :: TypeExpression schemas (null 'PGdate)
2081+date = UnsafeTypeExpression "date"
2082+-- | time of day (no time zone)
2083+time :: TypeExpression schemas (null 'PGtime)
2084+time = UnsafeTypeExpression "time"
2085+-- | time of day, including time zone
2086+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2087+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2089+interval :: TypeExpression schemas (null 'PGinterval)
2090+interval = UnsafeTypeExpression "interval"
2091+-- | universally unique identifier
2092+uuid :: TypeExpression schemas (null 'PGuuid)
2093+uuid = UnsafeTypeExpression "uuid"
2094+-- | IPv4 or IPv6 host address
2095+inet :: TypeExpression schemas (null 'PGinet)
2096+inet = UnsafeTypeExpression "inet"
2097+-- | textual JSON data
2098+json :: TypeExpression schemas (null 'PGjson)
2099+json = UnsafeTypeExpression "json"
2100+-- | binary JSON data, decomposed
2101+jsonb :: TypeExpression schemas (null 'PGjsonb)
2102+jsonb = UnsafeTypeExpression "jsonb"
2103+-- | variable length array
2105+ :: TypeExpression schemas pg
2106+ -> TypeExpression schemas (null ('PGvararray pg))
2107+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2108+-- | fixed length array
2110+-- >>> renderSQL (fixarray @'[2] json)
2113+ :: forall dims schemas null pg. SOP.All KnownNat dims
2114+ => TypeExpression schemas pg
2115+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2116+fixarray ty = UnsafeTypeExpression $
2117+ renderSQL ty <> renderDims @dims
2119+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2123+ . ByteString.intercalate "]["
2125+ $ hcmap (SOP.Proxy @KnownNat)
2126+ (K . fromString . show . natVal)
2127+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2128+tsvector :: TypeExpression schemas (null 'PGtsvector)
2129+tsvector = UnsafeTypeExpression "tsvector"
2130+tsquery :: TypeExpression schemas (null 'PGtsquery)
2131+tsquery = UnsafeTypeExpression "tsquery"
2133+-- | `pgtype` is a demoted version of a `PGType`
2134+class PGTyped schemas (ty :: NullityType) where
2135+ pgtype :: TypeExpression schemas ty
2136+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2137+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2138+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2139+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2140+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2141+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2142+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2143+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2144+instance PGTyped schemas (null 'PGtext) where pgtype = text
2145+instance (KnownNat n, 1 <= n)
2146+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2147+instance (KnownNat n, 1 <= n)
2148+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2149+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2150+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2151+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2152+instance PGTyped schemas (null 'PGdate) where pgtype = date
2153+instance PGTyped schemas (null 'PGtime) where pgtype = time
2154+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2155+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2156+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2157+instance PGTyped schemas (null 'PGjson) where pgtype = json
2158+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2159+instance PGTyped schemas ty
2160+ => PGTyped schemas (null ('PGvararray ty)) where
2161+ pgtype = vararray (pgtype @schemas @ty)
2162+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2163+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2164+ pgtype = fixarray @dims (pgtype @schemas @ty)
2165+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2166+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2168+{-----------------------------------------
2170+-----------------------------------------}
2172+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2173+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2174+-- set the sort direction of a `NotNull` result
2175+-- column to ascending or descending. Ascending order puts smaller values
2176+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2177+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2178+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2179+-- determine whether nulls appear before or after non-null values in the sort
2180+-- ordering of a `Null` result column.
2181+data SortExpression outer grp commons schemas params from where
2183+ :: Expression outer grp commons schemas params from ('NotNull ty)
2184+ -> SortExpression outer grp commons schemas params from
2186+ :: Expression outer grp commons schemas params from ('NotNull ty)
2187+ -> SortExpression outer grp commons schemas params from
2189+ :: Expression outer grp commons schemas params from ('Null ty)
2190+ -> SortExpression outer grp commons schemas params from
2192+ :: Expression outer grp commons schemas params from ('Null ty)
2193+ -> SortExpression outer grp commons schemas params from
2195+ :: Expression outer grp commons schemas params from ('Null ty)
2196+ -> SortExpression outer grp commons schemas params from
2198+ :: Expression outer grp commons schemas params from ('Null ty)
2199+ -> SortExpression outer grp commons schemas params from
2200+deriving instance Show (SortExpression outer grp commons schemas params from)
2203+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2204+to be sorted according to the specified `SortExpression`(s).
2205+If two rows are equal according to the leftmost expression,
2206+they are compared according to the next expression and so on.
2207+If they are equal according to all specified expressions,
2208+they are returned in an implementation-dependent order.
2210+You can also control the order in which rows are processed by window functions
2211+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2213+class OrderBy expr where
2215+ :: [SortExpression outer grp commons schemas params from]
2216+ -> expr outer grp commons schemas params from
2217+ -> expr outer grp commons schemas params from
2219+-- | Render a `SortExpression`.
2220+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2222+ Asc expression -> renderSQL expression <+> "ASC"
2223+ Desc expression -> renderSQL expression <+> "DESC"
2224+ AscNullsFirst expression -> renderSQL expression
2225+ <+> "ASC NULLS FIRST"
2226+ DescNullsFirst expression -> renderSQL expression
2227+ <+> "DESC NULLS FIRST"
2228+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2229+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2231+-- | A `WindowDefinition` is a set of table rows that are somehow related
2232+-- to the current row
2233+data WindowDefinition outer grp commons schemas params from where
2236+ => NP (Expression outer grp commons schemas params from) bys
2237+ -> [SortExpression outer grp commons schemas params from]
2238+ -> WindowDefinition outer grp commons schemas params from
2240+instance OrderBy WindowDefinition where
2241+ orderBy sortsR (WindowDefinition parts sortsL)
2242+ = WindowDefinition parts (sortsL ++ sortsR)
2244+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2245+ renderSQL (WindowDefinition part ord) =
2246+ renderPartitionByClause part <> renderOrderByClause ord
2248+ renderPartitionByClause = \case
2250+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2251+ renderOrderByClause = \case
2253+ srts -> " ORDER" <+> "BY"
2254+ <+> commaSeparated (renderSQL <$> srts)
2257+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2258+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2259+For each row, the window function is computed across the rows that fall into
2260+the same partition as the current row.
2264+ => NP (Expression outer grp commons schemas params from) bys
2265+ -> WindowDefinition outer grp commons schemas params from
2266+partitionBy bys = WindowDefinition bys []
2269+A window function performs a calculation across a set of table rows
2270+that are somehow related to the current row. This is comparable to the type
2271+of calculation that can be done with an aggregate function.
2272+However, window functions do not cause rows to become grouped into a single
2273+output row like non-window aggregate calls would.
2274+Instead, the rows retain their separate identities.
2275+Behind the scenes, the window function is able to access more than
2276+just the current row of the query result.
2278+newtype WindowFunction
2279+ (outer :: FromType)
2281+ (commons :: FromType)
2282+ (schemas :: SchemasType)
2283+ (params :: [NullityType])
2285+ (ty :: NullityType)
2286+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2287+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2289+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2290+ renderSQL = renderWindowFunction
2293+ = forall outer grp commons schemas params from
2294+ . WindowFunction outer grp commons schemas params from x
2295+ -- ^ cannot reference aliases
2298+ = forall outer grp commons schemas params from
2299+ . Expression outer grp commons schemas params from x
2301+ -> WindowFunction outer grp commons schemas params from y
2305+ = forall outer grp commons schemas params from
2306+ . NP (Expression outer grp commons schemas params from) xs
2308+ -> WindowFunction outer grp commons schemas params from y
2311+unsafeWindowFunction1 :: ByteString -> WinFun1 x y
2312+unsafeWindowFunction1 fun x
2313+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2315+unsafeWindowFunctionHet :: SOP.SListI xs => ByteString -> WinFunHet xs y
2316+unsafeWindowFunctionHet fun xs = UnsafeWindowFunction $ fun <>
2317+ parenthesized (renderCommaSeparated renderSQL xs)
2319+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2323+rank :: WinFun0 ('NotNull 'PGint8)
2324+rank = UnsafeWindowFunction "rank()"
2326+{- | number of the current row within its partition, counting from 1
2327+>>> printSQL rowNumber
2330+rowNumber :: WinFun0 ('NotNull 'PGint8)
2331+rowNumber = UnsafeWindowFunction "row_number()"
2333+{- | rank of the current row without gaps; this function counts peer groups
2334+>>> printSQL denseRank
2337+denseRank :: WinFun0 ('NotNull 'PGint8)
2338+denseRank = UnsafeWindowFunction "dense_rank()"
2340+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2341+>>> printSQL percentRank
2344+percentRank :: WinFun0 ('NotNull 'PGfloat8)
2345+percentRank = UnsafeWindowFunction "percent_rank()"
2347+{- | cumulative distribution: (number of partition rows
2348+preceding or peer with current row) / total partition rows
2349+>>> printSQL cumeDist
2352+cumeDist :: WinFun0 ('NotNull 'PGfloat8)
2353+cumeDist = UnsafeWindowFunction "cume_dist()"
2355+{- | integer ranging from 1 to the argument value,
2356+dividing the partition as equally as possible
2358+ntile :: WinFun1 ('NotNull 'PGint4) ('NotNull 'PGint4)
2359+ntile = unsafeWindowFunction1 "ntile"
2361+{- | returns value evaluated at the row that is offset rows before the current
2362+row within the partition; if there is no such row, instead return default
2363+(which must be of the same type as value). Both offset and default are
2364+evaluated with respect to the current row.
2366+lag :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2367+lag = unsafeWindowFunctionHet "lag"
2369+{- | returns value evaluated at the row that is offset rows after the current
2370+row within the partition; if there is no such row, instead return default
2371+(which must be of the same type as value). Both offset and default are
2372+evaluated with respect to the current row.
2374+lead :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2375+lead = unsafeWindowFunctionHet "lag"
2377+{- | returns value evaluated at the row that is the
2378+first row of the window frame
2380+firstValue :: WinFun1 ty ty
2381+firstValue = unsafeWindowFunction1 "first_value"
2383+{- | returns value evaluated at the row that is the
2384+last row of the window frame
2386+lastValue :: WinFun1 ty ty
2387+lastValue = unsafeWindowFunction1 "last_value"
2389+{- | returns value evaluated at the row that is the nth
2390+row of the window frame (counting from 1); null if no such row
2392+nthValue :: WinFunHet '[null ty, 'NotNull 'PGint4] ('Null ty)
2393+nthValue = unsafeWindowFunctionHet "nth_value"
2396+Create date from year, month and day fields
2398+>>> printSQL (makeDate (1984 :* 7 *: 3))
2399+make_date(1984, 7, 3)
2401+makeDate :: FunctionHet
2402+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2404+makeDate = unsafeFunctionHet "make_date"
2407+Create time from hour, minute and seconds fields
2409+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2410+make_time(8, 15, 23.5)
2412+makeTime :: FunctionHet
2413+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2415+makeTime = unsafeFunctionHet "make_time"
2418+Create timestamp from year, month, day, hour, minute and seconds fields
2420+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2421+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2423+makeTimestamp :: FunctionHet
2424+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2425+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2426+ ( null 'PGtimestamp )
2427+makeTimestamp = unsafeFunctionHet "make_timestamp"
2430+Create timestamp with time zone from
2431+year, month, day, hour, minute and seconds fields;
2432+the current time zone is used
2434+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2435+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2437+makeTimestamptz :: FunctionHet
2438+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2439+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2440+ ( null 'PGtimestamptz )
2441+makeTimestamptz = unsafeFunctionHet "make_timestamptz"
2444+Affine space operations on time types.
2446+class TimeOp time diff | time -> diff where
2448+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2449+ (make_date(1984, 7, 3) + 365)
2451+ (!+) :: Operator (null time) (null diff) (null time)
2452+ (!+) = unsafeBinaryOp "+"
2454+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2455+ (365 + make_date(1984, 7, 3))
2457+ (+!) :: Operator (null diff) (null time) (null time)
2458+ (+!) = unsafeBinaryOp "+"
2460+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2461+ (make_date(1984, 7, 3) - 365)
2463+ (!-) :: Operator (null time) (null diff) (null time)
2464+ (!-) = unsafeBinaryOp "-"
2466+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2467+ (make_date(1984, 7, 3) - CURRENT_DATE)
2469+ (!-!) :: Operator (null time) (null time) (null diff)
2470+ (!-!) = unsafeBinaryOp "-"
2471+instance TimeOp 'PGtimestamp 'PGinterval
2472+instance TimeOp 'PGtimestamptz 'PGinterval
2473+instance TimeOp 'PGtime 'PGinterval
2474+instance TimeOp 'PGtimetz 'PGinterval
2475+instance TimeOp 'PGinterval 'PGinterval
2476+instance TimeOp 'PGdate 'PGint4