@@ -1,13 +1,14 @@
2−Module: Squeal.PostgreSQL.Expression
2+Module: Squeal.PostgreSQL.Query
3Description: Squeal expressions
3Description: Squeal expressions
4−Copyright: (c) Eitan Chatav, 2019
4+Copyright: (c) Eitan Chatav, 2017
5Maintainer: eitan@morphism.tech
5Maintainer: eitan@morphism.tech
6Stability: experimental
6Stability: experimental
8Squeal expressions are the atoms used to build statements.
8Squeal expressions are the atoms used to build statements.
11+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
11{-# LANGUAGE
12{-# LANGUAGE
12 AllowAmbiguousTypes
13 AllowAmbiguousTypes
13 , ConstraintKinds
14 , ConstraintKinds
@@ -33,350 +34,563 @@ Squeal expressions are the atoms used to build statements.
33module Squeal.PostgreSQL.Expression
34module Squeal.PostgreSQL.Expression
34 ( -- * Expression
35 ( -- * Expression
35 Expression (..)
36 Expression (..)
36− , Expr
37+ , HasParameter (parameter)
37− , type (-->)
38+ , param
38− , FunctionDB
39+ -- ** Null
39− , unsafeFunction
40+ , null_
40− , function
41+ , notNull
41− , unsafeLeftOp
42+ , coalesce
42− , leftOp
43+ , fromNull
43− , unsafeRightOp
44+ , isNull
44− , rightOp
45+ , isNotNull
45− , Operator
46+ , matchNull
46− , OperatorDB
47+ , nullIf
47 , unsafeBinaryOp
54 , unsafeBinaryOp
48− , binaryOp
55+ , unsafeUnaryOp
49− , FunctionVar
56+ , unsafeFunction
50− , unsafeFunctionVar
57+ , unsafeVariadicFunction
51− , type (--->)
58+ , atan2_
52− , FunctionNDB
59+ , cast
53− , unsafeFunctionN
60+ , quot_
54− , functionN
61+ , rem_
55− , PGSubset (..)
62+ , trunc
56− , PGIntersect (..)
63+ , round_
95+ -- *** Json and Jsonb operators
100+ -- *** Jsonb operators
127+ , jsonExtractPathAsText
128+ , jsonbExtractPathAsText
140+ -- * Window Functions
141+ , WindowDefinition (..)
143+ , WindowFunction (..)
156+ , SortExpression (..)
159+ , TypeExpression (..)
184+ , timestampWithTimeZone
57 -- * Re-export
195 -- * Re-export
63import Control.Category
203import Control.Category
64import Control.DeepSeq
204import Control.DeepSeq
65import Data.ByteString (ByteString)
205import Data.ByteString (ByteString)
206+import Data.ByteString.Lazy (toStrict)
66import Data.Function ((&))
207import Data.Function ((&))
67import Data.Semigroup hiding (All)
208import Data.Semigroup hiding (All)
209+import qualified Data.Aeson as JSON
68import Data.String
211import Data.String
69−import Generics.SOP hiding (All, from)
213+import Generics.SOP hiding (from)
214+import GHC.Generics ((:*:) (..))
70import GHC.OverloadedLabels
215import GHC.OverloadedLabels
71import GHC.TypeLits
216import GHC.TypeLits
73import Prelude hiding (id, (.))
217import Prelude hiding (id, (.))
219+import qualified Data.ByteString as ByteString
75import qualified GHC.Generics as GHC
220import qualified GHC.Generics as GHC
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79import Squeal.PostgreSQL.Render
222import Squeal.PostgreSQL.Render
80import Squeal.PostgreSQL.Schema
223import Squeal.PostgreSQL.Schema
83−-- >>> import Squeal.PostgreSQL
85{-----------------------------------------
225{-----------------------------------------
86column expressions
226column expressions
87-----------------------------------------}
227-----------------------------------------}
89{- | `Expression`s are used in a variety of contexts,
229{- | `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,
230+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
231as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93`Squeal.PostgreSQL.Manipulation.update`,
232`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
233+or in search `Condition`s in a number of commands.
96The expression syntax allows the calculation of
235The expression syntax allows the calculation of
97values from primitive expression using arithmetic, logical,
236values from primitive expression using arithmetic, logical,
98and other operations.
237and 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
239newtype Expression
116− (commons :: FromType)
117 (grp :: Grouping)
240 (grp :: Grouping)
241+ (commons :: FromType)
118 (schemas :: SchemasType)
242 (schemas :: SchemasType)
119 (params :: [NullityType])
243 (params :: [NullityType])
120 (from :: FromType)
244 (from :: FromType)
121 (ty :: NullityType)
245 (ty :: NullityType)
122 = UnsafeExpression { renderExpression :: ByteString }
246 = UnsafeExpression { renderExpression :: ByteString }
123 deriving (GHC.Generic,Show,Eq,Ord,NFData)
247 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
249+instance RenderSQL (Expression grp commons schemas params from ty) where
125 renderSQL = renderExpression
250 renderSQL = renderExpression
127−-- | An `Expr` is a closed `Expression`.
252+{- | A `HasParameter` constraint is used to indicate a value that is
128−-- It is a F@RankNType@ but don't be scared.
253+supplied externally to a SQL statement.
129−-- Think of it as an expression which sees no
254+`Squeal.PostgreSQL.PQ.manipulateParams`,
130−-- namespaces, so you can't use parameters
255+`Squeal.PostgreSQL.PQ.queryParams` and
131−-- or alias references. It can be used as
256+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
132−-- a simple piece of more complex `Expression`s.
257+separately from the SQL command string, in which case `param`s are used to
133−type Expr x
258+refer to the out-of-line data values.
134− = forall outer commons grp schemas params from
135− . Expression outer commons grp schemas params from x
136− -- ^ cannot reference aliases
138−-- | A @RankNType@ for binary operators.
139−type Operator x1 x2 y
140− = forall outer commons grp schemas params from
141− . Expression outer commons grp schemas params from x1
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
152− -> Expression outer commons grp schemas params from x2
154− -> Expression outer commons grp schemas params from y
157−-- | A @RankNType@ for functions with a single argument.
158−-- These could be either function calls or unary operators.
159−-- This is a subtype of the usual Haskell function type `Prelude.->`,
160−-- indeed a subcategory as it is closed under the usual
161−-- `Prelude..` and `Prelude.id`.
163− = forall outer commons grp schemas params from
164− . Expression outer commons grp schemas params from x
166− -> Expression outer commons grp schemas params from y
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.
177−Use the `*:` operator to end your argument lists, like so.
179−>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
180−fun(TRUE, FALSE, LOCALTIME, TRUE)
183− = forall outer commons grp schemas params from
184− . NP (Expression outer commons grp schemas params from) xs
186− -> Expression outer commons grp schemas params from y
189−type FunctionNDB schemas xs y
190− = forall outer commons grp params from
191− . NP (Expression outer commons grp schemas params from) xs
193− -> Expression outer commons grp schemas params from y
196−{- | A @RankNType@ for functions with a variable-length list of
197−homogeneous arguments and at least 1 more argument.
199−type FunctionVar x0 x1 y
260+class KnownNat n => HasParameter
200− = forall outer commons grp schemas params from
261+ (n :: Nat)
201− . [Expression outer commons grp schemas params from x0]
262+ (params :: [NullityType])
202− -- ^ inputs
263+ (ty :: NullityType)
203− -> Expression outer commons grp schemas params from x1
264+ | n params -> ty where
204− -- ^ must have at least 1 input
265+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
205− -> Expression outer commons grp schemas params from y
266+ --
206− -- ^ output
267+ -- >>> let expr = parameter @1 int4 :: Expression grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
207−
268+ -- >>> printSQL expr
208−{- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)
269+ -- ($1 :: int4)
209−greatest(TRUE, NULL, FALSE)
270+ parameter
210−-}
271+ :: TypeExpression schemas ty
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
272+ -> Expression grp commons schemas params from ty
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
273+ parameter ty = UnsafeExpression $ parenthesized $
213− (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
274+ "$" <> renderNat @n <+> "::"
276+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
277+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
278+ => HasParameter n (ty' : params) ty
280+-- | `param` takes a `Nat` using type application and for basic types,
281+-- infers a `TypeExpression`.
283+-- >>> let expr = param @1 :: Expression grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
287+ :: forall n commons schemas params from grp ty
288+ . (PGTyped schemas ty, HasParameter n params ty)
289+ => Expression grp commons schemas params from ty -- ^ param
290+param = parameter @n (pgtype @schemas)
215−instance (HasUnique tab (Join outer from) row, Has col row ty)
292+instance (HasUnique tab from row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
293+ => IsLabel col (Expression 'Ungrouped commons schemas params from ty) where
217 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
294 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218−instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
295+instance (HasUnique tab from row, Has col row ty, column ~ (col ::: ty))
219− => IsLabel col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where
220− fromLabel = fromLabel @col :* Nil
221−instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222 => IsLabel col
296 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
297+ (Aliased (Expression 'Ungrouped commons schemas params from) column) where
224 fromLabel = fromLabel @col `As` Alias
298 fromLabel = fromLabel @col `As` Alias
225−instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
299+instance (HasUnique tab from row, Has col row ty, columns ~ '[col ::: ty])
226 => IsLabel col
300 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
301+ (NP (Aliased (Expression 'Ungrouped commons schemas params from)) columns) where
228 fromLabel = fromLabel @col :* Nil
302 fromLabel = fromLabel @col :* Nil
230−instance (Has tab (Join outer from) row, Has col row ty)
304+instance (Has tab from row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
305+ => IsQualified tab col (Expression 'Ungrouped commons schemas params from ty) where
232 tab ! col = UnsafeExpression $
306 tab ! col = UnsafeExpression $
233 renderSQL tab <> "." <> renderSQL col
307 renderSQL tab <> "." <> renderSQL col
234−instance (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
236− tab ! col = tab ! col :* Nil
237−instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
308+instance (Has tab from row, Has col row ty, column ~ (col ::: ty))
238 => IsQualified tab col
309 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
310+ (Aliased (Expression 'Ungrouped commons schemas params from) column) where
240 tab ! col = tab ! col `As` col
311 tab ! col = tab ! col `As` col
241−instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
312+instance (Has tab from row, Has col row ty, columns ~ '[col ::: ty])
242 => IsQualified tab col
313 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
314+ (NP (Aliased (Expression 'Ungrouped commons schemas params from)) columns) where
244 tab ! col = tab ! col :* Nil
315 tab ! col = tab ! col :* Nil
247− ( HasUnique tab (Join outer from) row
318+ ( HasUnique tab from row
248 , Has col row ty
319 , Has col row ty
249 , GroupedBy tab col bys
320 , GroupedBy tab col bys
250 ) => IsLabel col
321 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
322+ (Expression ('Grouped bys) commons schemas params from ty) where
252 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
323 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
254− ( HasUnique tab (Join outer from) row
325+ ( HasUnique tab from row
256− , GroupedBy tab col bys
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
260− fromLabel = fromLabel @col :* Nil
262− ( HasUnique tab (Join outer from) row
263 , Has col row ty
326 , Has col row ty
264 , GroupedBy tab col bys
327 , GroupedBy tab col bys
265 , column ~ (col ::: ty)
328 , column ~ (col ::: ty)
266 ) => IsLabel col
329 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
330+ (Aliased (Expression ('Grouped bys) commons schemas params from) column) where
268 fromLabel = fromLabel @col `As` Alias
331 fromLabel = fromLabel @col `As` Alias
270− ( HasUnique tab (Join outer from) row
333+ ( HasUnique tab from row
271 , Has col row ty
334 , Has col row ty
272 , GroupedBy tab col bys
335 , GroupedBy tab col bys
273 , columns ~ '[col ::: ty]
336 , columns ~ '[col ::: ty]
274 ) => IsLabel col
337 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
338+ (NP (Aliased (Expression ('Grouped bys) commons schemas params from)) columns) where
276 fromLabel = fromLabel @col :* Nil
339 fromLabel = fromLabel @col :* Nil
279− ( Has tab (Join outer from) row
342+ ( Has tab from row
280 , Has col row ty
343 , Has col row ty
281 , GroupedBy tab col bys
344 , GroupedBy tab col bys
282 ) => IsQualified tab col
345 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
346+ (Expression ('Grouped bys) commons schemas params from ty) where
284 tab ! col = UnsafeExpression $
347 tab ! col = UnsafeExpression $
285 renderSQL tab <> "." <> renderSQL col
348 renderSQL tab <> "." <> renderSQL col
287− ( Has tab (Join outer from) row
350+ ( Has tab from row
289− , GroupedBy tab col bys
291− ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
293− tab ! col = tab ! col :* Nil
295− ( Has tab (Join outer from) row
296 , Has col row ty
351 , Has col row ty
297 , GroupedBy tab col bys
352 , GroupedBy tab col bys
298 , column ~ (col ::: ty)
353 , column ~ (col ::: ty)
299 ) => IsQualified tab col
354 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
355+ (Aliased (Expression ('Grouped bys) commons schemas params from) column) where
301 tab ! col = tab ! col `As` col
356 tab ! col = tab ! col `As` col
303− ( Has tab (Join outer from) row
358+ ( Has tab from row
304 , Has col row ty
359 , Has col row ty
305 , GroupedBy tab col bys
360 , GroupedBy tab col bys
306 , columns ~ '[col ::: ty]
361 , columns ~ '[col ::: ty]
307 ) => IsQualified tab col
362 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
363+ (NP (Aliased (Expression ('Grouped bys) commons schemas params from)) columns) where
309 tab ! col = tab ! col :* Nil
364 tab ! col = tab ! col :* Nil
366+-- | analagous to `Nothing`
368+-- >>> printSQL null_
370+null_ :: Expression commons schemas rels grouping params ('Null ty)
371+null_ = UnsafeExpression "NULL"
373+-- | analagous to `Just`
375+-- >>> printSQL $ notNull true
378+ :: Expression commons schemas rels grouping params ('NotNull ty)
379+ -> Expression commons schemas rels grouping params ('Null ty)
380+notNull = UnsafeExpression . renderSQL
382+-- | return the leftmost value which is not NULL
384+-- >>> printSQL $ coalesce [null_, true] false
385+-- COALESCE(NULL, TRUE, FALSE)
387+ :: [Expression grp commons schemas params from ('Null ty)]
388+ -- ^ @NULL@s may be present
389+ -> Expression grp commons schemas params from ('NotNull ty)
390+ -- ^ @NULL@ is absent
391+ -> Expression grp commons schemas params from ('NotNull ty)
392+coalesce nullxs notNullx = UnsafeExpression $
393+ "COALESCE" <> parenthesized (commaSeparated
394+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
396+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
398+-- >>> printSQL $ fromNull true null_
399+-- COALESCE(NULL, TRUE)
401+ :: Expression grp commons schemas params from ('NotNull ty)
402+ -- ^ what to convert @NULL@ to
403+ -> Expression grp commons schemas params from ('Null ty)
404+ -> Expression grp commons schemas params from ('NotNull ty)
405+fromNull notNullx nullx = coalesce [nullx] notNullx
407+-- | >>> printSQL $ null_ & isNull
410+ :: Expression grp commons schemas params from ('Null ty)
411+ -- ^ possibly @NULL@
412+ -> Condition grp commons schemas params from
413+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
415+-- | >>> printSQL $ null_ & isNotNull
418+ :: Expression grp commons schemas params from ('Null ty)
419+ -- ^ possibly @NULL@
420+ -> Condition grp commons schemas params from
421+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
423+-- | analagous to `maybe` using @IS NULL@
425+-- >>> printSQL $ matchNull true not_ null_
426+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
428+ :: Expression grp commons schemas params from (nullty)
429+ -- ^ what to convert @NULL@ to
430+ -> ( Expression grp commons schemas params from ('NotNull ty)
431+ -> Expression grp commons schemas params from (nullty) )
432+ -- ^ function to perform when @NULL@ is absent
433+ -> Expression grp commons schemas params from ('Null ty)
434+ -> Expression grp commons schemas params from (nullty)
435+matchNull y f x = ifThenElse (isNull x) y
436+ (f (UnsafeExpression (renderSQL x)))
438+{-| right inverse to `fromNull`, if its arguments are equal then
439+`nullIf` gives @NULL@.
441+>>> :set -XTypeApplications -XDataKinds
442+>>> let expr = nullIf false (param @1) :: Expression grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
444+NULL IF (FALSE, ($1 :: bool))
447+ :: Expression grp commons schemas params from ('NotNull ty)
448+ -- ^ @NULL@ is absent
449+ -> Expression grp commons schemas params from ('NotNull ty)
450+ -- ^ @NULL@ is absent
451+ -> Expression grp commons schemas params from ('Null ty)
452+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
453+ (renderSQL x <> ", " <> renderSQL y)
455+-- | >>> printSQL $ array [null_, false, true]
456+-- ARRAY[NULL, FALSE, TRUE]
458+ :: [Expression grp commons schemas params from ty]
460+ -> Expression grp commons schemas params from (nullity ('PGvararray ty))
461+array xs = UnsafeExpression $
462+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
464+-- | >>> printSQL $ array [null_, false, true] & index 2
465+-- (ARRAY[NULL, FALSE, TRUE])[2]
467+ :: Word64 -- ^ index
468+ -> Expression grp commons schemas params from (nullity ('PGvararray ty)) -- ^ array
469+ -> Expression grp commons schemas params from (NullifyType ty)
470+index n expr = UnsafeExpression $
471+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
311instance (KnownSymbol label, label `In` labels) => IsPGlabel label
473instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
474+ (Expression grp commons schemas params from (nullity ('PGenum labels))) where
313 label = UnsafeExpression $ renderSQL (PGlabel @label)
475 label = UnsafeExpression $ renderSQL (PGlabel @label)
477+-- | A row constructor is an expression that builds a row value
478+-- (also called a composite value) using values for its member fields.
481+-- type Complex = 'PGcomposite
482+-- '[ "real" ::: 'NotNull 'PGfloat8
483+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
486+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression grp commons schemas params from ('NotNull Complex)
491+ => NP (Aliased (Expression grp commons schemas params from)) row
492+ -- ^ zero or more expressions for the row field values
493+ -> Expression grp commons schemas params from (nullity ('PGcomposite row))
494+row exprs = UnsafeExpression $ "ROW" <> parenthesized
495+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
498+-- type Complex = 'PGcomposite
499+-- '[ "real" ::: 'NotNull 'PGfloat8
500+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
501+-- type Schema = '["complex" ::: 'Typedef Complex]
504+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression grp '[] (Public Schema) from params ('NotNull Complex)
505+-- >>> printSQL $ i & field #complex #imaginary
506+-- (ROW(0, 1)::"complex")."imaginary"
508+ :: ( Has sch schemas schema
509+ , Has tydef schema ('Typedef ('PGcomposite row))
511+ => QualifiedAlias sch tydef -- ^ row type
512+ -> Alias field -- ^ field name
513+ -> Expression grp commons schemas params from ('NotNull ('PGcomposite row))
514+ -> Expression grp commons schemas params from ty
515+field td fld expr = UnsafeExpression $
516+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
517+ <> "." <> renderSQL fld
520+ (Expression grp commons schemas params from (nullity ('PGvararray ty))) where
521+ (<>) = unsafeBinaryOp "||"
524+ (Expression grp commons schemas params from (nullity ('PGvararray ty))) where
528+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
530+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
532+ :: Expression grp commons schemas params from (nullty)
533+ -- ^ needs at least 1 argument
534+ -> [Expression grp commons schemas params from (nullty)]
536+ -> Expression grp commons schemas params from (nullty)
537+greatest x xs = UnsafeExpression $ "GREATEST("
538+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
540+-- | >>> printSQL $ least currentTimestamp [null_]
541+-- LEAST(CURRENT_TIMESTAMP, NULL)
543+ :: Expression grp commons schemas params from (nullty)
544+ -- ^ needs at least 1 argument
545+ -> [Expression grp commons schemas params from (nullty)]
547+ -> Expression grp commons schemas params from (nullty)
548+least x xs = UnsafeExpression $ "LEAST("
549+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
315-- | >>> printSQL $ unsafeBinaryOp "OR" true false
551-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316-- (TRUE OR FALSE)
552-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
553+unsafeBinaryOp
556+ -> Expression grp commons schemas params from (ty0)
557+ -> Expression grp commons schemas params from (ty1)
558+ -> Expression grp commons schemas params from (ty2)
318unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
559unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319 renderSQL x <+> op <+> renderSQL y
560 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
562+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329-- (NOT TRUE)
563-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
565+ :: ByteString
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
566+ -- ^ operator
332−
567+ -> Expression grp commons schemas params from (ty0)
333−leftOp
568+ -> Expression grp commons schemas params from (ty1)
334− :: forall op sch schemas schema x y.
335− ( Has sch schemas schema
336− , Has op schema ('Operator ('LeftOp x y)) )
337− => FunctionDB schemas x y
338−leftOp = unsafeLeftOp $ renderSymbol @op
340−-- | >>> printSQL $ true & unsafeRightOp "IS NOT TRUE"
341−-- (TRUE IS NOT TRUE)
342−unsafeRightOp :: ByteString -> x --> y
343−unsafeRightOp op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
569+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
344−
570+ op <+> renderSQL x
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
572-- | >>> printSQL $ unsafeFunction "f" true
353-- f(TRUE)
573-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
574+unsafeFunction
577+ -> Expression grp commons schemas params from (xty)
578+ -> Expression grp commons schemas params from (yty)
355unsafeFunction fun x = UnsafeExpression $
579unsafeFunction fun x = UnsafeExpression $
356 fun <> parenthesized (renderSQL x)
580 fun <> parenthesized (renderSQL x)
358−function
582+-- | Helper for defining variadic functions.
359− :: (Has sch schemas schema, Has fun schema ('Function ('[x] :=> 'Returns y)))
583+unsafeVariadicFunction
360− => QualifiedAlias sch fun
584+ :: SListI elems
361− -> FunctionDB schemas x y
362−function = unsafeFunction . renderSQL
364−-- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a')
365−-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
366−unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
585+ => ByteString
587+ -> NP (Expression grp commons schemas params from) elems
588+ -> Expression grp commons schemas params from ret
367−unsafeFunctionN fun xs = UnsafeExpression $
589+unsafeVariadicFunction fun x = UnsafeExpression $
368− fun <> parenthesized (renderCommaSeparated renderSQL xs)
590+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
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
592instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
593+ => Num (Expression grp commons schemas params from (nullity ty)) where
380 (+) = unsafeBinaryOp "+"
594 (+) = unsafeBinaryOp "+"
381 (-) = unsafeBinaryOp "-"
595 (-) = unsafeBinaryOp "-"
382 (*) = unsafeBinaryOp "*"
596 (*) = unsafeBinaryOp "*"
@@ -388,17 +602,12 @@ instance ty `In` PGNum
390instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
604instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
605+ (Expression grp commons schemas params from (nullity ty)) where
392 (/) = unsafeBinaryOp "/"
606 (/) = unsafeBinaryOp "/"
393− fromRational
607+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
397− . showFFloat Nothing
400instance (ty `In` PGNum, ty `In` PGFloating) => Floating
609instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
610+ (Expression grp commons schemas params from (nullity ty)) where
402 pi = UnsafeExpression "pi()"
611 pi = UnsafeExpression "pi()"
403 exp = unsafeFunction "exp"
612 exp = unsafeFunction "exp"
404 log = unsafeFunction "ln"
613 log = unsafeFunction "ln"
@@ -419,54 +628,1541 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419 acosh x = log (x + sqrt (x*x - 1))
628 acosh x = log (x + sqrt (x*x - 1))
420 atanh x = log ((1 + x) / (1 - x)) / 2
629 atanh x = log ((1 + x) / (1 - x)) / 2
422−-- | Contained by operators
631+-- | >>> :{
423−class PGSubset ty where
632+-- let
424− (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
633+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
425− (@>) = unsafeBinaryOp "@>"
634+-- expression = atan2_ pi 2
426− (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
635+-- in printSQL expression
427− (<@) = unsafeBinaryOp "<@"
636+-- :}
428−instance PGSubset 'PGjsonb
637+-- atan2(pi(), 2)
429−instance PGSubset 'PGtsquery
638+atan2_
430−instance PGSubset ('PGvararray ty)
639+ :: float `In` PGFloating
431−instance PGSubset ('PGrange ty)
640+ => Expression grp commons schemas params from (nullity float)
433−class PGIntersect ty where
642+ -> Expression grp commons schemas params from (nullity float)
434− (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
643+ -- ^ denominator
435− (@&&) = unsafeBinaryOp "&&"
644+ -> Expression grp commons schemas params from (nullity float)
436−instance PGIntersect ('PGvararray ty)
645+atan2_ y x = UnsafeExpression $
437−instance PGIntersect ('PGrange ty)
646+ "atan2(" <> renderSQL y <> ", " <> renderSQL x <> ")"
648+-- When a `cast` is applied to an `Expression` of a known type, it
649+-- represents a run-time type conversion. The cast will succeed only if a
650+-- suitable type conversion operation has been defined.
652+-- | >>> printSQL $ true & cast int4
655+ :: TypeExpression schemas ty1
656+ -- ^ type to cast as
657+ -> Expression grp commons schemas params from ty0
658+ -- ^ value to convert
659+ -> Expression grp commons schemas params from ty1
660+cast ty x = UnsafeExpression $ parenthesized $
661+ renderSQL x <+> "::" <+> renderSQL ty
663+-- | integer division, truncates the result
667+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
668+-- expression = 5 `quot_` 2
669+-- in printSQL expression
673+ :: int `In` PGIntegral
674+ => Expression grp commons schemas params from (nullity int)
676+ -> Expression grp commons schemas params from (nullity int)
678+ -> Expression grp commons schemas params from (nullity int)
679+quot_ = unsafeBinaryOp "/"
681+-- | remainder upon integer division
685+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
686+-- expression = 5 `rem_` 2
687+-- in printSQL expression
691+ :: int `In` PGIntegral
692+ => Expression grp commons schemas params from (nullity int)
694+ -> Expression grp commons schemas params from (nullity int)
696+ -> Expression grp commons schemas params from (nullity int)
697+rem_ = unsafeBinaryOp "%"
701+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
702+-- expression = trunc pi
703+-- in printSQL expression
707+ :: frac `In` PGFloating
708+ => Expression grp commons schemas params from (nullity frac)
709+ -- ^ fractional number
710+ -> Expression grp commons schemas params from (nullity frac)
711+trunc = unsafeFunction "trunc"
715+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
716+-- expression = round_ pi
717+-- in printSQL expression
721+ :: frac `In` PGFloating
722+ => Expression grp commons schemas params from (nullity frac)
723+ -- ^ fractional number
724+ -> Expression grp commons schemas params from (nullity frac)
725+round_ = unsafeFunction "round"
729+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
730+-- expression = ceiling_ pi
731+-- in printSQL expression
735+ :: frac `In` PGFloating
736+ => Expression grp commons schemas params from (nullity frac)
737+ -- ^ fractional number
738+ -> Expression grp commons schemas params from (nullity frac)
739+ceiling_ = unsafeFunction "ceiling"
741+-- | A `Condition` is an `Expression`, which can evaluate
742+-- to `true`, `false` or `null_`. This is because SQL uses
743+-- a three valued logic.
744+type Condition grp commons schemas params from =
745+ Expression grp commons schemas params from ('Null 'PGbool)
747+-- | >>> printSQL true
749+true :: Expression grp commons schemas params from (nullity 'PGbool)
750+true = UnsafeExpression "TRUE"
752+-- | >>> printSQL false
754+false :: Expression grp commons schemas params from (nullity 'PGbool)
755+false = UnsafeExpression "FALSE"
757+-- | >>> printSQL $ not_ true
760+ :: Expression grp commons schemas params from (nullity 'PGbool)
761+ -> Expression grp commons schemas params from (nullity 'PGbool)
762+not_ = unsafeUnaryOp "NOT"
764+-- | >>> printSQL $ true .&& false
767+ :: Expression grp commons schemas params from (nullity 'PGbool)
768+ -> Expression grp commons schemas params from (nullity 'PGbool)
769+ -> Expression grp commons schemas params from (nullity 'PGbool)
771+(.&&) = unsafeBinaryOp "AND"
773+-- | >>> printSQL $ true .|| false
776+ :: Expression grp commons schemas params from (nullity 'PGbool)
777+ -> Expression grp commons schemas params from (nullity 'PGbool)
778+ -> Expression grp commons schemas params from (nullity 'PGbool)
780+(.||) = unsafeBinaryOp "OR"
784+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
785+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
786+-- in printSQL expression
788+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
790+ :: [ ( Condition grp commons schemas params from
791+ , Expression grp commons schemas params from ty
793+ -- ^ whens and thens
794+ -> Expression grp commons schemas params from ty
796+ -> Expression grp commons schemas params from ty
797+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
801+ [ " WHEN ", renderSQL when_
802+ , " THEN ", renderSQL then_
804+ | (when_,then_) <- whenThens
806+ , " ELSE ", renderSQL else_
812+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
813+-- expression = ifThenElse true 1 0
814+-- in printSQL expression
816+-- CASE WHEN TRUE THEN 1 ELSE 0 END
818+ :: Condition grp commons schemas params from
819+ -> Expression grp commons schemas params from ty -- ^ then
820+ -> Expression grp commons schemas params from ty -- ^ else
821+ -> Expression grp commons schemas params from ty
822+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
824+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
825+-- will produce @NULL@s if one of their arguments is @NULL@.
827+-- >>> printSQL $ true .== null_
830+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
831+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
832+ -> Condition grp commons schemas params from
833+(.==) = unsafeBinaryOp "="
836+-- | >>> printSQL $ true ./= null_
839+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
840+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
841+ -> Condition grp commons schemas params from
842+(./=) = unsafeBinaryOp "<>"
845+-- | >>> printSQL $ true .>= null_
848+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
849+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
850+ -> Condition grp commons schemas params from
851+(.>=) = unsafeBinaryOp ">="
854+-- | >>> printSQL $ true .< null_
857+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
858+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
859+ -> Condition grp commons schemas params from
860+(.<) = unsafeBinaryOp "<"
863+-- | >>> printSQL $ true .<= null_
866+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
867+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
868+ -> Condition grp commons schemas params from
869+(.<=) = unsafeBinaryOp "<="
872+-- | >>> printSQL $ true .> null_
875+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
876+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
877+ -> Condition grp commons schemas params from
878+(.>) = unsafeBinaryOp ">"
881+-- | >>> printSQL currentDate
884+ :: Expression grp commons schemas params from (nullity 'PGdate)
885+currentDate = UnsafeExpression "CURRENT_DATE"
887+-- | >>> printSQL currentTime
890+ :: Expression grp commons schemas params from (nullity 'PGtimetz)
891+currentTime = UnsafeExpression "CURRENT_TIME"
893+-- | >>> printSQL currentTimestamp
896+ :: Expression grp commons schemas params from (nullity 'PGtimestamptz)
897+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
899+-- | >>> printSQL localTime
902+ :: Expression grp commons schemas params from (nullity 'PGtime)
903+localTime = UnsafeExpression "LOCALTIME"
905+-- | >>> printSQL localTimestamp
908+ :: Expression grp commons schemas params from (nullity 'PGtimestamp)
909+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
911+{-----------------------------------------
913+-----------------------------------------}
439instance IsString
915instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
916+ (Expression grp commons schemas params from (nullity 'PGtext)) where
441 fromString str = UnsafeExpression $
917 fromString str = UnsafeExpression $
442 "E\'" <> fromString (escape =<< str) <> "\'"
918 "E\'" <> fromString (escape =<< str) <> "\'"
443−instance IsString
919+ where
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
920+ escape = \case
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
921+ '\NUL' -> "\\0"
446− "E\'" <> fromString (escape =<< str) <> "\'"
922+ '\'' -> "''"
447−instance IsString
923+ '"' -> "\\\""
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
924+ '\b' -> "\\b"
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
925+ '\n' -> "\\n"
450− "E\'" <> fromString (escape =<< str) <> "\'"
926+ '\r' -> "\\r"
452instance Semigroup
931instance 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
932+ (Expression grp commons schemas params from (nullity 'PGtext)) where
460− (<>) = unsafeBinaryOp "||"
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
463 (<>) = unsafeBinaryOp "||"
933 (<>) = unsafeBinaryOp "||"
465instance Monoid
935instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
936+ (Expression grp commons schemas params from (nullity 'PGtext)) where
467− mempty = fromString ""
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
471 mempty = fromString ""
937 mempty = fromString ""
472 mappend = (<>)
938 mappend = (<>)
940+-- | >>> printSQL $ lower "ARRRGGG"
943+ :: Expression grp commons schemas params from (nullity 'PGtext)
944+ -- ^ string to lower case
945+ -> Expression grp commons schemas params from (nullity 'PGtext)
946+lower = unsafeFunction "lower"
948+-- | >>> printSQL $ upper "eeee"
951+ :: Expression grp commons schemas params from (nullity 'PGtext)
952+ -- ^ string to upper case
953+ -> Expression grp commons schemas params from (nullity 'PGtext)
954+upper = unsafeFunction "upper"
956+-- | >>> printSQL $ charLength "four"
957+-- char_length(E'four')
959+ :: Expression grp commons schemas params from (nullity 'PGtext)
960+ -- ^ string to measure
961+ -> Expression grp commons schemas params from (nullity 'PGint4)
962+charLength = unsafeFunction "char_length"
964+-- | The `like` expression returns true if the @string@ matches
965+-- the supplied @pattern@. If @pattern@ does not contain percent signs
966+-- or underscores, then the pattern only represents the string itself;
967+-- in that case `like` acts like the equals operator. An underscore (_)
968+-- in pattern stands for (matches) any single character; a percent sign (%)
969+-- matches any sequence of zero or more characters.
971+-- >>> printSQL $ "abc" `like` "a%"
972+-- (E'abc' LIKE E'a%')
974+ :: Expression grp commons schemas params from (nullity 'PGtext)
976+ -> Expression grp commons schemas params from (nullity 'PGtext)
978+ -> Expression grp commons schemas params from (nullity 'PGbool)
979+like = unsafeBinaryOp "LIKE"
981+-- | The key word ILIKE can be used instead of LIKE to make the
982+-- match case-insensitive according to the active locale.
984+-- >>> printSQL $ "abc" `ilike` "a%"
985+-- (E'abc' ILIKE E'a%')
987+ :: Expression grp commons schemas params from (nullity 'PGtext)
989+ -> Expression grp commons schemas params from (nullity 'PGtext)
991+ -> Expression grp commons schemas params from (nullity 'PGbool)
992+ilike = unsafeBinaryOp "ILIKE"
994+{-----------------------------------------
995+ -- json and jsonb support
997+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
998+comments lifted directly from this page.
1000+Table 9.44: json and jsonb operators
1001+-----------------------------------------}
1003+-- | Get JSON value (object field or array element) at a key.
1005+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1006+ => Expression grp commons schemas params from (nullity json)
1007+ -> Expression grp commons schemas params from (nullity key)
1008+ -> Expression grp commons schemas params from ('Null json)
1010+(.->) = unsafeBinaryOp "->"
1012+-- | Get JSON value (object field or array element) at a key, as text.
1014+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1015+ => Expression grp commons schemas params from (nullity json)
1016+ -> Expression grp commons schemas params from (nullity key)
1017+ -> Expression grp commons schemas params from ('Null 'PGtext)
1019+(.->>) = unsafeBinaryOp "->>"
1021+-- | Get JSON value at a specified path.
1023+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1024+ => Expression grp commons schemas params from (nullity json)
1025+ -> Expression grp commons schemas params from (nullity path)
1026+ -> Expression grp commons schemas params from ('Null json)
1028+(.#>) = unsafeBinaryOp "#>"
1030+-- | Get JSON value at a specified path as text.
1032+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1033+ => Expression grp commons schemas params from (nullity json)
1034+ -> Expression grp commons schemas params from (nullity path)
1035+ -> Expression grp commons schemas params from ('Null 'PGtext)
1037+(.#>>) = unsafeBinaryOp "#>>"
1039+-- Additional jsonb operators
1041+-- | Does the left JSON value contain the right JSON path/value entries at the
1044+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1045+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1046+ -> Condition grp commons schemas params from
1048+(.@>) = unsafeBinaryOp "@>"
1050+-- | Are the left JSON path/value entries contained at the top level within the
1051+-- right JSON value?
1053+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1054+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1055+ -> Condition grp commons schemas params from
1057+(.<@) = unsafeBinaryOp "<@"
1059+-- | Does the string exist as a top-level key within the JSON value?
1061+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1062+ -> Expression grp commons schemas params from (nullity 'PGtext)
1063+ -> Condition grp commons schemas params from
1065+(.?) = unsafeBinaryOp "?"
1067+-- | Do any of these array strings exist as top-level keys?
1069+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1070+ -> Expression grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1071+ -> Condition grp commons schemas params from
1073+(.?|) = unsafeBinaryOp "?|"
1075+-- | Do all of these array strings exist as top-level keys?
1077+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1078+ -> Expression grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1079+ -> Condition grp commons schemas params from
1081+(.?&) = unsafeBinaryOp "?&"
1083+-- | Concatenate two jsonb values into a new jsonb value.
1085+ Semigroup (Expression commons schemas from grouping param (nullity 'PGjsonb)) where
1086+ (<>) = unsafeBinaryOp "||"
1088+-- | Delete a key or keys from a JSON object, or remove an array element.
1090+-- If the right operand is..
1092+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1093+-- are matched based on their key value.
1095+-- @ text[] @: Delete multiple key/value pairs or string elements
1096+-- from left operand. Key/value pairs are matched based on their key value.
1098+-- @ integer @: Delete the array element with specified index (Negative integers
1099+-- count from the end). Throws an error if top level container is not an array.
1101+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1102+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1103+ -> Expression grp commons schemas params from (nullity key)
1104+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1106+(.-.) = unsafeBinaryOp "-"
1108+-- | Delete the field or element with specified path (for JSON arrays, negative
1109+-- integers count from the end)
1111+ :: PGTextArray "(#-.)" arrayty
1112+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1113+ -> Expression grp commons schemas params from (nullity arrayty)
1114+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1116+(#-.) = unsafeBinaryOp "#-"
1118+{-----------------------------------------
1119+Table 9.45: JSON creation functions
1120+-----------------------------------------}
1122+-- | Literal binary JSON
1125+ => x -> Expression grp commons schemas params from (nullity 'PGjsonb)
1126+jsonbLit = cast jsonb . UnsafeExpression
1127+ . singleQuotedUtf8 . toStrict . JSON.encode
1132+ => x -> Expression grp commons schemas params from (nullity 'PGjson)
1133+jsonLit = cast json . UnsafeExpression
1134+ . singleQuotedUtf8 . toStrict . JSON.encode
1136+-- | Returns the value as json. Arrays and composites are converted
1137+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1138+-- type to json, the cast function will be used to perform the conversion;
1139+-- otherwise, a scalar value is produced. For any scalar type other than a
1140+-- number, a Boolean, or a null value, the text representation will be used, in
1141+-- such a fashion that it is a valid json value.
1143+ :: Expression grp commons schemas params from (nullity ty)
1144+ -> Expression grp commons schemas params from (nullity 'PGjson)
1145+toJson = unsafeFunction "to_json"
1147+-- | Returns the value as jsonb. Arrays and composites are converted
1148+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1149+-- type to json, the cast function will be used to perform the conversion;
1150+-- otherwise, a scalar value is produced. For any scalar type other than a
1151+-- number, a Boolean, or a null value, the text representation will be used, in
1152+-- such a fashion that it is a valid jsonb value.
1154+ :: Expression grp commons schemas params from (nullity ty)
1155+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1156+toJsonb = unsafeFunction "to_jsonb"
1158+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1159+-- becomes a JSON array of arrays.
1161+ :: PGArray "arrayToJson" arr
1162+ => Expression grp commons schemas params from (nullity arr)
1163+ -> Expression grp commons schemas params from (nullity 'PGjson)
1164+arrayToJson = unsafeFunction "array_to_json"
1166+-- | Returns the row as a JSON object.
1168+ :: Expression grp commons schemas params from (nullity ('PGcomposite ty))
1169+ -> Expression grp commons schemas params from (nullity 'PGjson)
1170+rowToJson = unsafeFunction "row_to_json"
1172+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1176+ => NP (Expression grp commons schemas params from) elems
1177+ -> Expression grp commons schemas params from (nullity 'PGjson)
1178+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1180+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1181+-- variadic argument list.
1184+ => NP (Expression grp commons schemas params from) elems
1185+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1186+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1190+ => NP (Aliased (Expression grp commons schemas params from)) elems
1193+ (`appEndo` []) . hcfoldMap (Proxy :: Proxy Top)
1194+ (\(col `As` name) -> Endo $ \xs ->
1195+ renderAliasString name : renderSQL col : xs)
1197+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1198+ renderAliasString = singleQuotedText . fromString . symbolVal
1200+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1201+-- argument list. The elements of the argument list must alternate between text
1205+ => NP (Aliased (Expression grp commons schemas params from)) elems
1206+ -> Expression grp commons schemas params from (nullity 'PGjson)
1208+ = unsafeFunction "json_build_object"
1211+ . unsafeRowFunction
1213+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1214+-- variadic argument list. The elements of the argument list must alternate
1215+-- between text and values.
1218+ => NP (Aliased (Expression grp commons schemas params from)) elems
1219+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1221+ = unsafeFunction "jsonb_build_object"
1224+ . unsafeRowFunction
1226+-- | Builds a JSON object out of a text array. The array must have either
1227+-- exactly one dimension with an even number of members, in which case they are
1228+-- taken as alternating key/value pairs, or two dimensions such that each inner
1229+-- array has exactly two elements, which are taken as a key/value pair.
1231+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1232+ => Expression grp commons schemas params from (nullity arr)
1233+ -> Expression grp commons schemas params from (nullity 'PGjson)
1234+jsonObject = unsafeFunction "json_object"
1236+-- | Builds a binary JSON object out of a text array. The array must have either
1237+-- exactly one dimension with an even number of members, in which case they are
1238+-- taken as alternating key/value pairs, or two dimensions such that each inner
1239+-- array has exactly two elements, which are taken as a key/value pair.
1241+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1242+ => Expression grp commons schemas params from (nullity arr)
1243+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1244+jsonbObject = unsafeFunction "jsonb_object"
1246+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1247+-- keys and one for values, that are zipped pairwise to create a JSON object.
1249+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1250+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1251+ => Expression grp commons schemas params from (nullity keysArray)
1252+ -> Expression grp commons schemas params from (nullity valuesArray)
1253+ -> Expression grp commons schemas params from (nullity 'PGjson)
1254+jsonZipObject ks vs =
1255+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1257+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1258+-- keys and one for values, that are zipped pairwise to create a binary JSON
1261+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1262+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1263+ => Expression grp commons schemas params from (nullity keysArray)
1264+ -> Expression grp commons schemas params from (nullity valuesArray)
1265+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1266+jsonbZipObject ks vs =
1267+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1269+{-----------------------------------------
1270+Table 9.46: JSON processing functions
1271+-----------------------------------------}
1273+-- | Returns the number of elements in the outermost JSON array.
1275+ :: Expression grp commons schemas params from (nullity 'PGjson)
1276+ -> Expression grp commons schemas params from (nullity 'PGint4)
1277+jsonArrayLength = unsafeFunction "json_array_length"
1279+-- | Returns the number of elements in the outermost binary JSON array.
1281+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1282+ -> Expression grp commons schemas params from (nullity 'PGint4)
1283+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1285+-- | Returns JSON value pointed to by the given path (equivalent to #>
1289+ => Expression grp commons schemas params from (nullity 'PGjson)
1290+ -> NP (Expression grp commons schemas params from) elems
1291+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1292+jsonExtractPath x xs =
1293+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1295+-- | Returns JSON value pointed to by the given path (equivalent to #>
1299+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1300+ -> NP (Expression grp commons schemas params from) elems
1301+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1302+jsonbExtractPath x xs =
1303+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1305+-- | Returns JSON value pointed to by the given path (equivalent to #>
1306+-- operator), as text.
1307+jsonExtractPathAsText
1309+ => Expression grp commons schemas params from (nullity 'PGjson)
1310+ -> NP (Expression grp commons schemas params from) elems
1311+ -> Expression grp commons schemas params from (nullity 'PGjson)
1312+jsonExtractPathAsText x xs =
1313+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1315+-- | Returns JSON value pointed to by the given path (equivalent to #>
1316+-- operator), as text.
1317+jsonbExtractPathAsText
1319+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1320+ -> NP (Expression grp commons schemas params from) elems
1321+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1322+jsonbExtractPathAsText x xs =
1323+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1325+-- | Returns the type of the outermost JSON value as a text string. Possible
1326+-- types are object, array, string, number, boolean, and null.
1328+ :: Expression grp commons schemas params from (nullity 'PGjson)
1329+ -> Expression grp commons schemas params from (nullity 'PGtext)
1330+jsonTypeof = unsafeFunction "json_typeof"
1332+-- | Returns the type of the outermost binary JSON value as a text string.
1333+-- Possible types are object, array, string, number, boolean, and null.
1335+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1336+ -> Expression grp commons schemas params from (nullity 'PGtext)
1337+jsonbTypeof = unsafeFunction "jsonb_typeof"
1339+-- | Returns its argument with all object fields that have null values omitted.
1340+-- Other null values are untouched.
1342+ :: Expression grp commons schemas params from (nullity 'PGjson)
1343+ -> Expression grp commons schemas params from (nullity 'PGjson)
1344+jsonStripNulls = unsafeFunction "json_strip_nulls"
1346+-- | Returns its argument with all object fields that have null values omitted.
1347+-- Other null values are untouched.
1349+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1350+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1351+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1353+-- | @ jsonbSet target path new_value create_missing @
1355+-- Returns target with the section designated by path replaced by new_value,
1356+-- or with new_value added if create_missing is true ( default is true) and the
1357+-- item designated by path does not exist. As with the path orientated
1358+-- operators, negative integers that appear in path count from the end of JSON
1361+ :: PGTextArray "jsonbSet" arr
1362+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1363+ -> Expression grp commons schemas params from (nullity arr)
1364+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1365+ -> Maybe (Expression grp commons schemas params from (nullity 'PGbool))
1366+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1367+jsonbSet tgt path val createMissing = case createMissing of
1368+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1369+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1371+-- | @ jsonbInsert target path new_value insert_after @
1373+-- Returns target with new_value inserted. If target section designated by
1374+-- path is in a JSONB array, new_value will be inserted before target or after
1375+-- if insert_after is true (default is false). If target section designated by
1376+-- path is in JSONB object, new_value will be inserted only if target does not
1377+-- exist. As with the path orientated operators, negative integers that appear
1378+-- in path count from the end of JSON arrays.
1380+ :: PGTextArray "jsonbInsert" arr
1381+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1382+ -> Expression grp commons schemas params from (nullity arr)
1383+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1384+ -> Maybe (Expression grp commons schemas params from (nullity 'PGbool))
1385+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1386+jsonbInsert tgt path val insertAfter = case insertAfter of
1387+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1388+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1390+-- | Returns its argument as indented JSON text.
1392+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1393+ -> Expression grp commons schemas params from (nullity 'PGtext)
1394+jsonbPretty = unsafeFunction "jsonb_pretty"
1396+{-----------------------------------------
1398+-----------------------------------------}
1400+class Aggregate expr1 expr2 aggr
1401+ | aggr -> expr1, aggr -> expr2 where
1403+ -- | A special aggregation that does not require an input
1407+ -- expression :: Expression (Grouped bys) commons schemas params from ('NotNull 'PGint8)
1408+ -- expression = countStar
1409+ -- in printSQL expression
1412+ countStar :: aggr ('NotNull 'PGint8)
1416+ -- expression :: Expression (Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1417+ -- expression = count (All #col)
1418+ -- in printSQL expression
1420+ -- count(ALL "col")
1424+ -> aggr ('NotNull 'PGint8)
1428+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)
1429+ -- expression = sum_ (Distinct #col)
1430+ -- in printSQL expression
1432+ -- sum(DISTINCT "col")
1435+ => expr1 (nullity ty)
1436+ -> aggr (nullity ty)
1440+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1441+ -- expression = bitAnd (Distinct #col)
1442+ -- in printSQL expression
1444+ -- bit_and(DISTINCT "col")
1446+ :: int `In` PGIntegral
1447+ => expr1 (nullity int)
1448+ -- ^ what to aggregate
1449+ -> aggr (nullity int)
1453+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1454+ -- expression = bitOr (All #col)
1455+ -- in printSQL expression
1457+ -- bit_or(ALL "col")
1459+ :: int `In` PGIntegral
1460+ => expr1 (nullity int)
1461+ -- ^ what to aggregate
1462+ -> aggr (nullity int)
1466+ -- winFun :: WindowFunction 'Ungrouped commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1467+ -- winFun = boolAnd #col
1468+ -- in printSQL winFun
1472+ :: expr1 (nullity 'PGbool)
1473+ -- ^ what to aggregate
1474+ -> aggr (nullity 'PGbool)
1478+ -- expression :: Expression (Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1479+ -- expression = boolOr (All #col)
1480+ -- in printSQL expression
1482+ -- bool_or(ALL "col")
1484+ :: expr1(nullity 'PGbool)
1485+ -- ^ what to aggregate
1486+ -> aggr (nullity 'PGbool)
1488+ -- | synonym for `boolAnd`
1492+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1493+ -- expression = every (Distinct #col)
1494+ -- in printSQL expression
1496+ -- every(DISTINCT "col")
1498+ :: expr1 (nullity 'PGbool)
1499+ -- ^ what to aggregate
1500+ -> aggr (nullity 'PGbool)
1502+ -- | maximum value of expression across all input values
1504+ :: expr1 (nullity ty)
1505+ -- ^ what to maximize
1506+ -> aggr (nullity ty)
1508+ -- | minimum value of expression across all input values
1510+ :: expr1 (nullity ty)
1511+ -- ^ what to minimize
1512+ -> aggr (nullity ty)
1514+ -- | average aggregation
1516+ :: expr1 (nullity ty)
1517+ -- ^ what to average
1518+ -> aggr (nullity (PGAvg ty))
1520+ {- | correlation coefficient
1523+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1524+ expression = corr (All (#y :*: #x))
1525+ in printSQL expression
1530+ :: expr2 (nullity 'PGfloat8)
1531+ -> aggr (nullity 'PGfloat8)
1533+ {- | population covariance
1536+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1537+ expression = covarPop (All (#y :*: #x))
1538+ in printSQL expression
1540+ covar_pop(ALL "y", "x")
1543+ :: expr2 (nullity 'PGfloat8)
1544+ -> aggr (nullity 'PGfloat8)
1546+ {- | sample covariance
1549+ winFun :: WindowFunction 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1550+ winFun = covarSamp (#y :*: #x)
1553+ covar_samp("y", "x")
1556+ :: expr2 (nullity 'PGfloat8)
1557+ -> aggr (nullity 'PGfloat8)
1559+ {- | average of the independent variable (sum(X)/N)
1562+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1563+ expression = regrAvgX (All (#y :*: #x))
1564+ in printSQL expression
1566+ regr_avgx(ALL "y", "x")
1569+ :: expr2 (nullity 'PGfloat8)
1570+ -> aggr (nullity 'PGfloat8)
1572+ {- | average of the dependent variable (sum(Y)/N)
1575+ winFun :: WindowFunction 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1576+ winFun = regrAvgY (#y :*: #x)
1579+ regr_avgy("y", "x")
1582+ :: expr2 (nullity 'PGfloat8)
1583+ -> aggr (nullity 'PGfloat8)
1585+ {- | number of input rows in which both expressions are nonnull
1588+ winFun :: WindowFunction 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGint8)
1589+ winFun = regrCount (#y :*: #x)
1592+ regr_count("y", "x")
1595+ :: expr2 (nullity 'PGfloat8)
1596+ -> aggr (nullity 'PGint8)
1598+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1601+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1602+ expression = regrIntercept (All (#y :*: #x))
1603+ in printSQL expression
1605+ regr_intercept(ALL "y", "x")
1608+ :: expr2 (nullity 'PGfloat8)
1609+ -> aggr (nullity 'PGfloat8)
1611+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1613+ :: expr2 (nullity 'PGfloat8)
1614+ -> aggr (nullity 'PGfloat8)
1616+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1617+ -- determined by the (X, Y) pairs
1619+ :: expr2 (nullity 'PGfloat8)
1620+ -> aggr (nullity 'PGfloat8)
1622+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1623+ -- (“sum of squares” of the independent variable)
1625+ :: expr2 (nullity 'PGfloat8)
1626+ -> aggr (nullity 'PGfloat8)
1628+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1629+ -- (“sum of products” of independent times dependent variable)
1631+ :: expr2 (nullity 'PGfloat8)
1632+ -> aggr (nullity 'PGfloat8)
1634+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1635+ -- (“sum of squares” of the dependent variable)
1637+ :: expr2 (nullity 'PGfloat8)
1638+ -> aggr (nullity 'PGfloat8)
1640+ -- | historical alias for `stddevSamp`
1642+ :: expr1 (nullity ty)
1643+ -> aggr (nullity (PGAvg ty))
1645+ -- | population standard deviation of the input values
1647+ :: expr1 (nullity ty)
1648+ -> aggr (nullity (PGAvg ty))
1650+ -- | sample standard deviation of the input values
1652+ :: expr1 (nullity ty)
1653+ -> aggr (nullity (PGAvg ty))
1655+ -- | historical alias for `varSamp`
1657+ :: expr1 (nullity ty)
1658+ -> aggr (nullity (PGAvg ty))
1660+ -- | population variance of the input values
1661+ -- (square of the population standard deviation)
1663+ :: expr1 (nullity ty)
1664+ -> aggr (nullity (PGAvg ty))
1666+ -- | sample variance of the input values
1667+ -- (square of the sample standard deviation)
1669+ :: expr1 (nullity ty)
1670+ -> aggr (nullity (PGAvg ty))
1672+data Distinction expr ty
1674+ | Distinct (expr ty)
1675+ deriving (GHC.Generic,Show,Eq,Ord)
1676+instance NFData (Distinction (Expression grp commons schemas params from) ty)
1677+instance RenderSQL (Distinction (Expression grp commons schemas params from) ty) where
1679+ All x -> "ALL" <+> renderSQL x
1680+ Distinct x -> "DISTINCT" <+> renderSQL x
1683+ ( Expression grp commons schemas params from
1685+ Expression grp commons schemas params from) xty ) where
1688+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1689+ Distinct (x :*: x') ->
1690+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1693+ (Distinction (Expression 'Ungrouped commons schemas params from))
1694+ (Distinction (Expression 'Ungrouped commons schemas params from :*: Expression 'Ungrouped commons schemas params from))
1695+ (Expression ('Grouped bys) commons schemas params from) where
1696+ countStar = UnsafeExpression "count(*)"
1697+ count = unsafeAggregate1 "count"
1698+ sum_ = unsafeAggregate1 "sum"
1699+ bitAnd = unsafeAggregate1 "bit_and"
1700+ bitOr = unsafeAggregate1 "bit_or"
1701+ boolAnd = unsafeAggregate1 "bool_and"
1702+ boolOr = unsafeAggregate1 "bool_or"
1703+ every = unsafeAggregate1 "every"
1704+ max_ = unsafeAggregate1 "max"
1705+ min_ = unsafeAggregate1 "min"
1706+ avg = unsafeAggregate1 "avg"
1707+ corr = unsafeAggregate2 "corr"
1708+ covarPop = unsafeAggregate2 "covar_pop"
1709+ covarSamp = unsafeAggregate2 "covar_samp"
1710+ regrAvgX = unsafeAggregate2 "regr_avgx"
1711+ regrAvgY = unsafeAggregate2 "regr_avgy"
1712+ regrCount = unsafeAggregate2 "regr_count"
1713+ regrIntercept = unsafeAggregate2 "regr_intercept"
1714+ regrR2 = unsafeAggregate2 "regr_r2"
1715+ regrSlope = unsafeAggregate2 "regr_slope"
1716+ regrSxx = unsafeAggregate2 "regr_sxx"
1717+ regrSxy = unsafeAggregate2 "regr_sxy"
1718+ regrSyy = unsafeAggregate2 "regr_syy"
1719+ stddev = unsafeAggregate1 "stddev"
1720+ stddevPop = unsafeAggregate1 "stddev_pop"
1721+ stddevSamp = unsafeAggregate1 "stddev_samp"
1722+ variance = unsafeAggregate1 "variance"
1723+ varPop = unsafeAggregate1 "var_pop"
1724+ varSamp = unsafeAggregate1 "var_samp"
1726+ (Expression grp commons schemas params from)
1727+ (Expression grp commons schemas params from :*: Expression grp commons schemas params from)
1728+ (WindowFunction grp commons schemas params from) where
1729+ countStar = UnsafeWindowFunction "count(*)"
1730+ count = unsafeWindowFunction1 "count"
1731+ sum_ = unsafeWindowFunction1 "sum"
1732+ bitAnd = unsafeWindowFunction1 "bit_and"
1733+ bitOr = unsafeWindowFunction1 "bit_or"
1734+ boolAnd = unsafeWindowFunction1 "bool_and"
1735+ boolOr = unsafeWindowFunction1 "bool_or"
1736+ every = unsafeWindowFunction1 "every"
1737+ max_ = unsafeWindowFunction1 "max"
1738+ min_ = unsafeWindowFunction1 "min"
1739+ avg = unsafeWindowFunction1 "avg"
1740+ corr = unsafeWindowFunction2 "corr"
1741+ covarPop = unsafeWindowFunction2 "covar_pop"
1742+ covarSamp = unsafeWindowFunction2 "covar_samp"
1743+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1744+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1745+ regrCount = unsafeWindowFunction2 "regr_count"
1746+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1747+ regrR2 = unsafeWindowFunction2 "regr_r2"
1748+ regrSlope = unsafeWindowFunction2 "regr_slope"
1749+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1750+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1751+ regrSyy = unsafeWindowFunction2 "regr_syy"
1752+ stddev = unsafeWindowFunction1 "stddev"
1753+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1754+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1755+ variance = unsafeWindowFunction1 "variance"
1756+ varPop = unsafeWindowFunction1 "var_pop"
1757+ varSamp = unsafeWindowFunction1 "var_samp"
1759+-- | escape hatch to define aggregate functions
1761+ :: ByteString -- ^ aggregate function
1762+ -> Distinction (Expression 'Ungrouped commons schemas params from) xty
1763+ -> Expression ('Grouped bys) commons schemas params from yty
1764+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1765+ [fun, "(", renderSQL x, ")"]
1767+-- | escape hatch to define aggregate binary functions
1769+ :: ByteString -- ^ aggregate function
1770+ -> Distinction (Expression 'Ungrouped commons schemas params from :*: Expression 'Ungrouped commons schemas params from) xty
1771+ -> Expression ('Grouped bys) commons schemas params from yty
1772+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1773+ [fun, "(", renderSQL xx, ")"]
1775+-- | A type family that calculates `PGAvg` type of a `PGType`.
1776+type family PGAvg ty where
1777+ PGAvg 'PGint2 = 'PGnumeric
1778+ PGAvg 'PGint4 = 'PGnumeric
1779+ PGAvg 'PGint8 = 'PGnumeric
1780+ PGAvg 'PGnumeric = 'PGnumeric
1781+ PGAvg 'PGfloat4 = 'PGfloat8
1782+ PGAvg 'PGfloat8 = 'PGfloat8
1783+ PGAvg 'PGinterval = 'PGinterval
1784+ -- PGAvg pg = TypeError
1786+{-----------------------------------------
1788+-----------------------------------------}
1790+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1791+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1792+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1793+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1794+instance RenderSQL (TypeExpression schemas ty) where
1795+ renderSQL = renderTypeExpression
1797+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1799+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1800+ => QualifiedAlias sch td
1801+ -> TypeExpression schemas (nullity ty)
1802+typedef = UnsafeTypeExpression . renderSQL
1804+-- | The composite type corresponding to a `Table` definition can be expressed
1807+ :: (Has sch schemas schema, Has tab schema ('Table table))
1808+ => QualifiedAlias sch tab
1809+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1810+typetable = UnsafeTypeExpression . renderSQL
1812+-- | The composite type corresponding to a `View` definition can be expressed
1815+ :: (Has sch schemas schema, Has vw schema ('View view))
1816+ => QualifiedAlias sch vw
1817+ -> TypeExpression schemas (nullity ('PGcomposite view))
1818+typeview = UnsafeTypeExpression . renderSQL
1820+-- | logical Boolean (true/false)
1821+bool :: TypeExpression schemas (nullity 'PGbool)
1822+bool = UnsafeTypeExpression "bool"
1823+-- | signed two-byte integer
1824+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1825+int2 = UnsafeTypeExpression "int2"
1826+smallint = UnsafeTypeExpression "smallint"
1827+-- | signed four-byte integer
1828+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1829+int4 = UnsafeTypeExpression "int4"
1830+int = UnsafeTypeExpression "int"
1831+integer = UnsafeTypeExpression "integer"
1832+-- | signed eight-byte integer
1833+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1834+int8 = UnsafeTypeExpression "int8"
1835+bigint = UnsafeTypeExpression "bigint"
1836+-- | arbitrary precision numeric type
1837+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1838+numeric = UnsafeTypeExpression "numeric"
1839+-- | single precision floating-point number (4 bytes)
1840+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1841+float4 = UnsafeTypeExpression "float4"
1842+real = UnsafeTypeExpression "real"
1843+-- | double precision floating-point number (8 bytes)
1844+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1845+float8 = UnsafeTypeExpression "float8"
1846+doublePrecision = UnsafeTypeExpression "double precision"
1847+-- | variable-length character string
1848+text :: TypeExpression schemas (nullity 'PGtext)
1849+text = UnsafeTypeExpression "text"
1850+-- | fixed-length character string
1852+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1853+ => TypeExpression schemas (nullity ('PGchar n))
1854+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1855+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1856+-- | variable-length character string
1857+varchar, characterVarying
1858+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1859+ => TypeExpression schemas (nullity ('PGvarchar n))
1860+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1861+characterVarying = UnsafeTypeExpression $
1862+ "character varying(" <> renderNat @n <> ")"
1863+-- | binary data ("byte array")
1864+bytea :: TypeExpression schemas (nullity 'PGbytea)
1865+bytea = UnsafeTypeExpression "bytea"
1866+-- | date and time (no time zone)
1867+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1868+timestamp = UnsafeTypeExpression "timestamp"
1869+-- | date and time, including time zone
1870+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1871+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1872+-- | calendar date (year, month, day)
1873+date :: TypeExpression schemas (nullity 'PGdate)
1874+date = UnsafeTypeExpression "date"
1875+-- | time of day (no time zone)
1876+time :: TypeExpression schemas (nullity 'PGtime)
1877+time = UnsafeTypeExpression "time"
1878+-- | time of day, including time zone
1879+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1880+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1882+interval :: TypeExpression schemas (nullity 'PGinterval)
1883+interval = UnsafeTypeExpression "interval"
1884+-- | universally unique identifier
1885+uuid :: TypeExpression schemas (nullity 'PGuuid)
1886+uuid = UnsafeTypeExpression "uuid"
1887+-- | IPv4 or IPv6 host address
1888+inet :: TypeExpression schemas (nullity 'PGinet)
1889+inet = UnsafeTypeExpression "inet"
1890+-- | textual JSON data
1891+json :: TypeExpression schemas (nullity 'PGjson)
1892+json = UnsafeTypeExpression "json"
1893+-- | binary JSON data, decomposed
1894+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1895+jsonb = UnsafeTypeExpression "jsonb"
1896+-- | variable length array
1898+ :: TypeExpression schemas pg
1899+ -> TypeExpression schemas (nullity ('PGvararray pg))
1900+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1901+-- | fixed length array
1903+-- >>> renderSQL (fixarray @'[2] json)
1906+ :: forall dims schemas nullity pg. All KnownNat dims
1907+ => TypeExpression schemas pg
1908+ -> TypeExpression schemas (nullity ('PGfixarray dims pg))
1909+fixarray ty = UnsafeTypeExpression $
1910+ renderSQL ty <> renderDims @dims
1912+ renderDims :: forall ns. All KnownNat ns => ByteString
1916+ . ByteString.intercalate "]["
1918+ $ hcmap (Proxy @KnownNat)
1919+ (K . fromString . show . natVal)
1920+ (hpure Proxy :: NP Proxy ns)
1922+-- | `pgtype` is a demoted version of a `PGType`
1923+class PGTyped schemas (ty :: NullityType) where
1924+ pgtype :: TypeExpression schemas ty
1925+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
1926+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
1927+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
1928+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
1929+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
1930+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
1931+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
1932+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
1933+instance (KnownNat n, 1 <= n)
1934+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
1935+instance (KnownNat n, 1 <= n)
1936+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
1937+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
1938+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
1939+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
1940+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
1941+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
1942+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
1943+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
1944+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
1945+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
1946+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
1947+instance PGTyped schemas ty
1948+ => PGTyped schemas (nullity ('PGvararray ty)) where
1949+ pgtype = vararray (pgtype @schemas @ty)
1950+instance (All KnownNat dims, PGTyped schemas ty)
1951+ => PGTyped schemas (nullity ('PGfixarray dims ty)) where
1952+ pgtype = fixarray @dims (pgtype @schemas @ty)
1954+{-----------------------------------------
1956+-----------------------------------------}
1958+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1959+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1960+-- column to ascending or descending. Ascending order puts smaller values
1961+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1962+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1963+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1964+-- determine whether nulls appear before or after non-null values in the sort
1965+-- ordering of a `Null` result column.
1966+data SortExpression grp commons schemas params from where
1968+ :: Expression grp commons schemas params from ('NotNull ty)
1969+ -> SortExpression grp commons schemas params from
1971+ :: Expression grp commons schemas params from ('NotNull ty)
1972+ -> SortExpression grp commons schemas params from
1974+ :: Expression grp commons schemas params from ('Null ty)
1975+ -> SortExpression grp commons schemas params from
1977+ :: Expression grp commons schemas params from ('Null ty)
1978+ -> SortExpression grp commons schemas params from
1980+ :: Expression grp commons schemas params from ('Null ty)
1981+ -> SortExpression grp commons schemas params from
1983+ :: Expression grp commons schemas params from ('Null ty)
1984+ -> SortExpression grp commons schemas params from
1985+deriving instance Show (SortExpression grp commons schemas params from)
1987+class OrderBy expr where
1989+ :: [SortExpression grp commons schemas params from]
1990+ -> expr grp commons schemas params from
1991+ -> expr grp commons schemas params from
1993+-- | Render a `SortExpression`.
1994+instance RenderSQL (SortExpression grp commons schemas params from) where
1996+ Asc expression -> renderSQL expression <+> "ASC"
1997+ Desc expression -> renderSQL expression <+> "DESC"
1998+ AscNullsFirst expression -> renderSQL expression
1999+ <+> "ASC NULLS FIRST"
2000+ DescNullsFirst expression -> renderSQL expression
2001+ <+> "DESC NULLS FIRST"
2002+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2003+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2005+data WindowDefinition grp commons schemas params from where
2008+ => NP (Expression grp commons schemas params from) bys
2009+ -> [SortExpression grp commons schemas params from]
2010+ -> WindowDefinition grp commons schemas params from
2012+instance OrderBy WindowDefinition where
2013+ orderBy sortsR (WindowDefinition parts sortsL)
2014+ = WindowDefinition parts (sortsL ++ sortsR)
2016+instance RenderSQL (WindowDefinition commons schemas from grp params) where
2017+ renderSQL (WindowDefinition part ord) =
2018+ renderPartitionByClause part <> renderOrderByClause ord
2020+ renderPartitionByClause = \case
2022+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2023+ renderOrderByClause = \case
2025+ srts -> " ORDER" <+> "BY"
2026+ <+> commaSeparated (renderSQL <$> srts)
2030+ => NP (Expression grp commons schemas params from) bys
2031+ -> WindowDefinition grp commons schemas params from
2032+partitionBy bys = WindowDefinition bys []
2034+newtype WindowFunction
2036+ (commons :: FromType)
2037+ (schemas :: SchemasType)
2038+ (params :: [NullityType])
2040+ (ty :: NullityType)
2041+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2042+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2044+instance RenderSQL (WindowFunction grp commons schemas params from ty) where
2045+ renderSQL = renderWindowFunction
2047+unsafeWindowFunction1
2049+ -> Expression grp commons schemas params from ty0
2050+ -> WindowFunction grp commons schemas params from ty1
2051+unsafeWindowFunction1 fun x
2052+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2054+unsafeWindowFunction2
2056+ -> (Expression grp commons schemas params from :*: Expression grp commons schemas params from) ty0
2057+ -> WindowFunction grp commons schemas params from ty1
2058+unsafeWindowFunction2 fun (x :*: x')
2059+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2061+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2065+rank :: WindowFunction grp commons schemas params from ('NotNull 'PGint8)
2066+rank = UnsafeWindowFunction "rank()"
2068+{- | number of the current row within its partition, counting from 1
2069+>>> printSQL rowNumber
2072+rowNumber :: WindowFunction grp commons schemas params from ('NotNull 'PGint8)
2073+rowNumber = UnsafeWindowFunction "row_number()"
2075+{- | rank of the current row without gaps; this function counts peer groups
2076+>>> printSQL denseRank
2079+denseRank :: WindowFunction grp commons schemas params from ('NotNull 'PGint8)
2080+denseRank = UnsafeWindowFunction "dense_rank()"
2082+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2083+>>> printSQL percentRank
2086+percentRank :: WindowFunction grp commons schemas params from ('NotNull 'PGfloat8)
2087+percentRank = UnsafeWindowFunction "percent_rank()"
2089+{- | cumulative distribution: (number of partition rows
2090+preceding or peer with current row) / total partition rows
2091+>>> printSQL cumeDist
2094+cumeDist :: WindowFunction grp commons schemas params from ('NotNull 'PGfloat8)
2095+cumeDist = UnsafeWindowFunction "cume_dist()"
2097+{- | integer ranging from 1 to the argument value,
2098+dividing the partition as equally as possible
2101+ :: Expression grp commons schemas params from ('NotNull 'PGint4)
2103+ -> WindowFunction grp commons schemas params from ('NotNull 'PGint4)
2104+ntile = unsafeWindowFunction1 "ntile"
2106+{- | returns value evaluated at the row that is offset rows before the current
2107+row within the partition; if there is no such row, instead return default
2108+(which must be of the same type as value). Both offset and default are
2109+evaluated with respect to the current row.
2112+ :: Expression grp commons schemas params from ty
2114+ -> Expression grp commons schemas params from ('NotNull 'PGint4)
2116+ -> Expression grp commons schemas params from ty
2118+ -> WindowFunction grp commons schemas params from ty
2119+lag value offset def = UnsafeWindowFunction $ "lag"
2121+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2123+{- | returns value evaluated at the row that is offset rows after the current
2124+row within the partition; if there is no such row, instead return default
2125+(which must be of the same type as value). Both offset and default are
2126+evaluated with respect to the current row.
2129+ :: Expression grp commons schemas params from ty
2131+ -> Expression grp commons schemas params from ('NotNull 'PGint4)
2133+ -> Expression grp commons schemas params from ty
2135+ -> WindowFunction grp commons schemas params from ty
2136+lead value offset def = UnsafeWindowFunction $ "lag"
2138+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2140+{- | returns value evaluated at the row that is the
2141+first row of the window frame
2144+ :: Expression grp commons schemas params from ty
2146+ -> WindowFunction grp commons schemas params from ty
2147+firstValue = unsafeWindowFunction1 "first_value"
2149+{- | returns value evaluated at the row that is the
2150+last row of the window frame
2153+ :: Expression grp commons schemas params from ty
2155+ -> WindowFunction grp commons schemas params from ty
2156+lastValue = unsafeWindowFunction1 "last_value"
2158+{- | returns value evaluated at the row that is the nth
2159+row of the window frame (counting from 1); null if no such row
2162+ :: Expression grp commons schemas params from (nullity ty)
2164+ -> Expression grp commons schemas params from ('NotNull 'PGint4)
2166+ -> WindowFunction grp commons schemas params from ('Null ty)
2167+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2168+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])