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