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