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