@@ -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,406 @@ 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 (..)
67 , PGSubset (..)
56− , PGIntersect (..)
68+ -- ** Functions
97+ , notBetweenSymmetric
124+ -- *** Json and Jsonb operators
129+ -- *** Jsonb operators
155+ , jsonExtractPathAsText
156+ , jsonbExtractPathAsText
175+ , websearchToTSquery
190+ -- * Window Functions
191+ , WindowDefinition (..)
193+ , WindowFunction (..)
206+ , SortExpression (..)
209+ , TypeExpression (..)
235+ , timestampWithTimeZone
57 -- * Re-export
248 -- * Re-export
63import Control.Category
254import Control.Category
64import Control.DeepSeq
255import Control.DeepSeq
65import Data.ByteString (ByteString)
256import Data.ByteString (ByteString)
257+import Data.ByteString.Lazy (toStrict)
66import Data.Function ((&))
258import Data.Function ((&))
67import Data.Semigroup hiding (All)
260import Data.Semigroup hiding (All)
261+import qualified Data.Aeson as JSON
68import Data.String
262import Data.String
69import Generics.SOP hiding (All, from)
264import Generics.SOP hiding (All, from)
70import GHC.OverloadedLabels
265import GHC.OverloadedLabels
71import GHC.TypeLits
266import GHC.TypeLits
72import Numeric
267import Numeric
73import Prelude hiding (id, (.))
268import Prelude hiding (id, (.))
270+import qualified Data.ByteString as ByteString
75import qualified GHC.Generics as GHC
271import qualified GHC.Generics as GHC
272+import qualified Generics.SOP as SOP
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79import Squeal.PostgreSQL.Render
274import Squeal.PostgreSQL.Render
80import Squeal.PostgreSQL.Schema
275import Squeal.PostgreSQL.Schema
83−-- >>> import Squeal.PostgreSQL
85{-----------------------------------------
277{-----------------------------------------
86column expressions
278column expressions
87-----------------------------------------}
279-----------------------------------------}
89{- | `Expression`s are used in a variety of contexts,
281{- | `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,
282+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
283as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93`Squeal.PostgreSQL.Manipulation.update`,
284`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
285+or in search `Condition`s in a number of commands.
96The expression syntax allows the calculation of
287The expression syntax allows the calculation of
97values from primitive expression using arithmetic, logical,
288values from primitive expression using arithmetic, logical,
98and other operations.
289and 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
291newtype Expression
115 (outer :: FromType)
292 (outer :: FromType)
116− (commons :: FromType)
117 (grp :: Grouping)
293 (grp :: Grouping)
294+ (commons :: FromType)
118 (schemas :: SchemasType)
295 (schemas :: SchemasType)
119 (params :: [NullityType])
296 (params :: [NullityType])
120 (from :: FromType)
297 (from :: FromType)
121 (ty :: NullityType)
298 (ty :: NullityType)
122 = UnsafeExpression { renderExpression :: ByteString }
299 = UnsafeExpression { renderExpression :: ByteString }
123 deriving (GHC.Generic,Show,Eq,Ord,NFData)
300 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
301+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125 renderSQL = renderExpression
302 renderSQL = renderExpression
127-- | An `Expr` is a closed `Expression`.
304-- | An `Expr` is a closed `Expression`.
128−-- It is a F@RankNType@ but don't be scared.
305+-- It is a F`RankNType` but don't be scared.
129-- Think of it as an expression which sees no
306-- Think of it as an expression which sees no
130-- namespaces, so you can't use parameters
307-- namespaces, so you can't use parameters
131-- or alias references. It can be used as
308-- or alias references. It can be used as
132-- a simple piece of more complex `Expression`s.
309-- a simple piece of more complex `Expression`s.
133type Expr x
310type Expr x
134− = forall outer commons grp schemas params from
311+ = forall outer grp commons schemas params from
135− . Expression outer commons grp schemas params from x
312+ . Expression outer grp commons schemas params from x
136 -- ^ cannot reference aliases
313 -- ^ cannot reference aliases
138−-- | A @RankNType@ for binary operators.
315+-- | A `RankNType` for binary operators.
139type Operator x1 x2 y
316type Operator x1 x2 y
140− = forall outer commons grp schemas params from
141− . Expression outer commons grp schemas params from x1
317+ = 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
318+ . Expression outer grp commons schemas params from x1
151 -- ^ left input
319 -- ^ left input
152− -> Expression outer commons grp schemas params from x2
320+ -> Expression outer grp commons schemas params from x2
153 -- ^ right input
321 -- ^ right input
154− -> Expression outer commons grp schemas params from y
322+ -> Expression outer grp commons schemas params from y
155 -- ^ output
323 -- ^ output
157−-- | A @RankNType@ for functions with a single argument.
325+-- | A `RankNType` for functions with a single argument.
158-- These could be either function calls or unary operators.
326-- These could be either function calls or unary operators.
159-- This is a subtype of the usual Haskell function type `Prelude.->`,
327-- This is a subtype of the usual Haskell function type `Prelude.->`,
160-- indeed a subcategory as it is closed under the usual
328-- indeed a subcategory as it is closed under the usual
161-- `Prelude..` and `Prelude.id`.
329-- `Prelude..` and `Prelude.id`.
162−type (-->) x y
330+type (:-->) x y
163− = forall outer commons grp schemas params from
331+ = forall outer grp commons schemas params from
164− . Expression outer commons grp schemas params from x
332+ . Expression outer grp commons schemas params from x
165 -- ^ input
333 -- ^ input
166− -> Expression outer commons grp schemas params from y
334+ -> Expression outer grp commons schemas params from y
167 -- ^ output
335 -- ^ 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.
337+{- | A `RankNType` for functions with a fixed-length list of heterogeneous arguments.
177Use the `*:` operator to end your argument lists, like so.
338Use the `*:` operator to end your argument lists, like so.
179−>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
340+>>> printSQL (unsafeFunctionHet "fun" (true :* false :* localTime *: true))
180fun(TRUE, FALSE, LOCALTIME, TRUE)
341fun(TRUE, FALSE, LOCALTIME, TRUE)
182−type (--->) xs y
343+type FunctionHet xs y
183− = forall outer commons grp schemas params from
344+ = 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
345+ . NP (Expression outer grp commons schemas params from) xs
192 -- ^ inputs
346 -- ^ inputs
193− -> Expression outer commons grp schemas params from y
347+ -> Expression outer grp commons schemas params from y
194 -- ^ output
348 -- ^ output
196−{- | A @RankNType@ for functions with a variable-length list of
350+{- | A `RankNType` for functions with a variable-length list of
197homogeneous arguments and at least 1 more argument.
351homogeneous arguments and at least 1 more argument.
199−type FunctionVar x0 x1 y
353+type FunctionHom x0 x1 y
200− = forall outer commons grp schemas params from
354+ = forall outer grp commons schemas params from
201− . [Expression outer commons grp schemas params from x0]
355+ . [Expression outer grp commons schemas params from x0]
202 -- ^ inputs
356 -- ^ inputs
203− -> Expression outer commons grp schemas params from x1
357+ -> Expression outer grp commons schemas params from x1
204 -- ^ must have at least 1 input
358 -- ^ must have at least 1 input
205− -> Expression outer commons grp schemas params from y
359+ -> Expression outer grp commons schemas params from y
206 -- ^ output
360 -- ^ output
208−{- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)
362+{- | >>> printSQL (unsafeFunctionHom "greatest" [true, null_] false)
209greatest(TRUE, NULL, FALSE)
363greatest(TRUE, NULL, FALSE)
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
365+unsafeFunctionHom :: ByteString -> FunctionHom x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
366+unsafeFunctionHom fun xs x = UnsafeExpression $ fun <> parenthesized
213 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
367 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
369+{- | A `HasParameter` constraint is used to indicate a value that is
370+supplied externally to a SQL statement.
371+`Squeal.PostgreSQL.PQ.manipulateParams`,
372+`Squeal.PostgreSQL.PQ.queryParams` and
373+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
374+separately from the SQL command string, in which case `param`s are used to
375+refer to the out-of-line data values.
377+class KnownNat n => HasParameter
379+ (params :: [NullityType])
381+ | n params -> ty where
382+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
384+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
385+ -- >>> printSQL expr
388+ :: TypeExpression schemas ty
389+ -> Expression outer grp commons schemas params from ty
390+ parameter ty = UnsafeExpression $ parenthesized $
391+ "$" <> renderNat @n <+> "::"
393+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
394+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
395+ => HasParameter n (ty' : params) ty
397+-- | `param` takes a `Nat` using type application and for basic types,
398+-- infers a `TypeExpression`.
400+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
404+ :: forall n outer commons schemas params from grp ty
405+ . (PGTyped schemas ty, HasParameter n params ty)
406+ => Expression outer grp commons schemas params from ty -- ^ param
407+param = parameter @n (pgtype @schemas)
215instance (HasUnique tab (Join outer from) row, Has col row ty)
409instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
410+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
411 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
412instance (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
413+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220 fromLabel = fromLabel @col :* Nil
414 fromLabel = fromLabel @col :* Nil
221instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
415instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222 => IsLabel col
416 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
417+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224 fromLabel = fromLabel @col `As` Alias
418 fromLabel = fromLabel @col `As` Alias
225instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
419instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226 => IsLabel col
420 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
421+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228 fromLabel = fromLabel @col :* Nil
422 fromLabel = fromLabel @col :* Nil
230instance (Has tab (Join outer from) row, Has col row ty)
424instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
425+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232 tab ! col = UnsafeExpression $
426 tab ! col = UnsafeExpression $
233 renderSQL tab <> "." <> renderSQL col
427 renderSQL tab <> "." <> renderSQL col
234instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])
428instance (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
429+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236 tab ! col = tab ! col :* Nil
430 tab ! col = tab ! col :* Nil
237instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
431instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238 => IsQualified tab col
432 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
433+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240 tab ! col = tab ! col `As` col
434 tab ! col = tab ! col `As` col
241instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
435instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242 => IsQualified tab col
436 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
437+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244 tab ! col = tab ! col :* Nil
438 tab ! col = tab ! col :* Nil
@@ -248,7 +442,7 @@ instance
248 , Has col row ty
442 , Has col row ty
249 , GroupedBy tab col bys
443 , GroupedBy tab col bys
250 ) => IsLabel col
444 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
445+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
446 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
254 ( HasUnique tab (Join outer from) row
448 ( HasUnique tab (Join outer from) row
@@ -256,7 +450,7 @@ instance
256 , GroupedBy tab col bys
450 , GroupedBy tab col bys
257 , tys ~ '[ty]
451 , tys ~ '[ty]
258 ) => IsLabel col
452 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
453+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260 fromLabel = fromLabel @col :* Nil
454 fromLabel = fromLabel @col :* Nil
262 ( HasUnique tab (Join outer from) row
456 ( HasUnique tab (Join outer from) row
@@ -264,7 +458,7 @@ instance
264 , GroupedBy tab col bys
458 , GroupedBy tab col bys
265 , column ~ (col ::: ty)
459 , column ~ (col ::: ty)
266 ) => IsLabel col
460 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
461+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268 fromLabel = fromLabel @col `As` Alias
462 fromLabel = fromLabel @col `As` Alias
270 ( HasUnique tab (Join outer from) row
464 ( HasUnique tab (Join outer from) row
@@ -272,7 +466,7 @@ instance
272 , GroupedBy tab col bys
466 , GroupedBy tab col bys
273 , columns ~ '[col ::: ty]
467 , columns ~ '[col ::: ty]
274 ) => IsLabel col
468 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
469+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276 fromLabel = fromLabel @col :* Nil
470 fromLabel = fromLabel @col :* Nil
@@ -280,7 +474,7 @@ instance
280 , Has col row ty
474 , Has col row ty
281 , GroupedBy tab col bys
475 , GroupedBy tab col bys
282 ) => IsQualified tab col
476 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
477+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284 tab ! col = UnsafeExpression $
478 tab ! col = UnsafeExpression $
285 renderSQL tab <> "." <> renderSQL col
479 renderSQL tab <> "." <> renderSQL col
@@ -289,7 +483,7 @@ instance
289 , GroupedBy tab col bys
483 , GroupedBy tab col bys
290 , tys ~ '[ty]
484 , tys ~ '[ty]
291 ) => IsQualified tab col
485 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
486+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293 tab ! col = tab ! col :* Nil
487 tab ! col = tab ! col :* Nil
295 ( Has tab (Join outer from) row
489 ( Has tab (Join outer from) row
@@ -297,7 +491,7 @@ instance
297 , GroupedBy tab col bys
491 , GroupedBy tab col bys
298 , column ~ (col ::: ty)
492 , column ~ (col ::: ty)
299 ) => IsQualified tab col
493 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
494+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301 tab ! col = tab ! col `As` col
495 tab ! col = tab ! col `As` col
303 ( Has tab (Join outer from) row
497 ( Has tab (Join outer from) row
@@ -305,78 +499,250 @@ instance
305 , GroupedBy tab col bys
499 , GroupedBy tab col bys
306 , columns ~ '[col ::: ty]
500 , columns ~ '[col ::: ty]
307 ) => IsQualified tab col
501 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
502+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309 tab ! col = tab ! col :* Nil
503 tab ! col = tab ! col :* Nil
505+-- | analagous to `Nothing`
507+-- >>> printSQL null_
509+null_ :: Expr ('Null ty)
510+null_ = UnsafeExpression "NULL"
512+-- | analagous to `Just`
514+-- >>> printSQL $ notNull true
516+notNull :: 'NotNull ty :--> 'Null ty
517+notNull = UnsafeExpression . renderSQL
519+-- | return the leftmost value which is not NULL
521+-- >>> printSQL $ coalesce [null_, true] false
522+-- COALESCE(NULL, TRUE, FALSE)
523+coalesce :: FunctionHom ('Null ty) ('NotNull ty) ('NotNull ty)
524+coalesce nullxs notNullx = UnsafeExpression $
525+ "COALESCE" <> parenthesized (commaSeparated
526+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
528+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
530+-- >>> printSQL $ fromNull true null_
531+-- COALESCE(NULL, TRUE)
533+ :: Expression outer grp commons schemas params from ('NotNull ty)
534+ -- ^ what to convert @NULL@ to
535+ -> Expression outer grp commons schemas params from ('Null ty)
536+ -> Expression outer grp commons schemas params from ('NotNull ty)
537+fromNull notNullx nullx = coalesce [nullx] notNullx
539+-- | >>> printSQL $ null_ & isNull
541+isNull :: 'Null ty :--> null 'PGbool
542+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
544+-- | >>> printSQL $ null_ & isNotNull
546+isNotNull :: 'Null ty :--> null 'PGbool
547+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
549+-- | analagous to `maybe` using @IS NULL@
551+-- >>> printSQL $ matchNull true not_ null_
552+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
554+ :: Expression outer grp commons schemas params from (nullty)
555+ -- ^ what to convert @NULL@ to
556+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
557+ -> Expression outer grp commons schemas params from (nullty) )
558+ -- ^ function to perform when @NULL@ is absent
559+ -> Expression outer grp commons schemas params from ('Null ty)
560+ -> Expression outer grp commons schemas params from (nullty)
561+matchNull y f x = ifThenElse (isNull x) y
562+ (f (UnsafeExpression (renderSQL x)))
564+{-| right inverse to `fromNull`, if its arguments are equal then
565+`nullIf` gives @NULL@.
567+>>> :set -XTypeApplications -XDataKinds
568+>>> let expr = nullIf (false *: param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
570+NULLIF(FALSE, ($1 :: bool))
572+nullIf :: FunctionHet '[ 'NotNull ty, 'NotNull ty] ('Null ty)
573+nullIf = unsafeFunctionHet "NULLIF"
575+-- | >>> printSQL $ array [null_, false, true]
576+-- ARRAY[NULL, FALSE, TRUE]
578+ :: [Expression outer grp commons schemas params from ty]
580+ -> Expression outer grp commons schemas params from (null ('PGvararray ty))
581+array xs = UnsafeExpression $ "ARRAY" <>
582+ bracketed (commaSeparated (renderSQL <$> xs))
584+{- | construct a 1-dimensional fixed length array
586+>>> printSQL $ array1 (null_ :* false *: true)
587+ARRAY[NULL, FALSE, TRUE]
589+>>> :type array1 (null_ :* false *: true)
590+array1 (null_ :* false *: true)
598+ (null ('PGfixarray '[3] ('Null 'PGbool)))
601+ :: (n ~ Length tys, SOP.All ((~) ty) tys)
602+ => NP (Expression outer grp commons schemas params from) tys
603+ -> Expression outer grp commons schemas params from (null ('PGfixarray '[n] ty))
604+array1 xs = UnsafeExpression $ "ARRAY" <>
605+ bracketed (renderCommaSeparated renderSQL xs)
607+{- | construct a 2-dimensional fixed length array
609+>>> printSQL $ array2 ((null_ :* false *: true) *: (false :* null_ *: true))
610+ARRAY[[NULL, FALSE, TRUE], [FALSE, NULL, TRUE]]
612+>>> :type array2 ((null_ :* false *: true) *: (false :* null_ *: true))
613+array2 ((null_ :* false *: true) *: (false :* null_ *: true))
621+ (null ('PGfixarray '[2, 3] ('Null 'PGbool)))
624+ :: ( SOP.All ((~) tys) tyss
625+ , SOP.All SOP.SListI tyss
627+ , SOP.All ((~) ty) tys
629+ => NP (NP (Expression outer grp commons schemas params from)) tyss
630+ -> Expression outer grp commons schemas params from (null ('PGfixarray '[n1,n2] ty))
631+array2 xss = UnsafeExpression $ "ARRAY" <>
632+ bracketed (renderCommaSeparatedConstraint @SOP.SListI (bracketed . renderCommaSeparated renderSQL) xss)
634+-- | >>> printSQL $ cardinality (array [null_, false, true])
635+-- cardinality(ARRAY[NULL, FALSE, TRUE])
636+cardinality :: null ('PGvararray ty) :--> null 'PGint8
637+cardinality = unsafeFunction "cardinality"
639+-- | >>> printSQL $ array [null_, false, true] & index 2
640+-- (ARRAY[NULL, FALSE, TRUE])[2]
642+ :: Word64 -- ^ index
643+ -> null ('PGvararray ty) :--> NullifyType ty
644+index n expr = UnsafeExpression $
645+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
311instance (KnownSymbol label, label `In` labels) => IsPGlabel label
647instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
648+ (Expression outer grp commons schemas params from (null ('PGenum labels))) where
313 label = UnsafeExpression $ renderSQL (PGlabel @label)
649 label = UnsafeExpression $ renderSQL (PGlabel @label)
651+-- | A row constructor is an expression that builds a row value
652+-- (also called a composite value) using values for its member fields.
655+-- type Complex = 'PGcomposite
656+-- '[ "real" ::: 'NotNull 'PGfloat8
657+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
660+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
665+ => NP (Aliased (Expression outer grp commons schemas params from)) row
666+ -- ^ zero or more expressions for the row field values
667+ -> Expression outer grp commons schemas params from (null ('PGcomposite row))
668+row exprs = UnsafeExpression $ "ROW" <> parenthesized
669+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
672+-- type Complex = 'PGcomposite
673+-- '[ "real" ::: 'NotNull 'PGfloat8
674+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
675+-- type Schema = '["complex" ::: 'Typedef Complex]
678+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
679+-- >>> printSQL $ i & field #complex #imaginary
680+-- (ROW(0, 1)::"complex")."imaginary"
682+ :: ( Has sch schemas schema
683+ , Has tydef schema ('Typedef ('PGcomposite row))
685+ => QualifiedAlias sch tydef -- ^ row type
686+ -> Alias field -- ^ field name
687+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
688+ -> Expression outer grp commons schemas params from ty
689+field td fld expr = UnsafeExpression $
690+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
691+ <> "." <> renderSQL fld
694+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
695+ (<>) = unsafeBinaryOp "||"
698+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
702+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
704+-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
705+greatest :: FunctionHom ty ty ty
706+greatest = unsafeFunctionHom "GREATEST"
708+-- | >>> printSQL $ least [null_] currentTimestamp
709+-- LEAST(NULL, CURRENT_TIMESTAMP)
710+least :: FunctionHom ty ty ty
711+least = unsafeFunctionHom "LEAST"
315-- | >>> printSQL $ unsafeBinaryOp "OR" true false
713-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316-- (TRUE OR FALSE)
714-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
715+unsafeBinaryOp :: ByteString {- ^ operator -} -> Operator ty0 ty1 ty2
318unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
716unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319 renderSQL x <+> op <+> renderSQL y
717 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
719+-- | >>> printSQL $ unsafeUnaryOpL "NOT" true
329-- (NOT TRUE)
720-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
721+unsafeUnaryOpL :: ByteString {- ^ operator -} -> x :--> y
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
722+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"
724+-- | >>> printSQL $ true & unsafeUnaryOpR "IS NOT TRUE"
341-- (TRUE IS NOT TRUE)
725-- (TRUE IS NOT TRUE)
342−unsafeRightOp :: ByteString -> x --> y
726+unsafeUnaryOpR :: ByteString {- ^ operator -} -> x :--> y
343−unsafeRightOp op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
727+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
729-- | >>> printSQL $ unsafeFunction "f" true
353-- f(TRUE)
730-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
731+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355unsafeFunction fun x = UnsafeExpression $
732unsafeFunction fun x = UnsafeExpression $
356 fun <> parenthesized (renderSQL x)
733 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')
735+-- | >>> printSQL $ unsafeFunctionHet "f" (currentTime :* localTimestamp :* false *: litChar 'a')
365-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
736-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
366−unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
737+unsafeFunctionHet
739+ => ByteString {- ^ function -}
367−unsafeFunctionN fun xs = UnsafeExpression $
741+unsafeFunctionHet fun xs = UnsafeExpression $
368 fun <> parenthesized (renderCommaSeparated renderSQL xs)
742 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
744instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
745+ => Num (Expression outer grp commons schemas params from (null ty)) where
380 (+) = unsafeBinaryOp "+"
746 (+) = unsafeBinaryOp "+"
381 (-) = unsafeBinaryOp "-"
747 (-) = unsafeBinaryOp "-"
382 (*) = unsafeBinaryOp "*"
748 (*) = unsafeBinaryOp "*"
@@ -388,7 +754,7 @@ instance ty `In` PGNum
390instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
756instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
757+ (Expression outer grp commons schemas params from (null ty)) where
392 (/) = unsafeBinaryOp "/"
758 (/) = unsafeBinaryOp "/"
393 fromRational
759 fromRational
394 = UnsafeExpression
760 = UnsafeExpression
@@ -398,7 +764,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398 . fromRat @Double
764 . fromRat @Double
400instance (ty `In` PGNum, ty `In` PGFloating) => Floating
766instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
767+ (Expression outer grp commons schemas params from (null ty)) where
402 pi = UnsafeExpression "pi()"
768 pi = UnsafeExpression "pi()"
403 exp = unsafeFunction "exp"
769 exp = unsafeFunction "exp"
404 log = unsafeFunction "ln"
770 log = unsafeFunction "ln"
@@ -419,54 +785,1748 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419 acosh x = log (x + sqrt (x*x - 1))
785 acosh x = log (x + sqrt (x*x - 1))
420 atanh x = log ((1 + x) / (1 - x)) / 2
786 atanh x = log ((1 + x) / (1 - x)) / 2
422−-- | Contained by operators
788+-- | >>> :{
423−class PGSubset ty where
789+-- let
424− (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
790+-- expression :: Expr (null 'PGfloat4)
425− (@>) = unsafeBinaryOp "@>"
791+-- expression = atan2_ (pi *: 2)
426− (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
792+-- in printSQL expression
427− (<@) = unsafeBinaryOp "<@"
793+-- :}
428−instance PGSubset 'PGjsonb
794+-- atan2(pi(), 2)
429−instance PGSubset 'PGtsquery
795+atan2_
430−instance PGSubset ('PGvararray ty)
796+ :: float `In` PGFloating
431−instance PGSubset ('PGrange ty)
797+ => FunctionHet '[ null float, null float] (null float)
798+atan2_ = unsafeFunctionHet "atan2"
800+-- When a `cast` is applied to an `Expression` of a known type, it
801+-- represents a run-time type conversion. The cast will succeed only if a
802+-- suitable type conversion operation has been defined.
804+-- | >>> printSQL $ true & cast int4
807+ :: TypeExpression schemas ty1
808+ -- ^ type to cast as
809+ -> Expression outer grp commons schemas params from ty0
810+ -- ^ value to convert
811+ -> Expression outer grp commons schemas params from ty1
812+cast ty x = UnsafeExpression $ parenthesized $
813+ renderSQL x <+> "::" <+> renderSQL ty
815+-- | integer division, truncates the result
819+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
820+-- expression = 5 `quot_` 2
821+-- in printSQL expression
825+ :: int `In` PGIntegral
826+ => Operator (null int) (null int) (null int)
827+quot_ = unsafeBinaryOp "/"
433−class PGIntersect ty where
829+-- | remainder upon integer division
434− (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
830+--
833+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
834+-- expression = 5 `rem_` 2
835+-- in printSQL expression
839+ :: int `In` PGIntegral
840+ => Operator (null int) (null int) (null int)
435− (@&&) = unsafeBinaryOp "&&"
841+rem_ = unsafeBinaryOp "%"
436−instance PGIntersect ('PGvararray ty)
842+
437−instance PGIntersect ('PGrange ty)
843+-- | >>> :{
845+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
846+-- expression = trunc pi
847+-- in printSQL expression
850+trunc :: frac `In` PGFloating => null frac :--> null frac
851+trunc = unsafeFunction "trunc"
855+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
856+-- expression = round_ pi
857+-- in printSQL expression
860+round_ :: frac `In` PGFloating => null frac :--> null frac
861+round_ = unsafeFunction "round"
865+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
866+-- expression = ceiling_ pi
867+-- in printSQL expression
870+ceiling_ :: frac `In` PGFloating => null frac :--> null frac
871+ceiling_ = unsafeFunction "ceiling"
873+-- | A `Condition` is an `Expression`, which can evaluate
874+-- to `true`, `false` or `null_`. This is because SQL uses
875+-- a three valued logic.
876+type Condition outer grp commons schemas params from =
877+ Expression outer grp commons schemas params from ('Null 'PGbool)
879+-- | >>> printSQL true
881+true :: Expr (null 'PGbool)
882+true = UnsafeExpression "TRUE"
884+-- | >>> printSQL false
886+false :: Expr (null 'PGbool)
887+false = UnsafeExpression "FALSE"
889+-- | >>> printSQL $ not_ true
891+not_ :: null 'PGbool :--> null 'PGbool
892+not_ = unsafeUnaryOpL "NOT"
894+-- | >>> printSQL $ true .&& false
896+(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
898+(.&&) = unsafeBinaryOp "AND"
900+-- | >>> printSQL $ true .|| false
902+(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
904+(.||) = unsafeBinaryOp "OR"
908+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
909+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
910+-- in printSQL expression
912+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
914+ :: [ ( Condition outer grp commons schemas params from
915+ , Expression outer grp commons schemas params from ty
917+ -- ^ whens and thens
918+ -> Expression outer grp commons schemas params from ty
920+ -> Expression outer grp commons schemas params from ty
921+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
925+ [ " WHEN ", renderSQL when_
926+ , " THEN ", renderSQL then_
928+ | (when_,then_) <- whenThens
930+ , " ELSE ", renderSQL else_
936+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
937+-- expression = ifThenElse true 1 0
938+-- in printSQL expression
940+-- CASE WHEN TRUE THEN 1 ELSE 0 END
942+ :: Condition outer grp commons schemas params from
943+ -> Expression outer grp commons schemas params from ty -- ^ then
944+ -> Expression outer grp commons schemas params from ty -- ^ else
945+ -> Expression outer grp commons schemas params from ty
946+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
948+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
949+-- will produce @NULL@s if one of their arguments is @NULL@.
951+-- >>> printSQL $ true .== null_
953+(.==) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
954+(.==) = unsafeBinaryOp "="
957+-- | >>> printSQL $ true ./= null_
959+(./=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
960+(./=) = unsafeBinaryOp "<>"
963+-- | >>> printSQL $ true .>= null_
965+(.>=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
966+(.>=) = unsafeBinaryOp ">="
969+-- | >>> printSQL $ true .< null_
971+(.<) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
972+(.<) = unsafeBinaryOp "<"
975+-- | >>> printSQL $ true .<= null_
977+(.<=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
978+(.<=) = unsafeBinaryOp "<="
981+-- | >>> printSQL $ true .> null_
983+(.>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
984+(.>) = unsafeBinaryOp ">"
987+{- | >>> printSQL $ true `between` (null_, false)
988+TRUE BETWEEN NULL AND FALSE
991+ :: Expression outer grp commons schemas params from (null ty)
992+ -> ( Expression outer grp commons schemas params from (null ty)
993+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
994+ -> Condition outer grp commons schemas params from
995+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
996+ <+> renderSQL x <+> "AND" <+> renderSQL y
998+{- | >>> printSQL $ true `notBetween` (null_, false)
999+TRUE NOT BETWEEN NULL AND FALSE
1002+ :: Expression outer grp commons schemas params from (null ty)
1003+ -> ( Expression outer grp commons schemas params from (null ty)
1004+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
1005+ -> Condition outer grp commons schemas params from
1006+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
1007+ <+> renderSQL x <+> "AND" <+> renderSQL y
1009+{- | between, after sorting the comparison values
1011+>>> printSQL $ true `betweenSymmetric` (null_, false)
1012+TRUE BETWEEN SYMMETRIC NULL AND FALSE
1015+ :: Expression outer grp commons schemas params from (null ty)
1016+ -> ( Expression outer grp commons schemas params from (null ty)
1017+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
1018+ -> Condition outer grp commons schemas params from
1019+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
1020+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
1022+{- | not between, after sorting the comparison values
1024+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
1025+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
1028+ :: Expression outer grp commons schemas params from (null ty)
1029+ -> ( Expression outer grp commons schemas params from (null ty)
1030+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
1031+ -> Condition outer grp commons schemas params from
1032+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
1033+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
1035+{- | not equal, treating null like an ordinary value
1037+>>> printSQL $ true `isDistinctFrom` null_
1038+(TRUE IS DISTINCT FROM NULL)
1040+isDistinctFrom :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
1041+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
1043+{- | equal, treating null like an ordinary value
1045+>>> printSQL $ true `isNotDistinctFrom` null_
1046+(TRUE IS NOT DISTINCT FROM NULL)
1048+isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ('NotNull 'PGbool)
1049+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
1053+>>> printSQL $ true & isTrue
1056+isTrue :: null0 'PGbool :--> null1 'PGbool
1057+isTrue = unsafeUnaryOpR "IS TRUE"
1059+{- | is false or unknown
1061+>>> printSQL $ true & isNotTrue
1064+isNotTrue :: null0 'PGbool :--> null1 'PGbool
1065+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
1069+>>> printSQL $ true & isFalse
1072+isFalse :: null0 'PGbool :--> null1 'PGbool
1073+isFalse = unsafeUnaryOpR "IS FALSE"
1075+{- | is true or unknown
1077+>>> printSQL $ true & isNotFalse
1080+isNotFalse :: null0 'PGbool :--> null1 'PGbool
1081+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1085+>>> printSQL $ true & isUnknown
1088+isUnknown :: null0 'PGbool :--> null1 'PGbool
1089+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1091+{- | is true or false
1093+>>> printSQL $ true & isNotUnknown
1094+(TRUE IS NOT UNKNOWN)
1096+isNotUnknown :: null0 'PGbool :--> null1 'PGbool
1097+isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"
1099+-- | >>> printSQL currentDate
1101+currentDate :: Expr (null 'PGdate)
1102+currentDate = UnsafeExpression "CURRENT_DATE"
1104+-- | >>> printSQL currentTime
1106+currentTime :: Expr (null 'PGtimetz)
1107+currentTime = UnsafeExpression "CURRENT_TIME"
1109+-- | >>> printSQL currentTimestamp
1110+-- CURRENT_TIMESTAMP
1111+currentTimestamp :: Expr (null 'PGtimestamptz)
1112+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1114+-- | >>> printSQL localTime
1116+localTime :: Expr (null 'PGtime)
1117+localTime = UnsafeExpression "LOCALTIME"
1119+-- | >>> printSQL localTimestamp
1121+localTimestamp :: Expr (null 'PGtimestamp)
1122+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1124+{-----------------------------------------
1126+-----------------------------------------}
1128+escape :: Char -> String
439instance IsString
1140instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
1141+ (Expression outer grp commons schemas params from (null 'PGtext)) where
441 fromString str = UnsafeExpression $
1142 fromString str = UnsafeExpression $
442 "E\'" <> fromString (escape =<< str) <> "\'"
1143 "E\'" <> fromString (escape =<< str) <> "\'"
443instance IsString
1144instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1145+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1146+ fromString str = cast tsvector . UnsafeExpression $
446 "E\'" <> fromString (escape =<< str) <> "\'"
1147 "E\'" <> fromString (escape =<< str) <> "\'"
447instance IsString
1148instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
1149+ (Expression outer grp commons schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1150+ fromString str = cast tsquery . UnsafeExpression $
450 "E\'" <> fromString (escape =<< str) <> "\'"
1151 "E\'" <> fromString (escape =<< str) <> "\'"
452instance Semigroup
1153instance 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
1154+ (Expression outer grp commons schemas params from (null 'PGtext)) where
460 (<>) = unsafeBinaryOp "||"
1155 (<>) = unsafeBinaryOp "||"
461instance Semigroup
1156instance Semigroup
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1157+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
463 (<>) = unsafeBinaryOp "||"
1158 (<>) = unsafeBinaryOp "||"
465instance Monoid
1160instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
1161+ (Expression outer grp commons schemas params from (null 'PGtext)) where
467 mempty = fromString ""
1162 mempty = fromString ""
468 mappend = (<>)
1163 mappend = (<>)
469instance Monoid
1164instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1165+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
471 mempty = fromString ""
1166 mempty = fromString ""
472 mappend = (<>)
1167 mappend = (<>)
1169+-- | >>> printSQL $ lower "ARRRGGG"
1170+-- lower(E'ARRRGGG')
1171+lower :: null 'PGtext :--> null 'PGtext
1172+lower = unsafeFunction "lower"
1174+-- | >>> printSQL $ upper "eeee"
1176+upper :: null 'PGtext :--> null 'PGtext
1177+upper = unsafeFunction "upper"
1179+-- | >>> printSQL $ charLength "four"
1180+-- char_length(E'four')
1181+charLength :: null 'PGtext :--> null 'PGint4
1182+charLength = unsafeFunction "char_length"
1184+-- | The `like` expression returns true if the @string@ matches
1185+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1186+-- or underscores, then the pattern only represents the string itself;
1187+-- in that case `like` acts like the equals operator. An underscore (_)
1188+-- in pattern stands for (matches) any single character; a percent sign (%)
1189+-- matches any sequence of zero or more characters.
1191+-- >>> printSQL $ "abc" `like` "a%"
1192+-- (E'abc' LIKE E'a%')
1193+like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1194+like = unsafeBinaryOp "LIKE"
1196+-- | The key word ILIKE can be used instead of LIKE to make the
1197+-- match case-insensitive according to the active locale.
1199+-- >>> printSQL $ "abc" `ilike` "a%"
1200+-- (E'abc' ILIKE E'a%')
1201+ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1202+ilike = unsafeBinaryOp "ILIKE"
1204+{-----------------------------------------
1205+ -- json and jsonb support
1207+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1208+comments lifted directly from this page.
1210+Table 9.44: json and jsonb operators
1211+-----------------------------------------}
1213+-- | Get JSON value (object field or array element) at a key.
1215+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1216+ => Operator (null json) (null key) ('Null json)
1218+(.->) = unsafeBinaryOp "->"
1220+-- | Get JSON value (object field or array element) at a key, as text.
1222+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1223+ => Operator (null json) (null key) ('Null 'PGtext)
1225+(.->>) = unsafeBinaryOp "->>"
1227+-- | Get JSON value at a specified path.
1229+ :: json `In` PGJsonType
1230+ => Operator (null json) (null ('PGvararray ('NotNull 'PGtext))) ('Null json)
1232+(.#>) = unsafeBinaryOp "#>"
1234+-- | Get JSON value at a specified path as text.
1236+ :: json `In` PGJsonType
1237+ => Operator (null json) (null ('PGvararray ('NotNull 'PGtext))) ('Null 'PGtext)
1239+(.#>>) = unsafeBinaryOp "#>>"
1241+-- Additional jsonb operators
1243+class PGSubset container where
1244+ (@>) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1245+ (@>) = unsafeBinaryOp "@>"
1246+ (<@) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1247+ (<@) = unsafeBinaryOp "<@"
1248+instance PGSubset 'PGjsonb
1249+instance PGSubset 'PGtsquery
1250+instance PGSubset ('PGvararray ty)
1252+-- | Does the string exist as a top-level key within the JSON value?
1253+(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ('Null 'PGbool)
1255+(.?) = unsafeBinaryOp "?"
1257+-- | Do any of these array strings exist as top-level keys?
1260+ (null ('PGvararray ('NotNull 'PGtext)))
1263+(.?|) = unsafeBinaryOp "?|"
1265+-- | Do all of these array strings exist as top-level keys?
1268+ (null ('PGvararray ('NotNull 'PGtext)))
1271+(.?&) = unsafeBinaryOp "?&"
1273+-- | Concatenate two jsonb values into a new jsonb value.
1275+ (Expression outer grp commons schemas params from (null 'PGjsonb)) where
1276+ (<>) = unsafeBinaryOp "||"
1278+-- | Delete a key or keys from a JSON object, or remove an array element.
1280+-- If the right operand is..
1282+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1283+-- are matched based on their key value.
1285+-- @ text[] @: Delete multiple key/value pairs or string elements
1286+-- from left operand. Key/value pairs are matched based on their key value.
1288+-- @ integer @: Delete the array element with specified index (Negative integers
1289+-- count from the end). Throws an error if top level container is not an array.
1291+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1292+ => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
1294+(.-.) = unsafeBinaryOp "-"
1296+-- | Delete the field or element with specified path (for JSON arrays, negative
1297+-- integers count from the end)
1298+(#-.) :: Operator (null 'PGjsonb) (null ('PGvararray ('NotNull 'PGtext))) (null 'PGjsonb)
1300+(#-.) = unsafeBinaryOp "#-"
1302+{-----------------------------------------
1303+Table 9.45: JSON creation functions
1304+-----------------------------------------}
1306+-- | Literal binary JSON
1307+jsonbLit :: JSON.ToJSON x => x -> Expr (null 'PGjsonb)
1308+jsonbLit = cast jsonb . UnsafeExpression
1309+ . singleQuotedUtf8 . toStrict . JSON.encode
1312+jsonLit :: JSON.ToJSON x => x -> Expr (null 'PGjson)
1313+jsonLit = cast json . UnsafeExpression
1314+ . singleQuotedUtf8 . toStrict . JSON.encode
1316+-- | Returns the value as json. Arrays and composites are converted
1317+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1318+-- type to json, the cast function will be used to perform the conversion;
1319+-- otherwise, a scalar value is produced. For any scalar type other than a
1320+-- number, a Boolean, or a null value, the text representation will be used, in
1321+-- such a fashion that it is a valid json value.
1322+toJson :: null ty :--> null 'PGjson
1323+toJson = unsafeFunction "to_json"
1325+-- | Returns the value as jsonb. Arrays and composites are converted
1326+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1327+-- type to json, the cast function will be used to perform the conversion;
1328+-- otherwise, a scalar value is produced. For any scalar type other than a
1329+-- number, a Boolean, or a null value, the text representation will be used, in
1330+-- such a fashion that it is a valid jsonb value.
1331+toJsonb :: null ty :--> null 'PGjsonb
1332+toJsonb = unsafeFunction "to_jsonb"
1334+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1335+-- becomes a JSON array of arrays.
1336+arrayToJson :: null ('PGvararray ty) :--> null 'PGjson
1337+arrayToJson = unsafeFunction "array_to_json"
1339+-- | Returns the row as a JSON object.
1340+rowToJson :: null ('PGcomposite ty) :--> null 'PGjson
1341+rowToJson = unsafeFunction "row_to_json"
1343+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1345+jsonBuildArray :: SListI tuple => FunctionHet tuple (null 'PGjson)
1346+jsonBuildArray = unsafeFunctionHet "json_build_array"
1348+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1349+-- variadic argument list.
1350+jsonbBuildArray :: SListI tuple => FunctionHet tuple (null 'PGjsonb)
1351+jsonbBuildArray = unsafeFunctionHet "jsonb_build_array"
1353+class PGBuildObject tys where
1354+instance PGBuildObject '[]
1355+instance (PGBuildObject tys, key `In` PGJsonKey)
1356+ => PGBuildObject ('NotNull key ': value ': tys)
1358+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1359+-- argument list. The elements of the argument list must alternate between text
1362+ :: (SListI elems, PGBuildObject elems)
1363+ => FunctionHet elems (null 'PGjson)
1364+jsonBuildObject = unsafeFunctionHet "json_build_object"
1366+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1367+-- variadic argument list. The elements of the argument list must alternate
1368+-- between keys and values.
1370+ :: (SListI elems, PGBuildObject elems)
1371+ => FunctionHet elems (null 'PGjsonb)
1372+jsonbBuildObject = unsafeFunctionHet "jsonb_build_object"
1374+-- | Builds a JSON object out of a text array.
1375+-- The array must have two dimensions
1376+-- such that each inner array has exactly two elements,
1377+-- which are taken as a key/value pair.
1379+ :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))
1381+jsonObject = unsafeFunction "json_object"
1383+-- | Builds a binary JSON object out of a text array.
1384+-- The array must have two dimensions
1385+-- such that each inner array has exactly two elements,
1386+-- which are taken as a key/value pair.
1388+ :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))
1390+jsonbObject = unsafeFunction "jsonb_object"
1392+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1393+-- keys and one for values, that are zipped pairwise to create a JSON object.
1394+jsonZipObject :: FunctionHet
1395+ '[ null ('PGvararray ('NotNull 'PGtext))
1396+ , null ('PGvararray ('NotNull 'PGtext)) ]
1398+jsonZipObject = unsafeFunctionHet "json_object"
1400+-- | This is an alternate form of 'jsonbObject' that takes two arrays; one for
1401+-- keys and one for values, that are zipped pairwise to create a binary JSON
1403+jsonbZipObject :: FunctionHet
1404+ '[ null ('PGvararray ('NotNull 'PGtext))
1405+ , null ('PGvararray ('NotNull 'PGtext)) ]
1407+jsonbZipObject = unsafeFunctionHet "jsonb_object"
1409+{-----------------------------------------
1410+Table 9.46: JSON processing functions
1411+-----------------------------------------}
1413+-- | Returns the number of elements in the outermost JSON array.
1414+jsonArrayLength :: null 'PGjson :--> null 'PGint4
1415+jsonArrayLength = unsafeFunction "json_array_length"
1417+-- | Returns the number of elements in the outermost binary JSON array.
1418+jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
1419+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1421+-- | Returns JSON value pointed to by the given path (equivalent to #>
1425+ => Expression outer grp commons schemas params from (null 'PGjson)
1426+ -> NP (Expression outer grp commons schemas params from) elems
1427+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1428+jsonExtractPath x xs =
1429+ unsafeFunctionHet "json_extract_path" (x :* xs)
1431+-- | Returns JSON value pointed to by the given path (equivalent to #>
1435+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1436+ -> NP (Expression outer grp commons schemas params from) elems
1437+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1438+jsonbExtractPath x xs =
1439+ unsafeFunctionHet "jsonb_extract_path" (x :* xs)
1441+-- | Returns JSON value pointed to by the given path (equivalent to #>
1442+-- operator), as text.
1443+jsonExtractPathAsText
1445+ => Expression outer grp commons schemas params from (null 'PGjson)
1446+ -> NP (Expression outer grp commons schemas params from) elems
1447+ -> Expression outer grp commons schemas params from (null 'PGjson)
1448+jsonExtractPathAsText x xs =
1449+ unsafeFunctionHet "json_extract_path_text" (x :* xs)
1451+-- | Returns JSON value pointed to by the given path (equivalent to #>
1452+-- operator), as text.
1453+jsonbExtractPathAsText
1455+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1456+ -> NP (Expression outer grp commons schemas params from) elems
1457+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1458+jsonbExtractPathAsText x xs =
1459+ unsafeFunctionHet "jsonb_extract_path_text" (x :* xs)
1461+-- | Returns the type of the outermost JSON value as a text string. Possible
1462+-- types are object, array, string, number, boolean, and null.
1463+jsonTypeof :: null 'PGjson :--> null 'PGtext
1464+jsonTypeof = unsafeFunction "json_typeof"
1466+-- | Returns the type of the outermost binary JSON value as a text string.
1467+-- Possible types are object, array, string, number, boolean, and null.
1468+jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
1469+jsonbTypeof = unsafeFunction "jsonb_typeof"
1471+-- | Returns its argument with all object fields that have null values omitted.
1472+-- Other null values are untouched.
1473+jsonStripNulls :: null 'PGjson :--> null 'PGjson
1474+jsonStripNulls = unsafeFunction "json_strip_nulls"
1476+-- | Returns its argument with all object fields that have null values omitted.
1477+-- Other null values are untouched.
1478+jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
1479+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1481+-- | @ jsonbSet target path new_value create_missing @
1483+-- Returns target with the section designated by path replaced by new_value,
1484+-- or with new_value added if create_missing is true ( default is true) and the
1485+-- item designated by path does not exist. As with the path orientated
1486+-- operators, negative integers that appear in path count from the end of JSON
1489+ :: Expression outer grp commons schemas params from (null 'PGjsonb)
1490+ -> Expression outer grp commons schemas params from (null ('PGvararray ('NotNull 'PGtext)))
1491+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1492+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1493+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1494+jsonbSet tgt path val createMissing = case createMissing of
1495+ Just m -> unsafeFunctionHet "jsonb_set" (tgt :* path :* val :* m :* Nil)
1496+ Nothing -> unsafeFunctionHet "jsonb_set" (tgt :* path :* val :* Nil)
1498+-- | @ jsonbInsert target path new_value insert_after @
1500+-- Returns target with new_value inserted. If target section designated by
1501+-- path is in a JSONB array, new_value will be inserted before target or after
1502+-- if insert_after is true (default is false). If target section designated by
1503+-- path is in JSONB object, new_value will be inserted only if target does not
1504+-- exist. As with the path orientated operators, negative integers that appear
1505+-- in path count from the end of JSON arrays.
1507+ :: Expression outer grp commons schemas params from (null 'PGjsonb)
1508+ -> Expression outer grp commons schemas params from (null ('PGvararray ('NotNull 'PGtext)))
1509+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1510+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1511+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1512+jsonbInsert tgt path val insertAfter = case insertAfter of
1513+ Just i -> unsafeFunctionHet "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1514+ Nothing -> unsafeFunctionHet "jsonb_insert" (tgt :* path :* val :* Nil)
1516+-- | Returns its argument as indented JSON text.
1517+jsonbPretty :: null 'PGjsonb :--> null 'PGtext
1518+jsonbPretty = unsafeFunction "jsonb_pretty"
1520+(@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)
1521+(@@) = unsafeBinaryOp "@@"
1523+(.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1524+(.&) = unsafeBinaryOp "&&"
1526+(.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1527+(.|) = unsafeBinaryOp "||"
1529+(.!) :: null 'PGtsquery :--> null 'PGtsquery
1530+(.!) = unsafeUnaryOpL "!!"
1532+(<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1533+(<->) = unsafeBinaryOp "<->"
1536+ :: null ('PGvararray ('NotNull 'PGtext))
1537+ :--> null 'PGtsvector
1538+arrayToTSvector = unsafeFunction "array_to_tsvector"
1540+tsvectorLength :: null 'PGtsvector :--> null 'PGint4
1541+tsvectorLength = unsafeFunction "length"
1543+numnode :: null 'PGtsquery :--> null 'PGint4
1544+numnode = unsafeFunction "numnode"
1546+plainToTSquery :: null 'PGtext :--> null 'PGtsquery
1547+plainToTSquery = unsafeFunction "plainto_tsquery"
1549+phraseToTSquery :: null 'PGtext :--> null 'PGtsquery
1550+phraseToTSquery = unsafeFunction "phraseto_tsquery"
1552+websearchToTSquery :: null 'PGtext :--> null 'PGtsquery
1553+websearchToTSquery = unsafeFunction "websearch_to_tsquery"
1555+queryTree :: null 'PGtsquery :--> null 'PGtext
1556+queryTree = unsafeFunction "query_tree"
1558+toTSquery :: null 'PGtext :--> null 'PGtsquery
1559+toTSquery = unsafeFunction "to_tsquery"
1562+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1563+ => null ty :--> null 'PGtsquery
1564+toTSvector = unsafeFunction "to_tsvector"
1567+ :: FunctionHet '[null 'PGtsvector, null ('PGchar 1)] (null 'PGtsvector)
1568+setWeight = unsafeFunctionHet "set_weight"
1570+litChar :: Char -> Expr (null ('PGchar 1))
1571+litChar chr = UnsafeExpression $
1572+ "E\'" <> fromString (escape =<< [chr]) <> "\'"
1574+strip :: null 'PGtsvector :--> null 'PGtsvector
1575+strip = unsafeFunction "strip"
1577+jsonToTSvector :: FunctionHet '[null 'PGjson, null 'PGjson] (null 'PGtsvector)
1578+jsonToTSvector = unsafeFunctionHet "json_to_tsvector"
1580+jsonbToTSvector :: FunctionHet '[null 'PGjsonb, null 'PGjsonb] (null 'PGtsvector)
1581+jsonbToTSvector = unsafeFunctionHet "jsonb_to_tsvector"
1583+tsDelete :: FunctionHet
1584+ '[null 'PGtsvector, null ('PGvararray ('NotNull 'PGtext))]
1586+tsDelete = unsafeFunctionHet "ts_delete"
1588+tsFilter :: FunctionHet
1589+ '[null 'PGtsvector, null ('PGvararray ('NotNull ('PGchar 1)))]
1591+tsFilter = unsafeFunctionHet "ts_filter"
1594+ :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1595+ => FunctionHet '[null document, null 'PGtsquery] (null 'PGtext)
1596+tsHeadline = unsafeFunctionHet "ts_headline"
1597+{-----------------------------------------
1599+-----------------------------------------}
1602+ = forall outer bys commons schemas params from
1603+ . Distinction (Expression outer 'Ungrouped commons schemas params from) x
1605+ -> Expression outer ('Grouped bys) commons schemas params from y
1609+ = forall outer bys commons schemas params from
1610+ . Distinction (NP (Expression outer 'Ungrouped commons schemas params from)) xs
1612+ -> Expression outer ('Grouped bys) commons schemas params from y
1615+unsafeAggregateHet :: SOP.SListI xs => ByteString -> AggrHet xs y
1616+unsafeAggregateHet fun xs = UnsafeExpression $ mconcat
1617+ [fun, "(", renderSQL xs, ")"]
1620+`Aggregate` functions compute a single result from a set of input values.
1621+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1622+as `WindowFunction`s.
1624+class Aggregate expr1 exprHet aggr
1625+ | aggr -> expr1, aggr -> exprHet where
1627+ -- | A special aggregation that does not require an input
1631+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1632+ -- expression = countStar
1633+ -- in printSQL expression
1636+ countStar :: aggr ('NotNull 'PGint8)
1640+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1641+ -- expression = count (All #col)
1642+ -- in printSQL expression
1644+ -- count(ALL "col")
1648+ -> aggr ('NotNull 'PGint8)
1652+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1653+ -- expression = sum_ (Distinct #col)
1654+ -- in printSQL expression
1656+ -- sum(DISTINCT "col")
1660+ -> aggr ('NotNull ty)
1662+ -- | input values, including nulls, concatenated into an array
1665+ -> aggr ('Null ('PGvararray ty))
1667+ -- | aggregates values as a JSON array
1670+ -> aggr ('Null 'PGjson)
1672+ -- | aggregates values as a JSON array
1675+ -> aggr ('Null 'PGjsonb)
1678+ the bitwise AND of all non-null input values, or null if none
1681+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1682+ expression = bitAnd (Distinct #col)
1683+ in printSQL expression
1685+ bit_and(DISTINCT "col")
1688+ :: int `In` PGIntegral
1689+ => expr1 (null int)
1690+ -- ^ what to aggregate
1691+ -> aggr ('Null int)
1694+ the bitwise OR of all non-null input values, or null if none
1698+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1699+ expression = bitOr (All #col)
1700+ in printSQL expression
1705+ :: int `In` PGIntegral
1706+ => expr1 (null int)
1707+ -- ^ what to aggregate
1708+ -> aggr ('Null int)
1711+ true if all input values are true, otherwise false
1715+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1716+ winFun = boolAnd #col
1722+ :: expr1 (null 'PGbool)
1723+ -- ^ what to aggregate
1724+ -> aggr ('Null 'PGbool)
1727+ true if at least one input value is true, otherwise false
1731+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1732+ expression = boolOr (All #col)
1733+ in printSQL expression
1738+ :: expr1 (null 'PGbool)
1739+ -- ^ what to aggregate
1740+ -> aggr ('Null 'PGbool)
1743+ equivalent to `boolAnd`
1747+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1748+ expression = every (Distinct #col)
1749+ in printSQL expression
1751+ every(DISTINCT "col")
1754+ :: expr1 (null 'PGbool)
1755+ -- ^ what to aggregate
1756+ -> aggr ('Null 'PGbool)
1758+ {- |maximum value of expression across all input values-}
1761+ -- ^ what to maximize
1764+ -- | minimum value of expression across all input values
1767+ -- ^ what to minimize
1770+ -- | the average (arithmetic mean) of all input values
1773+ -- ^ what to average
1774+ -> aggr ('Null (PGAvg ty))
1776+ {- | correlation coefficient
1779+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1780+ expression = corr (All (#y *: #x))
1781+ in printSQL expression
1786+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1787+ -> aggr ('Null 'PGfloat8)
1789+ {- | population covariance
1792+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1793+ expression = covarPop (All (#y *: #x))
1794+ in printSQL expression
1796+ covar_pop(ALL "y", "x")
1799+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1800+ -> aggr ('Null 'PGfloat8)
1802+ {- | sample covariance
1805+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1806+ winFun = covarSamp (#y *: #x)
1809+ covar_samp("y", "x")
1812+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1813+ -> aggr ('Null 'PGfloat8)
1815+ {- | average of the independent variable (sum(X)/N)
1818+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1819+ expression = regrAvgX (All (#y *: #x))
1820+ in printSQL expression
1822+ regr_avgx(ALL "y", "x")
1825+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1826+ -> aggr ('Null 'PGfloat8)
1828+ {- | average of the dependent variable (sum(Y)/N)
1831+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1832+ winFun = regrAvgY (#y *: #x)
1835+ regr_avgy("y", "x")
1838+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1839+ -> aggr ('Null 'PGfloat8)
1841+ {- | number of input rows in which both expressions are nonnull
1844+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1845+ winFun = regrCount (#y *: #x)
1848+ regr_count("y", "x")
1851+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1852+ -> aggr ('Null 'PGint8)
1854+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1857+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1858+ expression = regrIntercept (All (#y *: #x))
1859+ in printSQL expression
1861+ regr_intercept(ALL "y", "x")
1864+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1865+ -> aggr ('Null 'PGfloat8)
1867+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1869+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1870+ -> aggr ('Null 'PGfloat8)
1872+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1873+ -- determined by the (X, Y) pairs
1875+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1876+ -> aggr ('Null 'PGfloat8)
1878+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1879+ -- (“sum of squares” of the independent variable)
1881+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1882+ -> aggr ('Null 'PGfloat8)
1884+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1885+ -- (“sum of products” of independent times dependent variable)
1887+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1888+ -> aggr ('Null 'PGfloat8)
1890+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1891+ -- (“sum of squares” of the dependent variable)
1893+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1894+ -> aggr ('Null 'PGfloat8)
1896+ -- | historical alias for `stddevSamp`
1899+ -> aggr ('Null (PGAvg ty))
1901+ -- | population standard deviation of the input values
1904+ -> aggr ('Null (PGAvg ty))
1906+ -- | sample standard deviation of the input values
1909+ -> aggr ('Null (PGAvg ty))
1911+ -- | historical alias for `varSamp`
1914+ -> aggr ('Null (PGAvg ty))
1916+ -- | population variance of the input values
1917+ -- (square of the population standard deviation)
1920+ -> aggr ('Null (PGAvg ty))
1922+ -- | sample variance of the input values
1923+ -- (square of the sample standard deviation)
1926+ -> aggr ('Null (PGAvg ty))
1929+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1930+`All` invokes the aggregate once for each input row.
1931+`Distinct` invokes the aggregate once for each distinct value of the expression
1932+(or distinct set of values, for multiple expressions) found in the input
1934+data Distinction (expr :: kind -> Type) (ty :: kind)
1936+ | Distinct (expr ty)
1937+ deriving (GHC.Generic,Show,Eq,Ord)
1938+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1939+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1941+ All x -> "ALL" <+> renderSQL x
1942+ Distinct x -> "DISTINCT" <+> renderSQL x
1943+instance SOP.SListI tys => RenderSQL
1944+ (Distinction (NP (Expression outer grp commons schemas params from)) tys) where
1946+ All xs -> "ALL" <+> renderCommaSeparated renderSQL xs
1947+ Distinct xs -> "DISTINCT" <+> renderCommaSeparated renderSQL xs
1950+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1951+ (Distinction (NP (Expression outer 'Ungrouped commons schemas params from)))
1952+ (Expression outer ('Grouped bys) commons schemas params from) where
1953+ countStar = UnsafeExpression "count(*)"
1954+ count = unsafeAggregate1 "count"
1955+ sum_ = unsafeAggregate1 "sum"
1956+ arrayAgg = unsafeAggregate1 "array_agg"
1957+ jsonAgg = unsafeAggregate1 "json_agg"
1958+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1959+ bitAnd = unsafeAggregate1 "bit_and"
1960+ bitOr = unsafeAggregate1 "bit_or"
1961+ boolAnd = unsafeAggregate1 "bool_and"
1962+ boolOr = unsafeAggregate1 "bool_or"
1963+ every = unsafeAggregate1 "every"
1964+ max_ = unsafeAggregate1 "max"
1965+ min_ = unsafeAggregate1 "min"
1966+ avg = unsafeAggregate1 "avg"
1967+ corr = unsafeAggregateHet "corr"
1968+ covarPop = unsafeAggregateHet "covar_pop"
1969+ covarSamp = unsafeAggregateHet "covar_samp"
1970+ regrAvgX = unsafeAggregateHet "regr_avgx"
1971+ regrAvgY = unsafeAggregateHet "regr_avgy"
1972+ regrCount = unsafeAggregateHet "regr_count"
1973+ regrIntercept = unsafeAggregateHet "regr_intercept"
1974+ regrR2 = unsafeAggregateHet "regr_r2"
1975+ regrSlope = unsafeAggregateHet "regr_slope"
1976+ regrSxx = unsafeAggregateHet "regr_sxx"
1977+ regrSxy = unsafeAggregateHet "regr_sxy"
1978+ regrSyy = unsafeAggregateHet "regr_syy"
1979+ stddev = unsafeAggregate1 "stddev"
1980+ stddevPop = unsafeAggregate1 "stddev_pop"
1981+ stddevSamp = unsafeAggregate1 "stddev_samp"
1982+ variance = unsafeAggregate1 "variance"
1983+ varPop = unsafeAggregate1 "var_pop"
1984+ varSamp = unsafeAggregate1 "var_samp"
1986+ (Expression outer grp commons schemas params from)
1987+ (NP (Expression outer grp commons schemas params from))
1988+ (WindowFunction outer grp commons schemas params from) where
1989+ countStar = UnsafeWindowFunction "count(*)"
1990+ count = unsafeWindowFunction1 "count"
1991+ sum_ = unsafeWindowFunction1 "sum"
1992+ arrayAgg = unsafeWindowFunction1 "array_agg"
1993+ jsonAgg = unsafeWindowFunction1 "json_agg"
1994+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1995+ bitAnd = unsafeWindowFunction1 "bit_and"
1996+ bitOr = unsafeWindowFunction1 "bit_or"
1997+ boolAnd = unsafeWindowFunction1 "bool_and"
1998+ boolOr = unsafeWindowFunction1 "bool_or"
1999+ every = unsafeWindowFunction1 "every"
2000+ max_ = unsafeWindowFunction1 "max"
2001+ min_ = unsafeWindowFunction1 "min"
2002+ avg = unsafeWindowFunction1 "avg"
2003+ corr = unsafeWindowFunctionHet "corr"
2004+ covarPop = unsafeWindowFunctionHet "covar_pop"
2005+ covarSamp = unsafeWindowFunctionHet "covar_samp"
2006+ regrAvgX = unsafeWindowFunctionHet "regr_avgx"
2007+ regrAvgY = unsafeWindowFunctionHet "regr_avgy"
2008+ regrCount = unsafeWindowFunctionHet "regr_count"
2009+ regrIntercept = unsafeWindowFunctionHet "regr_intercept"
2010+ regrR2 = unsafeWindowFunctionHet "regr_r2"
2011+ regrSlope = unsafeWindowFunctionHet "regr_slope"
2012+ regrSxx = unsafeWindowFunctionHet "regr_sxx"
2013+ regrSxy = unsafeWindowFunctionHet "regr_sxy"
2014+ regrSyy = unsafeWindowFunctionHet "regr_syy"
2015+ stddev = unsafeWindowFunction1 "stddev"
2016+ stddevPop = unsafeWindowFunction1 "stddev_pop"
2017+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
2018+ variance = unsafeWindowFunction1 "variance"
2019+ varPop = unsafeWindowFunction1 "var_pop"
2020+ varSamp = unsafeWindowFunction1 "var_samp"
2022+-- | escape hatch to define aggregate functions
2024+ :: ByteString -- ^ aggregate function
2026+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
2027+ [fun, "(", renderSQL x, ")"]
2029+-- | A type family that calculates `PGAvg` type of a `PGType`.
2030+type family PGAvg ty where
2031+ PGAvg 'PGint2 = 'PGnumeric
2032+ PGAvg 'PGint4 = 'PGnumeric
2033+ PGAvg 'PGint8 = 'PGnumeric
2034+ PGAvg 'PGnumeric = 'PGnumeric
2035+ PGAvg 'PGfloat4 = 'PGfloat8
2036+ PGAvg 'PGfloat8 = 'PGfloat8
2037+ PGAvg 'PGinterval = 'PGinterval
2038+ PGAvg pg = TypeError
2039+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
2041+{-----------------------------------------
2043+-----------------------------------------}
2045+-- | `TypeExpression`s are used in `cast`s and
2046+-- `Squeal.PostgreSQL.Definition.createTable` commands.
2047+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
2048+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
2049+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2050+instance RenderSQL (TypeExpression schemas ty) where
2051+ renderSQL = renderTypeExpression
2053+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
2055+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
2056+ => QualifiedAlias sch td
2057+ -> TypeExpression schemas (null ty)
2058+typedef = UnsafeTypeExpression . renderSQL
2060+-- | The composite type corresponding to a `Table` definition can be expressed
2063+ :: (Has sch schemas schema, Has tab schema ('Table table))
2064+ => QualifiedAlias sch tab
2065+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
2066+typetable = UnsafeTypeExpression . renderSQL
2068+-- | The composite type corresponding to a `View` definition can be expressed
2071+ :: (Has sch schemas schema, Has vw schema ('View view))
2072+ => QualifiedAlias sch vw
2073+ -> TypeExpression schemas (null ('PGcomposite view))
2074+typeview = UnsafeTypeExpression . renderSQL
2076+-- | logical Boolean (true/false)
2077+bool :: TypeExpression schemas (null 'PGbool)
2078+bool = UnsafeTypeExpression "bool"
2079+-- | signed two-byte integer
2080+int2, smallint :: TypeExpression schemas (null 'PGint2)
2081+int2 = UnsafeTypeExpression "int2"
2082+smallint = UnsafeTypeExpression "smallint"
2083+-- | signed four-byte integer
2084+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2085+int4 = UnsafeTypeExpression "int4"
2086+int = UnsafeTypeExpression "int"
2087+integer = UnsafeTypeExpression "integer"
2088+-- | signed eight-byte integer
2089+int8, bigint :: TypeExpression schemas (null 'PGint8)
2090+int8 = UnsafeTypeExpression "int8"
2091+bigint = UnsafeTypeExpression "bigint"
2092+-- | arbitrary precision numeric type
2093+numeric :: TypeExpression schemas (null 'PGnumeric)
2094+numeric = UnsafeTypeExpression "numeric"
2095+-- | single precision floating-point number (4 bytes)
2096+float4, real :: TypeExpression schemas (null 'PGfloat4)
2097+float4 = UnsafeTypeExpression "float4"
2098+real = UnsafeTypeExpression "real"
2099+-- | double precision floating-point number (8 bytes)
2100+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2101+float8 = UnsafeTypeExpression "float8"
2102+doublePrecision = UnsafeTypeExpression "double precision"
2103+-- | currency amount
2104+money :: TypeExpression schema (null 'PGmoney)
2105+money = UnsafeTypeExpression "money"
2106+-- | variable-length character string
2107+text :: TypeExpression schemas (null 'PGtext)
2108+text = UnsafeTypeExpression "text"
2109+-- | fixed-length character string
2111+ :: forall n schemas null. (KnownNat n, 1 <= n)
2112+ => TypeExpression schemas (null ('PGchar n))
2113+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2114+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2115+-- | variable-length character string
2116+varchar, characterVarying
2117+ :: forall n schemas null. (KnownNat n, 1 <= n)
2118+ => TypeExpression schemas (null ('PGvarchar n))
2119+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2120+characterVarying = UnsafeTypeExpression $
2121+ "character varying(" <> renderNat @n <> ")"
2122+-- | binary data ("byte array")
2123+bytea :: TypeExpression schemas (null 'PGbytea)
2124+bytea = UnsafeTypeExpression "bytea"
2125+-- | date and time (no time zone)
2126+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2127+timestamp = UnsafeTypeExpression "timestamp"
2128+-- | date and time, including time zone
2129+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2130+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2131+-- | calendar date (year, month, day)
2132+date :: TypeExpression schemas (null 'PGdate)
2133+date = UnsafeTypeExpression "date"
2134+-- | time of day (no time zone)
2135+time :: TypeExpression schemas (null 'PGtime)
2136+time = UnsafeTypeExpression "time"
2137+-- | time of day, including time zone
2138+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2139+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2141+interval :: TypeExpression schemas (null 'PGinterval)
2142+interval = UnsafeTypeExpression "interval"
2143+-- | universally unique identifier
2144+uuid :: TypeExpression schemas (null 'PGuuid)
2145+uuid = UnsafeTypeExpression "uuid"
2146+-- | IPv4 or IPv6 host address
2147+inet :: TypeExpression schemas (null 'PGinet)
2148+inet = UnsafeTypeExpression "inet"
2149+-- | textual JSON data
2150+json :: TypeExpression schemas (null 'PGjson)
2151+json = UnsafeTypeExpression "json"
2152+-- | binary JSON data, decomposed
2153+jsonb :: TypeExpression schemas (null 'PGjsonb)
2154+jsonb = UnsafeTypeExpression "jsonb"
2155+-- | variable length array
2157+ :: TypeExpression schemas pg
2158+ -> TypeExpression schemas (null ('PGvararray pg))
2159+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2160+-- | fixed length array
2162+-- >>> renderSQL (fixarray @'[2] json)
2165+ :: forall dims schemas null pg. SOP.All KnownNat dims
2166+ => TypeExpression schemas pg
2167+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2168+fixarray ty = UnsafeTypeExpression $
2169+ renderSQL ty <> renderDims @dims
2171+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2175+ . ByteString.intercalate "]["
2177+ $ hcmap (SOP.Proxy @KnownNat)
2178+ (K . fromString . show . natVal)
2179+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2180+tsvector :: TypeExpression schemas (null 'PGtsvector)
2181+tsvector = UnsafeTypeExpression "tsvector"
2182+tsquery :: TypeExpression schemas (null 'PGtsquery)
2183+tsquery = UnsafeTypeExpression "tsquery"
2185+-- | `pgtype` is a demoted version of a `PGType`
2186+class PGTyped schemas (ty :: NullityType) where
2187+ pgtype :: TypeExpression schemas ty
2188+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2189+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2190+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2191+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2192+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2193+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2194+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2195+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2196+instance PGTyped schemas (null 'PGtext) where pgtype = text
2197+instance (KnownNat n, 1 <= n)
2198+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2199+instance (KnownNat n, 1 <= n)
2200+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2201+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2202+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2203+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2204+instance PGTyped schemas (null 'PGdate) where pgtype = date
2205+instance PGTyped schemas (null 'PGtime) where pgtype = time
2206+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2207+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2208+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2209+instance PGTyped schemas (null 'PGjson) where pgtype = json
2210+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2211+instance PGTyped schemas ty
2212+ => PGTyped schemas (null ('PGvararray ty)) where
2213+ pgtype = vararray (pgtype @schemas @ty)
2214+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2215+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2216+ pgtype = fixarray @dims (pgtype @schemas @ty)
2217+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2218+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2220+{-----------------------------------------
2222+-----------------------------------------}
2224+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2225+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2226+-- set the sort direction of a `NotNull` result
2227+-- column to ascending or descending. Ascending order puts smaller values
2228+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2229+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2230+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2231+-- determine whether nulls appear before or after non-null values in the sort
2232+-- ordering of a `Null` result column.
2233+data SortExpression outer grp commons schemas params from where
2235+ :: Expression outer grp commons schemas params from ('NotNull ty)
2236+ -> SortExpression outer grp commons schemas params from
2238+ :: Expression outer grp commons schemas params from ('NotNull ty)
2239+ -> SortExpression outer grp commons schemas params from
2241+ :: Expression outer grp commons schemas params from ('Null ty)
2242+ -> SortExpression outer grp commons schemas params from
2244+ :: Expression outer grp commons schemas params from ('Null ty)
2245+ -> SortExpression outer grp commons schemas params from
2247+ :: Expression outer grp commons schemas params from ('Null ty)
2248+ -> SortExpression outer grp commons schemas params from
2250+ :: Expression outer grp commons schemas params from ('Null ty)
2251+ -> SortExpression outer grp commons schemas params from
2252+deriving instance Show (SortExpression outer grp commons schemas params from)
2255+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2256+to be sorted according to the specified `SortExpression`(s).
2257+If two rows are equal according to the leftmost expression,
2258+they are compared according to the next expression and so on.
2259+If they are equal according to all specified expressions,
2260+they are returned in an implementation-dependent order.
2262+You can also control the order in which rows are processed by window functions
2263+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2265+class OrderBy expr where
2267+ :: [SortExpression outer grp commons schemas params from]
2268+ -> expr outer grp commons schemas params from
2269+ -> expr outer grp commons schemas params from
2271+-- | Render a `SortExpression`.
2272+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2274+ Asc expression -> renderSQL expression <+> "ASC"
2275+ Desc expression -> renderSQL expression <+> "DESC"
2276+ AscNullsFirst expression -> renderSQL expression
2277+ <+> "ASC NULLS FIRST"
2278+ DescNullsFirst expression -> renderSQL expression
2279+ <+> "DESC NULLS FIRST"
2280+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2281+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2283+-- | A `WindowDefinition` is a set of table rows that are somehow related
2284+-- to the current row
2285+data WindowDefinition outer grp commons schemas params from where
2288+ => NP (Expression outer grp commons schemas params from) bys
2289+ -> [SortExpression outer grp commons schemas params from]
2290+ -> WindowDefinition outer grp commons schemas params from
2292+instance OrderBy WindowDefinition where
2293+ orderBy sortsR (WindowDefinition parts sortsL)
2294+ = WindowDefinition parts (sortsL ++ sortsR)
2296+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2297+ renderSQL (WindowDefinition part ord) =
2298+ renderPartitionByClause part <> renderOrderByClause ord
2300+ renderPartitionByClause = \case
2302+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2303+ renderOrderByClause = \case
2305+ srts -> " ORDER" <+> "BY"
2306+ <+> commaSeparated (renderSQL <$> srts)
2309+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2310+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2311+For each row, the window function is computed across the rows that fall into
2312+the same partition as the current row.
2316+ => NP (Expression outer grp commons schemas params from) bys
2317+ -> WindowDefinition outer grp commons schemas params from
2318+partitionBy bys = WindowDefinition bys []
2321+A window function performs a calculation across a set of table rows
2322+that are somehow related to the current row. This is comparable to the type
2323+of calculation that can be done with an aggregate function.
2324+However, window functions do not cause rows to become grouped into a single
2325+output row like non-window aggregate calls would.
2326+Instead, the rows retain their separate identities.
2327+Behind the scenes, the window function is able to access more than
2328+just the current row of the query result.
2330+newtype WindowFunction
2331+ (outer :: FromType)
2333+ (commons :: FromType)
2334+ (schemas :: SchemasType)
2335+ (params :: [NullityType])
2337+ (ty :: NullityType)
2338+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2339+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2341+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2342+ renderSQL = renderWindowFunction
2345+ = forall outer grp commons schemas params from
2346+ . WindowFunction outer grp commons schemas params from x
2347+ -- ^ cannot reference aliases
2350+ = forall outer grp commons schemas params from
2351+ . Expression outer grp commons schemas params from x
2353+ -> WindowFunction outer grp commons schemas params from y
2357+ = forall outer grp commons schemas params from
2358+ . NP (Expression outer grp commons schemas params from) xs
2360+ -> WindowFunction outer grp commons schemas params from y
2363+unsafeWindowFunction1 :: ByteString -> WinFun1 x y
2364+unsafeWindowFunction1 fun x
2365+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2367+unsafeWindowFunctionHet :: SOP.SListI xs => ByteString -> WinFunHet xs y
2368+unsafeWindowFunctionHet fun xs = UnsafeWindowFunction $ fun <>
2369+ parenthesized (renderCommaSeparated renderSQL xs)
2371+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2375+rank :: WinFun0 ('NotNull 'PGint8)
2376+rank = UnsafeWindowFunction "rank()"
2378+{- | number of the current row within its partition, counting from 1
2379+>>> printSQL rowNumber
2382+rowNumber :: WinFun0 ('NotNull 'PGint8)
2383+rowNumber = UnsafeWindowFunction "row_number()"
2385+{- | rank of the current row without gaps; this function counts peer groups
2386+>>> printSQL denseRank
2389+denseRank :: WinFun0 ('NotNull 'PGint8)
2390+denseRank = UnsafeWindowFunction "dense_rank()"
2392+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2393+>>> printSQL percentRank
2396+percentRank :: WinFun0 ('NotNull 'PGfloat8)
2397+percentRank = UnsafeWindowFunction "percent_rank()"
2399+{- | cumulative distribution: (number of partition rows
2400+preceding or peer with current row) / total partition rows
2401+>>> printSQL cumeDist
2404+cumeDist :: WinFun0 ('NotNull 'PGfloat8)
2405+cumeDist = UnsafeWindowFunction "cume_dist()"
2407+{- | integer ranging from 1 to the argument value,
2408+dividing the partition as equally as possible
2410+ntile :: WinFun1 ('NotNull 'PGint4) ('NotNull 'PGint4)
2411+ntile = unsafeWindowFunction1 "ntile"
2413+{- | returns value evaluated at the row that is offset rows before the current
2414+row within the partition; if there is no such row, instead return default
2415+(which must be of the same type as value). Both offset and default are
2416+evaluated with respect to the current row.
2418+lag :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2419+lag = unsafeWindowFunctionHet "lag"
2421+{- | returns value evaluated at the row that is offset rows after the current
2422+row within the partition; if there is no such row, instead return default
2423+(which must be of the same type as value). Both offset and default are
2424+evaluated with respect to the current row.
2426+lead :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2427+lead = unsafeWindowFunctionHet "lag"
2429+{- | returns value evaluated at the row that is the
2430+first row of the window frame
2432+firstValue :: WinFun1 ty ty
2433+firstValue = unsafeWindowFunction1 "first_value"
2435+{- | returns value evaluated at the row that is the
2436+last row of the window frame
2438+lastValue :: WinFun1 ty ty
2439+lastValue = unsafeWindowFunction1 "last_value"
2441+{- | returns value evaluated at the row that is the nth
2442+row of the window frame (counting from 1); null if no such row
2444+nthValue :: WinFunHet '[null ty, 'NotNull 'PGint4] ('Null ty)
2445+nthValue = unsafeWindowFunctionHet "nth_value"
2448+Create date from year, month and day fields
2450+>>> printSQL (makeDate (1984 :* 7 *: 3))
2451+make_date(1984, 7, 3)
2453+makeDate :: FunctionHet
2454+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2456+makeDate = unsafeFunctionHet "make_date"
2459+Create time from hour, minute and seconds fields
2461+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2462+make_time(8, 15, 23.5)
2464+makeTime :: FunctionHet
2465+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2467+makeTime = unsafeFunctionHet "make_time"
2470+Create timestamp from year, month, day, hour, minute and seconds fields
2472+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2473+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2475+makeTimestamp :: FunctionHet
2476+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2477+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2478+ ( null 'PGtimestamp )
2479+makeTimestamp = unsafeFunctionHet "make_timestamp"
2482+Create timestamp with time zone from
2483+year, month, day, hour, minute and seconds fields;
2484+the current time zone is used
2486+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2487+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2489+makeTimestamptz :: FunctionHet
2490+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2491+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2492+ ( null 'PGtimestamptz )
2493+makeTimestamptz = unsafeFunctionHet "make_timestamptz"
2496+Affine space operations on time types.
2498+class TimeOp time diff | time -> diff where
2500+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2501+ (make_date(1984, 7, 3) + 365)
2503+ (!+) :: Operator (null time) (null diff) (null time)
2504+ (!+) = unsafeBinaryOp "+"
2506+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2507+ (365 + make_date(1984, 7, 3))
2509+ (+!) :: Operator (null diff) (null time) (null time)
2510+ (+!) = unsafeBinaryOp "+"
2512+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2513+ (make_date(1984, 7, 3) - 365)
2515+ (!-) :: Operator (null time) (null diff) (null time)
2516+ (!-) = unsafeBinaryOp "-"
2518+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2519+ (make_date(1984, 7, 3) - CURRENT_DATE)
2521+ (!-!) :: Operator (null time) (null time) (null diff)
2522+ (!-!) = unsafeBinaryOp "-"
2523+instance TimeOp 'PGtimestamp 'PGinterval
2524+instance TimeOp 'PGtimestamptz 'PGinterval
2525+instance TimeOp 'PGtime 'PGinterval
2526+instance TimeOp 'PGtimetz 'PGinterval
2527+instance TimeOp 'PGinterval 'PGinterval
2528+instance TimeOp 'PGdate 'PGint4