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