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