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