@@ -1,13 +1,14 @@
11{-|
2−Module: Squeal.PostgreSQL.Expression
2+Module: Squeal.PostgreSQL.Query
33Description: Squeal expressions
4−Copyright: (c) Eitan Chatav, 2019
4+Copyright: (c) Eitan Chatav, 2017
55Maintainer: eitan@morphism.tech
66Stability: experimental
77
88Squeal expressions are the atoms used to build statements.
99-}
1010
11+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
1112{-# LANGUAGE
1213 AllowAmbiguousTypes
1314 , ConstraintKinds
@@ -33,214 +34,290 @@ 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+ , (:*:) (..)
59199 , K (..)
60− , unK
61200 ) where
62201
63202import Control.Category
64203import Control.DeepSeq
65204import Data.ByteString (ByteString)
205+import Data.ByteString.Lazy (toStrict)
66206import Data.Function ((&))
67207import Data.Semigroup hiding (All)
208+import qualified Data.Aeson as JSON
209+import Data.Ratio
68210import Data.String
69−import Generics.SOP hiding (All, from)
211+import Data.Word
212+import Generics.SOP hiding (from)
213+import GHC.Generics ((:*:) (..))
70214import GHC.OverloadedLabels
71215import GHC.TypeLits
72−import Numeric
73216import Prelude hiding (id, (.))
74217
218+import qualified Data.ByteString as ByteString
75219import qualified GHC.Generics as GHC
76220
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79221import Squeal.PostgreSQL.Render
80222import Squeal.PostgreSQL.Schema
81223
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85224{-----------------------------------------
86225column expressions
87226-----------------------------------------}
88227
89228{- | `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,
229+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92230as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93231`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
232+or in search `Condition`s in a number of commands.
95233
96234The expression syntax allows the calculation of
97235values from primitive expression using arithmetic, logical,
98236and 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`.
113237-}
114238newtype Expression
115239 (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 outer 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 outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
268+ -- >>> printSQL expr
269+ -- ($1 :: int4)
270+ parameter
271+ :: TypeExpression schemas ty
272+ -> Expression outer 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 outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
284+-- >>> printSQL expr
285+-- ($1 :: int4)
286+param
287+ :: forall n outer commons schemas params from grp ty
288+ . (PGTyped schemas ty, HasParameter n params ty)
289+ => Expression outer grp commons schemas params from ty -- ^ param
290+param = parameter @n (pgtype @schemas)
214291
215292instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
293+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217294 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218295instance (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
296+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220297 fromLabel = fromLabel @col :* Nil
221298instance (HasUnique tab (Join outer 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 outer 'Ungrouped commons schemas params from) column) where
224301 fromLabel = fromLabel @col `As` Alias
225302instance (HasUnique tab (Join outer 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 outer 'Ungrouped commons schemas params from)) columns) where
228305 fromLabel = fromLabel @col :* Nil
229306
230307instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
308+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232309 tab ! col = UnsafeExpression $
233310 renderSQL tab <> "." <> renderSQL col
234311instance (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
312+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236313 tab ! col = tab ! col :* Nil
237314instance (Has tab (Join outer 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 outer 'Ungrouped commons schemas params from) column) where
240317 tab ! col = tab ! col `As` col
241318instance (Has tab (Join outer 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 outer 'Ungrouped commons schemas params from)) columns) where
244321 tab ! col = tab ! col :* Nil
245322
246323instance
@@ -248,7 +325,7 @@ instance
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 outer ('Grouped bys) commons schemas params from ty) where
252329 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253330instance
254331 ( HasUnique tab (Join outer from) row
@@ -256,7 +333,7 @@ instance
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 outer ('Grouped bys) commons schemas params from) tys) where
260337 fromLabel = fromLabel @col :* Nil
261338instance
262339 ( HasUnique tab (Join outer from) row
@@ -264,7 +341,7 @@ instance
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 outer ('Grouped bys) commons schemas params from) column) where
268345 fromLabel = fromLabel @col `As` Alias
269346instance
270347 ( HasUnique tab (Join outer from) row
@@ -272,7 +349,7 @@ instance
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 outer ('Grouped bys) commons schemas params from)) columns) where
276353 fromLabel = fromLabel @col :* Nil
277354
278355instance
@@ -280,7 +357,7 @@ instance
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 outer ('Grouped bys) commons schemas params from ty) where
284361 tab ! col = UnsafeExpression $
285362 renderSQL tab <> "." <> renderSQL col
286363instance
@@ -289,7 +366,7 @@ instance
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 outer ('Grouped bys) commons schemas params from) tys) where
293370 tab ! col = tab ! col :* Nil
294371instance
295372 ( Has tab (Join outer from) row
@@ -297,7 +374,7 @@ instance
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 outer ('Grouped bys) commons schemas params from) column) where
301378 tab ! col = tab ! col `As` col
302379instance
303380 ( Has tab (Join outer from) row
@@ -305,78 +382,237 @@ instance
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 outer ('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 outer grp commons schemas params from ('Null ty)
393+null_ = UnsafeExpression "NULL"
394+
395+-- | analagous to `Just`
396+--
397+-- >>> printSQL $ notNull true
398+-- TRUE
399+notNull
400+ :: Expression outer grp commons schemas params from ('NotNull ty)
401+ -> Expression outer grp commons schemas params from ('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 outer grp commons schemas params from ('Null ty)]
410+ -- ^ @NULL@s may be present
411+ -> Expression outer grp commons schemas params from ('NotNull ty)
412+ -- ^ @NULL@ is absent
413+ -> Expression outer 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 outer grp commons schemas params from ('NotNull ty)
424+ -- ^ what to convert @NULL@ to
425+ -> Expression outer grp commons schemas params from ('Null ty)
426+ -> Expression outer 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 outer grp commons schemas params from ('Null ty)
433+ -- ^ possibly @NULL@
434+ -> Condition outer 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 outer grp commons schemas params from ('Null ty)
441+ -- ^ possibly @NULL@
442+ -> Condition outer 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 outer grp commons schemas params from (nullty)
451+ -- ^ what to convert @NULL@ to
452+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
453+ -> Expression outer grp commons schemas params from (nullty) )
454+ -- ^ function to perform when @NULL@ is absent
455+ -> Expression outer grp commons schemas params from ('Null ty)
456+ -> Expression outer 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 outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
465+>>> printSQL expr
466+NULL IF (FALSE, ($1 :: bool))
467+-}
468+nullIf
469+ :: Expression outer grp commons schemas params from ('NotNull ty)
470+ -- ^ @NULL@ is absent
471+ -> Expression outer grp commons schemas params from ('NotNull ty)
472+ -- ^ @NULL@ is absent
473+ -> Expression outer 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 outer grp commons schemas params from ty]
481+ -- ^ array elements
482+ -> Expression outer 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 outer grp commons schemas params from (nullity ('PGvararray ty)) -- ^ array
491+ -> Expression outer 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 outer 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 outer grp commons schemas params from ('NotNull Complex)
509+-- >>> printSQL i
510+-- ROW(0, 1)
511+row
512+ :: SListI row
513+ => NP (Aliased (Expression outer grp commons schemas params from)) row
514+ -- ^ zero or more expressions for the row field values
515+ -> Expression outer 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 outer 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 outer grp commons schemas params from ('NotNull ('PGcomposite row))
536+ -> Expression outer 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 outer grp commons schemas params from (nullity ('PGvararray ty))) where
543+ (<>) = unsafeBinaryOp "||"
544+
545+instance Monoid
546+ (Expression outer grp commons schemas params from (nullity ('PGvararray ty))) where
547+ mempty = array []
548+ mappend = (<>)
549+
550+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
551+-- >>> printSQL expr
552+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
553+greatest
554+ :: Expression outer grp commons schemas params from (nullty)
555+ -- ^ needs at least 1 argument
556+ -> [Expression outer grp commons schemas params from (nullty)]
557+ -- ^ or more
558+ -> Expression outer 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 outer grp commons schemas params from (nullty)
566+ -- ^ needs at least 1 argument
567+ -> [Expression outer grp commons schemas params from (nullty)]
568+ -- ^ or more
569+ -> Expression outer 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 outer grp commons schemas params from (ty0)
579+ -> Expression outer grp commons schemas params from (ty1)
580+ -> Expression outer 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 outer grp commons schemas params from (ty0)
590+ -> Expression outer 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 outer grp commons schemas params from (xty)
600+ -> Expression outer 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 outer grp commons schemas params from) elems
610+ -> Expression outer 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 outer 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 outer 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 outer grp commons schemas params from (nullity ty)) where
402633 pi = UnsafeExpression "pi()"
403634 exp = unsafeFunction "exp"
404635 log = unsafeFunction "ln"
@@ -419,54 +650,1564 @@ 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 outer 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 outer grp commons schemas params from (nullity float)
663+ -- ^ numerator
664+ -> Expression outer grp commons schemas params from (nullity float)
665+ -- ^ denominator
666+ -> Expression outer 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 outer grp commons schemas params from ty0
680+ -- ^ value to convert
681+ -> Expression outer 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 outer 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 outer grp commons schemas params from (nullity int)
697+ -- ^ numerator
698+ -> Expression outer grp commons schemas params from (nullity int)
699+ -- ^ denominator
700+ -> Expression outer grp commons schemas params from (nullity int)
701+quot_ = unsafeBinaryOp "/"
702+
703+-- | remainder upon integer division
704+--
705+-- >>> :{
706+-- let
707+-- expression :: Expression outer 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 outer grp commons schemas params from (nullity int)
715+ -- ^ numerator
716+ -> Expression outer grp commons schemas params from (nullity int)
717+ -- ^ denominator
718+ -> Expression outer grp commons schemas params from (nullity int)
719+rem_ = unsafeBinaryOp "%"
720+
721+-- | >>> :{
722+-- let
723+-- expression :: Expression outer 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 outer grp commons schemas params from (nullity frac)
731+ -- ^ fractional number
732+ -> Expression outer grp commons schemas params from (nullity frac)
733+trunc = unsafeFunction "trunc"
734+
735+-- | >>> :{
736+-- let
737+-- expression :: Expression outer 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 outer grp commons schemas params from (nullity frac)
745+ -- ^ fractional number
746+ -> Expression outer grp commons schemas params from (nullity frac)
747+round_ = unsafeFunction "round"
748+
749+-- | >>> :{
750+-- let
751+-- expression :: Expression outer 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 outer grp commons schemas params from (nullity frac)
759+ -- ^ fractional number
760+ -> Expression outer 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 outer grp commons schemas params from =
767+ Expression outer grp commons schemas params from ('Null 'PGbool)
768+
769+-- | >>> printSQL true
770+-- TRUE
771+true :: Expression outer grp commons schemas params from (nullity 'PGbool)
772+true = UnsafeExpression "TRUE"
773+
774+-- | >>> printSQL false
775+-- FALSE
776+false :: Expression outer grp commons schemas params from (nullity 'PGbool)
777+false = UnsafeExpression "FALSE"
778+
779+-- | >>> printSQL $ not_ true
780+-- (NOT TRUE)
781+not_
782+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
783+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
784+not_ = unsafeUnaryOp "NOT"
785+
786+-- | >>> printSQL $ true .&& false
787+-- (TRUE AND FALSE)
788+(.&&)
789+ :: Expression outer grp commons schemas params from (nullity 'PGbool)
790+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
791+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGbool)
799+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
800+ -> Expression outer grp commons schemas params from (nullity 'PGbool)
801+infixr 2 .||
802+(.||) = unsafeBinaryOp "OR"
803+
804+-- | >>> :{
805+-- let
806+-- expression :: Expression outer 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 outer grp commons schemas params from
813+ , Expression outer grp commons schemas params from ty
814+ ) ]
815+ -- ^ whens and thens
816+ -> Expression outer grp commons schemas params from ty
817+ -- ^ else
818+ -> Expression outer 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 outer 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 outer grp commons schemas params from
841+ -> Expression outer grp commons schemas params from ty -- ^ then
842+ -> Expression outer grp commons schemas params from ty -- ^ else
843+ -> Expression outer 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 outer grp commons schemas params from (nullity0 ty) -- ^ lhs
853+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
854+ -> Condition outer grp commons schemas params from
855+(.==) = unsafeBinaryOp "="
856+infix 4 .==
857+
858+-- | >>> printSQL $ true ./= null_
859+-- (TRUE <> NULL)
860+(./=)
861+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
862+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
863+ -> Condition outer grp commons schemas params from
864+(./=) = unsafeBinaryOp "<>"
865+infix 4 ./=
866+
867+-- | >>> printSQL $ true .>= null_
868+-- (TRUE >= NULL)
869+(.>=)
870+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
871+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
872+ -> Condition outer grp commons schemas params from
873+(.>=) = unsafeBinaryOp ">="
874+infix 4 .>=
875+
876+-- | >>> printSQL $ true .< null_
877+-- (TRUE < NULL)
878+(.<)
879+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
880+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
881+ -> Condition outer grp commons schemas params from
882+(.<) = unsafeBinaryOp "<"
883+infix 4 .<
884+
885+-- | >>> printSQL $ true .<= null_
886+-- (TRUE <= NULL)
887+(.<=)
888+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
889+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
890+ -> Condition outer grp commons schemas params from
891+(.<=) = unsafeBinaryOp "<="
892+infix 4 .<=
893+
894+-- | >>> printSQL $ true .> null_
895+-- (TRUE > NULL)
896+(.>)
897+ :: Expression outer grp commons schemas params from (nullity0 ty) -- ^ lhs
898+ -> Expression outer grp commons schemas params from (nullity1 ty) -- ^ rhs
899+ -> Condition outer grp commons schemas params from
900+(.>) = unsafeBinaryOp ">"
901+infix 4 .>
902+
903+-- | >>> printSQL currentDate
904+-- CURRENT_DATE
905+currentDate
906+ :: Expression outer grp commons schemas params from (nullity 'PGdate)
907+currentDate = UnsafeExpression "CURRENT_DATE"
908+
909+-- | >>> printSQL currentTime
910+-- CURRENT_TIME
911+currentTime
912+ :: Expression outer grp commons schemas params from (nullity 'PGtimetz)
913+currentTime = UnsafeExpression "CURRENT_TIME"
914+
915+-- | >>> printSQL currentTimestamp
916+-- CURRENT_TIMESTAMP
917+currentTimestamp
918+ :: Expression outer grp commons schemas params from (nullity 'PGtimestamptz)
919+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
920+
921+-- | >>> printSQL localTime
922+-- LOCALTIME
923+localTime
924+ :: Expression outer grp commons schemas params from (nullity 'PGtime)
925+localTime = UnsafeExpression "LOCALTIME"
926+
927+-- | >>> printSQL localTimestamp
928+-- LOCALTIMESTAMP
929+localTimestamp
930+ :: Expression outer 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 outer 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 outer 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 outer 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 outer grp commons schemas params from (nullity 'PGtext)
966+ -- ^ string to lower case
967+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
968+lower = unsafeFunction "lower"
969+
970+-- | >>> printSQL $ upper "eeee"
971+-- upper(E'eeee')
972+upper
973+ :: Expression outer grp commons schemas params from (nullity 'PGtext)
974+ -- ^ string to upper case
975+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGtext)
982+ -- ^ string to measure
983+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGtext)
997+ -- ^ string
998+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
999+ -- ^ pattern
1000+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGtext)
1010+ -- ^ string
1011+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1012+ -- ^ pattern
1013+ -> Expression outer 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 outer grp commons schemas params from (nullity json)
1029+ -> Expression outer grp commons schemas params from (nullity key)
1030+ -> Expression outer 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 outer grp commons schemas params from (nullity json)
1038+ -> Expression outer grp commons schemas params from (nullity key)
1039+ -> Expression outer grp commons schemas params from ('Null 'PGtext)
1040+infixl 8 .->>
1041+(.->>) = unsafeBinaryOp "->>"
1042+
1043+-- | Get JSON value at a specified path.
1044+(.#>)
1045+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1046+ => Expression outer grp commons schemas params from (nullity json)
1047+ -> Expression outer grp commons schemas params from (nullity path)
1048+ -> Expression outer 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 outer grp commons schemas params from (nullity json)
1056+ -> Expression outer grp commons schemas params from (nullity path)
1057+ -> Expression outer grp commons schemas params from ('Null '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 outer grp commons schemas params from (nullity 'PGjsonb)
1067+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1068+ -> Condition outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1076+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1077+ -> Condition outer grp commons schemas params from
1078+infixl 9 .<@
1079+(.<@) = unsafeBinaryOp "<@"
1080+
1081+-- | Does the string exist as a top-level key within the JSON value?
1082+(.?)
1083+ :: Expression outer grp commons schemas params from (nullity 'PGjsonb)
1084+ -> Expression outer grp commons schemas params from (nullity 'PGtext)
1085+ -> Condition outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1092+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1093+ -> Condition outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1100+ -> Expression outer grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1101+ -> Condition outer grp commons schemas params from
1102+infixl 9 .?&
1103+(.?&) = unsafeBinaryOp "?&"
1104+
1105+-- | Concatenate two jsonb values into a new jsonb value.
1106+instance Semigroup
1107+ (Expression outer grp commons schemas params from (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 outer grp commons schemas params from (nullity 'PGjsonb)
1125+ -> Expression outer grp commons schemas params from (nullity key)
1126+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1135+ -> Expression outer grp commons schemas params from (nullity arrayty)
1136+ -> Expression outer 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 outer 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 outer 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 outer grp commons schemas params from (nullity ty)
1166+ -> Expression outer 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 outer grp commons schemas params from (nullity ty)
1177+ -> Expression outer 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 outer grp commons schemas params from (nullity arr)
1185+ -> Expression outer 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 outer grp commons schemas params from (nullity ('PGcomposite ty))
1191+ -> Expression outer 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 outer grp commons schemas params from) elems
1199+ -> Expression outer 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 outer grp commons schemas params from) elems
1207+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1208+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1209+
1210+unsafeRowFunction
1211+ :: All Top elems
1212+ => NP (Aliased (Expression outer 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 outer grp commons schemas params from)) elems
1228+ -> Expression outer 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 outer grp commons schemas params from)) elems
1241+ -> Expression outer 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 outer grp commons schemas params from (nullity arr)
1255+ -> Expression outer 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 outer grp commons schemas params from (nullity arr)
1265+ -> Expression outer 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 outer grp commons schemas params from (nullity keysArray)
1274+ -> Expression outer grp commons schemas params from (nullity valuesArray)
1275+ -> Expression outer 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 outer grp commons schemas params from (nullity keysArray)
1286+ -> Expression outer grp commons schemas params from (nullity valuesArray)
1287+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjson)
1298+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1304+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjson)
1312+ -> NP (Expression outer grp commons schemas params from) elems
1313+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1322+ -> NP (Expression outer grp commons schemas params from) elems
1323+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjson)
1332+ -> NP (Expression outer grp commons schemas params from) elems
1333+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1342+ -> NP (Expression outer grp commons schemas params from) elems
1343+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjson)
1351+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1358+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjson)
1365+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1372+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1385+ -> Expression outer grp commons schemas params from (nullity arr)
1386+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1387+ -> Maybe (Expression outer grp commons schemas params from (nullity 'PGbool))
1388+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1404+ -> Expression outer grp commons schemas params from (nullity arr)
1405+ -> Expression outer grp commons schemas params from (nullity 'PGjsonb)
1406+ -> Maybe (Expression outer grp commons schemas params from (nullity 'PGbool))
1407+ -> Expression outer 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 outer grp commons schemas params from (nullity 'PGjsonb)
1415+ -> Expression outer 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+ -- | aggregates values as a JSON array
1466+ jsonAgg
1467+ :: expr1 ty
1468+ -> aggr ('NotNull 'PGjson)
1469+
1470+ -- | aggregates values as a JSON array
1471+ jsonbAgg
1472+ :: expr1 ty
1473+ -> aggr ('NotNull 'PGjsonb)
1474+
1475+ -- | >>> :{
1476+ -- let
1477+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1478+ -- expression = bitAnd (Distinct #col)
1479+ -- in printSQL expression
1480+ -- :}
1481+ -- bit_and(DISTINCT "col")
1482+ bitAnd
1483+ :: int `In` PGIntegral
1484+ => expr1 (nullity int)
1485+ -- ^ what to aggregate
1486+ -> aggr (nullity int)
1487+
1488+ -- | >>> :{
1489+ -- let
1490+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1491+ -- expression = bitOr (All #col)
1492+ -- in printSQL expression
1493+ -- :}
1494+ -- bit_or(ALL "col")
1495+ bitOr
1496+ :: int `In` PGIntegral
1497+ => expr1 (nullity int)
1498+ -- ^ what to aggregate
1499+ -> aggr (nullity int)
1500+
1501+ -- | >>> :{
1502+ -- let
1503+ -- winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1504+ -- winFun = boolAnd #col
1505+ -- in printSQL winFun
1506+ -- :}
1507+ -- bool_and("col")
1508+ boolAnd
1509+ :: expr1 (nullity 'PGbool)
1510+ -- ^ what to aggregate
1511+ -> aggr (nullity 'PGbool)
1512+
1513+ -- | >>> :{
1514+ -- let
1515+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1516+ -- expression = boolOr (All #col)
1517+ -- in printSQL expression
1518+ -- :}
1519+ -- bool_or(ALL "col")
1520+ boolOr
1521+ :: expr1(nullity 'PGbool)
1522+ -- ^ what to aggregate
1523+ -> aggr (nullity 'PGbool)
1524+
1525+ -- | synonym for `boolAnd`
1526+ --
1527+ -- >>> :{
1528+ -- let
1529+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1530+ -- expression = every (Distinct #col)
1531+ -- in printSQL expression
1532+ -- :}
1533+ -- every(DISTINCT "col")
1534+ every
1535+ :: expr1 (nullity 'PGbool)
1536+ -- ^ what to aggregate
1537+ -> aggr (nullity 'PGbool)
1538+
1539+ -- | maximum value of expression across all input values
1540+ max_
1541+ :: expr1 (nullity ty)
1542+ -- ^ what to maximize
1543+ -> aggr (nullity ty)
1544+
1545+ -- | minimum value of expression across all input values
1546+ min_
1547+ :: expr1 (nullity ty)
1548+ -- ^ what to minimize
1549+ -> aggr (nullity ty)
1550+
1551+ -- | average aggregation
1552+ avg
1553+ :: expr1 (nullity ty)
1554+ -- ^ what to average
1555+ -> aggr (nullity (PGAvg ty))
1556+
1557+ {- | correlation coefficient
1558+ >>> :{
1559+ let
1560+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1561+ expression = corr (All (#y :*: #x))
1562+ in printSQL expression
1563+ :}
1564+ corr(ALL "y", "x")
1565+ -}
1566+ corr
1567+ :: expr2 (nullity 'PGfloat8)
1568+ -> aggr (nullity 'PGfloat8)
1569+
1570+ {- | population covariance
1571+ >>> :{
1572+ let
1573+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1574+ expression = covarPop (All (#y :*: #x))
1575+ in printSQL expression
1576+ :}
1577+ covar_pop(ALL "y", "x")
1578+ -}
1579+ covarPop
1580+ :: expr2 (nullity 'PGfloat8)
1581+ -> aggr (nullity 'PGfloat8)
1582+
1583+ {- | sample covariance
1584+ >>> :{
1585+ let
1586+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1587+ winFun = covarSamp (#y :*: #x)
1588+ in printSQL winFun
1589+ :}
1590+ covar_samp("y", "x")
1591+ -}
1592+ covarSamp
1593+ :: expr2 (nullity 'PGfloat8)
1594+ -> aggr (nullity 'PGfloat8)
1595+
1596+ {- | average of the independent variable (sum(X)/N)
1597+ >>> :{
1598+ let
1599+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1600+ expression = regrAvgX (All (#y :*: #x))
1601+ in printSQL expression
1602+ :}
1603+ regr_avgx(ALL "y", "x")
1604+ -}
1605+ regrAvgX
1606+ :: expr2 (nullity 'PGfloat8)
1607+ -> aggr (nullity 'PGfloat8)
1608+
1609+ {- | average of the dependent variable (sum(Y)/N)
1610+ >>> :{
1611+ let
1612+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1613+ winFun = regrAvgY (#y :*: #x)
1614+ in printSQL winFun
1615+ :}
1616+ regr_avgy("y", "x")
1617+ -}
1618+ regrAvgY
1619+ :: expr2 (nullity 'PGfloat8)
1620+ -> aggr (nullity 'PGfloat8)
1621+
1622+ {- | number of input rows in which both expressions are nonnull
1623+ >>> :{
1624+ let
1625+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGint8)
1626+ winFun = regrCount (#y :*: #x)
1627+ in printSQL winFun
1628+ :}
1629+ regr_count("y", "x")
1630+ -}
1631+ regrCount
1632+ :: expr2 (nullity 'PGfloat8)
1633+ -> aggr (nullity 'PGint8)
1634+
1635+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1636+ >>> :{
1637+ let
1638+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1639+ expression = regrIntercept (All (#y :*: #x))
1640+ in printSQL expression
1641+ :}
1642+ regr_intercept(ALL "y", "x")
1643+ -}
1644+ regrIntercept
1645+ :: expr2 (nullity 'PGfloat8)
1646+ -> aggr (nullity 'PGfloat8)
1647+
1648+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1649+ regrR2
1650+ :: expr2 (nullity 'PGfloat8)
1651+ -> aggr (nullity 'PGfloat8)
1652+
1653+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1654+ -- determined by the (X, Y) pairs
1655+ regrSlope
1656+ :: expr2 (nullity 'PGfloat8)
1657+ -> aggr (nullity 'PGfloat8)
1658+
1659+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1660+ -- (“sum of squares” of the independent variable)
1661+ regrSxx
1662+ :: expr2 (nullity 'PGfloat8)
1663+ -> aggr (nullity 'PGfloat8)
1664+
1665+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1666+ -- (“sum of products” of independent times dependent variable)
1667+ regrSxy
1668+ :: expr2 (nullity 'PGfloat8)
1669+ -> aggr (nullity 'PGfloat8)
1670+
1671+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1672+ -- (“sum of squares” of the dependent variable)
1673+ regrSyy
1674+ :: expr2 (nullity 'PGfloat8)
1675+ -> aggr (nullity 'PGfloat8)
1676+
1677+ -- | historical alias for `stddevSamp`
1678+ stddev
1679+ :: expr1 (nullity ty)
1680+ -> aggr (nullity (PGAvg ty))
1681+
1682+ -- | population standard deviation of the input values
1683+ stddevPop
1684+ :: expr1 (nullity ty)
1685+ -> aggr (nullity (PGAvg ty))
1686+
1687+ -- | sample standard deviation of the input values
1688+ stddevSamp
1689+ :: expr1 (nullity ty)
1690+ -> aggr (nullity (PGAvg ty))
1691+
1692+ -- | historical alias for `varSamp`
1693+ variance
1694+ :: expr1 (nullity ty)
1695+ -> aggr (nullity (PGAvg ty))
1696+
1697+ -- | population variance of the input values
1698+ -- (square of the population standard deviation)
1699+ varPop
1700+ :: expr1 (nullity ty)
1701+ -> aggr (nullity (PGAvg ty))
1702+
1703+ -- | sample variance of the input values
1704+ -- (square of the sample standard deviation)
1705+ varSamp
1706+ :: expr1 (nullity ty)
1707+ -> aggr (nullity (PGAvg ty))
1708+
1709+data Distinction expr ty
1710+ = All (expr ty)
1711+ | Distinct (expr ty)
1712+ deriving (GHC.Generic,Show,Eq,Ord)
1713+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1714+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1715+ renderSQL = \case
1716+ All x -> "ALL" <+> renderSQL x
1717+ Distinct x -> "DISTINCT" <+> renderSQL x
1718+instance RenderSQL
1719+ (Distinction
1720+ ( Expression outer grp commons schemas params from
1721+ :*:
1722+ Expression outer grp commons schemas params from) xty ) where
1723+ renderSQL = \case
1724+ All (x :*: x') ->
1725+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1726+ Distinct (x :*: x') ->
1727+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1728+
1729+instance Aggregate
1730+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1731+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1732+ (Expression outer ('Grouped bys) commons schemas params from) where
1733+ countStar = UnsafeExpression "count(*)"
1734+ count = unsafeAggregate1 "count"
1735+ sum_ = unsafeAggregate1 "sum"
1736+ arrayAgg = unsafeAggregate1 "array_agg"
1737+ jsonAgg = unsafeAggregate1 "json_agg"
1738+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1739+ bitAnd = unsafeAggregate1 "bit_and"
1740+ bitOr = unsafeAggregate1 "bit_or"
1741+ boolAnd = unsafeAggregate1 "bool_and"
1742+ boolOr = unsafeAggregate1 "bool_or"
1743+ every = unsafeAggregate1 "every"
1744+ max_ = unsafeAggregate1 "max"
1745+ min_ = unsafeAggregate1 "min"
1746+ avg = unsafeAggregate1 "avg"
1747+ corr = unsafeAggregate2 "corr"
1748+ covarPop = unsafeAggregate2 "covar_pop"
1749+ covarSamp = unsafeAggregate2 "covar_samp"
1750+ regrAvgX = unsafeAggregate2 "regr_avgx"
1751+ regrAvgY = unsafeAggregate2 "regr_avgy"
1752+ regrCount = unsafeAggregate2 "regr_count"
1753+ regrIntercept = unsafeAggregate2 "regr_intercept"
1754+ regrR2 = unsafeAggregate2 "regr_r2"
1755+ regrSlope = unsafeAggregate2 "regr_slope"
1756+ regrSxx = unsafeAggregate2 "regr_sxx"
1757+ regrSxy = unsafeAggregate2 "regr_sxy"
1758+ regrSyy = unsafeAggregate2 "regr_syy"
1759+ stddev = unsafeAggregate1 "stddev"
1760+ stddevPop = unsafeAggregate1 "stddev_pop"
1761+ stddevSamp = unsafeAggregate1 "stddev_samp"
1762+ variance = unsafeAggregate1 "variance"
1763+ varPop = unsafeAggregate1 "var_pop"
1764+ varSamp = unsafeAggregate1 "var_samp"
1765+instance Aggregate
1766+ (Expression outer grp commons schemas params from)
1767+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1768+ (WindowFunction outer grp commons schemas params from) where
1769+ countStar = UnsafeWindowFunction "count(*)"
1770+ count = unsafeWindowFunction1 "count"
1771+ sum_ = unsafeWindowFunction1 "sum"
1772+ arrayAgg = unsafeWindowFunction1 "array_agg"
1773+ jsonAgg = unsafeWindowFunction1 "json_agg"
1774+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1775+ bitAnd = unsafeWindowFunction1 "bit_and"
1776+ bitOr = unsafeWindowFunction1 "bit_or"
1777+ boolAnd = unsafeWindowFunction1 "bool_and"
1778+ boolOr = unsafeWindowFunction1 "bool_or"
1779+ every = unsafeWindowFunction1 "every"
1780+ max_ = unsafeWindowFunction1 "max"
1781+ min_ = unsafeWindowFunction1 "min"
1782+ avg = unsafeWindowFunction1 "avg"
1783+ corr = unsafeWindowFunction2 "corr"
1784+ covarPop = unsafeWindowFunction2 "covar_pop"
1785+ covarSamp = unsafeWindowFunction2 "covar_samp"
1786+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1787+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1788+ regrCount = unsafeWindowFunction2 "regr_count"
1789+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1790+ regrR2 = unsafeWindowFunction2 "regr_r2"
1791+ regrSlope = unsafeWindowFunction2 "regr_slope"
1792+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1793+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1794+ regrSyy = unsafeWindowFunction2 "regr_syy"
1795+ stddev = unsafeWindowFunction1 "stddev"
1796+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1797+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1798+ variance = unsafeWindowFunction1 "variance"
1799+ varPop = unsafeWindowFunction1 "var_pop"
1800+ varSamp = unsafeWindowFunction1 "var_samp"
1801+
1802+-- | escape hatch to define aggregate functions
1803+unsafeAggregate1
1804+ :: ByteString -- ^ aggregate function
1805+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1806+ -> Expression outer ('Grouped bys) commons schemas params from yty
1807+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1808+ [fun, "(", renderSQL x, ")"]
1809+
1810+-- | escape hatch to define aggregate binary functions
1811+unsafeAggregate2
1812+ :: ByteString -- ^ aggregate function
1813+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1814+ -> Expression outer ('Grouped bys) commons schemas params from yty
1815+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1816+ [fun, "(", renderSQL xx, ")"]
1817+
1818+-- | A type family that calculates `PGAvg` type of a `PGType`.
1819+type family PGAvg ty where
1820+ PGAvg 'PGint2 = 'PGnumeric
1821+ PGAvg 'PGint4 = 'PGnumeric
1822+ PGAvg 'PGint8 = 'PGnumeric
1823+ PGAvg 'PGnumeric = 'PGnumeric
1824+ PGAvg 'PGfloat4 = 'PGfloat8
1825+ PGAvg 'PGfloat8 = 'PGfloat8
1826+ PGAvg 'PGinterval = 'PGinterval
1827+ PGAvg pg = TypeError
1828+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1829+
1830+{-----------------------------------------
1831+type expressions
1832+-----------------------------------------}
1833+
1834+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1835+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1836+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1837+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1838+instance RenderSQL (TypeExpression schemas ty) where
1839+ renderSQL = renderTypeExpression
1840+
1841+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1842+typedef
1843+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1844+ => QualifiedAlias sch td
1845+ -> TypeExpression schemas (nullity ty)
1846+typedef = UnsafeTypeExpression . renderSQL
1847+
1848+-- | The composite type corresponding to a `Table` definition can be expressed
1849+-- by its alias.
1850+typetable
1851+ :: (Has sch schemas schema, Has tab schema ('Table table))
1852+ => QualifiedAlias sch tab
1853+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1854+typetable = UnsafeTypeExpression . renderSQL
1855+
1856+-- | The composite type corresponding to a `View` definition can be expressed
1857+-- by its alias.
1858+typeview
1859+ :: (Has sch schemas schema, Has vw schema ('View view))
1860+ => QualifiedAlias sch vw
1861+ -> TypeExpression schemas (nullity ('PGcomposite view))
1862+typeview = UnsafeTypeExpression . renderSQL
1863+
1864+-- | logical Boolean (true/false)
1865+bool :: TypeExpression schemas (nullity 'PGbool)
1866+bool = UnsafeTypeExpression "bool"
1867+-- | signed two-byte integer
1868+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1869+int2 = UnsafeTypeExpression "int2"
1870+smallint = UnsafeTypeExpression "smallint"
1871+-- | signed four-byte integer
1872+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1873+int4 = UnsafeTypeExpression "int4"
1874+int = UnsafeTypeExpression "int"
1875+integer = UnsafeTypeExpression "integer"
1876+-- | signed eight-byte integer
1877+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1878+int8 = UnsafeTypeExpression "int8"
1879+bigint = UnsafeTypeExpression "bigint"
1880+-- | arbitrary precision numeric type
1881+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1882+numeric = UnsafeTypeExpression "numeric"
1883+-- | single precision floating-point number (4 bytes)
1884+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1885+float4 = UnsafeTypeExpression "float4"
1886+real = UnsafeTypeExpression "real"
1887+-- | double precision floating-point number (8 bytes)
1888+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1889+float8 = UnsafeTypeExpression "float8"
1890+doublePrecision = UnsafeTypeExpression "double precision"
1891+-- | variable-length character string
1892+text :: TypeExpression schemas (nullity 'PGtext)
1893+text = UnsafeTypeExpression "text"
1894+-- | fixed-length character string
1895+char, character
1896+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1897+ => TypeExpression schemas (nullity ('PGchar n))
1898+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1899+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1900+-- | variable-length character string
1901+varchar, characterVarying
1902+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1903+ => TypeExpression schemas (nullity ('PGvarchar n))
1904+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1905+characterVarying = UnsafeTypeExpression $
1906+ "character varying(" <> renderNat @n <> ")"
1907+-- | binary data ("byte array")
1908+bytea :: TypeExpression schemas (nullity 'PGbytea)
1909+bytea = UnsafeTypeExpression "bytea"
1910+-- | date and time (no time zone)
1911+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1912+timestamp = UnsafeTypeExpression "timestamp"
1913+-- | date and time, including time zone
1914+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1915+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1916+-- | calendar date (year, month, day)
1917+date :: TypeExpression schemas (nullity 'PGdate)
1918+date = UnsafeTypeExpression "date"
1919+-- | time of day (no time zone)
1920+time :: TypeExpression schemas (nullity 'PGtime)
1921+time = UnsafeTypeExpression "time"
1922+-- | time of day, including time zone
1923+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1924+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1925+-- | time span
1926+interval :: TypeExpression schemas (nullity 'PGinterval)
1927+interval = UnsafeTypeExpression "interval"
1928+-- | universally unique identifier
1929+uuid :: TypeExpression schemas (nullity 'PGuuid)
1930+uuid = UnsafeTypeExpression "uuid"
1931+-- | IPv4 or IPv6 host address
1932+inet :: TypeExpression schemas (nullity 'PGinet)
1933+inet = UnsafeTypeExpression "inet"
1934+-- | textual JSON data
1935+json :: TypeExpression schemas (nullity 'PGjson)
1936+json = UnsafeTypeExpression "json"
1937+-- | binary JSON data, decomposed
1938+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1939+jsonb = UnsafeTypeExpression "jsonb"
1940+-- | variable length array
1941+vararray
1942+ :: TypeExpression schemas pg
1943+ -> TypeExpression schemas (nullity ('PGvararray pg))
1944+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1945+-- | fixed length array
1946+--
1947+-- >>> renderSQL (fixarray @'[2] json)
1948+-- "json[2]"
1949+fixarray
1950+ :: forall dims schemas nullity pg. All KnownNat dims
1951+ => TypeExpression schemas pg
1952+ -> TypeExpression schemas (nullity ('PGfixarray dims pg))
1953+fixarray ty = UnsafeTypeExpression $
1954+ renderSQL ty <> renderDims @dims
1955+ where
1956+ renderDims :: forall ns. All KnownNat ns => ByteString
1957+ renderDims =
1958+ ("[" <>)
1959+ . (<> "]")
1960+ . ByteString.intercalate "]["
1961+ . hcollapse
1962+ $ hcmap (Proxy @KnownNat)
1963+ (K . fromString . show . natVal)
1964+ (hpure Proxy :: NP Proxy ns)
1965+
1966+-- | `pgtype` is a demoted version of a `PGType`
1967+class PGTyped schemas (ty :: NullityType) where
1968+ pgtype :: TypeExpression schemas ty
1969+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
1970+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
1971+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
1972+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
1973+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
1974+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
1975+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
1976+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
1977+instance (KnownNat n, 1 <= n)
1978+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
1979+instance (KnownNat n, 1 <= n)
1980+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
1981+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
1982+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
1983+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
1984+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
1985+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
1986+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
1987+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
1988+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
1989+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
1990+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
1991+instance PGTyped schemas ty
1992+ => PGTyped schemas (nullity ('PGvararray ty)) where
1993+ pgtype = vararray (pgtype @schemas @ty)
1994+instance (All KnownNat dims, PGTyped schemas ty)
1995+ => PGTyped schemas (nullity ('PGfixarray dims ty)) where
1996+ pgtype = fixarray @dims (pgtype @schemas @ty)
1997+
1998+{-----------------------------------------
1999+Sorting
2000+-----------------------------------------}
2001+
2002+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
2003+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
2004+-- column to ascending or descending. Ascending order puts smaller values
2005+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2006+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2007+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2008+-- determine whether nulls appear before or after non-null values in the sort
2009+-- ordering of a `Null` result column.
2010+data SortExpression outer grp commons schemas params from where
2011+ Asc
2012+ :: Expression outer grp commons schemas params from ('NotNull ty)
2013+ -> SortExpression outer grp commons schemas params from
2014+ Desc
2015+ :: Expression outer grp commons schemas params from ('NotNull ty)
2016+ -> SortExpression outer grp commons schemas params from
2017+ AscNullsFirst
2018+ :: Expression outer grp commons schemas params from ('Null ty)
2019+ -> SortExpression outer grp commons schemas params from
2020+ AscNullsLast
2021+ :: Expression outer grp commons schemas params from ('Null ty)
2022+ -> SortExpression outer grp commons schemas params from
2023+ DescNullsFirst
2024+ :: Expression outer grp commons schemas params from ('Null ty)
2025+ -> SortExpression outer grp commons schemas params from
2026+ DescNullsLast
2027+ :: Expression outer grp commons schemas params from ('Null ty)
2028+ -> SortExpression outer grp commons schemas params from
2029+deriving instance Show (SortExpression outer grp commons schemas params from)
2030+
2031+class OrderBy expr where
2032+ orderBy
2033+ :: [SortExpression outer grp commons schemas params from]
2034+ -> expr outer grp commons schemas params from
2035+ -> expr outer grp commons schemas params from
2036+
2037+-- | Render a `SortExpression`.
2038+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2039+ renderSQL = \case
2040+ Asc expression -> renderSQL expression <+> "ASC"
2041+ Desc expression -> renderSQL expression <+> "DESC"
2042+ AscNullsFirst expression -> renderSQL expression
2043+ <+> "ASC NULLS FIRST"
2044+ DescNullsFirst expression -> renderSQL expression
2045+ <+> "DESC NULLS FIRST"
2046+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2047+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2048+
2049+data WindowDefinition outer grp commons schemas params from where
2050+ WindowDefinition
2051+ :: SListI bys
2052+ => NP (Expression outer grp commons schemas params from) bys
2053+ -> [SortExpression outer grp commons schemas params from]
2054+ -> WindowDefinition outer grp commons schemas params from
2055+
2056+instance OrderBy WindowDefinition where
2057+ orderBy sortsR (WindowDefinition parts sortsL)
2058+ = WindowDefinition parts (sortsL ++ sortsR)
2059+
2060+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2061+ renderSQL (WindowDefinition part ord) =
2062+ renderPartitionByClause part <> renderOrderByClause ord
2063+ where
2064+ renderPartitionByClause = \case
2065+ Nil -> ""
2066+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2067+ renderOrderByClause = \case
2068+ [] -> ""
2069+ srts -> " ORDER" <+> "BY"
2070+ <+> commaSeparated (renderSQL <$> srts)
2071+
2072+partitionBy
2073+ :: SListI bys
2074+ => NP (Expression outer grp commons schemas params from) bys
2075+ -> WindowDefinition outer grp commons schemas params from
2076+partitionBy bys = WindowDefinition bys []
2077+
2078+newtype WindowFunction
2079+ (outer :: FromType)
2080+ (grp :: Grouping)
2081+ (commons :: FromType)
2082+ (schemas :: SchemasType)
2083+ (params :: [NullityType])
2084+ (from :: FromType)
2085+ (ty :: NullityType)
2086+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2087+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2088+
2089+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2090+ renderSQL = renderWindowFunction
2091+
2092+unsafeWindowFunction1
2093+ :: ByteString
2094+ -> Expression outer grp commons schemas params from ty0
2095+ -> WindowFunction outer grp commons schemas params from ty1
2096+unsafeWindowFunction1 fun x
2097+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2098+
2099+unsafeWindowFunction2
2100+ :: ByteString
2101+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2102+ -> WindowFunction outer grp commons schemas params from ty1
2103+unsafeWindowFunction2 fun (x :*: x')
2104+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2105+
2106+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2107+>>> printSQL rank
2108+rank()
2109+-}
2110+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2111+rank = UnsafeWindowFunction "rank()"
2112+
2113+{- | number of the current row within its partition, counting from 1
2114+>>> printSQL rowNumber
2115+row_number()
2116+-}
2117+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2118+rowNumber = UnsafeWindowFunction "row_number()"
2119+
2120+{- | rank of the current row without gaps; this function counts peer groups
2121+>>> printSQL denseRank
2122+dense_rank()
2123+-}
2124+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2125+denseRank = UnsafeWindowFunction "dense_rank()"
2126+
2127+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2128+>>> printSQL percentRank
2129+percent_rank()
2130+-}
2131+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2132+percentRank = UnsafeWindowFunction "percent_rank()"
2133+
2134+{- | cumulative distribution: (number of partition rows
2135+preceding or peer with current row) / total partition rows
2136+>>> printSQL cumeDist
2137+cume_dist()
2138+-}
2139+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2140+cumeDist = UnsafeWindowFunction "cume_dist()"
2141+
2142+{- | integer ranging from 1 to the argument value,
2143+dividing the partition as equally as possible
2144+-}
2145+ntile
2146+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2147+ -- ^ num buckets
2148+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2149+ntile = unsafeWindowFunction1 "ntile"
2150+
2151+{- | returns value evaluated at the row that is offset rows before the current
2152+row within the partition; if there is no such row, instead return default
2153+(which must be of the same type as value). Both offset and default are
2154+evaluated with respect to the current row.
2155+-}
2156+lag
2157+ :: Expression outer grp commons schemas params from ty
2158+ -- ^ value
2159+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2160+ -- ^ offset
2161+ -> Expression outer grp commons schemas params from ty
2162+ -- ^ default
2163+ -> WindowFunction outer grp commons schemas params from ty
2164+lag value offset def = UnsafeWindowFunction $ "lag"
2165+ <> parenthesized
2166+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2167+
2168+{- | returns value evaluated at the row that is offset rows after the current
2169+row within the partition; if there is no such row, instead return default
2170+(which must be of the same type as value). Both offset and default are
2171+evaluated with respect to the current row.
2172+-}
2173+lead
2174+ :: Expression outer grp commons schemas params from ty
2175+ -- ^ value
2176+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2177+ -- ^ offset
2178+ -> Expression outer grp commons schemas params from ty
2179+ -- ^ default
2180+ -> WindowFunction outer grp commons schemas params from ty
2181+lead value offset def = UnsafeWindowFunction $ "lag"
2182+ <> parenthesized
2183+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2184+
2185+{- | returns value evaluated at the row that is the
2186+first row of the window frame
2187+-}
2188+firstValue
2189+ :: Expression outer grp commons schemas params from ty
2190+ -- ^ value
2191+ -> WindowFunction outer grp commons schemas params from ty
2192+firstValue = unsafeWindowFunction1 "first_value"
2193+
2194+{- | returns value evaluated at the row that is the
2195+last row of the window frame
2196+-}
2197+lastValue
2198+ :: Expression outer grp commons schemas params from ty
2199+ -- ^ value
2200+ -> WindowFunction outer grp commons schemas params from ty
2201+lastValue = unsafeWindowFunction1 "last_value"
2202+
2203+{- | returns value evaluated at the row that is the nth
2204+row of the window frame (counting from 1); null if no such row
2205+-}
2206+nthValue
2207+ :: Expression outer grp commons schemas params from (nullity ty)
2208+ -- ^ value
2209+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2210+ -- ^ nth
2211+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2212+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2213+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])