@@ -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,1606 @@ 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.All SOP.Top 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.All SOP.Top 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.All SOP.Top 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]] ('Null '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 (nullity ty)
1473+
1474+ -- | input values, including nulls, concatenated into an array
1475+ arrayAgg
1476+ :: expr1 ty
1477+ -> aggr ('NotNull ('PGvararray ty))
1478+
1479+ -- | aggregates values as a JSON array
1480+ jsonAgg
1481+ :: expr1 ty
1482+ -> aggr ('NotNull 'PGjson)
1483+
1484+ -- | aggregates values as a JSON array
1485+ jsonbAgg
1486+ :: expr1 ty
1487+ -> aggr ('NotNull 'PGjsonb)
1488+
1489+ -- | >>> :{
1490+ -- let
1491+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1492+ -- expression = bitAnd (Distinct #col)
1493+ -- in printSQL expression
1494+ -- :}
1495+ -- bit_and(DISTINCT "col")
1496+ bitAnd
1497+ :: int `In` PGIntegral
1498+ => expr1 (nullity int)
1499+ -- ^ what to aggregate
1500+ -> aggr (nullity int)
1501+
1502+ -- | >>> :{
1503+ -- let
1504+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1505+ -- expression = bitOr (All #col)
1506+ -- in printSQL expression
1507+ -- :}
1508+ -- bit_or(ALL "col")
1509+ bitOr
1510+ :: int `In` PGIntegral
1511+ => expr1 (nullity int)
1512+ -- ^ what to aggregate
1513+ -> aggr (nullity int)
1514+
1515+ -- | >>> :{
1516+ -- let
1517+ -- winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1518+ -- winFun = boolAnd #col
1519+ -- in printSQL winFun
1520+ -- :}
1521+ -- bool_and("col")
1522+ boolAnd
1523+ :: expr1 (nullity 'PGbool)
1524+ -- ^ what to aggregate
1525+ -> aggr (nullity 'PGbool)
1526+
1527+ -- | >>> :{
1528+ -- let
1529+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1530+ -- expression = boolOr (All #col)
1531+ -- in printSQL expression
1532+ -- :}
1533+ -- bool_or(ALL "col")
1534+ boolOr
1535+ :: expr1(nullity 'PGbool)
1536+ -- ^ what to aggregate
1537+ -> aggr (nullity 'PGbool)
1538+
1539+ -- | synonym for `boolAnd`
1540+ --
1541+ -- >>> :{
1542+ -- let
1543+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1544+ -- expression = every (Distinct #col)
1545+ -- in printSQL expression
1546+ -- :}
1547+ -- every(DISTINCT "col")
1548+ every
1549+ :: expr1 (nullity 'PGbool)
1550+ -- ^ what to aggregate
1551+ -> aggr (nullity 'PGbool)
1552+
1553+ -- | maximum value of expression across all input values
1554+ max_
1555+ :: expr1 (nullity ty)
1556+ -- ^ what to maximize
1557+ -> aggr (nullity ty)
1558+
1559+ -- | minimum value of expression across all input values
1560+ min_
1561+ :: expr1 (nullity ty)
1562+ -- ^ what to minimize
1563+ -> aggr (nullity ty)
1564+
1565+ -- | average aggregation
1566+ avg
1567+ :: expr1 (nullity ty)
1568+ -- ^ what to average
1569+ -> aggr (nullity (PGAvg ty))
1570+
1571+ {- | correlation coefficient
1572+ >>> :{
1573+ let
1574+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1575+ expression = corr (All (#y :*: #x))
1576+ in printSQL expression
1577+ :}
1578+ corr(ALL "y", "x")
1579+ -}
1580+ corr
1581+ :: expr2 (nullity 'PGfloat8)
1582+ -> aggr (nullity 'PGfloat8)
1583+
1584+ {- | population covariance
1585+ >>> :{
1586+ let
1587+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1588+ expression = covarPop (All (#y :*: #x))
1589+ in printSQL expression
1590+ :}
1591+ covar_pop(ALL "y", "x")
1592+ -}
1593+ covarPop
1594+ :: expr2 (nullity 'PGfloat8)
1595+ -> aggr (nullity 'PGfloat8)
1596+
1597+ {- | sample covariance
1598+ >>> :{
1599+ let
1600+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1601+ winFun = covarSamp (#y :*: #x)
1602+ in printSQL winFun
1603+ :}
1604+ covar_samp("y", "x")
1605+ -}
1606+ covarSamp
1607+ :: expr2 (nullity 'PGfloat8)
1608+ -> aggr (nullity 'PGfloat8)
1609+
1610+ {- | average of the independent variable (sum(X)/N)
1611+ >>> :{
1612+ let
1613+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1614+ expression = regrAvgX (All (#y :*: #x))
1615+ in printSQL expression
1616+ :}
1617+ regr_avgx(ALL "y", "x")
1618+ -}
1619+ regrAvgX
1620+ :: expr2 (nullity 'PGfloat8)
1621+ -> aggr (nullity 'PGfloat8)
1622+
1623+ {- | average of the dependent variable (sum(Y)/N)
1624+ >>> :{
1625+ let
1626+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1627+ winFun = regrAvgY (#y :*: #x)
1628+ in printSQL winFun
1629+ :}
1630+ regr_avgy("y", "x")
1631+ -}
1632+ regrAvgY
1633+ :: expr2 (nullity 'PGfloat8)
1634+ -> aggr (nullity 'PGfloat8)
1635+
1636+ {- | number of input rows in which both expressions are nonnull
1637+ >>> :{
1638+ let
1639+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGint8)
1640+ winFun = regrCount (#y :*: #x)
1641+ in printSQL winFun
1642+ :}
1643+ regr_count("y", "x")
1644+ -}
1645+ regrCount
1646+ :: expr2 (nullity 'PGfloat8)
1647+ -> aggr (nullity 'PGint8)
1648+
1649+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1650+ >>> :{
1651+ let
1652+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1653+ expression = regrIntercept (All (#y :*: #x))
1654+ in printSQL expression
1655+ :}
1656+ regr_intercept(ALL "y", "x")
1657+ -}
1658+ regrIntercept
1659+ :: expr2 (nullity 'PGfloat8)
1660+ -> aggr (nullity 'PGfloat8)
1661+
1662+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1663+ regrR2
1664+ :: expr2 (nullity 'PGfloat8)
1665+ -> aggr (nullity 'PGfloat8)
1666+
1667+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1668+ -- determined by the (X, Y) pairs
1669+ regrSlope
1670+ :: expr2 (nullity 'PGfloat8)
1671+ -> aggr (nullity 'PGfloat8)
1672+
1673+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1674+ -- (“sum of squares” of the independent variable)
1675+ regrSxx
1676+ :: expr2 (nullity 'PGfloat8)
1677+ -> aggr (nullity 'PGfloat8)
1678+
1679+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1680+ -- (“sum of products” of independent times dependent variable)
1681+ regrSxy
1682+ :: expr2 (nullity 'PGfloat8)
1683+ -> aggr (nullity 'PGfloat8)
1684+
1685+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1686+ -- (“sum of squares” of the dependent variable)
1687+ regrSyy
1688+ :: expr2 (nullity 'PGfloat8)
1689+ -> aggr (nullity 'PGfloat8)
1690+
1691+ -- | historical alias for `stddevSamp`
1692+ stddev
1693+ :: expr1 (nullity ty)
1694+ -> aggr (nullity (PGAvg ty))
1695+
1696+ -- | population standard deviation of the input values
1697+ stddevPop
1698+ :: expr1 (nullity ty)
1699+ -> aggr (nullity (PGAvg ty))
1700+
1701+ -- | sample standard deviation of the input values
1702+ stddevSamp
1703+ :: expr1 (nullity ty)
1704+ -> aggr (nullity (PGAvg ty))
1705+
1706+ -- | historical alias for `varSamp`
1707+ variance
1708+ :: expr1 (nullity ty)
1709+ -> aggr (nullity (PGAvg ty))
1710+
1711+ -- | population variance of the input values
1712+ -- (square of the population standard deviation)
1713+ varPop
1714+ :: expr1 (nullity ty)
1715+ -> aggr (nullity (PGAvg ty))
1716+
1717+ -- | sample variance of the input values
1718+ -- (square of the sample standard deviation)
1719+ varSamp
1720+ :: expr1 (nullity ty)
1721+ -> aggr (nullity (PGAvg ty))
1722+
1723+{- |
1724+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1725+`All` invokes the aggregate once for each input row.
1726+`Distinct` invokes the aggregate once for each distinct value of the expression
1727+(or distinct set of values, for multiple expressions) found in the input
1728+-}
1729+data Distinction expr ty
1730+ = All (expr ty)
1731+ | Distinct (expr ty)
1732+ deriving (GHC.Generic,Show,Eq,Ord)
1733+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1734+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1735+ renderSQL = \case
1736+ All x -> "ALL" <+> renderSQL x
1737+ Distinct x -> "DISTINCT" <+> renderSQL x
1738+instance RenderSQL
1739+ (Distinction
1740+ ( Expression outer grp commons schemas params from
1741+ :*:
1742+ Expression outer grp commons schemas params from) xty ) where
1743+ renderSQL = \case
1744+ All (x :*: x') ->
1745+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1746+ Distinct (x :*: x') ->
1747+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1748+
1749+instance Aggregate
1750+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1751+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1752+ (Expression outer ('Grouped bys) commons schemas params from) where
1753+ countStar = UnsafeExpression "count(*)"
1754+ count = unsafeAggregate1 "count"
1755+ sum_ = unsafeAggregate1 "sum"
1756+ arrayAgg = unsafeAggregate1 "array_agg"
1757+ jsonAgg = unsafeAggregate1 "json_agg"
1758+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1759+ bitAnd = unsafeAggregate1 "bit_and"
1760+ bitOr = unsafeAggregate1 "bit_or"
1761+ boolAnd = unsafeAggregate1 "bool_and"
1762+ boolOr = unsafeAggregate1 "bool_or"
1763+ every = unsafeAggregate1 "every"
1764+ max_ = unsafeAggregate1 "max"
1765+ min_ = unsafeAggregate1 "min"
1766+ avg = unsafeAggregate1 "avg"
1767+ corr = unsafeAggregate2 "corr"
1768+ covarPop = unsafeAggregate2 "covar_pop"
1769+ covarSamp = unsafeAggregate2 "covar_samp"
1770+ regrAvgX = unsafeAggregate2 "regr_avgx"
1771+ regrAvgY = unsafeAggregate2 "regr_avgy"
1772+ regrCount = unsafeAggregate2 "regr_count"
1773+ regrIntercept = unsafeAggregate2 "regr_intercept"
1774+ regrR2 = unsafeAggregate2 "regr_r2"
1775+ regrSlope = unsafeAggregate2 "regr_slope"
1776+ regrSxx = unsafeAggregate2 "regr_sxx"
1777+ regrSxy = unsafeAggregate2 "regr_sxy"
1778+ regrSyy = unsafeAggregate2 "regr_syy"
1779+ stddev = unsafeAggregate1 "stddev"
1780+ stddevPop = unsafeAggregate1 "stddev_pop"
1781+ stddevSamp = unsafeAggregate1 "stddev_samp"
1782+ variance = unsafeAggregate1 "variance"
1783+ varPop = unsafeAggregate1 "var_pop"
1784+ varSamp = unsafeAggregate1 "var_samp"
1785+instance Aggregate
1786+ (Expression outer grp commons schemas params from)
1787+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1788+ (WindowFunction outer grp commons schemas params from) where
1789+ countStar = UnsafeWindowFunction "count(*)"
1790+ count = unsafeWindowFunction1 "count"
1791+ sum_ = unsafeWindowFunction1 "sum"
1792+ arrayAgg = unsafeWindowFunction1 "array_agg"
1793+ jsonAgg = unsafeWindowFunction1 "json_agg"
1794+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1795+ bitAnd = unsafeWindowFunction1 "bit_and"
1796+ bitOr = unsafeWindowFunction1 "bit_or"
1797+ boolAnd = unsafeWindowFunction1 "bool_and"
1798+ boolOr = unsafeWindowFunction1 "bool_or"
1799+ every = unsafeWindowFunction1 "every"
1800+ max_ = unsafeWindowFunction1 "max"
1801+ min_ = unsafeWindowFunction1 "min"
1802+ avg = unsafeWindowFunction1 "avg"
1803+ corr = unsafeWindowFunction2 "corr"
1804+ covarPop = unsafeWindowFunction2 "covar_pop"
1805+ covarSamp = unsafeWindowFunction2 "covar_samp"
1806+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1807+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1808+ regrCount = unsafeWindowFunction2 "regr_count"
1809+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1810+ regrR2 = unsafeWindowFunction2 "regr_r2"
1811+ regrSlope = unsafeWindowFunction2 "regr_slope"
1812+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1813+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1814+ regrSyy = unsafeWindowFunction2 "regr_syy"
1815+ stddev = unsafeWindowFunction1 "stddev"
1816+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1817+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1818+ variance = unsafeWindowFunction1 "variance"
1819+ varPop = unsafeWindowFunction1 "var_pop"
1820+ varSamp = unsafeWindowFunction1 "var_samp"
1821+
1822+-- | escape hatch to define aggregate functions
1823+unsafeAggregate1
1824+ :: ByteString -- ^ aggregate function
1825+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1826+ -> Expression outer ('Grouped bys) commons schemas params from yty
1827+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1828+ [fun, "(", renderSQL x, ")"]
1829+
1830+-- | escape hatch to define aggregate binary functions
1831+unsafeAggregate2
1832+ :: ByteString -- ^ aggregate function
1833+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1834+ -> Expression outer ('Grouped bys) commons schemas params from yty
1835+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1836+ [fun, "(", renderSQL xx, ")"]
1837+
1838+-- | A type family that calculates `PGAvg` type of a `PGType`.
1839+type family PGAvg ty where
1840+ PGAvg 'PGint2 = 'PGnumeric
1841+ PGAvg 'PGint4 = 'PGnumeric
1842+ PGAvg 'PGint8 = 'PGnumeric
1843+ PGAvg 'PGnumeric = 'PGnumeric
1844+ PGAvg 'PGfloat4 = 'PGfloat8
1845+ PGAvg 'PGfloat8 = 'PGfloat8
1846+ PGAvg 'PGinterval = 'PGinterval
1847+ PGAvg pg = TypeError
1848+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1849+
1850+{-----------------------------------------
1851+type expressions
1852+-----------------------------------------}
1853+
1854+-- | `TypeExpression`s are used in `cast`s and
1855+-- `Squeal.PostgreSQL.Definition.createTable` commands.
1856+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1857+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1858+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1859+instance RenderSQL (TypeExpression schemas ty) where
1860+ renderSQL = renderTypeExpression
1861+
1862+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1863+typedef
1864+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1865+ => QualifiedAlias sch td
1866+ -> TypeExpression schemas (nullity ty)
1867+typedef = UnsafeTypeExpression . renderSQL
1868+
1869+-- | The composite type corresponding to a `Table` definition can be expressed
1870+-- by its alias.
1871+typetable
1872+ :: (Has sch schemas schema, Has tab schema ('Table table))
1873+ => QualifiedAlias sch tab
1874+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1875+typetable = UnsafeTypeExpression . renderSQL
1876+
1877+-- | The composite type corresponding to a `View` definition can be expressed
1878+-- by its alias.
1879+typeview
1880+ :: (Has sch schemas schema, Has vw schema ('View view))
1881+ => QualifiedAlias sch vw
1882+ -> TypeExpression schemas (nullity ('PGcomposite view))
1883+typeview = UnsafeTypeExpression . renderSQL
1884+
1885+-- | logical Boolean (true/false)
1886+bool :: TypeExpression schemas (nullity 'PGbool)
1887+bool = UnsafeTypeExpression "bool"
1888+-- | signed two-byte integer
1889+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1890+int2 = UnsafeTypeExpression "int2"
1891+smallint = UnsafeTypeExpression "smallint"
1892+-- | signed four-byte integer
1893+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1894+int4 = UnsafeTypeExpression "int4"
1895+int = UnsafeTypeExpression "int"
1896+integer = UnsafeTypeExpression "integer"
1897+-- | signed eight-byte integer
1898+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1899+int8 = UnsafeTypeExpression "int8"
1900+bigint = UnsafeTypeExpression "bigint"
1901+-- | arbitrary precision numeric type
1902+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1903+numeric = UnsafeTypeExpression "numeric"
1904+-- | single precision floating-point number (4 bytes)
1905+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1906+float4 = UnsafeTypeExpression "float4"
1907+real = UnsafeTypeExpression "real"
1908+-- | double precision floating-point number (8 bytes)
1909+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1910+float8 = UnsafeTypeExpression "float8"
1911+doublePrecision = UnsafeTypeExpression "double precision"
1912+-- | variable-length character string
1913+text :: TypeExpression schemas (nullity 'PGtext)
1914+text = UnsafeTypeExpression "text"
1915+-- | fixed-length character string
1916+char, character
1917+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1918+ => TypeExpression schemas (nullity ('PGchar n))
1919+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1920+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1921+-- | variable-length character string
1922+varchar, characterVarying
1923+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1924+ => TypeExpression schemas (nullity ('PGvarchar n))
1925+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1926+characterVarying = UnsafeTypeExpression $
1927+ "character varying(" <> renderNat @n <> ")"
1928+-- | binary data ("byte array")
1929+bytea :: TypeExpression schemas (nullity 'PGbytea)
1930+bytea = UnsafeTypeExpression "bytea"
1931+-- | date and time (no time zone)
1932+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1933+timestamp = UnsafeTypeExpression "timestamp"
1934+-- | date and time, including time zone
1935+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1936+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1937+-- | calendar date (year, month, day)
1938+date :: TypeExpression schemas (nullity 'PGdate)
1939+date = UnsafeTypeExpression "date"
1940+-- | time of day (no time zone)
1941+time :: TypeExpression schemas (nullity 'PGtime)
1942+time = UnsafeTypeExpression "time"
1943+-- | time of day, including time zone
1944+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1945+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1946+-- | time span
1947+interval :: TypeExpression schemas (nullity 'PGinterval)
1948+interval = UnsafeTypeExpression "interval"
1949+-- | universally unique identifier
1950+uuid :: TypeExpression schemas (nullity 'PGuuid)
1951+uuid = UnsafeTypeExpression "uuid"
1952+-- | IPv4 or IPv6 host address
1953+inet :: TypeExpression schemas (nullity 'PGinet)
1954+inet = UnsafeTypeExpression "inet"
1955+-- | textual JSON data
1956+json :: TypeExpression schemas (nullity 'PGjson)
1957+json = UnsafeTypeExpression "json"
1958+-- | binary JSON data, decomposed
1959+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1960+jsonb = UnsafeTypeExpression "jsonb"
1961+-- | variable length array
1962+vararray
1963+ :: TypeExpression schemas pg
1964+ -> TypeExpression schemas (nullity ('PGvararray pg))
1965+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1966+-- | fixed length array
1967+--
1968+-- >>> renderSQL (fixarray @'[2] json)
1969+-- "json[2]"
1970+fixarray
1971+ :: forall dims schemas nullity pg. SOP.All KnownNat dims
1972+ => TypeExpression schemas pg
1973+ -> TypeExpression schemas (nullity ('PGfixarray dims pg))
1974+fixarray ty = UnsafeTypeExpression $
1975+ renderSQL ty <> renderDims @dims
1976+ where
1977+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
1978+ renderDims =
1979+ ("[" <>)
1980+ . (<> "]")
1981+ . ByteString.intercalate "]["
1982+ . hcollapse
1983+ $ hcmap (SOP.Proxy @KnownNat)
1984+ (K . fromString . show . natVal)
1985+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
1986+
1987+-- | `pgtype` is a demoted version of a `PGType`
1988+class PGTyped schemas (ty :: NullityType) where
1989+ pgtype :: TypeExpression schemas ty
1990+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
1991+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
1992+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
1993+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
1994+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
1995+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
1996+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
1997+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
1998+instance (KnownNat n, 1 <= n)
1999+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
2000+instance (KnownNat n, 1 <= n)
2001+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
2002+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
2003+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
2004+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
2005+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
2006+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
2007+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
2008+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
2009+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
2010+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
2011+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
2012+instance PGTyped schemas ty
2013+ => PGTyped schemas (nullity ('PGvararray ty)) where
2014+ pgtype = vararray (pgtype @schemas @ty)
2015+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2016+ => PGTyped schemas (nullity ('PGfixarray dims ty)) where
2017+ pgtype = fixarray @dims (pgtype @schemas @ty)
2018+
2019+{-----------------------------------------
2020+Sorting
2021+-----------------------------------------}
2022+
2023+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2024+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2025+-- set the sort direction of a `NotNull` result
2026+-- column to ascending or descending. Ascending order puts smaller values
2027+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2028+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2029+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2030+-- determine whether nulls appear before or after non-null values in the sort
2031+-- ordering of a `Null` result column.
2032+data SortExpression outer grp commons schemas params from where
2033+ Asc
2034+ :: Expression outer grp commons schemas params from ('NotNull ty)
2035+ -> SortExpression outer grp commons schemas params from
2036+ Desc
2037+ :: Expression outer grp commons schemas params from ('NotNull ty)
2038+ -> SortExpression outer grp commons schemas params from
2039+ AscNullsFirst
2040+ :: Expression outer grp commons schemas params from ('Null ty)
2041+ -> SortExpression outer grp commons schemas params from
2042+ AscNullsLast
2043+ :: Expression outer grp commons schemas params from ('Null ty)
2044+ -> SortExpression outer grp commons schemas params from
2045+ DescNullsFirst
2046+ :: Expression outer grp commons schemas params from ('Null ty)
2047+ -> SortExpression outer grp commons schemas params from
2048+ DescNullsLast
2049+ :: Expression outer grp commons schemas params from ('Null ty)
2050+ -> SortExpression outer grp commons schemas params from
2051+deriving instance Show (SortExpression outer grp commons schemas params from)
2052+
2053+{- |
2054+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2055+to be sorted according to the specified `SortExpression`(s).
2056+If two rows are equal according to the leftmost expression,
2057+they are compared according to the next expression and so on.
2058+If they are equal according to all specified expressions,
2059+they are returned in an implementation-dependent order.
2060+
2061+You can also control the order in which rows are processed by window functions
2062+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2063+-}
2064+class OrderBy expr where
2065+ orderBy
2066+ :: [SortExpression outer grp commons schemas params from]
2067+ -> expr outer grp commons schemas params from
2068+ -> expr outer grp commons schemas params from
2069+
2070+-- | Render a `SortExpression`.
2071+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2072+ renderSQL = \case
2073+ Asc expression -> renderSQL expression <+> "ASC"
2074+ Desc expression -> renderSQL expression <+> "DESC"
2075+ AscNullsFirst expression -> renderSQL expression
2076+ <+> "ASC NULLS FIRST"
2077+ DescNullsFirst expression -> renderSQL expression
2078+ <+> "DESC NULLS FIRST"
2079+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2080+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2081+
2082+-- | A `WindowDefinition` is a set of table rows that are somehow related
2083+-- to the current row
2084+data WindowDefinition outer grp commons schemas params from where
2085+ WindowDefinition
2086+ :: SListI bys
2087+ => NP (Expression outer grp commons schemas params from) bys
2088+ -> [SortExpression outer grp commons schemas params from]
2089+ -> WindowDefinition outer grp commons schemas params from
2090+
2091+instance OrderBy WindowDefinition where
2092+ orderBy sortsR (WindowDefinition parts sortsL)
2093+ = WindowDefinition parts (sortsL ++ sortsR)
2094+
2095+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2096+ renderSQL (WindowDefinition part ord) =
2097+ renderPartitionByClause part <> renderOrderByClause ord
2098+ where
2099+ renderPartitionByClause = \case
2100+ Nil -> ""
2101+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2102+ renderOrderByClause = \case
2103+ [] -> ""
2104+ srts -> " ORDER" <+> "BY"
2105+ <+> commaSeparated (renderSQL <$> srts)
2106+
2107+{- |
2108+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2109+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2110+For each row, the window function is computed across the rows that fall into
2111+the same partition as the current row.
2112+-}
2113+partitionBy
2114+ :: SListI bys
2115+ => NP (Expression outer grp commons schemas params from) bys
2116+ -> WindowDefinition outer grp commons schemas params from
2117+partitionBy bys = WindowDefinition bys []
2118+
2119+{- |
2120+A window function performs a calculation across a set of table rows
2121+that are somehow related to the current row. This is comparable to the type
2122+of calculation that can be done with an aggregate function.
2123+However, window functions do not cause rows to become grouped into a single
2124+output row like non-window aggregate calls would.
2125+Instead, the rows retain their separate identities.
2126+Behind the scenes, the window function is able to access more than
2127+just the current row of the query result.
2128+-}
2129+newtype WindowFunction
2130+ (outer :: FromType)
2131+ (grp :: Grouping)
2132+ (commons :: FromType)
2133+ (schemas :: SchemasType)
2134+ (params :: [NullityType])
2135+ (from :: FromType)
2136+ (ty :: NullityType)
2137+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2138+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2139+
2140+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2141+ renderSQL = renderWindowFunction
2142+
2143+unsafeWindowFunction1
2144+ :: ByteString
2145+ -> Expression outer grp commons schemas params from ty0
2146+ -> WindowFunction outer grp commons schemas params from ty1
2147+unsafeWindowFunction1 fun x
2148+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2149+
2150+unsafeWindowFunction2
2151+ :: ByteString
2152+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2153+ -> WindowFunction outer grp commons schemas params from ty1
2154+unsafeWindowFunction2 fun (x :*: x')
2155+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2156+
2157+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2158+>>> printSQL rank
2159+rank()
2160+-}
2161+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2162+rank = UnsafeWindowFunction "rank()"
2163+
2164+{- | number of the current row within its partition, counting from 1
2165+>>> printSQL rowNumber
2166+row_number()
2167+-}
2168+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2169+rowNumber = UnsafeWindowFunction "row_number()"
2170+
2171+{- | rank of the current row without gaps; this function counts peer groups
2172+>>> printSQL denseRank
2173+dense_rank()
2174+-}
2175+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2176+denseRank = UnsafeWindowFunction "dense_rank()"
2177+
2178+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2179+>>> printSQL percentRank
2180+percent_rank()
2181+-}
2182+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2183+percentRank = UnsafeWindowFunction "percent_rank()"
2184+
2185+{- | cumulative distribution: (number of partition rows
2186+preceding or peer with current row) / total partition rows
2187+>>> printSQL cumeDist
2188+cume_dist()
2189+-}
2190+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2191+cumeDist = UnsafeWindowFunction "cume_dist()"
2192+
2193+{- | integer ranging from 1 to the argument value,
2194+dividing the partition as equally as possible
2195+-}
2196+ntile
2197+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2198+ -- ^ num buckets
2199+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2200+ntile = unsafeWindowFunction1 "ntile"
2201+
2202+{- | returns value evaluated at the row that is offset rows before the current
2203+row within the partition; if there is no such row, instead return default
2204+(which must be of the same type as value). Both offset and default are
2205+evaluated with respect to the current row.
2206+-}
2207+lag
2208+ :: Expression outer grp commons schemas params from ty
2209+ -- ^ value
2210+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2211+ -- ^ offset
2212+ -> Expression outer grp commons schemas params from ty
2213+ -- ^ default
2214+ -> WindowFunction outer grp commons schemas params from ty
2215+lag value offset def = UnsafeWindowFunction $ "lag"
2216+ <> parenthesized
2217+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2218+
2219+{- | returns value evaluated at the row that is offset rows after 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+lead
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+lead 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 the
2237+first row of the window frame
2238+-}
2239+firstValue
2240+ :: Expression outer grp commons schemas params from ty
2241+ -- ^ value
2242+ -> WindowFunction outer grp commons schemas params from ty
2243+firstValue = unsafeWindowFunction1 "first_value"
2244+
2245+{- | returns value evaluated at the row that is the
2246+last row of the window frame
2247+-}
2248+lastValue
2249+ :: Expression outer grp commons schemas params from ty
2250+ -- ^ value
2251+ -> WindowFunction outer grp commons schemas params from ty
2252+lastValue = unsafeWindowFunction1 "last_value"
2253+
2254+{- | returns value evaluated at the row that is the nth
2255+row of the window frame (counting from 1); null if no such row
2256+-}
2257+nthValue
2258+ :: Expression outer grp commons schemas params from (nullity ty)
2259+ -- ^ value
2260+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2261+ -- ^ nth
2262+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2263+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2264+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])