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