@@ -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,298 @@ 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
45− , Operator
46− , OperatorDB
37+ , HasParameter (parameter)
38+ , param
39+ -- ** Null
40+ , null_
41+ , notNull
42+ , coalesce
43+ , fromNull
44+ , isNull
45+ , isNotNull
46+ , matchNull
47+ , nullIf
48+ -- ** Collections
49+ , array
50+ , cardinality
51+ , index
52+ , row
53+ , field
54+ -- ** Functions
4755 , unsafeBinaryOp
48− , binaryOp
49− , FunctionVar
50− , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
53− , unsafeFunctionN
54− , functionN
55− , PGSubset (..)
56− , PGIntersect (..)
56+ , unsafeUnaryOp
57+ , unsafeFunction
58+ , unsafeVariadicFunction
59+ , atan2_
60+ , cast
61+ , quot_
62+ , rem_
63+ , trunc
64+ , round_
65+ , ceiling_
66+ , greatest
67+ , least
68+ -- ** Conditions
69+ , true
70+ , false
71+ , not_
72+ , (.&&)
73+ , (.||)
74+ , Condition
75+ , caseWhenThenElse
76+ , ifThenElse
77+ , (.==)
78+ , (./=)
79+ , (.>=)
80+ , (.<)
81+ , (.<=)
82+ , (.>)
83+ -- ** Time
84+ , currentDate
85+ , currentTime
86+ , currentTimestamp
87+ , localTime
88+ , localTimestamp
89+ , TimeOp (..)
90+ , makeDate
91+ , makeTime
92+ , makeTimestamp
93+ , makeTimestamptz
94+ -- ** Text
95+ , lower
96+ , upper
97+ , charLength
98+ , like
99+ , ilike
100+ -- ** Json
101+ -- *** Json and Jsonb operators
102+ , (.->)
103+ , (.->>)
104+ , (.#>)
105+ , (.#>>)
106+ -- *** Jsonb operators
107+ , (.@>)
108+ , (.<@)
109+ , (.?)
110+ , (.?|)
111+ , (.?&)
112+ , (.-.)
113+ , (#-.)
114+ -- *** Functions
115+ , jsonLit
116+ , jsonbLit
117+ , toJson
118+ , toJsonb
119+ , arrayToJson
120+ , rowToJson
121+ , jsonBuildArray
122+ , jsonbBuildArray
123+ , jsonBuildObject
124+ , jsonbBuildObject
125+ , jsonObject
126+ , jsonbObject
127+ , jsonZipObject
128+ , jsonbZipObject
129+ , jsonArrayLength
130+ , jsonbArrayLength
131+ , jsonExtractPath
132+ , jsonbExtractPath
133+ , jsonExtractPathAsText
134+ , jsonbExtractPathAsText
135+ , jsonTypeof
136+ , jsonbTypeof
137+ , jsonStripNulls
138+ , jsonbStripNulls
139+ , jsonbSet
140+ , jsonbInsert
141+ , jsonbPretty
142+ -- ** Aggregation
143+ , Aggregate (..)
144+ , Distinction (..)
145+ , PGAvg
146+ -- * Window Functions
147+ , WindowDefinition (..)
148+ , partitionBy
149+ , WindowFunction (..)
150+ , rank
151+ , rowNumber
152+ , denseRank
153+ , percentRank
154+ , cumeDist
155+ , ntile
156+ , lag
157+ , lead
158+ , firstValue
159+ , lastValue
160+ , nthValue
161+ -- * Sorting
162+ , SortExpression (..)
163+ , OrderBy (..)
164+ -- * Types
165+ , TypeExpression (..)
166+ , PGTyped (..)
167+ , typedef
168+ , typetable
169+ , typeview
170+ , bool
171+ , int2
172+ , smallint
173+ , int4
174+ , int
175+ , integer
176+ , int8
177+ , bigint
178+ , numeric
179+ , float4
180+ , real
181+ , float8
182+ , doublePrecision
183+ , money
184+ , text
185+ , char
186+ , character
187+ , varchar
188+ , characterVarying
189+ , bytea
190+ , timestamp
191+ , timestampWithTimeZone
192+ , date
193+ , time
194+ , timeWithTimeZone
195+ , interval
196+ , uuid
197+ , inet
198+ , json
199+ , jsonb
200+ , vararray
201+ , fixarray
57202 -- * Re-export
58203 , (&)
204+ , NP (..)
205+ , (:*:) (..)
59206 , K (..)
60− , unK
61207 ) where
62208
63209import Control.Category
64210import Control.DeepSeq
65211import Data.ByteString (ByteString)
212+import Data.ByteString.Lazy (toStrict)
66213import Data.Function ((&))
67214import Data.Semigroup hiding (All)
215+import qualified Data.Aeson as JSON
68216import Data.String
217+import Data.Word
69218import Generics.SOP hiding (All, from)
219+import GHC.Generics ((:*:) (..))
70220import GHC.OverloadedLabels
71221import GHC.TypeLits
72222import Numeric
73223import Prelude hiding (id, (.))
74224
225+import qualified Data.ByteString as ByteString
75226import qualified GHC.Generics as GHC
227+import qualified Generics.SOP as SOP
76228
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79229import Squeal.PostgreSQL.Render
80230import Squeal.PostgreSQL.Schema
81231
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85232{-----------------------------------------
86233column expressions
87234-----------------------------------------}
88235
89236{- | `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,
237+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92238as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93239`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
240+or in search `Condition`s in a number of commands.
95241
96242The expression syntax allows the calculation of
97243values from primitive expression using arithmetic, logical,
98244and 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`.
113245-}
114246newtype Expression
115247 (outer :: FromType)
116− (commons :: FromType)
117248 (grp :: Grouping)
249+ (commons :: FromType)
118250 (schemas :: SchemasType)
119251 (params :: [NullityType])
120252 (from :: FromType)
121253 (ty :: NullityType)
122254 = UnsafeExpression { renderExpression :: ByteString }
123255 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
256+
257+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125258 renderSQL = renderExpression
126259
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.
139−type 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)
260+{- | A `HasParameter` constraint is used to indicate a value that is
261+supplied externally to a SQL statement.
262+`Squeal.PostgreSQL.PQ.manipulateParams`,
263+`Squeal.PostgreSQL.PQ.queryParams` and
264+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
265+separately from the SQL command string, in which case `param`s are used to
266+refer to the out-of-line data values.
210267-}
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
213− (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
268+class KnownNat n => HasParameter
269+ (n :: Nat)
270+ (params :: [NullityType])
271+ (ty :: NullityType)
272+ | n params -> ty where
273+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
274+ --
275+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
276+ -- >>> printSQL expr
277+ -- ($1 :: int4)
278+ parameter
279+ :: TypeExpression schemas ty
280+ -> Expression outer grp commons schemas params from ty
281+ parameter ty = UnsafeExpression $ parenthesized $
282+ "$" <> renderNat @n <+> "::"
283+ <+> renderSQL ty
284+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
285+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
286+ => HasParameter n (ty' : params) ty
287+
288+-- | `param` takes a `Nat` using type application and for basic types,
289+-- infers a `TypeExpression`.
290+--
291+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
292+-- >>> printSQL expr
293+-- ($1 :: int4)
294+param
295+ :: forall n outer commons schemas params from grp ty
296+ . (PGTyped schemas ty, HasParameter n params ty)
297+ => Expression outer grp commons schemas params from ty -- ^ param
298+param = parameter @n (pgtype @schemas)
214299
215300instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
301+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217302 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218303instance (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
304+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220305 fromLabel = fromLabel @col :* Nil
221306instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222307 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
308+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224309 fromLabel = fromLabel @col `As` Alias
225310instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226311 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
312+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228313 fromLabel = fromLabel @col :* Nil
229314
230315instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
316+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232317 tab ! col = UnsafeExpression $
233318 renderSQL tab <> "." <> renderSQL col
234319instance (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
320+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236321 tab ! col = tab ! col :* Nil
237322instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238323 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
324+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240325 tab ! col = tab ! col `As` col
241326instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242327 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
328+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244329 tab ! col = tab ! col :* Nil
245330
246331instance
@@ -248,7 +333,7 @@ instance
248333 , Has col row ty
249334 , GroupedBy tab col bys
250335 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
336+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252337 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253338instance
254339 ( HasUnique tab (Join outer from) row
@@ -256,7 +341,7 @@ instance
256341 , GroupedBy tab col bys
257342 , tys ~ '[ty]
258343 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
344+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260345 fromLabel = fromLabel @col :* Nil
261346instance
262347 ( HasUnique tab (Join outer from) row
@@ -264,7 +349,7 @@ instance
264349 , GroupedBy tab col bys
265350 , column ~ (col ::: ty)
266351 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
352+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268353 fromLabel = fromLabel @col `As` Alias
269354instance
270355 ( HasUnique tab (Join outer from) row
@@ -272,7 +357,7 @@ instance
272357 , GroupedBy tab col bys
273358 , columns ~ '[col ::: ty]
274359 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
360+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276361 fromLabel = fromLabel @col :* Nil
277362
278363instance
@@ -280,7 +365,7 @@ instance
280365 , Has col row ty
281366 , GroupedBy tab col bys
282367 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
368+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284369 tab ! col = UnsafeExpression $
285370 renderSQL tab <> "." <> renderSQL col
286371instance
@@ -289,7 +374,7 @@ instance
289374 , GroupedBy tab col bys
290375 , tys ~ '[ty]
291376 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
377+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293378 tab ! col = tab ! col :* Nil
294379instance
295380 ( Has tab (Join outer from) row
@@ -297,7 +382,7 @@ instance
297382 , GroupedBy tab col bys
298383 , column ~ (col ::: ty)
299384 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
385+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301386 tab ! col = tab ! col `As` col
302387instance
303388 ( Has tab (Join outer from) row
@@ -305,78 +390,244 @@ instance
305390 , GroupedBy tab col bys
306391 , columns ~ '[col ::: ty]
307392 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
393+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309394 tab ! col = tab ! col :* Nil
310395
396+-- | analagous to `Nothing`
397+--
398+-- >>> printSQL null_
399+-- NULL
400+null_ :: Expression outer grp commons schemas params from ('Null ty)
401+null_ = UnsafeExpression "NULL"
402+
403+-- | analagous to `Just`
404+--
405+-- >>> printSQL $ notNull true
406+-- TRUE
407+notNull
408+ :: Expression outer grp commons schemas params from ('NotNull ty)
409+ -> Expression outer grp commons schemas params from ('Null ty)
410+notNull = UnsafeExpression . renderSQL
411+
412+-- | return the leftmost value which is not NULL
413+--
414+-- >>> printSQL $ coalesce [null_, true] false
415+-- COALESCE(NULL, TRUE, FALSE)
416+coalesce
417+ :: [Expression outer grp commons schemas params from ('Null ty)]
418+ -- ^ @NULL@s may be present
419+ -> Expression outer grp commons schemas params from ('NotNull ty)
420+ -- ^ @NULL@ is absent
421+ -> Expression outer grp commons schemas params from ('NotNull ty)
422+coalesce nullxs notNullx = UnsafeExpression $
423+ "COALESCE" <> parenthesized (commaSeparated
424+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
425+
426+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
427+--
428+-- >>> printSQL $ fromNull true null_
429+-- COALESCE(NULL, TRUE)
430+fromNull
431+ :: Expression outer grp commons schemas params from ('NotNull ty)
432+ -- ^ what to convert @NULL@ to
433+ -> Expression outer grp commons schemas params from ('Null ty)
434+ -> Expression outer grp commons schemas params from ('NotNull ty)
435+fromNull notNullx nullx = coalesce [nullx] notNullx
436+
437+-- | >>> printSQL $ null_ & isNull
438+-- NULL IS NULL
439+isNull
440+ :: Expression outer grp commons schemas params from ('Null ty)
441+ -- ^ possibly @NULL@
442+ -> Condition outer grp commons schemas params from
443+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
444+
445+-- | >>> printSQL $ null_ & isNotNull
446+-- NULL IS NOT NULL
447+isNotNull
448+ :: Expression outer grp commons schemas params from ('Null ty)
449+ -- ^ possibly @NULL@
450+ -> Condition outer grp commons schemas params from
451+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
452+
453+-- | analagous to `maybe` using @IS NULL@
454+--
455+-- >>> printSQL $ matchNull true not_ null_
456+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
457+matchNull
458+ :: Expression outer grp commons schemas params from (nullty)
459+ -- ^ what to convert @NULL@ to
460+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
461+ -> Expression outer grp commons schemas params from (nullty) )
462+ -- ^ function to perform when @NULL@ is absent
463+ -> Expression outer grp commons schemas params from ('Null ty)
464+ -> Expression outer grp commons schemas params from (nullty)
465+matchNull y f x = ifThenElse (isNull x) y
466+ (f (UnsafeExpression (renderSQL x)))
467+
468+{-| right inverse to `fromNull`, if its arguments are equal then
469+`nullIf` gives @NULL@.
470+
471+>>> :set -XTypeApplications -XDataKinds
472+>>> let expr = nullIf false (param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
473+>>> printSQL expr
474+NULL IF (FALSE, ($1 :: bool))
475+-}
476+nullIf
477+ :: Expression outer grp commons schemas params from ('NotNull ty)
478+ -- ^ @NULL@ is absent
479+ -> Expression outer grp commons schemas params from ('NotNull ty)
480+ -- ^ @NULL@ is absent
481+ -> Expression outer grp commons schemas params from ('Null ty)
482+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
483+ (renderSQL x <> ", " <> renderSQL y)
484+
485+-- | >>> printSQL $ array [null_, false, true]
486+-- ARRAY[NULL, FALSE, TRUE]
487+array
488+ :: [Expression outer grp commons schemas params from ty]
489+ -- ^ array elements
490+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ty))
491+array xs = UnsafeExpression $
492+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
493+
494+-- | >>> printSQL $ cardinality (array [null_, false, true])
495+-- cardinality(ARRAY[NULL, FALSE, TRUE])
496+cardinality
497+ :: Expression outer grp commons schemas params from (nullity ('PGvararray ty))
498+ -> Expression outer grp commons schemas params from (nullity 'PGint8)
499+cardinality = unsafeFunction "cardinality"
500+
501+-- | >>> printSQL $ array [null_, false, true] & index 2
502+-- (ARRAY[NULL, FALSE, TRUE])[2]
503+index
504+ :: Word64 -- ^ index
505+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ty)) -- ^ array
506+ -> Expression outer grp commons schemas params from (NullifyType ty)
507+index n expr = UnsafeExpression $
508+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
509+
311510instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
511+ (Expression outer grp commons schemas params from (nullity ('PGenum labels))) where
313512 label = UnsafeExpression $ renderSQL (PGlabel @label)
314513
514+-- | A row constructor is an expression that builds a row value
515+-- (also called a composite value) using values for its member fields.
516+--
517+-- >>> :{
518+-- type Complex = 'PGcomposite
519+-- '[ "real" ::: 'NotNull 'PGfloat8
520+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
521+-- :}
522+--
523+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
524+-- >>> printSQL i
525+-- ROW(0, 1)
526+row
527+ :: SListI row
528+ => NP (Aliased (Expression outer grp commons schemas params from)) row
529+ -- ^ zero or more expressions for the row field values
530+ -> Expression outer grp commons schemas params from (nullity ('PGcomposite row))
531+row exprs = UnsafeExpression $ "ROW" <> parenthesized
532+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
533+
534+-- | >>> :{
535+-- type Complex = 'PGcomposite
536+-- '[ "real" ::: 'NotNull 'PGfloat8
537+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
538+-- type Schema = '["complex" ::: 'Typedef Complex]
539+-- :}
540+--
541+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
542+-- >>> printSQL $ i & field #complex #imaginary
543+-- (ROW(0, 1)::"complex")."imaginary"
544+field
545+ :: ( Has sch schemas schema
546+ , Has tydef schema ('Typedef ('PGcomposite row))
547+ , Has field row ty)
548+ => QualifiedAlias sch tydef -- ^ row type
549+ -> Alias field -- ^ field name
550+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
551+ -> Expression outer grp commons schemas params from ty
552+field td fld expr = UnsafeExpression $
553+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
554+ <> "." <> renderSQL fld
555+
556+instance Semigroup
557+ (Expression outer grp commons schemas params from (nullity ('PGvararray ty))) where
558+ (<>) = unsafeBinaryOp "||"
559+
560+instance Monoid
561+ (Expression outer grp commons schemas params from (nullity ('PGvararray ty))) where
562+ mempty = array []
563+ mappend = (<>)
564+
565+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
566+-- >>> printSQL expr
567+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
568+greatest
569+ :: Expression outer grp commons schemas params from (nullty)
570+ -- ^ needs at least 1 argument
571+ -> [Expression outer grp commons schemas params from (nullty)]
572+ -- ^ or more
573+ -> Expression outer grp commons schemas params from (nullty)
574+greatest x xs = UnsafeExpression $ "GREATEST("
575+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
576+
577+-- | >>> printSQL $ least currentTimestamp [null_]
578+-- LEAST(CURRENT_TIMESTAMP, NULL)
579+least
580+ :: Expression outer grp commons schemas params from (nullty)
581+ -- ^ needs at least 1 argument
582+ -> [Expression outer grp commons schemas params from (nullty)]
583+ -- ^ or more
584+ -> Expression outer grp commons schemas params from (nullty)
585+least x xs = UnsafeExpression $ "LEAST("
586+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
587+
315588-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316589-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
590+unsafeBinaryOp
591+ :: ByteString
592+ -- ^ operator
593+ -> Expression outer grp commons schemas params from (ty0)
594+ -> Expression outer grp commons schemas params from (ty1)
595+ -> Expression outer grp commons schemas params from (ty2)
318596unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319597 renderSQL x <+> op <+> renderSQL y
320598
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
599+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329600-- (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
601+unsafeUnaryOp
602+ :: ByteString
603+ -- ^ operator
604+ -> Expression outer grp commons schemas params from (ty0)
605+ -> Expression outer grp commons schemas params from (ty1)
606+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
607+ op <+> renderSQL x
351608
352609-- | >>> printSQL $ unsafeFunction "f" true
353610-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
611+unsafeFunction
612+ :: ByteString
613+ -- ^ function
614+ -> Expression outer grp commons schemas params from (xty)
615+ -> Expression outer grp commons schemas params from (yty)
355616unsafeFunction fun x = UnsafeExpression $
356617 fun <> parenthesized (renderSQL x)
357618
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)
369−
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
619+-- | Helper for defining variadic functions.
620+unsafeVariadicFunction
621+ :: SListI elems
622+ => ByteString
623+ -- ^ function
624+ -> NP (Expression outer grp commons schemas params from) elems
625+ -> Expression outer grp commons schemas params from ret
626+unsafeVariadicFunction fun x = UnsafeExpression $
627+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
377628
378629instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
630+ => Num (Expression outer grp commons schemas params from (nullity ty)) where
380631 (+) = unsafeBinaryOp "+"
381632 (-) = unsafeBinaryOp "-"
382633 (*) = unsafeBinaryOp "*"
@@ -388,7 +639,7 @@ instance ty `In` PGNum
388639 . show
389640
390641instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
642+ (Expression outer grp commons schemas params from (nullity ty)) where
392643 (/) = unsafeBinaryOp "/"
393644 fromRational
394645 = UnsafeExpression
@@ -398,7 +649,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398649 . fromRat @Double
399650
400651instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
652+ (Expression outer grp commons schemas params from (nullity ty)) where
402653 pi = UnsafeExpression "pi()"
403654 exp = unsafeFunction "exp"
404655 log = unsafeFunction "ln"
@@ -419,54 +670,1748 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419670 acosh x = log (x + sqrt (x*x - 1))
420671 atanh x = log ((1 + x) / (1 - x)) / 2
421672
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)
673+-- | >>> :{
674+-- let
675+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
676+-- expression = atan2_ pi 2
677+-- in printSQL expression
678+-- :}
679+-- atan2(pi(), 2)
680+atan2_
681+ :: float `In` PGFloating
682+ => Expression outer grp commons schemas params from (nullity float)
683+ -- ^ numerator
684+ -> Expression outer grp commons schemas params from (nullity float)
685+ -- ^ denominator
686+ -> Expression outer grp commons schemas params from (nullity float)
687+atan2_ y x = UnsafeExpression $
688+ "atan2(" <> renderSQL y <> ", " <> renderSQL x <> ")"
689+
690+-- When a `cast` is applied to an `Expression` of a known type, it
691+-- represents a run-time type conversion. The cast will succeed only if a
692+-- suitable type conversion operation has been defined.
693+--
694+-- | >>> printSQL $ true & cast int4
695+-- (TRUE :: int4)
696+cast
697+ :: TypeExpression schemas ty1
698+ -- ^ type to cast as
699+ -> Expression outer grp commons schemas params from ty0
700+ -- ^ value to convert
701+ -> Expression outer grp commons schemas params from ty1
702+cast ty x = UnsafeExpression $ parenthesized $
703+ renderSQL x <+> "::" <+> renderSQL ty
704+
705+-- | integer division, truncates the result
706+--
707+-- >>> :{
708+-- let
709+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
710+-- expression = 5 `quot_` 2
711+-- in printSQL expression
712+-- :}
713+-- (5 / 2)
714+quot_
715+ :: int `In` PGIntegral
716+ => Expression outer grp commons schemas params from (nullity int)
717+ -- ^ numerator
718+ -> Expression outer grp commons schemas params from (nullity int)
719+ -- ^ denominator
720+ -> Expression outer grp commons schemas params from (nullity int)
721+quot_ = unsafeBinaryOp "/"
722+
723+-- | remainder upon integer division
724+--
725+-- >>> :{
726+-- let
727+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
728+-- expression = 5 `rem_` 2
729+-- in printSQL expression
730+-- :}
731+-- (5 % 2)
732+rem_
733+ :: int `In` PGIntegral
734+ => Expression outer grp commons schemas params from (nullity int)
735+ -- ^ numerator
736+ -> Expression outer grp commons schemas params from (nullity int)
737+ -- ^ denominator
738+ -> Expression outer grp commons schemas params from (nullity int)
739+rem_ = unsafeBinaryOp "%"
740+
741+-- | >>> :{
742+-- let
743+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
744+-- expression = trunc pi
745+-- in printSQL expression
746+-- :}
747+-- trunc(pi())
748+trunc
749+ :: frac `In` PGFloating
750+ => Expression outer grp commons schemas params from (nullity frac)
751+ -- ^ fractional number
752+ -> Expression outer grp commons schemas params from (nullity frac)
753+trunc = unsafeFunction "trunc"
754+
755+-- | >>> :{
756+-- let
757+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
758+-- expression = round_ pi
759+-- in printSQL expression
760+-- :}
761+-- round(pi())
762+round_
763+ :: frac `In` PGFloating
764+ => Expression outer grp commons schemas params from (nullity frac)
765+ -- ^ fractional number
766+ -> Expression outer grp commons schemas params from (nullity frac)
767+round_ = unsafeFunction "round"
768+
769+-- | >>> :{
770+-- let
771+-- expression :: Expression outer grp commons schemas params from (nullity 'PGfloat4)
772+-- expression = ceiling_ pi
773+-- in printSQL expression
774+-- :}
775+-- ceiling(pi())
776+ceiling_
777+ :: frac `In` PGFloating
778+ => Expression outer grp commons schemas params from (nullity frac)
779+ -- ^ fractional number
780+ -> Expression outer grp commons schemas params from (nullity frac)
781+ceiling_ = unsafeFunction "ceiling"
782+
783+-- | A `Condition` is an `Expression`, which can evaluate
784+-- to `true`, `false` or `null_`. This is because SQL uses
785+-- a three valued logic.
786+type Condition outer grp commons schemas params from =
787+ Expression outer grp commons schemas params from ('Null 'PGbool)
788+
789+-- | >>> printSQL true
790+-- TRUE
791+true :: Expression outer grp commons schemas params from (nullity 'PGbool)
792+true = UnsafeExpression "TRUE"
793+
794+-- | >>> printSQL false
795+-- FALSE
796+false :: Expression outer grp commons schemas params from (nullity 'PGbool)
797+false = UnsafeExpression "FALSE"
798+
799+-- | >>> printSQL $ not_ true
800+-- (NOT TRUE)
801+not_
802+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
803+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
804+not_ = unsafeUnaryOp "NOT"
805+
806+-- | >>> printSQL $ true .&& false
807+-- (TRUE AND FALSE)
808+(.&&)
809+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
810+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
811+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
812+infixr 3 .&&
813+(.&&) = unsafeBinaryOp "AND"
814+
815+-- | >>> printSQL $ true .|| false
816+-- (TRUE OR FALSE)
817+(.||)
818+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
819+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
820+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
821+infixr 2 .||
822+(.||) = unsafeBinaryOp "OR"
823+
824+-- | >>> :{
825+-- let
826+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
827+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
828+-- in printSQL expression
829+-- :}
830+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
831+caseWhenThenElse
832+ :: [ ( Condition outer grp commons schemas params from
833+ , Expression outer grp commons schemas params from ty
834+ ) ]
835+ -- ^ whens and thens
836+ -> Expression outer grp commons schemas params from ty
837+ -- ^ else
838+ -> Expression outer grp commons schemas params from ty
839+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
840+ [ "CASE"
841+ , mconcat
842+ [ mconcat
843+ [ " WHEN ", renderSQL when_
844+ , " THEN ", renderSQL then_
845+ ]
846+ | (when_,then_) <- whenThens
847+ ]
848+ , " ELSE ", renderSQL else_
849+ , " END"
850+ ]
851+
852+-- | >>> :{
853+-- let
854+-- expression :: Expression outer grp commons schemas params from (nullity 'PGint2)
855+-- expression = ifThenElse true 1 0
856+-- in printSQL expression
857+-- :}
858+-- CASE WHEN TRUE THEN 1 ELSE 0 END
859+ifThenElse
860+ :: Condition outer grp commons schemas params from
861+ -> Expression outer grp commons schemas params from ty -- ^ then
862+ -> Expression outer grp commons schemas params from ty -- ^ else
863+ -> Expression outer grp commons schemas params from ty
864+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
865+
866+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
867+-- will produce @NULL@s if one of their arguments is @NULL@.
868+--
869+-- >>> printSQL $ true .== null_
870+-- (TRUE = NULL)
871+(.==)
872+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
873+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
874+ -> Condition outer grp commons schemas params from
875+(.==) = unsafeBinaryOp "="
876+infix 4 .==
877+
878+-- | >>> printSQL $ true ./= null_
879+-- (TRUE <> NULL)
880+(./=)
881+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
882+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
883+ -> Condition outer grp commons schemas params from
884+(./=) = unsafeBinaryOp "<>"
885+infix 4 ./=
886+
887+-- | >>> printSQL $ true .>= null_
888+-- (TRUE >= NULL)
889+(.>=)
890+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
891+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
892+ -> Condition outer grp commons schemas params from
893+(.>=) = unsafeBinaryOp ">="
894+infix 4 .>=
895+
896+-- | >>> printSQL $ true .< null_
897+-- (TRUE < NULL)
898+(.<)
899+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
900+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
901+ -> Condition outer grp commons schemas params from
902+(.<) = unsafeBinaryOp "<"
903+infix 4 .<
904+
905+-- | >>> printSQL $ true .<= null_
906+-- (TRUE <= NULL)
907+(.<=)
908+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
909+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
910+ -> Condition outer grp commons schemas params from
911+(.<=) = unsafeBinaryOp "<="
912+infix 4 .<=
913+
914+-- | >>> printSQL $ true .> null_
915+-- (TRUE > NULL)
916+(.>)
917+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
918+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
919+ -> Condition outer grp commons schemas params from
920+(.>) = unsafeBinaryOp ">"
921+infix 4 .>
922+
923+-- | >>> printSQL currentDate
924+-- CURRENT_DATE
925+currentDate
926+ :: Expression outer grp commons schemas params from (nullity 'PGdate)
927+currentDate = UnsafeExpression "CURRENT_DATE"
928+
929+-- | >>> printSQL currentTime
930+-- CURRENT_TIME
931+currentTime
932+ :: Expression outer grp commons schemas params from (nullity 'PGtimetz)
933+currentTime = UnsafeExpression "CURRENT_TIME"
934+
935+-- | >>> printSQL currentTimestamp
936+-- CURRENT_TIMESTAMP
937+currentTimestamp
938+ :: Expression outer grp commons schemas params from (nullity 'PGtimestamptz)
939+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
940+
941+-- | >>> printSQL localTime
942+-- LOCALTIME
943+localTime
944+ :: Expression outer grp commons schemas params from (nullity 'PGtime)
945+localTime = UnsafeExpression "LOCALTIME"
946+
947+-- | >>> printSQL localTimestamp
948+-- LOCALTIMESTAMP
949+localTimestamp
950+ :: Expression outer grp commons schemas params from (nullity 'PGtimestamp)
951+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
952+
953+{-----------------------------------------
954+text
955+-----------------------------------------}
438956
439957instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
958+ (Expression outer grp commons schemas params from (nullity 'PGtext)) where
441959 fromString str = UnsafeExpression $
442960 "E\'" <> fromString (escape =<< str) <> "\'"
443−instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
446− "E\'" <> fromString (escape =<< str) <> "\'"
447−instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
450− "E\'" <> fromString (escape =<< str) <> "\'"
961+ where
962+ escape = \case
963+ '\NUL' -> "\\0"
964+ '\'' -> "''"
965+ '"' -> "\\\""
966+ '\b' -> "\\b"
967+ '\n' -> "\\n"
968+ '\r' -> "\\r"
969+ '\t' -> "\\t"
970+ '\\' -> "\\\\"
971+ c -> [c]
451972
452973instance Semigroup
453− (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
454− (<>) = unsafeBinaryOp "||"
455−instance Semigroup
456− (Expression outer commons grp schemas params from (null 'PGjsonb)) where
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
974+ (Expression outer grp commons schemas params from (nullity 'PGtext)) where
463975 (<>) = unsafeBinaryOp "||"
464976
465977instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
467− mempty = fromString ""
468− mappend = (<>)
469−instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
978+ (Expression outer grp commons schemas params from (nullity 'PGtext)) where
471979 mempty = fromString ""
472980 mappend = (<>)
981+
982+-- | >>> printSQL $ lower "ARRRGGG"
983+-- lower(E'ARRRGGG')
984+lower
985+ :: Expression outer grp commons schemas params from (nullity 'PGtext)
986+ -- ^ string to lower case
987+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
988+lower = unsafeFunction "lower"
989+
990+-- | >>> printSQL $ upper "eeee"
991+-- upper(E'eeee')
992+upper
993+ :: Expression outer grp commons schemas params from (nullity 'PGtext)
994+ -- ^ string to upper case
995+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
996+upper = unsafeFunction "upper"
997+
998+-- | >>> printSQL $ charLength "four"
999+-- char_length(E'four')
1000+charLength
1001+ :: Expression outer grp commons schemas params from (nullity 'PGtext)
1002+ -- ^ string to measure
1003+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
1004+charLength = unsafeFunction "char_length"
1005+
1006+-- | The `like` expression returns true if the @string@ matches
1007+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1008+-- or underscores, then the pattern only represents the string itself;
1009+-- in that case `like` acts like the equals operator. An underscore (_)
1010+-- in pattern stands for (matches) any single character; a percent sign (%)
1011+-- matches any sequence of zero or more characters.
1012+--
1013+-- >>> printSQL $ "abc" `like` "a%"
1014+-- (E'abc' LIKE E'a%')
1015+like
1016+ :: Expression outer grp commons schemas params from (nullity 'PGtext)
1017+ -- ^ string
1018+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1019+ -- ^ pattern
1020+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
1021+like = unsafeBinaryOp "LIKE"
1022+
1023+-- | The key word ILIKE can be used instead of LIKE to make the
1024+-- match case-insensitive according to the active locale.
1025+--
1026+-- >>> printSQL $ "abc" `ilike` "a%"
1027+-- (E'abc' ILIKE E'a%')
1028+ilike
1029+ :: Expression outer grp commons schemas params from (nullity 'PGtext)
1030+ -- ^ string
1031+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1032+ -- ^ pattern
1033+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
1034+ilike = unsafeBinaryOp "ILIKE"
1035+
1036+{-----------------------------------------
1037+ -- json and jsonb support
1038+
1039+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1040+comments lifted directly from this page.
1041+
1042+Table 9.44: json and jsonb operators
1043+-----------------------------------------}
1044+
1045+-- | Get JSON value (object field or array element) at a key.
1046+(.->)
1047+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1048+ => Expression outer grp commons schemas params from (nullity json)
1049+ -> Expression outer grp commons schemas params from (nullity key)
1050+ -> Expression outer grp commons schemas params from ('Null json)
1051+infixl 8 .->
1052+(.->) = unsafeBinaryOp "->"
1053+
1054+-- | Get JSON value (object field or array element) at a key, as text.
1055+(.->>)
1056+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1057+ => Expression outer grp commons schemas params from (nullity json)
1058+ -> Expression outer grp commons schemas params from (nullity key)
1059+ -> Expression outer grp commons schemas params from ('Null 'PGtext)
1060+infixl 8 .->>
1061+(.->>) = unsafeBinaryOp "->>"
1062+
1063+-- | Get JSON value at a specified path.
1064+(.#>)
1065+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1066+ => Expression outer grp commons schemas params from (nullity json)
1067+ -> Expression outer grp commons schemas params from (nullity path)
1068+ -> Expression outer grp commons schemas params from ('Null json)
1069+infixl 8 .#>
1070+(.#>) = unsafeBinaryOp "#>"
1071+
1072+-- | Get JSON value at a specified path as text.
1073+(.#>>)
1074+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1075+ => Expression outer grp commons schemas params from (nullity json)
1076+ -> Expression outer grp commons schemas params from (nullity path)
1077+ -> Expression outer grp commons schemas params from ('Null 'PGtext)
1078+infixl 8 .#>>
1079+(.#>>) = unsafeBinaryOp "#>>"
1080+
1081+-- Additional jsonb operators
1082+
1083+-- | Does the left JSON value contain the right JSON path/value entries at the
1084+-- top level?
1085+(.@>)
1086+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1087+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1088+ -> Condition outer grp commons schemas params from
1089+infixl 9 .@>
1090+(.@>) = unsafeBinaryOp "@>"
1091+
1092+-- | Are the left JSON path/value entries contained at the top level within the
1093+-- right JSON value?
1094+(.<@)
1095+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1096+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1097+ -> Condition outer grp commons schemas params from
1098+infixl 9 .<@
1099+(.<@) = unsafeBinaryOp "<@"
1100+
1101+-- | Does the string exist as a top-level key within the JSON value?
1102+(.?)
1103+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1104+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1105+ -> Condition outer grp commons schemas params from
1106+infixl 9 .?
1107+(.?) = unsafeBinaryOp "?"
1108+
1109+-- | Do any of these array strings exist as top-level keys?
1110+(.?|)
1111+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1112+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1113+ -> Condition outer grp commons schemas params from
1114+infixl 9 .?|
1115+(.?|) = unsafeBinaryOp "?|"
1116+
1117+-- | Do all of these array strings exist as top-level keys?
1118+(.?&)
1119+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1120+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1121+ -> Condition outer grp commons schemas params from
1122+infixl 9 .?&
1123+(.?&) = unsafeBinaryOp "?&"
1124+
1125+-- | Concatenate two jsonb values into a new jsonb value.
1126+instance Semigroup
1127+ (Expression outer grp commons schemas params from (nullity 'PGjsonb)) where
1128+ (<>) = unsafeBinaryOp "||"
1129+
1130+-- | Delete a key or keys from a JSON object, or remove an array element.
1131+--
1132+-- If the right operand is..
1133+--
1134+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1135+-- are matched based on their key value.
1136+--
1137+-- @ text[] @: Delete multiple key/value pairs or string elements
1138+-- from left operand. Key/value pairs are matched based on their key value.
1139+--
1140+-- @ integer @: Delete the array element with specified index (Negative integers
1141+-- count from the end). Throws an error if top level container is not an array.
1142+(.-.)
1143+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1144+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1145+ -> Expression outer grp commons schemas params from (nullity key)
1146+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1147+infixl 6 .-.
1148+(.-.) = unsafeBinaryOp "-"
1149+
1150+-- | Delete the field or element with specified path (for JSON arrays, negative
1151+-- integers count from the end)
1152+(#-.)
1153+ :: PGTextArray "(#-.)" arrayty
1154+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1155+ -> Expression outer grp commons schemas params from (nullity arrayty)
1156+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1157+infixl 6 #-.
1158+(#-.) = unsafeBinaryOp "#-"
1159+
1160+{-----------------------------------------
1161+Table 9.45: JSON creation functions
1162+-----------------------------------------}
1163+
1164+-- | Literal binary JSON
1165+jsonbLit
1166+ :: JSON.ToJSON x
1167+ => x -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1168+jsonbLit = cast jsonb . UnsafeExpression
1169+ . singleQuotedUtf8 . toStrict . JSON.encode
1170+
1171+-- | Literal JSON
1172+jsonLit
1173+ :: JSON.ToJSON x
1174+ => x -> Expression outer grp commons schemas params from (nullity 'PGjson)
1175+jsonLit = cast json . UnsafeExpression
1176+ . singleQuotedUtf8 . toStrict . JSON.encode
1177+
1178+-- | Returns the value as json. Arrays and composites are converted
1179+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1180+-- type to json, the cast function will be used to perform the conversion;
1181+-- otherwise, a scalar value is produced. For any scalar type other than a
1182+-- number, a Boolean, or a null value, the text representation will be used, in
1183+-- such a fashion that it is a valid json value.
1184+toJson
1185+ :: Expression outer grp commons schemas params from (nullity ty)
1186+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1187+toJson = unsafeFunction "to_json"
1188+
1189+-- | Returns the value as jsonb. Arrays and composites are converted
1190+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1191+-- type to json, the cast function will be used to perform the conversion;
1192+-- otherwise, a scalar value is produced. For any scalar type other than a
1193+-- number, a Boolean, or a null value, the text representation will be used, in
1194+-- such a fashion that it is a valid jsonb value.
1195+toJsonb
1196+ :: Expression outer grp commons schemas params from (nullity ty)
1197+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1198+toJsonb = unsafeFunction "to_jsonb"
1199+
1200+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1201+-- becomes a JSON array of arrays.
1202+arrayToJson
1203+ :: PGArray "arrayToJson" arr
1204+ => Expression outer grp commons schemas params from (nullity arr)
1205+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1206+arrayToJson = unsafeFunction "array_to_json"
1207+
1208+-- | Returns the row as a JSON object.
1209+rowToJson
1210+ :: Expression outer grp commons schemas params from (nullity ('PGcomposite ty))
1211+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1212+rowToJson = unsafeFunction "row_to_json"
1213+
1214+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1215+-- argument list.
1216+jsonBuildArray
1217+ :: SListI elems
1218+ => NP (Expression outer grp commons schemas params from) elems
1219+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1220+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1221+
1222+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1223+-- variadic argument list.
1224+jsonbBuildArray
1225+ :: SListI elems
1226+ => NP (Expression outer grp commons schemas params from) elems
1227+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1228+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1229+
1230+unsafeRowFunction
1231+ :: SOP.SListI elems
1232+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1233+ -> [ByteString]
1234+unsafeRowFunction =
1235+ (`appEndo` []) . hcfoldMap (Proxy :: SOP.Proxy SOP.Top)
1236+ (\(col `As` name) -> Endo $ \xs ->
1237+ renderAliasString name : renderSQL col : xs)
1238+ where
1239+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1240+ renderAliasString = singleQuotedText . fromString . symbolVal
1241+
1242+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1243+-- argument list. The elements of the argument list must alternate between text
1244+-- and values.
1245+jsonBuildObject
1246+ :: SOP.SListI elems
1247+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1248+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1249+jsonBuildObject
1250+ = unsafeFunction "json_build_object"
1251+ . UnsafeExpression
1252+ . commaSeparated
1253+ . unsafeRowFunction
1254+
1255+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1256+-- variadic argument list. The elements of the argument list must alternate
1257+-- between text and values.
1258+jsonbBuildObject
1259+ :: SOP.SListI elems
1260+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1261+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1262+jsonbBuildObject
1263+ = unsafeFunction "jsonb_build_object"
1264+ . UnsafeExpression
1265+ . commaSeparated
1266+ . unsafeRowFunction
1267+
1268+-- | Builds a JSON object out of a text array. The array must have either
1269+-- exactly one dimension with an even number of members, in which case they are
1270+-- taken as alternating key/value pairs, or two dimensions such that each inner
1271+-- array has exactly two elements, which are taken as a key/value pair.
1272+jsonObject
1273+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1274+ => Expression outer grp commons schemas params from (nullity arr)
1275+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1276+jsonObject = unsafeFunction "json_object"
1277+
1278+-- | Builds a binary JSON object out of a text array. The array must have either
1279+-- exactly one dimension with an even number of members, in which case they are
1280+-- taken as alternating key/value pairs, or two dimensions such that each inner
1281+-- array has exactly two elements, which are taken as a key/value pair.
1282+jsonbObject
1283+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1284+ => Expression outer grp commons schemas params from (nullity arr)
1285+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1286+jsonbObject = unsafeFunction "jsonb_object"
1287+
1288+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1289+-- keys and one for values, that are zipped pairwise to create a JSON object.
1290+jsonZipObject
1291+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1292+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1293+ => Expression outer grp commons schemas params from (nullity keysArray)
1294+ -> Expression outer grp commons schemas params from (nullity valuesArray)
1295+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1296+jsonZipObject ks vs =
1297+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1298+
1299+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1300+-- keys and one for values, that are zipped pairwise to create a binary JSON
1301+-- object.
1302+jsonbZipObject
1303+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1304+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1305+ => Expression outer grp commons schemas params from (nullity keysArray)
1306+ -> Expression outer grp commons schemas params from (nullity valuesArray)
1307+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1308+jsonbZipObject ks vs =
1309+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1310+
1311+{-----------------------------------------
1312+Table 9.46: JSON processing functions
1313+-----------------------------------------}
1314+
1315+-- | Returns the number of elements in the outermost JSON array.
1316+jsonArrayLength
1317+ :: Expression outer grp commons schemas params from (nullity 'PGjson)
1318+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
1319+jsonArrayLength = unsafeFunction "json_array_length"
1320+
1321+-- | Returns the number of elements in the outermost binary JSON array.
1322+jsonbArrayLength
1323+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1324+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
1325+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1326+
1327+-- | Returns JSON value pointed to by the given path (equivalent to #>
1328+-- operator).
1329+jsonExtractPath
1330+ :: SListI elems
1331+ => Expression outer grp commons schemas params from (nullity 'PGjson)
1332+ -> NP (Expression outer grp commons schemas params from) elems
1333+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1334+jsonExtractPath x xs =
1335+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1336+
1337+-- | Returns JSON value pointed to by the given path (equivalent to #>
1338+-- operator).
1339+jsonbExtractPath
1340+ :: SListI elems
1341+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1342+ -> NP (Expression outer grp commons schemas params from) elems
1343+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1344+jsonbExtractPath x xs =
1345+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1346+
1347+-- | Returns JSON value pointed to by the given path (equivalent to #>
1348+-- operator), as text.
1349+jsonExtractPathAsText
1350+ :: SListI elems
1351+ => Expression outer grp commons schemas params from (nullity 'PGjson)
1352+ -> NP (Expression outer grp commons schemas params from) elems
1353+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1354+jsonExtractPathAsText x xs =
1355+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1356+
1357+-- | Returns JSON value pointed to by the given path (equivalent to #>
1358+-- operator), as text.
1359+jsonbExtractPathAsText
1360+ :: SListI elems
1361+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1362+ -> NP (Expression outer grp commons schemas params from) elems
1363+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1364+jsonbExtractPathAsText x xs =
1365+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1366+
1367+-- | Returns the type of the outermost JSON value as a text string. Possible
1368+-- types are object, array, string, number, boolean, and null.
1369+jsonTypeof
1370+ :: Expression outer grp commons schemas params from (nullity 'PGjson)
1371+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1372+jsonTypeof = unsafeFunction "json_typeof"
1373+
1374+-- | Returns the type of the outermost binary JSON value as a text string.
1375+-- Possible types are object, array, string, number, boolean, and null.
1376+jsonbTypeof
1377+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1378+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1379+jsonbTypeof = unsafeFunction "jsonb_typeof"
1380+
1381+-- | Returns its argument with all object fields that have null values omitted.
1382+-- Other null values are untouched.
1383+jsonStripNulls
1384+ :: Expression outer grp commons schemas params from (nullity 'PGjson)
1385+ -> Expression outer grp commons schemas params from (nullity 'PGjson)
1386+jsonStripNulls = unsafeFunction "json_strip_nulls"
1387+
1388+-- | Returns its argument with all object fields that have null values omitted.
1389+-- Other null values are untouched.
1390+jsonbStripNulls
1391+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1392+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1393+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1394+
1395+-- | @ jsonbSet target path new_value create_missing @
1396+--
1397+-- Returns target with the section designated by path replaced by new_value,
1398+-- or with new_value added if create_missing is true ( default is true) and the
1399+-- item designated by path does not exist. As with the path orientated
1400+-- operators, negative integers that appear in path count from the end of JSON
1401+-- arrays.
1402+jsonbSet
1403+ :: PGTextArray "jsonbSet" arr
1404+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1405+ -> Expression outer grp commons schemas params from (nullity arr)
1406+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1407+ -> Maybe (Expression outer grp commons schemas params from (nullity 'PGbool))
1408+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1409+jsonbSet tgt path val createMissing = case createMissing of
1410+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1411+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1412+
1413+-- | @ jsonbInsert target path new_value insert_after @
1414+--
1415+-- Returns target with new_value inserted. If target section designated by
1416+-- path is in a JSONB array, new_value will be inserted before target or after
1417+-- if insert_after is true (default is false). If target section designated by
1418+-- path is in JSONB object, new_value will be inserted only if target does not
1419+-- exist. As with the path orientated operators, negative integers that appear
1420+-- in path count from the end of JSON arrays.
1421+jsonbInsert
1422+ :: PGTextArray "jsonbInsert" arr
1423+ => Expression outer grp commons schemas params from (nullity 'PGjsonb)
1424+ -> Expression outer grp commons schemas params from (nullity arr)
1425+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1426+ -> Maybe (Expression outer grp commons schemas params from (nullity 'PGbool))
1427+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1428+jsonbInsert tgt path val insertAfter = case insertAfter of
1429+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1430+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1431+
1432+-- | Returns its argument as indented JSON text.
1433+jsonbPretty
1434+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1435+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1436+jsonbPretty = unsafeFunction "jsonb_pretty"
1437+
1438+{-----------------------------------------
1439+aggregation
1440+-----------------------------------------}
1441+
1442+{- |
1443+`Aggregate` functions compute a single result from a set of input values.
1444+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1445+as `WindowFunction`s.
1446+-}
1447+class Aggregate expr1 expr2 aggr
1448+ | aggr -> expr1, aggr -> expr2 where
1449+
1450+ -- | A special aggregation that does not require an input
1451+ --
1452+ -- >>> :{
1453+ -- let
1454+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1455+ -- expression = countStar
1456+ -- in printSQL expression
1457+ -- :}
1458+ -- count(*)
1459+ countStar :: aggr ('NotNull 'PGint8)
1460+
1461+ -- | >>> :{
1462+ -- let
1463+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1464+ -- expression = count (All #col)
1465+ -- in printSQL expression
1466+ -- :}
1467+ -- count(ALL "col")
1468+ count
1469+ :: expr1 ty
1470+ -- ^ what to count
1471+ -> aggr ('NotNull 'PGint8)
1472+
1473+ -- | >>> :{
1474+ -- let
1475+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1476+ -- expression = sum_ (Distinct #col)
1477+ -- in printSQL expression
1478+ -- :}
1479+ -- sum(DISTINCT "col")
1480+ sum_
1481+ :: ty `In` PGNum
1482+ => expr1 (nullity ty)
1483+ -> aggr ('NotNull ty)
1484+
1485+ -- | input values, including nulls, concatenated into an array
1486+ arrayAgg
1487+ :: expr1 ty
1488+ -> aggr ('Null ('PGvararray ty))
1489+
1490+ -- | aggregates values as a JSON array
1491+ jsonAgg
1492+ :: expr1 ty
1493+ -> aggr ('Null 'PGjson)
1494+
1495+ -- | aggregates values as a JSON array
1496+ jsonbAgg
1497+ :: expr1 ty
1498+ -> aggr ('Null 'PGjsonb)
1499+
1500+ {- |
1501+ the bitwise AND of all non-null input values, or null if none
1502+ >>> :{
1503+ let
1504+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] ('Null 'PGint4)
1505+ expression = bitAnd (Distinct #col)
1506+ in printSQL expression
1507+ :}
1508+ bit_and(DISTINCT "col")
1509+ -}
1510+ bitAnd
1511+ :: int `In` PGIntegral
1512+ => expr1 (nullity int)
1513+ -- ^ what to aggregate
1514+ -> aggr ('Null int)
1515+
1516+ {- |
1517+ the bitwise OR of all non-null input values, or null if none
1518+
1519+ >>> :{
1520+ let
1521+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] ('Null 'PGint4)
1522+ expression = bitOr (All #col)
1523+ in printSQL expression
1524+ :}
1525+ bit_or(ALL "col")
1526+ -}
1527+ bitOr
1528+ :: int `In` PGIntegral
1529+ => expr1 (nullity int)
1530+ -- ^ what to aggregate
1531+ -> aggr ('Null int)
1532+
1533+ {- |
1534+ true if all input values are true, otherwise false
1535+
1536+ >>> :{
1537+ let
1538+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] ('Null 'PGbool)
1539+ winFun = boolAnd #col
1540+ in printSQL winFun
1541+ :}
1542+ bool_and("col")
1543+ -}
1544+ boolAnd
1545+ :: expr1 (nullity 'PGbool)
1546+ -- ^ what to aggregate
1547+ -> aggr ('Null 'PGbool)
1548+
1549+ {- |
1550+ true if at least one input value is true, otherwise false
1551+
1552+ >>> :{
1553+ let
1554+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] ('Null 'PGbool)
1555+ expression = boolOr (All #col)
1556+ in printSQL expression
1557+ :}
1558+ bool_or(ALL "col")
1559+ -}
1560+ boolOr
1561+ :: expr1(nullity 'PGbool)
1562+ -- ^ what to aggregate
1563+ -> aggr ('Null 'PGbool)
1564+
1565+ {- |
1566+ equivalent to `boolAnd`
1567+
1568+ >>> :{
1569+ let
1570+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] ('Null 'PGbool)
1571+ expression = every (Distinct #col)
1572+ in printSQL expression
1573+ :}
1574+ every(DISTINCT "col")
1575+ -}
1576+ every
1577+ :: expr1 (nullity 'PGbool)
1578+ -- ^ what to aggregate
1579+ -> aggr ('Null 'PGbool)
1580+
1581+ {- |maximum value of expression across all input values-}
1582+ max_
1583+ :: expr1 (nullity ty)
1584+ -- ^ what to maximize
1585+ -> aggr ('Null ty)
1586+
1587+ -- | minimum value of expression across all input values
1588+ min_
1589+ :: expr1 (nullity ty)
1590+ -- ^ what to minimize
1591+ -> aggr ('Null ty)
1592+
1593+ -- | the average (arithmetic mean) of all input values
1594+ avg
1595+ :: expr1 (nullity ty)
1596+ -- ^ what to average
1597+ -> aggr ('Null (PGAvg ty))
1598+
1599+ {- | correlation coefficient
1600+ >>> :{
1601+ let
1602+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1603+ expression = corr (All (#y :*: #x))
1604+ in printSQL expression
1605+ :}
1606+ corr(ALL "y", "x")
1607+ -}
1608+ corr
1609+ :: expr2 (nullity 'PGfloat8)
1610+ -> aggr ('Null 'PGfloat8)
1611+
1612+ {- | population covariance
1613+ >>> :{
1614+ let
1615+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1616+ expression = covarPop (All (#y :*: #x))
1617+ in printSQL expression
1618+ :}
1619+ covar_pop(ALL "y", "x")
1620+ -}
1621+ covarPop
1622+ :: expr2 (nullity 'PGfloat8)
1623+ -> aggr ('Null 'PGfloat8)
1624+
1625+ {- | sample covariance
1626+ >>> :{
1627+ let
1628+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1629+ winFun = covarSamp (#y :*: #x)
1630+ in printSQL winFun
1631+ :}
1632+ covar_samp("y", "x")
1633+ -}
1634+ covarSamp
1635+ :: expr2 (nullity 'PGfloat8)
1636+ -> aggr ('Null 'PGfloat8)
1637+
1638+ {- | average of the independent variable (sum(X)/N)
1639+ >>> :{
1640+ let
1641+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1642+ expression = regrAvgX (All (#y :*: #x))
1643+ in printSQL expression
1644+ :}
1645+ regr_avgx(ALL "y", "x")
1646+ -}
1647+ regrAvgX
1648+ :: expr2 (nullity 'PGfloat8)
1649+ -> aggr ('Null 'PGfloat8)
1650+
1651+ {- | average of the dependent variable (sum(Y)/N)
1652+ >>> :{
1653+ let
1654+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1655+ winFun = regrAvgY (#y :*: #x)
1656+ in printSQL winFun
1657+ :}
1658+ regr_avgy("y", "x")
1659+ -}
1660+ regrAvgY
1661+ :: expr2 (nullity 'PGfloat8)
1662+ -> aggr ('Null 'PGfloat8)
1663+
1664+ {- | number of input rows in which both expressions are nonnull
1665+ >>> :{
1666+ let
1667+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1668+ winFun = regrCount (#y :*: #x)
1669+ in printSQL winFun
1670+ :}
1671+ regr_count("y", "x")
1672+ -}
1673+ regrCount
1674+ :: expr2 (nullity 'PGfloat8)
1675+ -> aggr ('Null 'PGint8)
1676+
1677+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1678+ >>> :{
1679+ let
1680+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1681+ expression = regrIntercept (All (#y :*: #x))
1682+ in printSQL expression
1683+ :}
1684+ regr_intercept(ALL "y", "x")
1685+ -}
1686+ regrIntercept
1687+ :: expr2 (nullity 'PGfloat8)
1688+ -> aggr ('Null 'PGfloat8)
1689+
1690+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1691+ regrR2
1692+ :: expr2 (nullity 'PGfloat8)
1693+ -> aggr ('Null 'PGfloat8)
1694+
1695+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1696+ -- determined by the (X, Y) pairs
1697+ regrSlope
1698+ :: expr2 (nullity 'PGfloat8)
1699+ -> aggr ('Null 'PGfloat8)
1700+
1701+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1702+ -- (“sum of squares” of the independent variable)
1703+ regrSxx
1704+ :: expr2 (nullity 'PGfloat8)
1705+ -> aggr ('Null 'PGfloat8)
1706+
1707+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1708+ -- (“sum of products” of independent times dependent variable)
1709+ regrSxy
1710+ :: expr2 (nullity 'PGfloat8)
1711+ -> aggr ('Null 'PGfloat8)
1712+
1713+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1714+ -- (“sum of squares” of the dependent variable)
1715+ regrSyy
1716+ :: expr2 (nullity 'PGfloat8)
1717+ -> aggr ('Null 'PGfloat8)
1718+
1719+ -- | historical alias for `stddevSamp`
1720+ stddev
1721+ :: expr1 (nullity ty)
1722+ -> aggr ('Null (PGAvg ty))
1723+
1724+ -- | population standard deviation of the input values
1725+ stddevPop
1726+ :: expr1 (nullity ty)
1727+ -> aggr ('Null (PGAvg ty))
1728+
1729+ -- | sample standard deviation of the input values
1730+ stddevSamp
1731+ :: expr1 (nullity ty)
1732+ -> aggr ('Null (PGAvg ty))
1733+
1734+ -- | historical alias for `varSamp`
1735+ variance
1736+ :: expr1 (nullity ty)
1737+ -> aggr ('Null (PGAvg ty))
1738+
1739+ -- | population variance of the input values
1740+ -- (square of the population standard deviation)
1741+ varPop
1742+ :: expr1 (nullity ty)
1743+ -> aggr ('Null (PGAvg ty))
1744+
1745+ -- | sample variance of the input values
1746+ -- (square of the sample standard deviation)
1747+ varSamp
1748+ :: expr1 (nullity ty)
1749+ -> aggr ('Null (PGAvg ty))
1750+
1751+{- |
1752+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1753+`All` invokes the aggregate once for each input row.
1754+`Distinct` invokes the aggregate once for each distinct value of the expression
1755+(or distinct set of values, for multiple expressions) found in the input
1756+-}
1757+data Distinction expr ty
1758+ = All (expr ty)
1759+ | Distinct (expr ty)
1760+ deriving (GHC.Generic,Show,Eq,Ord)
1761+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1762+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1763+ renderSQL = \case
1764+ All x -> "ALL" <+> renderSQL x
1765+ Distinct x -> "DISTINCT" <+> renderSQL x
1766+instance RenderSQL
1767+ (Distinction
1768+ ( Expression outer grp commons schemas params from
1769+ :*:
1770+ Expression outer grp commons schemas params from) xty ) where
1771+ renderSQL = \case
1772+ All (x :*: x') ->
1773+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1774+ Distinct (x :*: x') ->
1775+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1776+
1777+instance Aggregate
1778+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1779+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1780+ (Expression outer ('Grouped bys) commons schemas params from) where
1781+ countStar = UnsafeExpression "count(*)"
1782+ count = unsafeAggregate1 "count"
1783+ sum_ = unsafeAggregate1 "sum"
1784+ arrayAgg = unsafeAggregate1 "array_agg"
1785+ jsonAgg = unsafeAggregate1 "json_agg"
1786+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1787+ bitAnd = unsafeAggregate1 "bit_and"
1788+ bitOr = unsafeAggregate1 "bit_or"
1789+ boolAnd = unsafeAggregate1 "bool_and"
1790+ boolOr = unsafeAggregate1 "bool_or"
1791+ every = unsafeAggregate1 "every"
1792+ max_ = unsafeAggregate1 "max"
1793+ min_ = unsafeAggregate1 "min"
1794+ avg = unsafeAggregate1 "avg"
1795+ corr = unsafeAggregate2 "corr"
1796+ covarPop = unsafeAggregate2 "covar_pop"
1797+ covarSamp = unsafeAggregate2 "covar_samp"
1798+ regrAvgX = unsafeAggregate2 "regr_avgx"
1799+ regrAvgY = unsafeAggregate2 "regr_avgy"
1800+ regrCount = unsafeAggregate2 "regr_count"
1801+ regrIntercept = unsafeAggregate2 "regr_intercept"
1802+ regrR2 = unsafeAggregate2 "regr_r2"
1803+ regrSlope = unsafeAggregate2 "regr_slope"
1804+ regrSxx = unsafeAggregate2 "regr_sxx"
1805+ regrSxy = unsafeAggregate2 "regr_sxy"
1806+ regrSyy = unsafeAggregate2 "regr_syy"
1807+ stddev = unsafeAggregate1 "stddev"
1808+ stddevPop = unsafeAggregate1 "stddev_pop"
1809+ stddevSamp = unsafeAggregate1 "stddev_samp"
1810+ variance = unsafeAggregate1 "variance"
1811+ varPop = unsafeAggregate1 "var_pop"
1812+ varSamp = unsafeAggregate1 "var_samp"
1813+instance Aggregate
1814+ (Expression outer grp commons schemas params from)
1815+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1816+ (WindowFunction outer grp commons schemas params from) where
1817+ countStar = UnsafeWindowFunction "count(*)"
1818+ count = unsafeWindowFunction1 "count"
1819+ sum_ = unsafeWindowFunction1 "sum"
1820+ arrayAgg = unsafeWindowFunction1 "array_agg"
1821+ jsonAgg = unsafeWindowFunction1 "json_agg"
1822+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1823+ bitAnd = unsafeWindowFunction1 "bit_and"
1824+ bitOr = unsafeWindowFunction1 "bit_or"
1825+ boolAnd = unsafeWindowFunction1 "bool_and"
1826+ boolOr = unsafeWindowFunction1 "bool_or"
1827+ every = unsafeWindowFunction1 "every"
1828+ max_ = unsafeWindowFunction1 "max"
1829+ min_ = unsafeWindowFunction1 "min"
1830+ avg = unsafeWindowFunction1 "avg"
1831+ corr = unsafeWindowFunction2 "corr"
1832+ covarPop = unsafeWindowFunction2 "covar_pop"
1833+ covarSamp = unsafeWindowFunction2 "covar_samp"
1834+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1835+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1836+ regrCount = unsafeWindowFunction2 "regr_count"
1837+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1838+ regrR2 = unsafeWindowFunction2 "regr_r2"
1839+ regrSlope = unsafeWindowFunction2 "regr_slope"
1840+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1841+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1842+ regrSyy = unsafeWindowFunction2 "regr_syy"
1843+ stddev = unsafeWindowFunction1 "stddev"
1844+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1845+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1846+ variance = unsafeWindowFunction1 "variance"
1847+ varPop = unsafeWindowFunction1 "var_pop"
1848+ varSamp = unsafeWindowFunction1 "var_samp"
1849+
1850+-- | escape hatch to define aggregate functions
1851+unsafeAggregate1
1852+ :: ByteString -- ^ aggregate function
1853+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1854+ -> Expression outer ('Grouped bys) commons schemas params from yty
1855+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1856+ [fun, "(", renderSQL x, ")"]
1857+
1858+-- | escape hatch to define aggregate binary functions
1859+unsafeAggregate2
1860+ :: ByteString -- ^ aggregate function
1861+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1862+ -> Expression outer ('Grouped bys) commons schemas params from yty
1863+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1864+ [fun, "(", renderSQL xx, ")"]
1865+
1866+-- | A type family that calculates `PGAvg` type of a `PGType`.
1867+type family PGAvg ty where
1868+ PGAvg 'PGint2 = 'PGnumeric
1869+ PGAvg 'PGint4 = 'PGnumeric
1870+ PGAvg 'PGint8 = 'PGnumeric
1871+ PGAvg 'PGnumeric = 'PGnumeric
1872+ PGAvg 'PGfloat4 = 'PGfloat8
1873+ PGAvg 'PGfloat8 = 'PGfloat8
1874+ PGAvg 'PGinterval = 'PGinterval
1875+ PGAvg pg = TypeError
1876+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1877+
1878+{-----------------------------------------
1879+type expressions
1880+-----------------------------------------}
1881+
1882+-- | `TypeExpression`s are used in `cast`s and
1883+-- `Squeal.PostgreSQL.Definition.createTable` commands.
1884+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1885+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1886+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1887+instance RenderSQL (TypeExpression schemas ty) where
1888+ renderSQL = renderTypeExpression
1889+
1890+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1891+typedef
1892+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1893+ => QualifiedAlias sch td
1894+ -> TypeExpression schemas (nullity ty)
1895+typedef = UnsafeTypeExpression . renderSQL
1896+
1897+-- | The composite type corresponding to a `Table` definition can be expressed
1898+-- by its alias.
1899+typetable
1900+ :: (Has sch schemas schema, Has tab schema ('Table table))
1901+ => QualifiedAlias sch tab
1902+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1903+typetable = UnsafeTypeExpression . renderSQL
1904+
1905+-- | The composite type corresponding to a `View` definition can be expressed
1906+-- by its alias.
1907+typeview
1908+ :: (Has sch schemas schema, Has vw schema ('View view))
1909+ => QualifiedAlias sch vw
1910+ -> TypeExpression schemas (nullity ('PGcomposite view))
1911+typeview = UnsafeTypeExpression . renderSQL
1912+
1913+-- | logical Boolean (true/false)
1914+bool :: TypeExpression schemas (nullity 'PGbool)
1915+bool = UnsafeTypeExpression "bool"
1916+-- | signed two-byte integer
1917+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1918+int2 = UnsafeTypeExpression "int2"
1919+smallint = UnsafeTypeExpression "smallint"
1920+-- | signed four-byte integer
1921+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1922+int4 = UnsafeTypeExpression "int4"
1923+int = UnsafeTypeExpression "int"
1924+integer = UnsafeTypeExpression "integer"
1925+-- | signed eight-byte integer
1926+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1927+int8 = UnsafeTypeExpression "int8"
1928+bigint = UnsafeTypeExpression "bigint"
1929+-- | arbitrary precision numeric type
1930+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1931+numeric = UnsafeTypeExpression "numeric"
1932+-- | single precision floating-point number (4 bytes)
1933+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1934+float4 = UnsafeTypeExpression "float4"
1935+real = UnsafeTypeExpression "real"
1936+-- | double precision floating-point number (8 bytes)
1937+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1938+float8 = UnsafeTypeExpression "float8"
1939+doublePrecision = UnsafeTypeExpression "double precision"
1940+-- | currency amount
1941+money :: TypeExpression schema (nullity 'PGmoney)
1942+money = UnsafeTypeExpression "money"
1943+-- | variable-length character string
1944+text :: TypeExpression schemas (nullity 'PGtext)
1945+text = UnsafeTypeExpression "text"
1946+-- | fixed-length character string
1947+char, character
1948+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1949+ => TypeExpression schemas (nullity ('PGchar n))
1950+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1951+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1952+-- | variable-length character string
1953+varchar, characterVarying
1954+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1955+ => TypeExpression schemas (nullity ('PGvarchar n))
1956+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1957+characterVarying = UnsafeTypeExpression $
1958+ "character varying(" <> renderNat @n <> ")"
1959+-- | binary data ("byte array")
1960+bytea :: TypeExpression schemas (nullity 'PGbytea)
1961+bytea = UnsafeTypeExpression "bytea"
1962+-- | date and time (no time zone)
1963+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1964+timestamp = UnsafeTypeExpression "timestamp"
1965+-- | date and time, including time zone
1966+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1967+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1968+-- | calendar date (year, month, day)
1969+date :: TypeExpression schemas (nullity 'PGdate)
1970+date = UnsafeTypeExpression "date"
1971+-- | time of day (no time zone)
1972+time :: TypeExpression schemas (nullity 'PGtime)
1973+time = UnsafeTypeExpression "time"
1974+-- | time of day, including time zone
1975+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1976+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1977+-- | time span
1978+interval :: TypeExpression schemas (nullity 'PGinterval)
1979+interval = UnsafeTypeExpression "interval"
1980+-- | universally unique identifier
1981+uuid :: TypeExpression schemas (nullity 'PGuuid)
1982+uuid = UnsafeTypeExpression "uuid"
1983+-- | IPv4 or IPv6 host address
1984+inet :: TypeExpression schemas (nullity 'PGinet)
1985+inet = UnsafeTypeExpression "inet"
1986+-- | textual JSON data
1987+json :: TypeExpression schemas (nullity 'PGjson)
1988+json = UnsafeTypeExpression "json"
1989+-- | binary JSON data, decomposed
1990+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1991+jsonb = UnsafeTypeExpression "jsonb"
1992+-- | variable length array
1993+vararray
1994+ :: TypeExpression schemas pg
1995+ -> TypeExpression schemas (nullity ('PGvararray pg))
1996+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1997+-- | fixed length array
1998+--
1999+-- >>> renderSQL (fixarray @'[2] json)
2000+-- "json[2]"
2001+fixarray
2002+ :: forall dims schemas nullity pg. SOP.All KnownNat dims
2003+ => TypeExpression schemas pg
2004+ -> TypeExpression schemas (nullity ('PGfixarray dims pg))
2005+fixarray ty = UnsafeTypeExpression $
2006+ renderSQL ty <> renderDims @dims
2007+ where
2008+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2009+ renderDims =
2010+ ("[" <>)
2011+ . (<> "]")
2012+ . ByteString.intercalate "]["
2013+ . hcollapse
2014+ $ hcmap (SOP.Proxy @KnownNat)
2015+ (K . fromString . show . natVal)
2016+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2017+
2018+-- | `pgtype` is a demoted version of a `PGType`
2019+class PGTyped schemas (ty :: NullityType) where
2020+ pgtype :: TypeExpression schemas ty
2021+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
2022+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
2023+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
2024+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
2025+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
2026+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
2027+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
2028+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
2029+instance (KnownNat n, 1 <= n)
2030+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
2031+instance (KnownNat n, 1 <= n)
2032+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
2033+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
2034+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
2035+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
2036+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
2037+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
2038+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
2039+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
2040+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
2041+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
2042+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
2043+instance PGTyped schemas ty
2044+ => PGTyped schemas (nullity ('PGvararray ty)) where
2045+ pgtype = vararray (pgtype @schemas @ty)
2046+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2047+ => PGTyped schemas (nullity ('PGfixarray dims ty)) where
2048+ pgtype = fixarray @dims (pgtype @schemas @ty)
2049+
2050+{-----------------------------------------
2051+Sorting
2052+-----------------------------------------}
2053+
2054+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2055+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2056+-- set the sort direction of a `NotNull` result
2057+-- column to ascending or descending. Ascending order puts smaller values
2058+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2059+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2060+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2061+-- determine whether nulls appear before or after non-null values in the sort
2062+-- ordering of a `Null` result column.
2063+data SortExpression outer grp commons schemas params from where
2064+ Asc
2065+ :: Expression outer grp commons schemas params from ('NotNull ty)
2066+ -> SortExpression outer grp commons schemas params from
2067+ Desc
2068+ :: Expression outer grp commons schemas params from ('NotNull ty)
2069+ -> SortExpression outer grp commons schemas params from
2070+ AscNullsFirst
2071+ :: Expression outer grp commons schemas params from ('Null ty)
2072+ -> SortExpression outer grp commons schemas params from
2073+ AscNullsLast
2074+ :: Expression outer grp commons schemas params from ('Null ty)
2075+ -> SortExpression outer grp commons schemas params from
2076+ DescNullsFirst
2077+ :: Expression outer grp commons schemas params from ('Null ty)
2078+ -> SortExpression outer grp commons schemas params from
2079+ DescNullsLast
2080+ :: Expression outer grp commons schemas params from ('Null ty)
2081+ -> SortExpression outer grp commons schemas params from
2082+deriving instance Show (SortExpression outer grp commons schemas params from)
2083+
2084+{- |
2085+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2086+to be sorted according to the specified `SortExpression`(s).
2087+If two rows are equal according to the leftmost expression,
2088+they are compared according to the next expression and so on.
2089+If they are equal according to all specified expressions,
2090+they are returned in an implementation-dependent order.
2091+
2092+You can also control the order in which rows are processed by window functions
2093+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2094+-}
2095+class OrderBy expr where
2096+ orderBy
2097+ :: [SortExpression outer grp commons schemas params from]
2098+ -> expr outer grp commons schemas params from
2099+ -> expr outer grp commons schemas params from
2100+
2101+-- | Render a `SortExpression`.
2102+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2103+ renderSQL = \case
2104+ Asc expression -> renderSQL expression <+> "ASC"
2105+ Desc expression -> renderSQL expression <+> "DESC"
2106+ AscNullsFirst expression -> renderSQL expression
2107+ <+> "ASC NULLS FIRST"
2108+ DescNullsFirst expression -> renderSQL expression
2109+ <+> "DESC NULLS FIRST"
2110+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2111+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2112+
2113+-- | A `WindowDefinition` is a set of table rows that are somehow related
2114+-- to the current row
2115+data WindowDefinition outer grp commons schemas params from where
2116+ WindowDefinition
2117+ :: SListI bys
2118+ => NP (Expression outer grp commons schemas params from) bys
2119+ -> [SortExpression outer grp commons schemas params from]
2120+ -> WindowDefinition outer grp commons schemas params from
2121+
2122+instance OrderBy WindowDefinition where
2123+ orderBy sortsR (WindowDefinition parts sortsL)
2124+ = WindowDefinition parts (sortsL ++ sortsR)
2125+
2126+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2127+ renderSQL (WindowDefinition part ord) =
2128+ renderPartitionByClause part <> renderOrderByClause ord
2129+ where
2130+ renderPartitionByClause = \case
2131+ Nil -> ""
2132+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2133+ renderOrderByClause = \case
2134+ [] -> ""
2135+ srts -> " ORDER" <+> "BY"
2136+ <+> commaSeparated (renderSQL <$> srts)
2137+
2138+{- |
2139+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2140+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2141+For each row, the window function is computed across the rows that fall into
2142+the same partition as the current row.
2143+-}
2144+partitionBy
2145+ :: SListI bys
2146+ => NP (Expression outer grp commons schemas params from) bys
2147+ -> WindowDefinition outer grp commons schemas params from
2148+partitionBy bys = WindowDefinition bys []
2149+
2150+{- |
2151+A window function performs a calculation across a set of table rows
2152+that are somehow related to the current row. This is comparable to the type
2153+of calculation that can be done with an aggregate function.
2154+However, window functions do not cause rows to become grouped into a single
2155+output row like non-window aggregate calls would.
2156+Instead, the rows retain their separate identities.
2157+Behind the scenes, the window function is able to access more than
2158+just the current row of the query result.
2159+-}
2160+newtype WindowFunction
2161+ (outer :: FromType)
2162+ (grp :: Grouping)
2163+ (commons :: FromType)
2164+ (schemas :: SchemasType)
2165+ (params :: [NullityType])
2166+ (from :: FromType)
2167+ (ty :: NullityType)
2168+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2169+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2170+
2171+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2172+ renderSQL = renderWindowFunction
2173+
2174+unsafeWindowFunction1
2175+ :: ByteString
2176+ -> Expression outer grp commons schemas params from ty0
2177+ -> WindowFunction outer grp commons schemas params from ty1
2178+unsafeWindowFunction1 fun x
2179+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2180+
2181+unsafeWindowFunction2
2182+ :: ByteString
2183+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2184+ -> WindowFunction outer grp commons schemas params from ty1
2185+unsafeWindowFunction2 fun (x :*: x')
2186+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2187+
2188+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2189+>>> printSQL rank
2190+rank()
2191+-}
2192+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2193+rank = UnsafeWindowFunction "rank()"
2194+
2195+{- | number of the current row within its partition, counting from 1
2196+>>> printSQL rowNumber
2197+row_number()
2198+-}
2199+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2200+rowNumber = UnsafeWindowFunction "row_number()"
2201+
2202+{- | rank of the current row without gaps; this function counts peer groups
2203+>>> printSQL denseRank
2204+dense_rank()
2205+-}
2206+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2207+denseRank = UnsafeWindowFunction "dense_rank()"
2208+
2209+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2210+>>> printSQL percentRank
2211+percent_rank()
2212+-}
2213+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2214+percentRank = UnsafeWindowFunction "percent_rank()"
2215+
2216+{- | cumulative distribution: (number of partition rows
2217+preceding or peer with current row) / total partition rows
2218+>>> printSQL cumeDist
2219+cume_dist()
2220+-}
2221+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2222+cumeDist = UnsafeWindowFunction "cume_dist()"
2223+
2224+{- | integer ranging from 1 to the argument value,
2225+dividing the partition as equally as possible
2226+-}
2227+ntile
2228+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2229+ -- ^ num buckets
2230+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2231+ntile = unsafeWindowFunction1 "ntile"
2232+
2233+{- | returns value evaluated at the row that is offset rows before the current
2234+row within the partition; if there is no such row, instead return default
2235+(which must be of the same type as value). Both offset and default are
2236+evaluated with respect to the current row.
2237+-}
2238+lag
2239+ :: Expression outer grp commons schemas params from ty
2240+ -- ^ value
2241+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2242+ -- ^ offset
2243+ -> Expression outer grp commons schemas params from ty
2244+ -- ^ default
2245+ -> WindowFunction outer grp commons schemas params from ty
2246+lag value offset def = UnsafeWindowFunction $ "lag"
2247+ <> parenthesized
2248+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2249+
2250+{- | returns value evaluated at the row that is offset rows after the current
2251+row within the partition; if there is no such row, instead return default
2252+(which must be of the same type as value). Both offset and default are
2253+evaluated with respect to the current row.
2254+-}
2255+lead
2256+ :: Expression outer grp commons schemas params from ty
2257+ -- ^ value
2258+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2259+ -- ^ offset
2260+ -> Expression outer grp commons schemas params from ty
2261+ -- ^ default
2262+ -> WindowFunction outer grp commons schemas params from ty
2263+lead value offset def = UnsafeWindowFunction $ "lag"
2264+ <> parenthesized
2265+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2266+
2267+{- | returns value evaluated at the row that is the
2268+first row of the window frame
2269+-}
2270+firstValue
2271+ :: Expression outer grp commons schemas params from ty
2272+ -- ^ value
2273+ -> WindowFunction outer grp commons schemas params from ty
2274+firstValue = unsafeWindowFunction1 "first_value"
2275+
2276+{- | returns value evaluated at the row that is the
2277+last row of the window frame
2278+-}
2279+lastValue
2280+ :: Expression outer grp commons schemas params from ty
2281+ -- ^ value
2282+ -> WindowFunction outer grp commons schemas params from ty
2283+lastValue = unsafeWindowFunction1 "last_value"
2284+
2285+{- | returns value evaluated at the row that is the nth
2286+row of the window frame (counting from 1); null if no such row
2287+-}
2288+nthValue
2289+ :: Expression outer grp commons schemas params from (nullity ty)
2290+ -- ^ value
2291+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2292+ -- ^ nth
2293+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2294+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2295+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])
2296+
2297+{-|
2298+Create date from year, month and day fields
2299+
2300+>>> printSQL (makeDate 1984 7 3)
2301+make_date(1984, 7, 3)
2302+-}
2303+makeDate
2304+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2305+ -- ^ year
2306+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2307+ -- ^ month
2308+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2309+ -- ^ day
2310+ -> Expression outer grp commons schemas params from (nullity 'PGdate)
2311+makeDate y m d = UnsafeExpression $ "make_date" <>
2312+ parenthesized (renderCommaSeparated renderSQL (y :* m :* d :* Nil))
2313+
2314+{-|
2315+Create time from hour, minute and seconds fields
2316+
2317+>>> printSQL (makeTime 8 15 23.5)
2318+make_time(8, 15, 23.5)
2319+-}
2320+makeTime
2321+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2322+ -- ^ hour
2323+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2324+ -- ^ min
2325+ -> Expression outer grp commons schemas params from (nullity 'PGfloat8)
2326+ -- ^ sec
2327+ -> Expression outer grp commons schemas params from (nullity 'PGtime)
2328+makeTime h m s = UnsafeExpression $ "make_time" <>
2329+ parenthesized (renderCommaSeparated renderSQL (h :* m :* s :* Nil))
2330+
2331+{-|
2332+Create timestamp from year, month, day, hour, minute and seconds fields
2333+
2334+>>> printSQL (makeTimestamp 2013 7 15 8 15 23.5)
2335+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2336+-}
2337+makeTimestamp
2338+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2339+ -- ^ year
2340+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2341+ -- ^ month
2342+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2343+ -- ^ day
2344+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2345+ -- ^ hour
2346+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2347+ -- ^ min
2348+ -> Expression outer grp commons schemas params from (nullity 'PGfloat8)
2349+ -- ^ sec
2350+ -> Expression outer grp commons schemas params from (nullity 'PGtimestamp)
2351+makeTimestamp y mon d h m s =
2352+ UnsafeExpression $ "make_timestamp" <> parenthesized
2353+ (renderCommaSeparated renderSQL (y :* mon :* d :* h :* m :* s :* Nil))
2354+
2355+{-|
2356+Create timestamp with time zone from
2357+year, month, day, hour, minute and seconds fields;
2358+the current time zone is used
2359+
2360+>>> printSQL (makeTimestamptz 2013 7 15 8 15 23.5)
2361+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2362+-}
2363+makeTimestamptz
2364+ :: Expression outer grp commons schemas params from (nullity 'PGint4)
2365+ -- ^ year
2366+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2367+ -- ^ month
2368+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2369+ -- ^ day
2370+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2371+ -- ^ hour
2372+ -> Expression outer grp commons schemas params from (nullity 'PGint4)
2373+ -- ^ min
2374+ -> Expression outer grp commons schemas params from (nullity 'PGfloat8)
2375+ -- ^ sec
2376+ -> Expression outer grp commons schemas params from (nullity 'PGtimestamptz)
2377+makeTimestamptz y mon d h m s =
2378+ UnsafeExpression $ "make_timestamptz" <> parenthesized
2379+ (renderCommaSeparated renderSQL (y :* mon :* d :* h :* m :* s :* Nil))
2380+
2381+{-|
2382+Affine space operations on time types.
2383+-}
2384+class TimeOp time diff | time -> diff where
2385+ {-|
2386+ >>> printSQL (makeDate 1984 7 3 !+ 365)
2387+ (make_date(1984, 7, 3) + 365)
2388+ -}
2389+ (!+)
2390+ :: Expression outer grp commons schemas params from (nullity time)
2391+ -> Expression outer grp commons schemas params from (nullity diff)
2392+ -> Expression outer grp commons schemas params from (nullity time)
2393+ (!+) = unsafeBinaryOp "+"
2394+ {-|
2395+ >>> printSQL (365 +! makeDate 1984 7 3)
2396+ (365 + make_date(1984, 7, 3))
2397+ -}
2398+ (+!)
2399+ :: Expression outer grp commons schemas params from (nullity diff)
2400+ -> Expression outer grp commons schemas params from (nullity time)
2401+ -> Expression outer grp commons schemas params from (nullity time)
2402+ (+!) = unsafeBinaryOp "+"
2403+ {-|
2404+ >>> printSQL (makeDate 1984 7 3 !-! currentDate)
2405+ (make_date(1984, 7, 3) - CURRENT_DATE)
2406+ -}
2407+ (!-!)
2408+ :: Expression outer grp commons schemas params from (nullity time)
2409+ -> Expression outer grp commons schemas params from (nullity time)
2410+ -> Expression outer grp commons schemas params from (nullity diff)
2411+ (!-!) = unsafeBinaryOp "-"
2412+instance TimeOp 'PGtimestamp 'PGinterval
2413+instance TimeOp 'PGtimestamptz 'PGinterval
2414+instance TimeOp 'PGtime 'PGinterval
2415+instance TimeOp 'PGtimetz 'PGinterval
2416+instance TimeOp 'PGinterval 'PGinterval
2417+instance TimeOp 'PGdate 'PGint4