@@ -1,13 +1,14 @@
11{-|
22Module: Squeal.PostgreSQL.Expression
33Description: Squeal expressions
4−Copyright: (c) Eitan Chatav, 2019
4+Copyright: (c) Eitan Chatav, 2017
55Maintainer: eitan@morphism.tech
66Stability: experimental
77
88Squeal expressions are the atoms used to build statements.
99-}
1010
11+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
1112{-# LANGUAGE
1213 AllowAmbiguousTypes
1314 , ConstraintKinds
@@ -33,214 +34,344 @@ Squeal expressions are the atoms used to build statements.
3334module Squeal.PostgreSQL.Expression
3435 ( -- * Expression
3536 Expression (..)
36− , Expr
37− , type (-->)
38− , FunctionDB
39− , unsafeFunction
40− , function
41− , unsafeLeftOp
42− , leftOp
43− , unsafeRightOp
44− , rightOp
4537 , Operator
46− , OperatorDB
38+ , (:-->)
39+ , HasParameter (parameter)
40+ , param
41+ -- ** Null
42+ , null_
43+ , notNull
44+ , coalesce
45+ , fromNull
46+ , isNull
47+ , isNotNull
48+ , matchNull
49+ , nullIf
50+ -- ** Collections
51+ , array
52+ , cardinality
53+ , index
54+ , row
55+ , field
56+ -- ** Functions
4757 , unsafeBinaryOp
48− , binaryOp
49− , FunctionVar
50− , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
53− , unsafeFunctionN
54− , functionN
55− , PGSubset (..)
56− , PGIntersect (..)
58+ , unsafeUnaryOp
59+ , unsafeFunction
60+ , unsafeVariadicFunction
61+ , atan2_
62+ , cast
63+ , quot_
64+ , rem_
65+ , trunc
66+ , round_
67+ , ceiling_
68+ , greatest
69+ , least
70+ -- ** Conditions
71+ , true
72+ , false
73+ , not_
74+ , (.&&)
75+ , (.||)
76+ , Condition
77+ , caseWhenThenElse
78+ , ifThenElse
79+ , (.==)
80+ , (./=)
81+ , (.>=)
82+ , (.<)
83+ , (.<=)
84+ , (.>)
85+ , between
86+ , notBetween
87+ , betweenSymmetric
88+ , notBetweenSymmetric
89+ , isDistinctFrom
90+ , isNotDistinctFrom
91+ , isTrue
92+ , isNotTrue
93+ , isFalse
94+ , isNotFalse
95+ , isUnknown
96+ , isNotUnknown
97+ -- ** Time
98+ , currentDate
99+ , currentTime
100+ , currentTimestamp
101+ , localTime
102+ , localTimestamp
103+ , TimeOp (..)
104+ , makeDate
105+ , makeTime
106+ , makeTimestamp
107+ , makeTimestamptz
108+ -- ** Text
109+ , lower
110+ , upper
111+ , charLength
112+ , like
113+ , ilike
114+ -- ** Json
115+ -- *** Json and Jsonb operators
116+ , (.->)
117+ , (.->>)
118+ , (.#>)
119+ , (.#>>)
120+ -- *** Jsonb operators
121+ , (.@>)
122+ , (.<@)
123+ , (.?)
124+ , (.?|)
125+ , (.?&)
126+ , (.-.)
127+ , (#-.)
128+ -- *** Functions
129+ , jsonLit
130+ , jsonbLit
131+ , toJson
132+ , toJsonb
133+ , arrayToJson
134+ , rowToJson
135+ , jsonBuildArray
136+ , jsonbBuildArray
137+ , jsonBuildObject
138+ , jsonbBuildObject
139+ , jsonObject
140+ , jsonbObject
141+ , jsonZipObject
142+ , jsonbZipObject
143+ , jsonArrayLength
144+ , jsonbArrayLength
145+ , jsonExtractPath
146+ , jsonbExtractPath
147+ , jsonExtractPathAsText
148+ , jsonbExtractPathAsText
149+ , jsonTypeof
150+ , jsonbTypeof
151+ , jsonStripNulls
152+ , jsonbStripNulls
153+ , jsonbSet
154+ , jsonbInsert
155+ , jsonbPretty
156+ -- ** Text Search
157+ , (@@)
158+ , (.&)
159+ , (.|)
160+ , (.!)
161+ , (<->)
162+ -- ** Aggregation
163+ , Aggregate (..)
164+ , Distinction (..)
165+ , PGAvg
166+ -- * Window Functions
167+ , WindowDefinition (..)
168+ , partitionBy
169+ , WindowFunction (..)
170+ , rank
171+ , rowNumber
172+ , denseRank
173+ , percentRank
174+ , cumeDist
175+ , ntile
176+ , lag
177+ , lead
178+ , firstValue
179+ , lastValue
180+ , nthValue
181+ -- * Sorting
182+ , SortExpression (..)
183+ , OrderBy (..)
184+ -- * Types
185+ , TypeExpression (..)
186+ , PGTyped (..)
187+ , typedef
188+ , typetable
189+ , typeview
190+ , bool
191+ , int2
192+ , smallint
193+ , int4
194+ , int
195+ , integer
196+ , int8
197+ , bigint
198+ , numeric
199+ , float4
200+ , real
201+ , float8
202+ , doublePrecision
203+ , money
204+ , text
205+ , char
206+ , character
207+ , varchar
208+ , characterVarying
209+ , bytea
210+ , timestamp
211+ , timestampWithTimeZone
212+ , date
213+ , time
214+ , timeWithTimeZone
215+ , interval
216+ , uuid
217+ , inet
218+ , json
219+ , jsonb
220+ , vararray
221+ , fixarray
222+ , tsvector
223+ , tsquery
224+ , arrayToTSvector
225+ , tsvectorLength
226+ , numnode
227+ , plainToTSquery
228+ , phraseToTSquery
229+ , websearchToTSquery
230+ , queryTree
231+ , toTSquery
232+ , toTSvector
57233 -- * Re-export
58234 , (&)
235+ , NP (..)
236+ , (:*:) (..)
59237 , K (..)
60− , unK
61238 ) where
62239
63240import Control.Category
64241import Control.DeepSeq
65242import Data.ByteString (ByteString)
243+import Data.ByteString.Lazy (toStrict)
66244import Data.Function ((&))
67245import Data.Semigroup hiding (All)
246+import qualified Data.Aeson as JSON
68247import Data.String
248+import Data.Word
69249import Generics.SOP hiding (All, from)
250+import GHC.Generics ((:*:) (..))
70251import GHC.OverloadedLabels
71252import GHC.TypeLits
72253import Numeric
73254import Prelude hiding (id, (.))
74255
256+import qualified Data.ByteString as ByteString
75257import qualified GHC.Generics as GHC
258+import qualified Generics.SOP as SOP
76259
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79260import Squeal.PostgreSQL.Render
80261import Squeal.PostgreSQL.Schema
81262
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85263{-----------------------------------------
86264column expressions
87265-----------------------------------------}
88266
89267{- | `Expression`s are used in a variety of contexts,
90−such as in the target `Squeal.PostgreSQL.Query.List` of the
91−`Squeal.PostgreSQL.Query.select` command,
268+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92269as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93270`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
271+or in search `Condition`s in a number of commands.
95272
96273The expression syntax allows the calculation of
97274values from primitive expression using arithmetic, logical,
98275and other operations.
99−
100−The type parameters of `Expression` are
101−
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`.
113276-}
114277newtype Expression
115278 (outer :: FromType)
116− (commons :: FromType)
117279 (grp :: Grouping)
280+ (commons :: FromType)
118281 (schemas :: SchemasType)
119282 (params :: [NullityType])
120283 (from :: FromType)
121284 (ty :: NullityType)
122285 = UnsafeExpression { renderExpression :: ByteString }
123286 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
287+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125288 renderSQL = renderExpression
126289
127−-- | An `Expr` is a closed `Expression`.
128−-- It is a F@RankNType@ but don't be scared.
129−-- Think of it as an expression which sees no
130−-- namespaces, so you can't use parameters
131−-- or alias references. It can be used as
132−-- a simple piece of more complex `Expression`s.
133−type Expr x
134− = forall outer commons grp schemas params from
135− . Expression outer commons grp schemas params from x
136− -- ^ cannot reference aliases
137−
138−-- | A @RankNType@ for binary operators.
139290type Operator x1 x2 y
140− = forall outer commons grp schemas params from
141− . Expression outer commons grp schemas params from x1
142− -- ^ left input
143− -> Expression outer commons grp schemas params from x2
144− -- ^ right input
145− -> Expression outer commons grp schemas params from y
146− -- ^ output
147−
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
150− . Expression outer commons grp schemas params from x1
151− -- ^ left input
152− -> Expression outer commons grp schemas params from x2
153− -- ^ right input
154− -> Expression outer commons grp schemas params from y
155− -- ^ output
156−
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`.
162−type (-->) x y
163− = forall outer commons grp schemas params from
164− . Expression outer commons grp schemas params from x
165− -- ^ input
166− -> Expression outer commons grp schemas params from y
167− -- ^ output
168−
169−type FunctionDB schemas x y
170− = forall outer commons grp params from
171− . Expression outer commons grp schemas params from x
172− -- ^ input
173− -> Expression outer commons grp schemas params from y
174− -- ^ output
175−
176−{- | A @RankNType@ for functions with a fixed-length list of heterogeneous arguments.
177−Use the `*:` operator to end your argument lists, like so.
178−
179−>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
180−fun(TRUE, FALSE, LOCALTIME, TRUE)
181−-}
182−type (--->) xs y
183− = forall outer commons grp schemas params from
184− . NP (Expression outer commons grp schemas params from) xs
185− -- ^ inputs
186− -> Expression outer commons grp schemas params from y
187− -- ^ output
188−
189−type FunctionNDB schemas xs y
190− = forall outer commons grp params from
191− . NP (Expression outer commons grp schemas params from) xs
192− -- ^ inputs
193− -> Expression outer commons grp schemas params from y
194− -- ^ output
195−
196−{- | A @RankNType@ for functions with a variable-length list of
197−homogeneous arguments and at least 1 more argument.
198−-}
199−type FunctionVar x0 x1 y
200− = forall outer commons grp schemas params from
201− . [Expression outer commons grp schemas params from x0]
202− -- ^ inputs
203− -> Expression outer commons grp schemas params from x1
204− -- ^ must have at least 1 input
205− -> Expression outer commons grp schemas params from y
206− -- ^ output
207−
208−{- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)
209−greatest(TRUE, NULL, FALSE)
210−-}
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
213− (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
291+ = forall outer grp commons schemas params from
292+ . Expression outer grp commons schemas params from x1
293+ -> Expression outer grp commons schemas params from x2
294+ -> Expression outer grp commons schemas params from y
295+
296+type (:-->) x y
297+ = forall outer grp commons schemas params from
298+ . Expression outer grp commons schemas params from x
299+ -> Expression outer grp commons schemas params from y
300+
301+type FunctionHet xs y
302+ = forall outer grp commons schemas params from
303+ . NP (Expression outer grp commons schemas params from) xs
304+ -> Expression outer grp commons schemas params from y
305+
306+{- | A `HasParameter` constraint is used to indicate a value that is
307+supplied externally to a SQL statement.
308+`Squeal.PostgreSQL.PQ.manipulateParams`,
309+`Squeal.PostgreSQL.PQ.queryParams` and
310+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
311+separately from the SQL command string, in which case `param`s are used to
312+refer to the out-of-line data values.
313+-}
314+class KnownNat n => HasParameter
315+ (n :: Nat)
316+ (params :: [NullityType])
317+ (ty :: NullityType)
318+ | n params -> ty where
319+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
320+ --
321+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
322+ -- >>> printSQL expr
323+ -- ($1 :: int4)
324+ parameter
325+ :: TypeExpression schemas ty
326+ -> Expression outer grp commons schemas params from ty
327+ parameter ty = UnsafeExpression $ parenthesized $
328+ "$" <> renderNat @n <+> "::"
329+ <+> renderSQL ty
330+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
331+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
332+ => HasParameter n (ty' : params) ty
333+
334+-- | `param` takes a `Nat` using type application and for basic types,
335+-- infers a `TypeExpression`.
336+--
337+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
338+-- >>> printSQL expr
339+-- ($1 :: int4)
340+param
341+ :: forall n outer commons schemas params from grp ty
342+ . (PGTyped schemas ty, HasParameter n params ty)
343+ => Expression outer grp commons schemas params from ty -- ^ param
344+param = parameter @n (pgtype @schemas)
214345
215346instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
347+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217348 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218349instance (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
350+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220351 fromLabel = fromLabel @col :* Nil
221352instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222353 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
354+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224355 fromLabel = fromLabel @col `As` Alias
225356instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226357 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
358+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228359 fromLabel = fromLabel @col :* Nil
229360
230361instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
362+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232363 tab ! col = UnsafeExpression $
233364 renderSQL tab <> "." <> renderSQL col
234365instance (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
366+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236367 tab ! col = tab ! col :* Nil
237368instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238369 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
370+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240371 tab ! col = tab ! col `As` col
241372instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242373 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
374+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244375 tab ! col = tab ! col :* Nil
245376
246377instance
@@ -248,7 +379,7 @@ instance
248379 , Has col row ty
249380 , GroupedBy tab col bys
250381 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
382+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252383 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253384instance
254385 ( HasUnique tab (Join outer from) row
@@ -256,7 +387,7 @@ instance
256387 , GroupedBy tab col bys
257388 , tys ~ '[ty]
258389 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
390+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260391 fromLabel = fromLabel @col :* Nil
261392instance
262393 ( HasUnique tab (Join outer from) row
@@ -264,7 +395,7 @@ instance
264395 , GroupedBy tab col bys
265396 , column ~ (col ::: ty)
266397 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
398+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268399 fromLabel = fromLabel @col `As` Alias
269400instance
270401 ( HasUnique tab (Join outer from) row
@@ -272,7 +403,7 @@ instance
272403 , GroupedBy tab col bys
273404 , columns ~ '[col ::: ty]
274405 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
406+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276407 fromLabel = fromLabel @col :* Nil
277408
278409instance
@@ -280,7 +411,7 @@ instance
280411 , Has col row ty
281412 , GroupedBy tab col bys
282413 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
414+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284415 tab ! col = UnsafeExpression $
285416 renderSQL tab <> "." <> renderSQL col
286417instance
@@ -289,7 +420,7 @@ instance
289420 , GroupedBy tab col bys
290421 , tys ~ '[ty]
291422 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
423+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293424 tab ! col = tab ! col :* Nil
294425instance
295426 ( Has tab (Join outer from) row
@@ -297,7 +428,7 @@ instance
297428 , GroupedBy tab col bys
298429 , column ~ (col ::: ty)
299430 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
431+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301432 tab ! col = tab ! col `As` col
302433instance
303434 ( Has tab (Join outer from) row
@@ -305,78 +436,239 @@ instance
305436 , GroupedBy tab col bys
306437 , columns ~ '[col ::: ty]
307438 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
439+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309440 tab ! col = tab ! col :* Nil
310441
442+-- | analagous to `Nothing`
443+--
444+-- >>> printSQL null_
445+-- NULL
446+null_ :: Expression outer grp commons schemas params from ('Null ty)
447+null_ = UnsafeExpression "NULL"
448+
449+-- | analagous to `Just`
450+--
451+-- >>> printSQL $ notNull true
452+-- TRUE
453+notNull
454+ :: Expression outer grp commons schemas params from ('NotNull ty)
455+ -> Expression outer grp commons schemas params from ('Null ty)
456+notNull = UnsafeExpression . renderSQL
457+
458+-- | return the leftmost value which is not NULL
459+--
460+-- >>> printSQL $ coalesce [null_, true] false
461+-- COALESCE(NULL, TRUE, FALSE)
462+coalesce
463+ :: [Expression outer grp commons schemas params from ('Null ty)]
464+ -- ^ @NULL@s may be present
465+ -> Expression outer grp commons schemas params from ('NotNull ty)
466+ -- ^ @NULL@ is absent
467+ -> Expression outer grp commons schemas params from ('NotNull ty)
468+coalesce nullxs notNullx = UnsafeExpression $
469+ "COALESCE" <> parenthesized (commaSeparated
470+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
471+
472+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
473+--
474+-- >>> printSQL $ fromNull true null_
475+-- COALESCE(NULL, TRUE)
476+fromNull
477+ :: Expression outer grp commons schemas params from ('NotNull ty)
478+ -- ^ what to convert @NULL@ to
479+ -> Expression outer grp commons schemas params from ('Null ty)
480+ -> Expression outer grp commons schemas params from ('NotNull ty)
481+fromNull notNullx nullx = coalesce [nullx] notNullx
482+
483+-- | >>> printSQL $ null_ & isNull
484+-- NULL IS NULL
485+isNull
486+ :: Expression outer grp commons schemas params from ('Null ty)
487+ -- ^ possibly @NULL@
488+ -> Condition outer grp commons schemas params from
489+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
490+
491+-- | >>> printSQL $ null_ & isNotNull
492+-- NULL IS NOT NULL
493+isNotNull
494+ :: Expression outer grp commons schemas params from ('Null ty)
495+ -- ^ possibly @NULL@
496+ -> Condition outer grp commons schemas params from
497+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
498+
499+-- | analagous to `maybe` using @IS NULL@
500+--
501+-- >>> printSQL $ matchNull true not_ null_
502+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
503+matchNull
504+ :: Expression outer grp commons schemas params from (nullty)
505+ -- ^ what to convert @NULL@ to
506+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
507+ -> Expression outer grp commons schemas params from (nullty) )
508+ -- ^ function to perform when @NULL@ is absent
509+ -> Expression outer grp commons schemas params from ('Null ty)
510+ -> Expression outer grp commons schemas params from (nullty)
511+matchNull y f x = ifThenElse (isNull x) y
512+ (f (UnsafeExpression (renderSQL x)))
513+
514+{-| right inverse to `fromNull`, if its arguments are equal then
515+`nullIf` gives @NULL@.
516+
517+>>> :set -XTypeApplications -XDataKinds
518+>>> let expr = nullIf false (param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
519+>>> printSQL expr
520+NULL IF (FALSE, ($1 :: bool))
521+-}
522+nullIf
523+ :: Expression outer grp commons schemas params from ('NotNull ty)
524+ -- ^ @NULL@ is absent
525+ -> Expression outer grp commons schemas params from ('NotNull ty)
526+ -- ^ @NULL@ is absent
527+ -> Expression outer grp commons schemas params from ('Null ty)
528+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
529+ (renderSQL x <> ", " <> renderSQL y)
530+
531+-- | >>> printSQL $ array [null_, false, true]
532+-- ARRAY[NULL, FALSE, TRUE]
533+array
534+ :: [Expression outer grp commons schemas params from ty]
535+ -- ^ array elements
536+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ty))
537+array xs = UnsafeExpression $
538+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
539+
540+-- | >>> printSQL $ cardinality (array [null_, false, true])
541+-- cardinality(ARRAY[NULL, FALSE, TRUE])
542+cardinality :: nullity ('PGvararray ty) :--> nullity 'PGint8
543+cardinality = unsafeFunction "cardinality"
544+
545+-- | >>> printSQL $ array [null_, false, true] & index 2
546+-- (ARRAY[NULL, FALSE, TRUE])[2]
547+index
548+ :: Word64 -- ^ index
549+ -> nullity ('PGvararray ty) -- ^ array
550+ :--> NullifyType ty
551+index n expr = UnsafeExpression $
552+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
553+
311554instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
555+ (Expression outer grp commons schemas params from (nullity ('PGenum labels))) where
313556 label = UnsafeExpression $ renderSQL (PGlabel @label)
314557
558+-- | A row constructor is an expression that builds a row value
559+-- (also called a composite value) using values for its member fields.
560+--
561+-- >>> :{
562+-- type Complex = 'PGcomposite
563+-- '[ "real" ::: 'NotNull 'PGfloat8
564+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
565+-- :}
566+--
567+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
568+-- >>> printSQL i
569+-- ROW(0, 1)
570+row
571+ :: SListI row
572+ => NP (Aliased (Expression outer grp commons schemas params from)) row
573+ -- ^ zero or more expressions for the row field values
574+ -> Expression outer grp commons schemas params from (nullity ('PGcomposite row))
575+row exprs = UnsafeExpression $ "ROW" <> parenthesized
576+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
577+
578+-- | >>> :{
579+-- type Complex = 'PGcomposite
580+-- '[ "real" ::: 'NotNull 'PGfloat8
581+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
582+-- type Schema = '["complex" ::: 'Typedef Complex]
583+-- :}
584+--
585+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
586+-- >>> printSQL $ i & field #complex #imaginary
587+-- (ROW(0, 1)::"complex")."imaginary"
588+field
589+ :: ( Has sch schemas schema
590+ , Has tydef schema ('Typedef ('PGcomposite row))
591+ , Has field row ty)
592+ => QualifiedAlias sch tydef -- ^ row type
593+ -> Alias field -- ^ field name
594+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
595+ -> Expression outer grp commons schemas params from ty
596+field td fld expr = UnsafeExpression $
597+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
598+ <> "." <> renderSQL fld
599+
600+instance Semigroup
601+ (Expression outer grp commons schemas params from (nullity ('PGvararray ty))) where
602+ (<>) = unsafeBinaryOp "||"
603+
604+instance Monoid
605+ (Expression outer grp commons schemas params from (nullity ('PGvararray ty))) where
606+ mempty = array []
607+ mappend = (<>)
608+
609+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
610+-- >>> printSQL expr
611+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
612+greatest
613+ :: Expression outer grp commons schemas params from (nullty)
614+ -- ^ needs at least 1 argument
615+ -> [Expression outer grp commons schemas params from (nullty)]
616+ -- ^ or more
617+ -> Expression outer grp commons schemas params from (nullty)
618+greatest x xs = UnsafeExpression $ "GREATEST("
619+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
620+
621+-- | >>> printSQL $ least currentTimestamp [null_]
622+-- LEAST(CURRENT_TIMESTAMP, NULL)
623+least
624+ :: Expression outer grp commons schemas params from (nullty)
625+ -- ^ needs at least 1 argument
626+ -> [Expression outer grp commons schemas params from (nullty)]
627+ -- ^ or more
628+ -> Expression outer grp commons schemas params from (nullty)
629+least x xs = UnsafeExpression $ "LEAST("
630+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
631+
315632-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316633-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
634+unsafeBinaryOp
635+ :: ByteString
636+ -- ^ operator
637+ -> Operator ty0 ty1 ty2
318638unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319639 renderSQL x <+> op <+> renderSQL y
320640
321−binaryOp
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
327−
328−-- | >>> printSQL $ unsafeLeftOp "NOT" true
641+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329642-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
332−
333−leftOp
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
339−
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
344−
345−rightOp
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
643+unsafeUnaryOp :: ByteString {- ^ operator -} -> x :--> y
644+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
645+ op <+> renderSQL x
351646
352647-- | >>> printSQL $ unsafeFunction "f" true
353648-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
649+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355650unsafeFunction fun x = UnsafeExpression $
356651 fun <> parenthesized (renderSQL x)
357652
358−function
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
363−
364−-- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a')
365−-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
366−unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
367−unsafeFunctionN fun xs = UnsafeExpression $
653+unsafeFunctionHet
654+ :: SListI xs
655+ => ByteString {- ^ function -}
656+ -> FunctionHet xs y
657+unsafeFunctionHet fun xs = UnsafeExpression $
368658 fun <> parenthesized (renderCommaSeparated renderSQL xs)
369659
370−functionN
371− :: ( Has sch schemas schema
372− , Has fun schema ('Function (xs :=> 'Returns y))
373− , SListI xs )
374− => QualifiedAlias sch fun
375− -> FunctionNDB schemas xs y
376−functionN = unsafeFunctionN . renderSQL
660+-- | Helper for defining variadic functions.
661+unsafeVariadicFunction
662+ :: SListI elems
663+ => ByteString
664+ -- ^ function
665+ -> NP (Expression outer grp commons schemas params from) elems
666+ -> Expression outer grp commons schemas params from ret
667+unsafeVariadicFunction fun x = UnsafeExpression $
668+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
377669
378670instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
671+ => Num (Expression outer grp commons schemas params from (nullity ty)) where
380672 (+) = unsafeBinaryOp "+"
381673 (-) = unsafeBinaryOp "-"
382674 (*) = unsafeBinaryOp "*"
@@ -388,7 +680,7 @@ instance ty `In` PGNum
388680 . show
389681
390682instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
683+ (Expression outer grp commons schemas params from (nullity ty)) where
392684 (/) = unsafeBinaryOp "/"
393685 fromRational
394686 = UnsafeExpression
@@ -398,7 +690,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398690 . fromRat @Double
399691
400692instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
693+ (Expression outer grp commons schemas params from (nullity ty)) where
402694 pi = UnsafeExpression "pi()"
403695 exp = unsafeFunction "exp"
404696 log = unsafeFunction "ln"
@@ -419,54 +711,1839 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419711 acosh x = log (x + sqrt (x*x - 1))
420712 atanh x = log ((1 + x) / (1 - x)) / 2
421713
422−-- | Contained by operators
423−class PGSubset ty where
424− (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
425− (@>) = unsafeBinaryOp "@>"
426− (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
427− (<@) = unsafeBinaryOp "<@"
428−instance PGSubset 'PGjsonb
429−instance PGSubset 'PGtsquery
430−instance PGSubset ('PGvararray ty)
431−instance PGSubset ('PGrange ty)
432−
433−class PGIntersect ty where
434− (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
435− (@&&) = unsafeBinaryOp "&&"
436−instance PGIntersect ('PGvararray ty)
437−instance PGIntersect ('PGrange ty)
714+-- | >>> :{
715+-- let
716+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
717+-- expression = atan2_ pi 2
718+-- in printSQL expression
719+-- :}
720+-- atan2(pi(), 2)
721+atan2_
722+ :: float `In` PGFloating
723+ => Expression outer grp commons schemas params from (nullity float)
724+ -- ^ numerator
725+ -> Expression outer grp commons schemas params from (nullity float)
726+ -- ^ denominator
727+ -> Expression outer grp commons schemas params from (nullity float)
728+atan2_ y x = UnsafeExpression $
729+ "atan2(" <> renderSQL y <> ", " <> renderSQL x <> ")"
730+
731+-- When a `cast` is applied to an `Expression` of a known type, it
732+-- represents a run-time type conversion. The cast will succeed only if a
733+-- suitable type conversion operation has been defined.
734+--
735+-- | >>> printSQL $ true & cast int4
736+-- (TRUE :: int4)
737+cast
738+ :: TypeExpression schemas ty1
739+ -- ^ type to cast as
740+ -> Expression outer grp commons schemas params from ty0
741+ -- ^ value to convert
742+ -> Expression outer grp commons schemas params from ty1
743+cast ty x = UnsafeExpression $ parenthesized $
744+ renderSQL x <+> "::" <+> renderSQL ty
745+
746+-- | integer division, truncates the result
747+--
748+-- >>> :{
749+-- let
750+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
751+-- expression = 5 `quot_` 2
752+-- in printSQL expression
753+-- :}
754+-- (5 / 2)
755+quot_
756+ :: int `In` PGIntegral
757+ => Operator (nullity int) (nullity int) (nullity int)
758+quot_ = unsafeBinaryOp "/"
759+
760+-- | remainder upon integer division
761+--
762+-- >>> :{
763+-- let
764+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
765+-- expression = 5 `rem_` 2
766+-- in printSQL expression
767+-- :}
768+-- (5 % 2)
769+rem_
770+ :: int `In` PGIntegral
771+ => Operator (nullity int) (nullity int) (nullity int)
772+rem_ = unsafeBinaryOp "%"
773+
774+-- | >>> :{
775+-- let
776+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
777+-- expression = trunc pi
778+-- in printSQL expression
779+-- :}
780+-- trunc(pi())
781+trunc :: frac `In` PGFloating => nullity frac :--> nullity frac
782+trunc = unsafeFunction "trunc"
783+
784+-- | >>> :{
785+-- let
786+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
787+-- expression = round_ pi
788+-- in printSQL expression
789+-- :}
790+-- round(pi())
791+round_ :: frac `In` PGFloating => nullity frac :--> nullity frac
792+round_ = unsafeFunction "round"
793+
794+-- | >>> :{
795+-- let
796+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
797+-- expression = ceiling_ pi
798+-- in printSQL expression
799+-- :}
800+-- ceiling(pi())
801+ceiling_ :: frac `In` PGFloating => nullity frac :--> nullity frac
802+ceiling_ = unsafeFunction "ceiling"
803+
804+-- | A `Condition` is an `Expression`, which can evaluate
805+-- to `true`, `false` or `null_`. This is because SQL uses
806+-- a three valued logic.
807+type Condition outer grp commons schemas params from =
808+ Expression outer grp commons schemas params from ('Null 'PGbool)
809+
810+-- | >>> printSQL true
811+-- TRUE
812+true :: Expression outer grp commons schemas params from (nullity 'PGbool)
813+true = UnsafeExpression "TRUE"
814+
815+-- | >>> printSQL false
816+-- FALSE
817+false :: Expression outer grp commons schemas params from (nullity 'PGbool)
818+false = UnsafeExpression "FALSE"
819+
820+-- | >>> printSQL $ not_ true
821+-- (NOT TRUE)
822+not_ :: nullity 'PGbool :--> nullity 'PGbool
823+not_ = unsafeUnaryOp "NOT"
824+
825+-- | >>> printSQL $ true .&& false
826+-- (TRUE AND FALSE)
827+(.&&) :: Operator (nullity 'PGbool) (nullity 'PGbool) (nullity 'PGbool)
828+infixr 3 .&&
829+(.&&) = unsafeBinaryOp "AND"
830+
831+-- | >>> printSQL $ true .|| false
832+-- (TRUE OR FALSE)
833+(.||) :: Operator (nullity 'PGbool) (nullity 'PGbool) (nullity 'PGbool)
834+infixr 2 .||
835+(.||) = unsafeBinaryOp "OR"
836+
837+-- | >>> :{
838+-- let
839+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
840+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
841+-- in printSQL expression
842+-- :}
843+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
844+caseWhenThenElse
845+ :: [ ( Condition outer grp commons schemas params from
846+ , Expression outer grp commons schemas params from ty
847+ ) ]
848+ -- ^ whens and thens
849+ -> Expression outer grp commons schemas params from ty
850+ -- ^ else
851+ -> Expression outer grp commons schemas params from ty
852+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
853+ [ "CASE"
854+ , mconcat
855+ [ mconcat
856+ [ " WHEN ", renderSQL when_
857+ , " THEN ", renderSQL then_
858+ ]
859+ | (when_,then_) <- whenThens
860+ ]
861+ , " ELSE ", renderSQL else_
862+ , " END"
863+ ]
864+
865+-- | >>> :{
866+-- let
867+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
868+-- expression = ifThenElse true 1 0
869+-- in printSQL expression
870+-- :}
871+-- CASE WHEN TRUE THEN 1 ELSE 0 END
872+ifThenElse
873+ :: Condition outer grp commons schemas params from
874+ -> Expression outer grp commons schemas params from ty -- ^ then
875+ -> Expression outer grp commons schemas params from ty -- ^ else
876+ -> Expression outer grp commons schemas params from ty
877+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
878+
879+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
880+-- will produce @NULL@s if one of their arguments is @NULL@.
881+--
882+-- >>> printSQL $ true .== null_
883+-- (TRUE = NULL)
884+(.==) :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
885+(.==) = unsafeBinaryOp "="
886+infix 4 .==
887+
888+-- | >>> printSQL $ true ./= null_
889+-- (TRUE <> NULL)
890+(./=) :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
891+(./=) = unsafeBinaryOp "<>"
892+infix 4 ./=
893+
894+-- | >>> printSQL $ true .>= null_
895+-- (TRUE >= NULL)
896+(.>=) :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
897+(.>=) = unsafeBinaryOp ">="
898+infix 4 .>=
899+
900+-- | >>> printSQL $ true .< null_
901+-- (TRUE < NULL)
902+(.<) :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
903+(.<) = unsafeBinaryOp "<"
904+infix 4 .<
905+
906+-- | >>> printSQL $ true .<= null_
907+-- (TRUE <= NULL)
908+(.<=) :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
909+(.<=) = unsafeBinaryOp "<="
910+infix 4 .<=
911+
912+-- | >>> printSQL $ true .> null_
913+-- (TRUE > NULL)
914+(.>) :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
915+(.>) = unsafeBinaryOp ">"
916+infix 4 .>
917+
918+{- | between
919+>>> printSQL $ true `between` (null_, false)
920+TRUE BETWEEN NULL AND FALSE
921+-}
922+between
923+ :: Expression outer grp commons schemas params from (nullity ty)
924+ -> ( Expression outer grp commons schemas params from (nullity ty)
925+ , Expression outer grp commons schemas params from (nullity ty) ) -- ^ bounds
926+ -> Condition outer grp commons schemas params from
927+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
928+ <+> renderSQL x <+> "AND" <+> renderSQL y
929+
930+{- | not between
931+>>> printSQL $ true `notBetween` (null_, false)
932+TRUE NOT BETWEEN NULL AND FALSE
933+-}
934+notBetween
935+ :: Expression outer grp commons schemas params from (nullity ty)
936+ -> ( Expression outer grp commons schemas params from (nullity ty)
937+ , Expression outer grp commons schemas params from (nullity ty) ) -- ^ bounds
938+ -> Condition outer grp commons schemas params from
939+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
940+ <+> renderSQL x <+> "AND" <+> renderSQL y
941+
942+{- | between, after sorting the comparison values
943+>>> printSQL $ true `betweenSymmetric` (null_, false)
944+TRUE BETWEEN SYMMETRIC NULL AND FALSE
945+-}
946+betweenSymmetric
947+ :: Expression outer grp commons schemas params from (nullity ty)
948+ -> ( Expression outer grp commons schemas params from (nullity ty)
949+ , Expression outer grp commons schemas params from (nullity ty) ) -- ^ bounds
950+ -> Condition outer grp commons schemas params from
951+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
952+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
953+
954+{- | not between, after sorting the comparison values
955+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
956+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
957+-}
958+notBetweenSymmetric
959+ :: Expression outer grp commons schemas params from (nullity ty)
960+ -> ( Expression outer grp commons schemas params from (nullity ty)
961+ , Expression outer grp commons schemas params from (nullity ty) ) -- ^ bounds
962+ -> Condition outer grp commons schemas params from
963+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
964+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
965+
966+{- | not equal, treating null like an ordinary value
967+>>> printSQL $ true `isDistinctFrom` null_
968+(TRUE IS DISTINCT FROM NULL)
969+-}
970+isDistinctFrom :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
971+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
972+
973+{- | equal, treating null like an ordinary value
974+>>> printSQL $ true `isNotDistinctFrom` null_
975+(TRUE IS NOT DISTINCT FROM NULL)
976+-}
977+isNotDistinctFrom :: Operator (nullity0 ty) (nullity1 ty) ('Null 'PGbool)
978+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
979+
980+{- | is true
981+>>> printSQL $ true & isTrue
982+TRUE IS TRUE
983+-}
984+isTrue
985+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
986+ -> Condition outer grp commons schemas params from
987+isTrue b = UnsafeExpression $ renderSQL b <+> "IS TRUE"
988+
989+{- | is false or unknown
990+>>> printSQL $ true & isNotTrue
991+TRUE IS NOT TRUE
992+-}
993+isNotTrue
994+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
995+ -> Condition outer grp commons schemas params from
996+isNotTrue b = UnsafeExpression $ renderSQL b <+> "IS NOT TRUE"
997+
998+{- | is false
999+>>> printSQL $ true & isFalse
1000+TRUE IS FALSE
1001+-}
1002+isFalse
1003+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
1004+ -> Condition outer grp commons schemas params from
1005+isFalse b = UnsafeExpression $ renderSQL b <+> "IS FALSE"
1006+
1007+{- | is true or unknown
1008+>>> printSQL $ true & isNotFalse
1009+TRUE IS NOT FALSE
1010+-}
1011+isNotFalse
1012+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
1013+ -> Condition outer grp commons schemas params from
1014+isNotFalse b = UnsafeExpression $ renderSQL b <+> "IS NOT FALSE"
1015+
1016+{- | is unknown
1017+>>> printSQL $ true & isUnknown
1018+TRUE IS UNKNOWN
1019+-}
1020+isUnknown
1021+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
1022+ -> Condition outer grp commons schemas params from
1023+isUnknown b = UnsafeExpression $ renderSQL b <+> "IS UNKNOWN"
1024+
1025+{- | is true or false
1026+>>> printSQL $ true & isNotUnknown
1027+TRUE IS NOT UNKNOWN
1028+-}
1029+isNotUnknown
1030+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
1031+ -> Condition outer grp commons schemas params from
1032+isNotUnknown b = UnsafeExpression $ renderSQL b <+> "IS NOT UNKNOWN"
1033+
1034+-- | >>> printSQL currentDate
1035+-- CURRENT_DATE
1036+currentDate
1037+ :: Expression outer grp commons schemas params from (nullity 'PGdate)
1038+currentDate = UnsafeExpression "CURRENT_DATE"
1039+
1040+-- | >>> printSQL currentTime
1041+-- CURRENT_TIME
1042+currentTime
1043+ :: Expression outer grp commons schemas params from (nullity 'PGtimetz)
1044+currentTime = UnsafeExpression "CURRENT_TIME"
1045+
1046+-- | >>> printSQL currentTimestamp
1047+-- CURRENT_TIMESTAMP
1048+currentTimestamp
1049+ :: Expression outer grp commons schemas params from (nullity 'PGtimestamptz)
1050+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1051+
1052+-- | >>> printSQL localTime
1053+-- LOCALTIME
1054+localTime
1055+ :: Expression outer grp commons schemas params from (nullity 'PGtime)
1056+localTime = UnsafeExpression "LOCALTIME"
1057+
1058+-- | >>> printSQL localTimestamp
1059+-- LOCALTIMESTAMP
1060+localTimestamp
1061+ :: Expression outer grp commons schemas params from (nullity 'PGtimestamp)
1062+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1063+
1064+{-----------------------------------------
1065+text
1066+-----------------------------------------}
1067+
1068+escape :: Char -> String
1069+escape = \case
1070+ '\NUL' -> "\\0"
1071+ '\'' -> "''"
1072+ '"' -> "\\\""
1073+ '\b' -> "\\b"
1074+ '\n' -> "\\n"
1075+ '\r' -> "\\r"
1076+ '\t' -> "\\t"
1077+ '\\' -> "\\\\"
1078+ c -> [c]
4381079
4391080instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
1081+ (Expression outer grp commons schemas params from (nullity 'PGtext)) where
4411082 fromString str = UnsafeExpression $
4421083 "E\'" <> fromString (escape =<< str) <> "\'"
4431084instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1085+ (Expression outer grp commons schemas params from (nullity 'PGtsvector)) where
1086+ fromString str = cast tsvector . UnsafeExpression $
4461087 "E\'" <> fromString (escape =<< str) <> "\'"
4471088instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1089+ (Expression outer grp commons schemas params from (nullity 'PGtsquery)) where
1090+ fromString str = cast tsquery . UnsafeExpression $
4501091 "E\'" <> fromString (escape =<< str) <> "\'"
4511092
4521093instance Semigroup
453− (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
454− (<>) = unsafeBinaryOp "||"
455−instance Semigroup
456− (Expression outer commons grp schemas params from (null 'PGjsonb)) where
1094+ (Expression outer grp commons schemas params from (nullity 'PGtext)) where
4571095 (<>) = unsafeBinaryOp "||"
4581096instance Semigroup
459− (Expression outer commons grp schemas params from (null 'PGtext)) where
460− (<>) = unsafeBinaryOp "||"
461−instance Semigroup
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1097+ (Expression outer grp commons schemas params from (nullity 'PGtsvector)) where
4631098 (<>) = unsafeBinaryOp "||"
4641099
4651100instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
1101+ (Expression outer grp commons schemas params from (nullity 'PGtext)) where
4671102 mempty = fromString ""
4681103 mappend = (<>)
4691104instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1105+ (Expression outer grp commons schemas params from (nullity 'PGtsvector)) where
4711106 mempty = fromString ""
4721107 mappend = (<>)
1108+
1109+-- | >>> printSQL $ lower "ARRRGGG"
1110+-- lower(E'ARRRGGG')
1111+lower
1112+ :: nullity 'PGtext
1113+ -- ^ string to lower case
1114+ :--> nullity 'PGtext
1115+lower = unsafeFunction "lower"
1116+
1117+-- | >>> printSQL $ upper "eeee"
1118+-- upper(E'eeee')
1119+upper
1120+ :: nullity 'PGtext
1121+ -- ^ string to upper case
1122+ :--> nullity 'PGtext
1123+upper = unsafeFunction "upper"
1124+
1125+-- | >>> printSQL $ charLength "four"
1126+-- char_length(E'four')
1127+charLength
1128+ :: nullity 'PGtext
1129+ -- ^ string to measure
1130+ :--> nullity 'PGint4
1131+charLength = unsafeFunction "char_length"
1132+
1133+-- | The `like` expression returns true if the @string@ matches
1134+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1135+-- or underscores, then the pattern only represents the string itself;
1136+-- in that case `like` acts like the equals operator. An underscore (_)
1137+-- in pattern stands for (matches) any single character; a percent sign (%)
1138+-- matches any sequence of zero or more characters.
1139+--
1140+-- >>> printSQL $ "abc" `like` "a%"
1141+-- (E'abc' LIKE E'a%')
1142+like :: Operator (nullity 'PGtext) (nullity 'PGtext) ('Null 'PGbool)
1143+like = unsafeBinaryOp "LIKE"
1144+
1145+-- | The key word ILIKE can be used instead of LIKE to make the
1146+-- match case-insensitive according to the active locale.
1147+--
1148+-- >>> printSQL $ "abc" `ilike` "a%"
1149+-- (E'abc' ILIKE E'a%')
1150+ilike :: Operator (nullity 'PGtext) (nullity 'PGtext) ('Null 'PGbool)
1151+ilike = unsafeBinaryOp "ILIKE"
1152+
1153+{-----------------------------------------
1154+ -- json and jsonb support
1155+
1156+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1157+comments lifted directly from this page.
1158+
1159+Table 9.44: json and jsonb operators
1160+-----------------------------------------}
1161+
1162+-- | Get JSON value (object field or array element) at a key.
1163+(.->)
1164+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1165+ => Operator (nullity json) (nullity key) ('Null json)
1166+infixl 8 .->
1167+(.->) = unsafeBinaryOp "->"
1168+
1169+-- | Get JSON value (object field or array element) at a key, as text.
1170+(.->>)
1171+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1172+ => Operator (nullity json) (nullity key) ('Null 'PGtext)
1173+infixl 8 .->>
1174+(.->>) = unsafeBinaryOp "->>"
1175+
1176+-- | Get JSON value at a specified path.
1177+(.#>)
1178+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1179+ => Operator (nullity json) (nullity path) ('Null json)
1180+infixl 8 .#>
1181+(.#>) = unsafeBinaryOp "#>"
1182+
1183+-- | Get JSON value at a specified path as text.
1184+(.#>>)
1185+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1186+ => Operator (nullity json) (nullity path) ('Null 'PGtext)
1187+infixl 8 .#>>
1188+(.#>>) = unsafeBinaryOp "#>>"
1189+
1190+-- Additional jsonb operators
1191+
1192+-- | Does the left JSON value contain the right JSON path/value entries at the
1193+-- top level?
1194+(.@>)
1195+ :: Operator (nullity 'PGjsonb) (nullity 'PGjsonb) ('Null 'PGbool)
1196+infixl 9 .@>
1197+(.@>) = unsafeBinaryOp "@>"
1198+
1199+-- | Are the left JSON path/value entries contained at the top level within the
1200+-- right JSON value?
1201+(.<@) :: Operator (nullity 'PGjsonb) (nullity 'PGjsonb) ('Null 'PGbool)
1202+infixl 9 .<@
1203+(.<@) = unsafeBinaryOp "<@"
1204+
1205+-- | Does the string exist as a top-level key within the JSON value?
1206+(.?) :: Operator (nullity 'PGjsonb) (nullity 'PGtext) ('Null 'PGbool)
1207+infixl 9 .?
1208+(.?) = unsafeBinaryOp "?"
1209+
1210+-- | Do any of these array strings exist as top-level keys?
1211+(.?|) :: Operator
1212+ (nullity 'PGjsonb)
1213+ (nullity ('PGvararray ('NotNull 'PGtext)))
1214+ ('Null 'PGbool)
1215+infixl 9 .?|
1216+(.?|) = unsafeBinaryOp "?|"
1217+
1218+-- | Do all of these array strings exist as top-level keys?
1219+(.?&) :: Operator
1220+ (nullity 'PGjsonb)
1221+ (nullity ('PGvararray ('NotNull 'PGtext)))
1222+ ('Null 'PGbool)
1223+infixl 9 .?&
1224+(.?&) = unsafeBinaryOp "?&"
1225+
1226+-- | Concatenate two jsonb values into a new jsonb value.
1227+instance Semigroup
1228+ (Expression outer grp commons schemas params from (nullity 'PGjsonb)) where
1229+ (<>) = unsafeBinaryOp "||"
1230+
1231+-- | Delete a key or keys from a JSON object, or remove an array element.
1232+--
1233+-- If the right operand is..
1234+--
1235+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1236+-- are matched based on their key value.
1237+--
1238+-- @ text[] @: Delete multiple key/value pairs or string elements
1239+-- from left operand. Key/value pairs are matched based on their key value.
1240+--
1241+-- @ integer @: Delete the array element with specified index (Negative integers
1242+-- count from the end). Throws an error if top level container is not an array.
1243+(.-.)
1244+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1245+ => Operator (nullity 'PGjsonb) (nullity key) (nullity 'PGjsonb)
1246+infixl 6 .-.
1247+(.-.) = unsafeBinaryOp "-"
1248+
1249+-- | Delete the field or element with specified path (for JSON arrays, negative
1250+-- integers count from the end)
1251+(#-.)
1252+ :: PGTextArray "(#-.)" arrayty
1253+ => Operator (nullity 'PGjsonb) (nullity arrayty)(nullity 'PGjsonb)
1254+infixl 6 #-.
1255+(#-.) = unsafeBinaryOp "#-"
1256+
1257+{-----------------------------------------
1258+Table 9.45: JSON creation functions
1259+-----------------------------------------}
1260+
1261+-- | Literal binary JSON
1262+jsonbLit
1263+ :: JSON.ToJSON x
1264+ => x -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1265+jsonbLit = cast jsonb . UnsafeExpression
1266+ . singleQuotedUtf8 . toStrict . JSON.encode
1267+
1268+-- | Literal JSON
1269+jsonLit
1270+ :: JSON.ToJSON x
1271+ => x -> Expression outer grp commons schemas params from (nullity 'PGjson)
1272+jsonLit = cast json . UnsafeExpression
1273+ . singleQuotedUtf8 . toStrict . JSON.encode
1274+
1275+-- | Returns the value as json. Arrays and composites are converted
1276+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1277+-- type to json, the cast function will be used to perform the conversion;
1278+-- otherwise, a scalar value is produced. For any scalar type other than a
1279+-- number, a Boolean, or a null value, the text representation will be used, in
1280+-- such a fashion that it is a valid json value.
1281+toJson :: nullity ty :--> nullity 'PGjson
1282+toJson = unsafeFunction "to_json"
1283+
1284+-- | Returns the value as jsonb. Arrays and composites are converted
1285+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1286+-- type to json, the cast function will be used to perform the conversion;
1287+-- otherwise, a scalar value is produced. For any scalar type other than a
1288+-- number, a Boolean, or a null value, the text representation will be used, in
1289+-- such a fashion that it is a valid jsonb value.
1290+toJsonb :: nullity ty :--> nullity 'PGjsonb
1291+toJsonb = unsafeFunction "to_jsonb"
1292+
1293+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1294+-- becomes a JSON array of arrays.
1295+arrayToJson
1296+ :: PGArray "arrayToJson" arr
1297+ => nullity arr :--> nullity 'PGjson
1298+arrayToJson = unsafeFunction "array_to_json"
1299+
1300+-- | Returns the row as a JSON object.
1301+rowToJson :: nullity ('PGcomposite ty) :--> nullity 'PGjson
1302+rowToJson = unsafeFunction "row_to_json"
1303+
1304+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1305+-- argument list.
1306+jsonBuildArray
1307+ :: SListI elems
1308+ => NP (Expression outer grp commons schemas params from) elems
1309+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1310+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1311+
1312+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1313+-- variadic argument list.
1314+jsonbBuildArray
1315+ :: SListI elems
1316+ => NP (Expression outer grp commons schemas params from) elems
1317+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1318+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1319+
1320+unsafeRowFunction
1321+ :: SOP.SListI elems
1322+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1323+ -> [ByteString]
1324+unsafeRowFunction =
1325+ (`appEndo` []) . hcfoldMap (Proxy :: SOP.Proxy SOP.Top)
1326+ (\(col `As` name) -> Endo $ \xs ->
1327+ renderAliasString name : renderSQL col : xs)
1328+ where
1329+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1330+ renderAliasString = singleQuotedText . fromString . symbolVal
1331+
1332+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1333+-- argument list. The elements of the argument list must alternate between text
1334+-- and values.
1335+jsonBuildObject
1336+ :: SOP.SListI elems
1337+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1338+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1339+jsonBuildObject
1340+ = unsafeFunction "json_build_object"
1341+ . UnsafeExpression
1342+ . commaSeparated
1343+ . unsafeRowFunction
1344+
1345+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1346+-- variadic argument list. The elements of the argument list must alternate
1347+-- between text and values.
1348+jsonbBuildObject
1349+ :: SOP.SListI elems
1350+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1351+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1352+jsonbBuildObject
1353+ = unsafeFunction "jsonb_build_object"
1354+ . UnsafeExpression
1355+ . commaSeparated
1356+ . unsafeRowFunction
1357+
1358+-- | Builds a JSON object out of a text array. The array must have either
1359+-- exactly one dimension with an even number of members, in which case they are
1360+-- taken as alternating key/value pairs, or two dimensions such that each inner
1361+-- array has exactly two elements, which are taken as a key/value pair.
1362+jsonObject
1363+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1364+ => nullity arr :--> nullity 'PGjson
1365+jsonObject = unsafeFunction "json_object"
1366+
1367+-- | Builds a binary JSON object out of a text array. The array must have either
1368+-- exactly one dimension with an even number of members, in which case they are
1369+-- taken as alternating key/value pairs, or two dimensions such that each inner
1370+-- array has exactly two elements, which are taken as a key/value pair.
1371+jsonbObject
1372+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1373+ => nullity arr :--> nullity 'PGjsonb
1374+jsonbObject = unsafeFunction "jsonb_object"
1375+
1376+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1377+-- keys and one for values, that are zipped pairwise to create a JSON object.
1378+jsonZipObject
1379+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1380+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1381+ => Expression outer grp commons schemas params from (nullity keysArray)
1382+ -> Expression outer grp commons schemas params from (nullity valuesArray)
1383+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1384+jsonZipObject ks vs =
1385+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1386+
1387+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1388+-- keys and one for values, that are zipped pairwise to create a binary JSON
1389+-- object.
1390+jsonbZipObject
1391+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1392+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1393+ => Expression outer grp commons schemas params from (nullity keysArray)
1394+ -> Expression outer grp commons schemas params from (nullity valuesArray)
1395+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1396+jsonbZipObject ks vs =
1397+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1398+
1399+{-----------------------------------------
1400+Table 9.46: JSON processing functions
1401+-----------------------------------------}
1402+
1403+-- | Returns the number of elements in the outermost JSON array.
1404+jsonArrayLength :: nullity 'PGjson :--> nullity 'PGint4
1405+jsonArrayLength = unsafeFunction "json_array_length"
1406+
1407+-- | Returns the number of elements in the outermost binary JSON array.
1408+jsonbArrayLength :: nullity 'PGjsonb :--> nullity 'PGint4
1409+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1410+
1411+-- | Returns JSON value pointed to by the given path (equivalent to #>
1412+-- operator).
1413+jsonExtractPath
1414+ :: SListI elems
1415+ => Expression outer grp commons schemas params from (nullity 'PGjson)
1416+ -> NP (Expression outer grp commons schemas params from) elems
1417+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1418+jsonExtractPath x xs =
1419+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1420+
1421+-- | Returns JSON value pointed to by the given path (equivalent to #>
1422+-- operator).
1423+jsonbExtractPath
1424+ :: SListI elems
1425+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1426+ -> NP (Expression outer grp commons schemas params from) elems
1427+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1428+jsonbExtractPath x xs =
1429+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1430+
1431+-- | Returns JSON value pointed to by the given path (equivalent to #>
1432+-- operator), as text.
1433+jsonExtractPathAsText
1434+ :: SListI elems
1435+ => Expression outer grp commons schemas params from (nullity 'PGjson)
1436+ -> NP (Expression outer grp commons schemas params from) elems
1437+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1438+jsonExtractPathAsText x xs =
1439+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1440+
1441+-- | Returns JSON value pointed to by the given path (equivalent to #>
1442+-- operator), as text.
1443+jsonbExtractPathAsText
1444+ :: SListI elems
1445+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1446+ -> NP (Expression outer grp commons schemas params from) elems
1447+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1448+jsonbExtractPathAsText x xs =
1449+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1450+
1451+-- | Returns the type of the outermost JSON value as a text string. Possible
1452+-- types are object, array, string, number, boolean, and null.
1453+jsonTypeof :: nullity 'PGjson :--> nullity 'PGtext
1454+jsonTypeof = unsafeFunction "json_typeof"
1455+
1456+-- | Returns the type of the outermost binary JSON value as a text string.
1457+-- Possible types are object, array, string, number, boolean, and null.
1458+jsonbTypeof :: nullity 'PGjsonb :--> nullity 'PGtext
1459+jsonbTypeof = unsafeFunction "jsonb_typeof"
1460+
1461+-- | Returns its argument with all object fields that have null values omitted.
1462+-- Other null values are untouched.
1463+jsonStripNulls :: nullity 'PGjson :--> nullity 'PGjson
1464+jsonStripNulls = unsafeFunction "json_strip_nulls"
1465+
1466+-- | Returns its argument with all object fields that have null values omitted.
1467+-- Other null values are untouched.
1468+jsonbStripNulls :: nullity 'PGjsonb :--> nullity 'PGjsonb
1469+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1470+
1471+-- | @ jsonbSet target path new_value create_missing @
1472+--
1473+-- Returns target with the section designated by path replaced by new_value,
1474+-- or with new_value added if create_missing is true ( default is true) and the
1475+-- item designated by path does not exist. As with the path orientated
1476+-- operators, negative integers that appear in path count from the end of JSON
1477+-- arrays.
1478+jsonbSet
1479+ :: PGTextArray "jsonbSet" arr
1480+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1481+ -> Expression outer grp commons schemas params from (nullity arr)
1482+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1483+ -> Maybe (Expression outer grp commons schemas params from (nullity 'PGbool))
1484+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1485+jsonbSet tgt path val createMissing = case createMissing of
1486+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1487+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1488+
1489+-- | @ jsonbInsert target path new_value insert_after @
1490+--
1491+-- Returns target with new_value inserted. If target section designated by
1492+-- path is in a JSONB array, new_value will be inserted before target or after
1493+-- if insert_after is true (default is false). If target section designated by
1494+-- path is in JSONB object, new_value will be inserted only if target does not
1495+-- exist. As with the path orientated operators, negative integers that appear
1496+-- in path count from the end of JSON arrays.
1497+jsonbInsert
1498+ :: PGTextArray "jsonbInsert" arr
1499+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1500+ -> Expression outer grp commons schemas params from (nullity arr)
1501+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1502+ -> Maybe (Expression outer grp commons schemas params from (nullity 'PGbool))
1503+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1504+jsonbInsert tgt path val insertAfter = case insertAfter of
1505+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1506+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1507+
1508+-- | Returns its argument as indented JSON text.
1509+jsonbPretty :: nullity 'PGjsonb :--> nullity 'PGtext
1510+jsonbPretty = unsafeFunction "jsonb_pretty"
1511+
1512+(@@) :: Operator (nullity 'PGtsvector) (nullity 'PGtsquery) ('Null 'PGbool)
1513+(@@) = unsafeBinaryOp "@@"
1514+
1515+(.&) :: Operator (nullity 'PGtsquery) (nullity 'PGtsquery) (nullity 'PGtsquery)
1516+(.&) = unsafeBinaryOp "&&"
1517+
1518+(.|) :: Operator (nullity 'PGtsquery) (nullity 'PGtsquery) (nullity 'PGtsquery)
1519+(.|) = unsafeBinaryOp "||"
1520+
1521+(.!) :: nullity 'PGtsquery :--> nullity 'PGtsquery
1522+(.!) = unsafeUnaryOp "!!"
1523+
1524+(<->) :: Operator (nullity 'PGtsquery) (nullity 'PGtsquery) (nullity 'PGtsquery)
1525+(<->) = unsafeBinaryOp "<->"
1526+
1527+arrayToTSvector
1528+ :: nullity ('PGvararray ('NotNull 'PGtext))
1529+ :--> nullity 'PGtsvector
1530+arrayToTSvector = unsafeFunction "array_to_tsvector"
1531+
1532+tsvectorLength :: nullity 'PGtsvector :--> nullity 'PGint4
1533+tsvectorLength = unsafeFunction "length"
1534+
1535+numnode :: nullity 'PGtsquery :--> nullity 'PGint4
1536+numnode = unsafeFunction "numnode"
1537+
1538+plainToTSquery
1539+ :: FunctionHet '[nullity 'PGtext, nullity 'PGtext] (nullity 'PGtsquery)
1540+plainToTSquery = unsafeFunctionHet "plainto_tsquery"
1541+
1542+phraseToTSquery
1543+ :: FunctionHet '[nullity 'PGtext, nullity 'PGtext] (nullity 'PGtsquery)
1544+phraseToTSquery = unsafeFunctionHet "phraseto_tsquery"
1545+
1546+websearchToTSquery
1547+ :: FunctionHet '[nullity 'PGtext, nullity 'PGtext] (nullity 'PGtsquery)
1548+websearchToTSquery = unsafeFunctionHet "websearch_to_tsquery"
1549+
1550+queryTree :: nullity 'PGtsquery :--> nullity 'PGtext
1551+queryTree = unsafeFunction "query_tree"
1552+
1553+toTSquery
1554+ :: FunctionHet '[nullity 'PGtext, nullity 'PGtext] (nullity 'PGtsquery)
1555+toTSquery = unsafeFunctionHet "to_tsquery"
1556+
1557+toTSvector
1558+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1559+ => FunctionHet '[nullity 'PGtext, nullity ty] (nullity 'PGtsquery)
1560+toTSvector = unsafeFunctionHet "to_tsvector"
1561+
1562+{-----------------------------------------
1563+aggregation
1564+-----------------------------------------}
1565+
1566+{- |
1567+`Aggregate` functions compute a single result from a set of input values.
1568+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1569+as `WindowFunction`s.
1570+-}
1571+class Aggregate expr1 expr2 aggr
1572+ | aggr -> expr1, aggr -> expr2 where
1573+
1574+ -- | A special aggregation that does not require an input
1575+ --
1576+ -- >>> :{
1577+ -- let
1578+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1579+ -- expression = countStar
1580+ -- in printSQL expression
1581+ -- :}
1582+ -- count(*)
1583+ countStar :: aggr ('NotNull 'PGint8)
1584+
1585+ -- | >>> :{
1586+ -- let
1587+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1588+ -- expression = count (All #col)
1589+ -- in printSQL expression
1590+ -- :}
1591+ -- count(ALL "col")
1592+ count
1593+ :: expr1 ty
1594+ -- ^ what to count
1595+ -> aggr ('NotNull 'PGint8)
1596+
1597+ -- | >>> :{
1598+ -- let
1599+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1600+ -- expression = sum_ (Distinct #col)
1601+ -- in printSQL expression
1602+ -- :}
1603+ -- sum(DISTINCT "col")
1604+ sum_
1605+ :: ty `In` PGNum
1606+ => expr1 (nullity ty)
1607+ -> aggr ('NotNull ty)
1608+
1609+ -- | input values, including nulls, concatenated into an array
1610+ arrayAgg
1611+ :: expr1 ty
1612+ -> aggr ('Null ('PGvararray ty))
1613+
1614+ -- | aggregates values as a JSON array
1615+ jsonAgg
1616+ :: expr1 ty
1617+ -> aggr ('Null 'PGjson)
1618+
1619+ -- | aggregates values as a JSON array
1620+ jsonbAgg
1621+ :: expr1 ty
1622+ -> aggr ('Null 'PGjsonb)
1623+
1624+ {- |
1625+ the bitwise AND of all non-null input values, or null if none
1626+ >>> :{
1627+ let
1628+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] ('Null 'PGint4)
1629+ expression = bitAnd (Distinct #col)
1630+ in printSQL expression
1631+ :}
1632+ bit_and(DISTINCT "col")
1633+ -}
1634+ bitAnd
1635+ :: int `In` PGIntegral
1636+ => expr1 (nullity int)
1637+ -- ^ what to aggregate
1638+ -> aggr ('Null int)
1639+
1640+ {- |
1641+ the bitwise OR of all non-null input values, or null if none
1642+
1643+ >>> :{
1644+ let
1645+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] ('Null 'PGint4)
1646+ expression = bitOr (All #col)
1647+ in printSQL expression
1648+ :}
1649+ bit_or(ALL "col")
1650+ -}
1651+ bitOr
1652+ :: int `In` PGIntegral
1653+ => expr1 (nullity int)
1654+ -- ^ what to aggregate
1655+ -> aggr ('Null int)
1656+
1657+ {- |
1658+ true if all input values are true, otherwise false
1659+
1660+ >>> :{
1661+ let
1662+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] ('Null 'PGbool)
1663+ winFun = boolAnd #col
1664+ in printSQL winFun
1665+ :}
1666+ bool_and("col")
1667+ -}
1668+ boolAnd
1669+ :: expr1 (nullity 'PGbool)
1670+ -- ^ what to aggregate
1671+ -> aggr ('Null 'PGbool)
1672+
1673+ {- |
1674+ true if at least one input value is true, otherwise false
1675+
1676+ >>> :{
1677+ let
1678+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] ('Null 'PGbool)
1679+ expression = boolOr (All #col)
1680+ in printSQL expression
1681+ :}
1682+ bool_or(ALL "col")
1683+ -}
1684+ boolOr
1685+ :: expr1(nullity 'PGbool)
1686+ -- ^ what to aggregate
1687+ -> aggr ('Null 'PGbool)
1688+
1689+ {- |
1690+ equivalent to `boolAnd`
1691+
1692+ >>> :{
1693+ let
1694+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] ('Null 'PGbool)
1695+ expression = every (Distinct #col)
1696+ in printSQL expression
1697+ :}
1698+ every(DISTINCT "col")
1699+ -}
1700+ every
1701+ :: expr1 (nullity 'PGbool)
1702+ -- ^ what to aggregate
1703+ -> aggr ('Null 'PGbool)
1704+
1705+ {- |maximum value of expression across all input values-}
1706+ max_
1707+ :: expr1 (nullity ty)
1708+ -- ^ what to maximize
1709+ -> aggr ('Null ty)
1710+
1711+ -- | minimum value of expression across all input values
1712+ min_
1713+ :: expr1 (nullity ty)
1714+ -- ^ what to minimize
1715+ -> aggr ('Null ty)
1716+
1717+ -- | the average (arithmetic mean) of all input values
1718+ avg
1719+ :: expr1 (nullity ty)
1720+ -- ^ what to average
1721+ -> aggr ('Null (PGAvg ty))
1722+
1723+ {- | correlation coefficient
1724+ >>> :{
1725+ let
1726+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1727+ expression = corr (All (#y :*: #x))
1728+ in printSQL expression
1729+ :}
1730+ corr(ALL "y", "x")
1731+ -}
1732+ corr
1733+ :: expr2 (nullity 'PGfloat8)
1734+ -> aggr ('Null 'PGfloat8)
1735+
1736+ {- | population covariance
1737+ >>> :{
1738+ let
1739+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1740+ expression = covarPop (All (#y :*: #x))
1741+ in printSQL expression
1742+ :}
1743+ covar_pop(ALL "y", "x")
1744+ -}
1745+ covarPop
1746+ :: expr2 (nullity 'PGfloat8)
1747+ -> aggr ('Null 'PGfloat8)
1748+
1749+ {- | sample covariance
1750+ >>> :{
1751+ let
1752+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1753+ winFun = covarSamp (#y :*: #x)
1754+ in printSQL winFun
1755+ :}
1756+ covar_samp("y", "x")
1757+ -}
1758+ covarSamp
1759+ :: expr2 (nullity 'PGfloat8)
1760+ -> aggr ('Null 'PGfloat8)
1761+
1762+ {- | average of the independent variable (sum(X)/N)
1763+ >>> :{
1764+ let
1765+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1766+ expression = regrAvgX (All (#y :*: #x))
1767+ in printSQL expression
1768+ :}
1769+ regr_avgx(ALL "y", "x")
1770+ -}
1771+ regrAvgX
1772+ :: expr2 (nullity 'PGfloat8)
1773+ -> aggr ('Null 'PGfloat8)
1774+
1775+ {- | average of the dependent variable (sum(Y)/N)
1776+ >>> :{
1777+ let
1778+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1779+ winFun = regrAvgY (#y :*: #x)
1780+ in printSQL winFun
1781+ :}
1782+ regr_avgy("y", "x")
1783+ -}
1784+ regrAvgY
1785+ :: expr2 (nullity 'PGfloat8)
1786+ -> aggr ('Null 'PGfloat8)
1787+
1788+ {- | number of input rows in which both expressions are nonnull
1789+ >>> :{
1790+ let
1791+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1792+ winFun = regrCount (#y :*: #x)
1793+ in printSQL winFun
1794+ :}
1795+ regr_count("y", "x")
1796+ -}
1797+ regrCount
1798+ :: expr2 (nullity 'PGfloat8)
1799+ -> aggr ('Null 'PGint8)
1800+
1801+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1802+ >>> :{
1803+ let
1804+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1805+ expression = regrIntercept (All (#y :*: #x))
1806+ in printSQL expression
1807+ :}
1808+ regr_intercept(ALL "y", "x")
1809+ -}
1810+ regrIntercept
1811+ :: expr2 (nullity 'PGfloat8)
1812+ -> aggr ('Null 'PGfloat8)
1813+
1814+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1815+ regrR2
1816+ :: expr2 (nullity 'PGfloat8)
1817+ -> aggr ('Null 'PGfloat8)
1818+
1819+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1820+ -- determined by the (X, Y) pairs
1821+ regrSlope
1822+ :: expr2 (nullity 'PGfloat8)
1823+ -> aggr ('Null 'PGfloat8)
1824+
1825+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1826+ -- (“sum of squares” of the independent variable)
1827+ regrSxx
1828+ :: expr2 (nullity 'PGfloat8)
1829+ -> aggr ('Null 'PGfloat8)
1830+
1831+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1832+ -- (“sum of products” of independent times dependent variable)
1833+ regrSxy
1834+ :: expr2 (nullity 'PGfloat8)
1835+ -> aggr ('Null 'PGfloat8)
1836+
1837+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1838+ -- (“sum of squares” of the dependent variable)
1839+ regrSyy
1840+ :: expr2 (nullity 'PGfloat8)
1841+ -> aggr ('Null 'PGfloat8)
1842+
1843+ -- | historical alias for `stddevSamp`
1844+ stddev
1845+ :: expr1 (nullity ty)
1846+ -> aggr ('Null (PGAvg ty))
1847+
1848+ -- | population standard deviation of the input values
1849+ stddevPop
1850+ :: expr1 (nullity ty)
1851+ -> aggr ('Null (PGAvg ty))
1852+
1853+ -- | sample standard deviation of the input values
1854+ stddevSamp
1855+ :: expr1 (nullity ty)
1856+ -> aggr ('Null (PGAvg ty))
1857+
1858+ -- | historical alias for `varSamp`
1859+ variance
1860+ :: expr1 (nullity ty)
1861+ -> aggr ('Null (PGAvg ty))
1862+
1863+ -- | population variance of the input values
1864+ -- (square of the population standard deviation)
1865+ varPop
1866+ :: expr1 (nullity ty)
1867+ -> aggr ('Null (PGAvg ty))
1868+
1869+ -- | sample variance of the input values
1870+ -- (square of the sample standard deviation)
1871+ varSamp
1872+ :: expr1 (nullity ty)
1873+ -> aggr ('Null (PGAvg ty))
1874+
1875+{- |
1876+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1877+`All` invokes the aggregate once for each input row.
1878+`Distinct` invokes the aggregate once for each distinct value of the expression
1879+(or distinct set of values, for multiple expressions) found in the input
1880+-}
1881+data Distinction expr ty
1882+ = All (expr ty)
1883+ | Distinct (expr ty)
1884+ deriving (GHC.Generic,Show,Eq,Ord)
1885+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1886+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1887+ renderSQL = \case
1888+ All x -> "ALL" <+> renderSQL x
1889+ Distinct x -> "DISTINCT" <+> renderSQL x
1890+instance RenderSQL
1891+ (Distinction
1892+ ( Expression outer grp commons schemas params from
1893+ :*:
1894+ Expression outer grp commons schemas params from) xty ) where
1895+ renderSQL = \case
1896+ All (x :*: x') ->
1897+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1898+ Distinct (x :*: x') ->
1899+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1900+
1901+instance Aggregate
1902+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1903+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1904+ (Expression outer ('Grouped bys) commons schemas params from) where
1905+ countStar = UnsafeExpression "count(*)"
1906+ count = unsafeAggregate1 "count"
1907+ sum_ = unsafeAggregate1 "sum"
1908+ arrayAgg = unsafeAggregate1 "array_agg"
1909+ jsonAgg = unsafeAggregate1 "json_agg"
1910+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1911+ bitAnd = unsafeAggregate1 "bit_and"
1912+ bitOr = unsafeAggregate1 "bit_or"
1913+ boolAnd = unsafeAggregate1 "bool_and"
1914+ boolOr = unsafeAggregate1 "bool_or"
1915+ every = unsafeAggregate1 "every"
1916+ max_ = unsafeAggregate1 "max"
1917+ min_ = unsafeAggregate1 "min"
1918+ avg = unsafeAggregate1 "avg"
1919+ corr = unsafeAggregate2 "corr"
1920+ covarPop = unsafeAggregate2 "covar_pop"
1921+ covarSamp = unsafeAggregate2 "covar_samp"
1922+ regrAvgX = unsafeAggregate2 "regr_avgx"
1923+ regrAvgY = unsafeAggregate2 "regr_avgy"
1924+ regrCount = unsafeAggregate2 "regr_count"
1925+ regrIntercept = unsafeAggregate2 "regr_intercept"
1926+ regrR2 = unsafeAggregate2 "regr_r2"
1927+ regrSlope = unsafeAggregate2 "regr_slope"
1928+ regrSxx = unsafeAggregate2 "regr_sxx"
1929+ regrSxy = unsafeAggregate2 "regr_sxy"
1930+ regrSyy = unsafeAggregate2 "regr_syy"
1931+ stddev = unsafeAggregate1 "stddev"
1932+ stddevPop = unsafeAggregate1 "stddev_pop"
1933+ stddevSamp = unsafeAggregate1 "stddev_samp"
1934+ variance = unsafeAggregate1 "variance"
1935+ varPop = unsafeAggregate1 "var_pop"
1936+ varSamp = unsafeAggregate1 "var_samp"
1937+instance Aggregate
1938+ (Expression outer grp commons schemas params from)
1939+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1940+ (WindowFunction outer grp commons schemas params from) where
1941+ countStar = UnsafeWindowFunction "count(*)"
1942+ count = unsafeWindowFunction1 "count"
1943+ sum_ = unsafeWindowFunction1 "sum"
1944+ arrayAgg = unsafeWindowFunction1 "array_agg"
1945+ jsonAgg = unsafeWindowFunction1 "json_agg"
1946+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1947+ bitAnd = unsafeWindowFunction1 "bit_and"
1948+ bitOr = unsafeWindowFunction1 "bit_or"
1949+ boolAnd = unsafeWindowFunction1 "bool_and"
1950+ boolOr = unsafeWindowFunction1 "bool_or"
1951+ every = unsafeWindowFunction1 "every"
1952+ max_ = unsafeWindowFunction1 "max"
1953+ min_ = unsafeWindowFunction1 "min"
1954+ avg = unsafeWindowFunction1 "avg"
1955+ corr = unsafeWindowFunction2 "corr"
1956+ covarPop = unsafeWindowFunction2 "covar_pop"
1957+ covarSamp = unsafeWindowFunction2 "covar_samp"
1958+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1959+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1960+ regrCount = unsafeWindowFunction2 "regr_count"
1961+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1962+ regrR2 = unsafeWindowFunction2 "regr_r2"
1963+ regrSlope = unsafeWindowFunction2 "regr_slope"
1964+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1965+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1966+ regrSyy = unsafeWindowFunction2 "regr_syy"
1967+ stddev = unsafeWindowFunction1 "stddev"
1968+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1969+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1970+ variance = unsafeWindowFunction1 "variance"
1971+ varPop = unsafeWindowFunction1 "var_pop"
1972+ varSamp = unsafeWindowFunction1 "var_samp"
1973+
1974+-- | escape hatch to define aggregate functions
1975+unsafeAggregate1
1976+ :: ByteString -- ^ aggregate function
1977+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1978+ -> Expression outer ('Grouped bys) commons schemas params from yty
1979+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1980+ [fun, "(", renderSQL x, ")"]
1981+
1982+-- | escape hatch to define aggregate binary functions
1983+unsafeAggregate2
1984+ :: ByteString -- ^ aggregate function
1985+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1986+ -> Expression outer ('Grouped bys) commons schemas params from yty
1987+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1988+ [fun, "(", renderSQL xx, ")"]
1989+
1990+-- | A type family that calculates `PGAvg` type of a `PGType`.
1991+type family PGAvg ty where
1992+ PGAvg 'PGint2 = 'PGnumeric
1993+ PGAvg 'PGint4 = 'PGnumeric
1994+ PGAvg 'PGint8 = 'PGnumeric
1995+ PGAvg 'PGnumeric = 'PGnumeric
1996+ PGAvg 'PGfloat4 = 'PGfloat8
1997+ PGAvg 'PGfloat8 = 'PGfloat8
1998+ PGAvg 'PGinterval = 'PGinterval
1999+ PGAvg pg = TypeError
2000+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
2001+
2002+{-----------------------------------------
2003+type expressions
2004+-----------------------------------------}
2005+
2006+-- | `TypeExpression`s are used in `cast`s and
2007+-- `Squeal.PostgreSQL.Definition.createTable` commands.
2008+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
2009+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
2010+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2011+instance RenderSQL (TypeExpression schemas ty) where
2012+ renderSQL = renderTypeExpression
2013+
2014+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
2015+typedef
2016+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
2017+ => QualifiedAlias sch td
2018+ -> TypeExpression schemas (nullity ty)
2019+typedef = UnsafeTypeExpression . renderSQL
2020+
2021+-- | The composite type corresponding to a `Table` definition can be expressed
2022+-- by its alias.
2023+typetable
2024+ :: (Has sch schemas schema, Has tab schema ('Table table))
2025+ => QualifiedAlias sch tab
2026+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
2027+typetable = UnsafeTypeExpression . renderSQL
2028+
2029+-- | The composite type corresponding to a `View` definition can be expressed
2030+-- by its alias.
2031+typeview
2032+ :: (Has sch schemas schema, Has vw schema ('View view))
2033+ => QualifiedAlias sch vw
2034+ -> TypeExpression schemas (nullity ('PGcomposite view))
2035+typeview = UnsafeTypeExpression . renderSQL
2036+
2037+-- | logical Boolean (true/false)
2038+bool :: TypeExpression schemas (nullity 'PGbool)
2039+bool = UnsafeTypeExpression "bool"
2040+-- | signed two-byte integer
2041+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
2042+int2 = UnsafeTypeExpression "int2"
2043+smallint = UnsafeTypeExpression "smallint"
2044+-- | signed four-byte integer
2045+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
2046+int4 = UnsafeTypeExpression "int4"
2047+int = UnsafeTypeExpression "int"
2048+integer = UnsafeTypeExpression "integer"
2049+-- | signed eight-byte integer
2050+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
2051+int8 = UnsafeTypeExpression "int8"
2052+bigint = UnsafeTypeExpression "bigint"
2053+-- | arbitrary precision numeric type
2054+numeric :: TypeExpression schemas (nullity 'PGnumeric)
2055+numeric = UnsafeTypeExpression "numeric"
2056+-- | single precision floating-point number (4 bytes)
2057+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
2058+float4 = UnsafeTypeExpression "float4"
2059+real = UnsafeTypeExpression "real"
2060+-- | double precision floating-point number (8 bytes)
2061+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
2062+float8 = UnsafeTypeExpression "float8"
2063+doublePrecision = UnsafeTypeExpression "double precision"
2064+-- | currency amount
2065+money :: TypeExpression schema (nullity 'PGmoney)
2066+money = UnsafeTypeExpression "money"
2067+-- | variable-length character string
2068+text :: TypeExpression schemas (nullity 'PGtext)
2069+text = UnsafeTypeExpression "text"
2070+-- | fixed-length character string
2071+char, character
2072+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
2073+ => TypeExpression schemas (nullity ('PGchar n))
2074+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2075+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2076+-- | variable-length character string
2077+varchar, characterVarying
2078+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
2079+ => TypeExpression schemas (nullity ('PGvarchar n))
2080+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2081+characterVarying = UnsafeTypeExpression $
2082+ "character varying(" <> renderNat @n <> ")"
2083+-- | binary data ("byte array")
2084+bytea :: TypeExpression schemas (nullity 'PGbytea)
2085+bytea = UnsafeTypeExpression "bytea"
2086+-- | date and time (no time zone)
2087+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
2088+timestamp = UnsafeTypeExpression "timestamp"
2089+-- | date and time, including time zone
2090+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
2091+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2092+-- | calendar date (year, month, day)
2093+date :: TypeExpression schemas (nullity 'PGdate)
2094+date = UnsafeTypeExpression "date"
2095+-- | time of day (no time zone)
2096+time :: TypeExpression schemas (nullity 'PGtime)
2097+time = UnsafeTypeExpression "time"
2098+-- | time of day, including time zone
2099+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
2100+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2101+-- | time span
2102+interval :: TypeExpression schemas (nullity 'PGinterval)
2103+interval = UnsafeTypeExpression "interval"
2104+-- | universally unique identifier
2105+uuid :: TypeExpression schemas (nullity 'PGuuid)
2106+uuid = UnsafeTypeExpression "uuid"
2107+-- | IPv4 or IPv6 host address
2108+inet :: TypeExpression schemas (nullity 'PGinet)
2109+inet = UnsafeTypeExpression "inet"
2110+-- | textual JSON data
2111+json :: TypeExpression schemas (nullity 'PGjson)
2112+json = UnsafeTypeExpression "json"
2113+-- | binary JSON data, decomposed
2114+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
2115+jsonb = UnsafeTypeExpression "jsonb"
2116+-- | variable length array
2117+vararray
2118+ :: TypeExpression schemas pg
2119+ -> TypeExpression schemas (nullity ('PGvararray pg))
2120+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2121+-- | fixed length array
2122+--
2123+-- >>> renderSQL (fixarray @'[2] json)
2124+-- "json[2]"
2125+fixarray
2126+ :: forall dims schemas nullity pg. SOP.All KnownNat dims
2127+ => TypeExpression schemas pg
2128+ -> TypeExpression schemas (nullity ('PGfixarray dims pg))
2129+fixarray ty = UnsafeTypeExpression $
2130+ renderSQL ty <> renderDims @dims
2131+ where
2132+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2133+ renderDims =
2134+ ("[" <>)
2135+ . (<> "]")
2136+ . ByteString.intercalate "]["
2137+ . hcollapse
2138+ $ hcmap (SOP.Proxy @KnownNat)
2139+ (K . fromString . show . natVal)
2140+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2141+tsvector :: TypeExpression schemas (nullity 'PGtsvector)
2142+tsvector = UnsafeTypeExpression "tsvector"
2143+tsquery :: TypeExpression schemas (nullity 'PGtsquery)
2144+tsquery = UnsafeTypeExpression "tsquery"
2145+
2146+-- | `pgtype` is a demoted version of a `PGType`
2147+class PGTyped schemas (ty :: NullityType) where
2148+ pgtype :: TypeExpression schemas ty
2149+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
2150+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
2151+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
2152+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
2153+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
2154+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
2155+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
2156+instance PGTyped schemas (nullity 'PGmoney) where pgtype = money
2157+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
2158+instance (KnownNat n, 1 <= n)
2159+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
2160+instance (KnownNat n, 1 <= n)
2161+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
2162+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
2163+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
2164+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
2165+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
2166+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
2167+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
2168+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
2169+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
2170+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
2171+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
2172+instance PGTyped schemas ty
2173+ => PGTyped schemas (nullity ('PGvararray ty)) where
2174+ pgtype = vararray (pgtype @schemas @ty)
2175+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2176+ => PGTyped schemas (nullity ('PGfixarray dims ty)) where
2177+ pgtype = fixarray @dims (pgtype @schemas @ty)
2178+instance PGTyped schemas (nullity 'PGtsvector) where pgtype = tsvector
2179+instance PGTyped schemas (nullity 'PGtsquery) where pgtype = tsquery
2180+
2181+{-----------------------------------------
2182+Sorting
2183+-----------------------------------------}
2184+
2185+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2186+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2187+-- set the sort direction of a `NotNull` result
2188+-- column to ascending or descending. Ascending order puts smaller values
2189+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2190+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2191+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2192+-- determine whether nulls appear before or after non-null values in the sort
2193+-- ordering of a `Null` result column.
2194+data SortExpression outer grp commons schemas params from where
2195+ Asc
2196+ :: Expression outer grp commons schemas params from ('NotNull ty)
2197+ -> SortExpression outer grp commons schemas params from
2198+ Desc
2199+ :: Expression outer grp commons schemas params from ('NotNull ty)
2200+ -> SortExpression outer grp commons schemas params from
2201+ AscNullsFirst
2202+ :: Expression outer grp commons schemas params from ('Null ty)
2203+ -> SortExpression outer grp commons schemas params from
2204+ AscNullsLast
2205+ :: Expression outer grp commons schemas params from ('Null ty)
2206+ -> SortExpression outer grp commons schemas params from
2207+ DescNullsFirst
2208+ :: Expression outer grp commons schemas params from ('Null ty)
2209+ -> SortExpression outer grp commons schemas params from
2210+ DescNullsLast
2211+ :: Expression outer grp commons schemas params from ('Null ty)
2212+ -> SortExpression outer grp commons schemas params from
2213+deriving instance Show (SortExpression outer grp commons schemas params from)
2214+
2215+{- |
2216+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2217+to be sorted according to the specified `SortExpression`(s).
2218+If two rows are equal according to the leftmost expression,
2219+they are compared according to the next expression and so on.
2220+If they are equal according to all specified expressions,
2221+they are returned in an implementation-dependent order.
2222+
2223+You can also control the order in which rows are processed by window functions
2224+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2225+-}
2226+class OrderBy expr where
2227+ orderBy
2228+ :: [SortExpression outer grp commons schemas params from]
2229+ -> expr outer grp commons schemas params from
2230+ -> expr outer grp commons schemas params from
2231+
2232+-- | Render a `SortExpression`.
2233+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2234+ renderSQL = \case
2235+ Asc expression -> renderSQL expression <+> "ASC"
2236+ Desc expression -> renderSQL expression <+> "DESC"
2237+ AscNullsFirst expression -> renderSQL expression
2238+ <+> "ASC NULLS FIRST"
2239+ DescNullsFirst expression -> renderSQL expression
2240+ <+> "DESC NULLS FIRST"
2241+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2242+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2243+
2244+-- | A `WindowDefinition` is a set of table rows that are somehow related
2245+-- to the current row
2246+data WindowDefinition outer grp commons schemas params from where
2247+ WindowDefinition
2248+ :: SListI bys
2249+ => NP (Expression outer grp commons schemas params from) bys
2250+ -> [SortExpression outer grp commons schemas params from]
2251+ -> WindowDefinition outer grp commons schemas params from
2252+
2253+instance OrderBy WindowDefinition where
2254+ orderBy sortsR (WindowDefinition parts sortsL)
2255+ = WindowDefinition parts (sortsL ++ sortsR)
2256+
2257+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2258+ renderSQL (WindowDefinition part ord) =
2259+ renderPartitionByClause part <> renderOrderByClause ord
2260+ where
2261+ renderPartitionByClause = \case
2262+ Nil -> ""
2263+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2264+ renderOrderByClause = \case
2265+ [] -> ""
2266+ srts -> " ORDER" <+> "BY"
2267+ <+> commaSeparated (renderSQL <$> srts)
2268+
2269+{- |
2270+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2271+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2272+For each row, the window function is computed across the rows that fall into
2273+the same partition as the current row.
2274+-}
2275+partitionBy
2276+ :: SListI bys
2277+ => NP (Expression outer grp commons schemas params from) bys
2278+ -> WindowDefinition outer grp commons schemas params from
2279+partitionBy bys = WindowDefinition bys []
2280+
2281+{- |
2282+A window function performs a calculation across a set of table rows
2283+that are somehow related to the current row. This is comparable to the type
2284+of calculation that can be done with an aggregate function.
2285+However, window functions do not cause rows to become grouped into a single
2286+output row like non-window aggregate calls would.
2287+Instead, the rows retain their separate identities.
2288+Behind the scenes, the window function is able to access more than
2289+just the current row of the query result.
2290+-}
2291+newtype WindowFunction
2292+ (outer :: FromType)
2293+ (grp :: Grouping)
2294+ (commons :: FromType)
2295+ (schemas :: SchemasType)
2296+ (params :: [NullityType])
2297+ (from :: FromType)
2298+ (ty :: NullityType)
2299+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2300+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2301+
2302+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2303+ renderSQL = renderWindowFunction
2304+
2305+unsafeWindowFunction1
2306+ :: ByteString
2307+ -> Expression outer grp commons schemas params from ty0
2308+ -> WindowFunction outer grp commons schemas params from ty1
2309+unsafeWindowFunction1 fun x
2310+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2311+
2312+unsafeWindowFunction2
2313+ :: ByteString
2314+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2315+ -> WindowFunction outer grp commons schemas params from ty1
2316+unsafeWindowFunction2 fun (x :*: x')
2317+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2318+
2319+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2320+>>> printSQL rank
2321+rank()
2322+-}
2323+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2324+rank = UnsafeWindowFunction "rank()"
2325+
2326+{- | number of the current row within its partition, counting from 1
2327+>>> printSQL rowNumber
2328+row_number()
2329+-}
2330+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2331+rowNumber = UnsafeWindowFunction "row_number()"
2332+
2333+{- | rank of the current row without gaps; this function counts peer groups
2334+>>> printSQL denseRank
2335+dense_rank()
2336+-}
2337+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2338+denseRank = UnsafeWindowFunction "dense_rank()"
2339+
2340+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2341+>>> printSQL percentRank
2342+percent_rank()
2343+-}
2344+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2345+percentRank = UnsafeWindowFunction "percent_rank()"
2346+
2347+{- | cumulative distribution: (number of partition rows
2348+preceding or peer with current row) / total partition rows
2349+>>> printSQL cumeDist
2350+cume_dist()
2351+-}
2352+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2353+cumeDist = UnsafeWindowFunction "cume_dist()"
2354+
2355+{- | integer ranging from 1 to the argument value,
2356+dividing the partition as equally as possible
2357+-}
2358+ntile
2359+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2360+ -- ^ num buckets
2361+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2362+ntile = unsafeWindowFunction1 "ntile"
2363+
2364+{- | returns value evaluated at the row that is offset rows before the current
2365+row within the partition; if there is no such row, instead return default
2366+(which must be of the same type as value). Both offset and default are
2367+evaluated with respect to the current row.
2368+-}
2369+lag
2370+ :: Expression outer grp commons schemas params from ty
2371+ -- ^ value
2372+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2373+ -- ^ offset
2374+ -> Expression outer grp commons schemas params from ty
2375+ -- ^ default
2376+ -> WindowFunction outer grp commons schemas params from ty
2377+lag value offset def = UnsafeWindowFunction $ "lag"
2378+ <> parenthesized
2379+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2380+
2381+{- | returns value evaluated at the row that is offset rows after the current
2382+row within the partition; if there is no such row, instead return default
2383+(which must be of the same type as value). Both offset and default are
2384+evaluated with respect to the current row.
2385+-}
2386+lead
2387+ :: Expression outer grp commons schemas params from ty
2388+ -- ^ value
2389+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2390+ -- ^ offset
2391+ -> Expression outer grp commons schemas params from ty
2392+ -- ^ default
2393+ -> WindowFunction outer grp commons schemas params from ty
2394+lead value offset def = UnsafeWindowFunction $ "lag"
2395+ <> parenthesized
2396+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2397+
2398+{- | returns value evaluated at the row that is the
2399+first row of the window frame
2400+-}
2401+firstValue
2402+ :: Expression outer grp commons schemas params from ty
2403+ -- ^ value
2404+ -> WindowFunction outer grp commons schemas params from ty
2405+firstValue = unsafeWindowFunction1 "first_value"
2406+
2407+{- | returns value evaluated at the row that is the
2408+last row of the window frame
2409+-}
2410+lastValue
2411+ :: Expression outer grp commons schemas params from ty
2412+ -- ^ value
2413+ -> WindowFunction outer grp commons schemas params from ty
2414+lastValue = unsafeWindowFunction1 "last_value"
2415+
2416+{- | returns value evaluated at the row that is the nth
2417+row of the window frame (counting from 1); null if no such row
2418+-}
2419+nthValue
2420+ :: Expression outer grp commons schemas params from (nullity ty)
2421+ -- ^ value
2422+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2423+ -- ^ nth
2424+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2425+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2426+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])
2427+
2428+{-|
2429+Create date from year, month and day fields
2430+
2431+>>> printSQL (makeDate 1984 7 3)
2432+make_date(1984, 7, 3)
2433+-}
2434+makeDate
2435+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2436+ -- ^ year
2437+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2438+ -- ^ month
2439+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2440+ -- ^ day
2441+ -> Expression outer grp commons schemas params from (nullity 'PGdate)
2442+makeDate y m d = UnsafeExpression $ "make_date" <>
2443+ parenthesized (renderCommaSeparated renderSQL (y :* m :* d :* Nil))
2444+
2445+{-|
2446+Create time from hour, minute and seconds fields
2447+
2448+>>> printSQL (makeTime 8 15 23.5)
2449+make_time(8, 15, 23.5)
2450+-}
2451+makeTime
2452+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2453+ -- ^ hour
2454+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2455+ -- ^ min
2456+ -> Expression outer grp commons schemas params from (nullity 'PGfloat8)
2457+ -- ^ sec
2458+ -> Expression outer grp commons schemas params from (nullity 'PGtime)
2459+makeTime h m s = UnsafeExpression $ "make_time" <>
2460+ parenthesized (renderCommaSeparated renderSQL (h :* m :* s :* Nil))
2461+
2462+{-|
2463+Create timestamp from year, month, day, hour, minute and seconds fields
2464+
2465+>>> printSQL (makeTimestamp 2013 7 15 8 15 23.5)
2466+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2467+-}
2468+makeTimestamp
2469+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2470+ -- ^ year
2471+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2472+ -- ^ month
2473+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2474+ -- ^ day
2475+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2476+ -- ^ hour
2477+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2478+ -- ^ min
2479+ -> Expression outer grp commons schemas params from (nullity 'PGfloat8)
2480+ -- ^ sec
2481+ -> Expression outer grp commons schemas params from (nullity 'PGtimestamp)
2482+makeTimestamp y mon d h m s =
2483+ UnsafeExpression $ "make_timestamp" <> parenthesized
2484+ (renderCommaSeparated renderSQL (y :* mon :* d :* h :* m :* s :* Nil))
2485+
2486+{-|
2487+Create timestamp with time zone from
2488+year, month, day, hour, minute and seconds fields;
2489+the current time zone is used
2490+
2491+>>> printSQL (makeTimestamptz 2013 7 15 8 15 23.5)
2492+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2493+-}
2494+makeTimestamptz
2495+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2496+ -- ^ year
2497+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2498+ -- ^ month
2499+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2500+ -- ^ day
2501+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2502+ -- ^ hour
2503+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2504+ -- ^ min
2505+ -> Expression outer grp commons schemas params from (nullity 'PGfloat8)
2506+ -- ^ sec
2507+ -> Expression outer grp commons schemas params from (nullity 'PGtimestamptz)
2508+makeTimestamptz y mon d h m s =
2509+ UnsafeExpression $ "make_timestamptz" <> parenthesized
2510+ (renderCommaSeparated renderSQL (y :* mon :* d :* h :* m :* s :* Nil))
2511+
2512+{-|
2513+Affine space operations on time types.
2514+-}
2515+class TimeOp time diff | time -> diff where
2516+ {-|
2517+ >>> printSQL (makeDate 1984 7 3 !+ 365)
2518+ (make_date(1984, 7, 3) + 365)
2519+ -}
2520+ (!+) :: Operator (nullity time) (nullity diff) (nullity time)
2521+ (!+) = unsafeBinaryOp "+"
2522+ {-|
2523+ >>> printSQL (365 +! makeDate 1984 7 3)
2524+ (365 + make_date(1984, 7, 3))
2525+ -}
2526+ (+!) :: Operator (nullity diff) (nullity time) (nullity time)
2527+ (+!) = unsafeBinaryOp "+"
2528+ {-|
2529+ >>> printSQL (makeDate 1984 7 3 !- 365)
2530+ (make_date(1984, 7, 3) - 365)
2531+ -}
2532+ (!-) :: Operator (nullity time) (nullity diff) (nullity time)
2533+ (!-) = unsafeBinaryOp "-"
2534+ {-|
2535+ >>> printSQL (makeDate 1984 7 3 !-! currentDate)
2536+ (make_date(1984, 7, 3) - CURRENT_DATE)
2537+ -}
2538+ (!-!) :: Operator (nullity time) (nullity time) (nullity diff)
2539+ (!-!) = unsafeBinaryOp "-"
2540+instance TimeOp 'PGtimestamp 'PGinterval
2541+instance TimeOp 'PGtimestamptz 'PGinterval
2542+instance TimeOp 'PGtime 'PGinterval
2543+instance TimeOp 'PGtimetz 'PGinterval
2544+instance TimeOp 'PGinterval 'PGinterval
2545+instance TimeOp 'PGdate 'PGint4
2546+infixl 6 !+
2547+infixl 6 +!
2548+infixl 6 !-
2549+infixl 6 !-!