@@ -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
@@ -15,13 +16,11 @@ Squeal expressions are the atoms used to build statements.
1516 , FlexibleContexts
1617 , FlexibleInstances
1718 , FunctionalDependencies
18− , GADTs
1919 , GeneralizedNewtypeDeriving
2020 , LambdaCase
2121 , MagicHash
2222 , OverloadedStrings
2323 , ScopedTypeVariables
24− , StandaloneDeriving
2524 , TypeApplications
2625 , TypeFamilies
2726 , TypeInType
@@ -32,351 +31,505 @@ Squeal expressions are the atoms used to build statements.
3231
3332module Squeal.PostgreSQL.Expression
3433 ( -- * Expression
35− Expression (..)
36− , Expr
37− , type (-->)
38− , FunctionDB
39− , unsafeFunction
40− , function
41− , unsafeLeftOp
42− , leftOp
43− , unsafeRightOp
44− , rightOp
45− , Operator
46− , OperatorDB
34+ Expression (UnsafeExpression, renderExpression)
35+ , HasParameter (parameter)
36+ , param
37+ -- ** Null
38+ , null_
39+ , notNull
40+ , coalesce
41+ , fromNull
42+ , isNull
43+ , isNotNull
44+ , matchNull
45+ , nullIf
46+ -- ** Collections
47+ , array
48+ , row
49+ -- ** Functions
4750 , unsafeBinaryOp
48− , binaryOp
49− , FunctionVar
50− , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
53− , unsafeFunctionN
54− , functionN
55− , PGSubset (..)
56− , PGIntersect (..)
51+ , unsafeUnaryOp
52+ , unsafeFunction
53+ , unsafeVariadicFunction
54+ , atan2_
55+ , cast
56+ , quot_
57+ , rem_
58+ , trunc
59+ , round_
60+ , ceiling_
61+ , greatest
62+ , least
63+ -- ** Conditions
64+ , Condition
65+ , true
66+ , false
67+ , not_
68+ , (.&&)
69+ , (.||)
70+ , caseWhenThenElse
71+ , ifThenElse
72+ , (.==)
73+ , (./=)
74+ , (.>=)
75+ , (.<)
76+ , (.<=)
77+ , (.>)
78+ -- ** Time
79+ , currentDate
80+ , currentTime
81+ , currentTimestamp
82+ , localTime
83+ , localTimestamp
84+ -- ** Text
85+ , lower
86+ , upper
87+ , charLength
88+ , like
89+ -- ** json or jsonb operators
90+ , PGarray
91+ , PGarrayOf
92+ , PGjsonKey
93+ , PGjson_
94+ , PGobjectpairs
95+ , (.->)
96+ , (.->>)
97+ , (.#>)
98+ , (.#>>)
99+ -- *** jsonb only operators
100+ , (.@>)
101+ , (.<@)
102+ , (.?)
103+ , (.?|)
104+ , (.?&)
105+ , (.||.)
106+ , (.-.)
107+ , (#-.)
108+ -- *** Functions
109+ , toJson
110+ , toJsonb
111+ , arrayToJson
112+ , rowToJson
113+ , jsonBuildArray
114+ , jsonbBuildArray
115+ , jsonBuildObject
116+ , jsonbBuildObject
117+ , jsonObject
118+ , jsonbObject
119+ , jsonZipObject
120+ , jsonbZipObject
121+ , jsonArrayLength
122+ , jsonbArrayLength
123+ , jsonEachAsComposite
124+ , jsonbEachAsComposite
125+ , jsonObjectKeys
126+ , jsonbObjectKeys
127+ -- ** Aggregation
128+ , unsafeAggregate, unsafeAggregateDistinct
129+ , sum_, sumDistinct
130+ , PGAvg (avg, avgDistinct)
131+ , bitAnd, bitOr, boolAnd, boolOr
132+ , bitAndDistinct, bitOrDistinct, boolAndDistinct, boolOrDistinct
133+ , countStar
134+ , count, countDistinct
135+ , every, everyDistinct
136+ , max_, maxDistinct, min_, minDistinct
137+ -- * Types
138+ , TypeExpression (UnsafeTypeExpression, renderTypeExpression)
139+ , PGTyped (pgtype)
140+ , bool
141+ , int2
142+ , smallint
143+ , int4
144+ , int
145+ , integer
146+ , int8
147+ , bigint
148+ , numeric
149+ , float4
150+ , real
151+ , float8
152+ , doublePrecision
153+ , text
154+ , char
155+ , character
156+ , varchar
157+ , characterVarying
158+ , bytea
159+ , timestamp
160+ , timestampWithTimeZone
161+ , date
162+ , time
163+ , timeWithTimeZone
164+ , interval
165+ , uuid
166+ , inet
167+ , json
168+ , jsonb
169+ , vararray
170+ , fixarray
57171 -- * Re-export
58172 , (&)
59− , K (..)
60− , unK
173+ , NP ((:*), Nil)
61174 ) where
62175
63176import Control.Category
64177import Control.DeepSeq
65178import Data.ByteString (ByteString)
66179import Data.Function ((&))
67−import Data.Semigroup hiding (All)
180+import Data.Semigroup
181+import Data.Ratio
68182import Data.String
69−import Generics.SOP hiding (All, from)
183+import Generics.SOP hiding (from)
184+import GHC.Exts (Constraint)
70185import GHC.OverloadedLabels
71186import GHC.TypeLits
72−import Numeric
73187import Prelude hiding (id, (.))
74188
75189import qualified GHC.Generics as GHC
76190
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79191import Squeal.PostgreSQL.Render
80192import Squeal.PostgreSQL.Schema
81193
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85194{-----------------------------------------
86195column expressions
87196-----------------------------------------}
88197
89198{- | `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,
199+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92200as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93201`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
202+or in search `Condition`s in a number of commands.
95203
96204The expression syntax allows the calculation of
97205values from primitive expression using arithmetic, logical,
98206and 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`.
113207-}
114208newtype Expression
115− (outer :: FromType)
116− (commons :: FromType)
117− (grp :: Grouping)
118− (schemas :: SchemasType)
209+ (schema :: SchemaType)
210+ (relations :: RelationsType)
211+ (grouping :: Grouping)
119212 (params :: [NullityType])
120− (from :: FromType)
121213 (ty :: NullityType)
122214 = UnsafeExpression { renderExpression :: ByteString }
123215 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
216+
217+instance RenderSQL (Expression schema relations grouping params ty) where
125218 renderSQL = renderExpression
126219
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.
220+{- | A `HasParameter` constraint is used to indicate a value that is
221+supplied externally to a SQL statement.
222+`Squeal.PostgreSQL.PQ.manipulateParams`,
223+`Squeal.PostgreSQL.PQ.queryParams` and
224+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
225+separately from the SQL command string, in which case `param`s are used to
226+refer to the out-of-line data values.
198227-}
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)
214−
215−instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
217− fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218−instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])
219− => IsLabel col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where
220− fromLabel = fromLabel @col :* Nil
221−instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222− => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
224− fromLabel = fromLabel @col `As` Alias
225−instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226− => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
228− fromLabel = fromLabel @col :* Nil
229−
230−instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
232− tab ! col = UnsafeExpression $
233− renderSQL tab <> "." <> renderSQL col
234−instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])
235− => IsQualified tab col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where
236− tab ! col = tab ! col :* Nil
237−instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238− => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
240− tab ! col = tab ! col `As` col
241−instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242− => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
244− tab ! col = tab ! col :* Nil
228+class KnownNat n => HasParameter
229+ (n :: Nat)
230+ (schema :: SchemaType)
231+ (params :: [NullityType])
232+ (ty :: NullityType)
233+ | n params -> ty where
234+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
235+ --
236+ -- >>> let expr = parameter @1 int4 :: Expression sch rels grp '[ 'Null 'PGint4] ('Null 'PGint4)
237+ -- >>> printSQL expr
238+ -- ($1 :: int4)
239+ parameter
240+ :: TypeExpression schema (PGTypeOf ty)
241+ -> Expression schema relations grouping params ty
242+ parameter ty = UnsafeExpression $ parenthesized $
243+ "$" <> renderNat (Proxy @n) <+> "::"
244+ <+> renderTypeExpression ty
245+instance {-# OVERLAPPING #-} HasParameter 1 schema (ty1:tys) ty1
246+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) schema params ty)
247+ => HasParameter n schema (ty' : params) ty
248+
249+-- | `param` takes a `Nat` using type application and for basic types,
250+-- infers a `TypeExpression`.
251+--
252+-- >>> let expr = param @1 :: Expression sch rels grp '[ 'Null 'PGint4] ('Null 'PGint4)
253+-- >>> printSQL expr
254+-- ($1 :: int4)
255+param
256+ :: forall n schema params relations grouping ty
257+ . (PGTyped schema (PGTypeOf ty), HasParameter n schema params ty)
258+ => Expression schema relations grouping params ty -- ^ param
259+param = parameter @n pgtype
260+
261+instance (HasUnique relation relations columns, Has column columns ty)
262+ => IsLabel column (Expression schema relations 'Ungrouped params ty) where
263+ fromLabel = UnsafeExpression $ renderAlias (Alias @column)
264+instance (HasUnique relation relations columns, Has column columns ty)
265+ => IsLabel column
266+ (Aliased (Expression schema relations 'Ungrouped params) (column ::: ty)) where
267+ fromLabel = fromLabel @column `As` Alias @column
268+instance (HasUnique relation relations columns, Has column columns ty)
269+ => IsLabel column
270+ (NP (Aliased (Expression schema relations 'Ungrouped params)) '[column ::: ty]) where
271+ fromLabel = fromLabel @column :* Nil
272+
273+instance (Has relation relations columns, Has column columns ty)
274+ => IsQualified relation column (Expression schema relations 'Ungrouped params ty) where
275+ relation ! column = UnsafeExpression $
276+ renderAlias relation <> "." <> renderAlias column
277+instance (Has relation relations columns, Has column columns ty)
278+ => IsQualified relation column
279+ (Aliased (Expression schema relations 'Ungrouped params) (column ::: ty)) where
280+ relation ! column = relation ! column `As` column
281+instance (Has relation relations columns, Has column columns ty)
282+ => IsQualified relation column
283+ (NP (Aliased (Expression schema relations 'Ungrouped params)) '[column ::: ty]) where
284+ relation ! column = relation ! column :* Nil
245285
246286instance
247− ( HasUnique tab (Join outer from) row
248− , Has col row ty
249− , GroupedBy tab col bys
250− ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
252− fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253−instance
254− ( HasUnique tab (Join outer from) row
255− , Has col row ty
256− , GroupedBy tab col bys
257− , tys ~ '[ty]
258− ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
260− fromLabel = fromLabel @col :* Nil
287+ ( HasUnique relation relations columns
288+ , Has column columns ty
289+ , GroupedBy relation column bys
290+ ) => IsLabel column
291+ (Expression schema relations ('Grouped bys) params ty) where
292+ fromLabel = UnsafeExpression $ renderAlias (Alias @column)
261293instance
262− ( HasUnique tab (Join outer from) row
263− , Has col row ty
264− , GroupedBy tab col bys
265− , column ~ (col ::: ty)
266− ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
268− fromLabel = fromLabel @col `As` Alias
294+ ( HasUnique relation relations columns
295+ , Has column columns ty
296+ , GroupedBy relation column bys
297+ ) => IsLabel column
298+ ( Aliased (Expression schema relations ('Grouped bys) params)
299+ (column ::: ty) ) where
300+ fromLabel = fromLabel @column `As` Alias @column
269301instance
270− ( HasUnique tab (Join outer from) row
271− , Has col row ty
272− , GroupedBy tab col bys
273− , columns ~ '[col ::: ty]
274− ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
276− fromLabel = fromLabel @col :* Nil
302+ ( HasUnique relation relations columns
303+ , Has column columns ty
304+ , GroupedBy relation column bys
305+ ) => IsLabel column
306+ ( NP (Aliased (Expression schema relations ('Grouped bys) params))
307+ '[column ::: ty] ) where
308+ fromLabel = fromLabel @column :* Nil
277309
278310instance
279− ( Has tab (Join outer from) row
280− , Has col row ty
281− , GroupedBy tab col bys
282− ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
284− tab ! col = UnsafeExpression $
285− renderSQL tab <> "." <> renderSQL col
286−instance
287− ( Has tab (Join outer from) row
288− , Has col row ty
289− , GroupedBy tab col bys
290− , tys ~ '[ty]
291− ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
293− tab ! col = tab ! col :* Nil
311+ ( Has relation relations columns
312+ , Has column columns ty
313+ , GroupedBy relation column bys
314+ ) => IsQualified relation column
315+ (Expression schema relations ('Grouped bys) params ty) where
316+ relation ! column = UnsafeExpression $
317+ renderAlias relation <> "." <> renderAlias column
294318instance
295− ( Has tab (Join outer from) row
296− , Has col row ty
297− , GroupedBy tab col bys
298− , column ~ (col ::: ty)
299− ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
301− tab ! col = tab ! col `As` col
319+ ( Has relation relations columns
320+ , Has column columns ty
321+ , GroupedBy relation column bys
322+ ) => IsQualified relation column
323+ (Aliased (Expression schema relations ('Grouped bys) params)
324+ (column ::: ty)) where
325+ relation ! column = relation ! column `As` column
302326instance
303− ( Has tab (Join outer from) row
304− , Has col row ty
305− , GroupedBy tab col bys
306− , columns ~ '[col ::: ty]
307− ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
309− tab ! col = tab ! col :* Nil
327+ ( Has relation relations columns
328+ , Has column columns ty
329+ , GroupedBy relation column bys
330+ ) => IsQualified relation column
331+ ( NP (Aliased (Expression schema relations ('Grouped bys) params))
332+ '[column ::: ty]) where
333+ relation ! column = relation ! column :* Nil
334+
335+-- | analagous to `Nothing`
336+--
337+-- >>> printSQL null_
338+-- NULL
339+null_ :: Expression schema rels grouping params ('Null ty)
340+null_ = UnsafeExpression "NULL"
341+
342+-- | analagous to `Just`
343+--
344+-- >>> printSQL $ notNull true
345+-- TRUE
346+notNull
347+ :: Expression schema rels grouping params ('NotNull ty)
348+ -> Expression schema rels grouping params ('Null ty)
349+notNull = UnsafeExpression . renderExpression
350+
351+-- | return the leftmost value which is not NULL
352+--
353+-- >>> printSQL $ coalesce [null_, notNull true] false
354+-- COALESCE(NULL, TRUE, FALSE)
355+coalesce
356+ :: [Expression schema relations grouping params ('Null ty)]
357+ -- ^ @NULL@s may be present
358+ -> Expression schema relations grouping params ('NotNull ty)
359+ -- ^ @NULL@ is absent
360+ -> Expression schema relations grouping params ('NotNull ty)
361+coalesce nullxs notNullx = UnsafeExpression $
362+ "COALESCE" <> parenthesized (commaSeparated
363+ ((renderExpression <$> nullxs) <> [renderExpression notNullx]))
364+
365+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
366+--
367+-- >>> printSQL $ fromNull true null_
368+-- COALESCE(NULL, TRUE)
369+fromNull
370+ :: Expression schema relations grouping params ('NotNull ty)
371+ -- ^ what to convert @NULL@ to
372+ -> Expression schema relations grouping params ('Null ty)
373+ -> Expression schema relations grouping params ('NotNull ty)
374+fromNull notNullx nullx = coalesce [nullx] notNullx
375+
376+-- | >>> printSQL $ null_ & isNull
377+-- NULL IS NULL
378+isNull
379+ :: Expression schema relations grouping params ('Null ty)
380+ -- ^ possibly @NULL@
381+ -> Condition schema relations grouping params
382+isNull x = UnsafeExpression $ renderExpression x <+> "IS NULL"
383+
384+-- | >>> printSQL $ null_ & isNotNull
385+-- NULL IS NOT NULL
386+isNotNull
387+ :: Expression schema relations grouping params ('Null ty)
388+ -- ^ possibly @NULL@
389+ -> Condition schema relations grouping params
390+isNotNull x = UnsafeExpression $ renderExpression x <+> "IS NOT NULL"
391+
392+-- | analagous to `maybe` using @IS NULL@
393+--
394+-- >>> printSQL $ matchNull true not_ null_
395+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
396+matchNull
397+ :: Expression schema relations grouping params (nullty)
398+ -- ^ what to convert @NULL@ to
399+ -> ( Expression schema relations grouping params ('NotNull ty)
400+ -> Expression schema relations grouping params (nullty) )
401+ -- ^ function to perform when @NULL@ is absent
402+ -> Expression schema relations grouping params ('Null ty)
403+ -> Expression schema relations grouping params (nullty)
404+matchNull y f x = ifThenElse (isNull x) y
405+ (f (UnsafeExpression (renderExpression x)))
406+
407+{-| right inverse to `fromNull`, if its arguments are equal then
408+`nullIf` gives @NULL@.
409+
410+>>> :set -XTypeApplications -XDataKinds
411+>>> let expr = nullIf false (param @1) :: Expression schema rels grp '[ 'NotNull 'PGbool] ('Null 'PGbool)
412+>>> printSQL expr
413+NULL IF (FALSE, ($1 :: bool))
414+-}
415+nullIf
416+ :: Expression schema relations grouping params ('NotNull ty)
417+ -- ^ @NULL@ is absent
418+ -> Expression schema relations grouping params ('NotNull ty)
419+ -- ^ @NULL@ is absent
420+ -> Expression schema relations grouping params ('Null ty)
421+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
422+ (renderExpression x <> ", " <> renderExpression y)
423+
424+-- | >>> printSQL $ array [null_, notNull false, notNull true]
425+-- ARRAY[NULL, FALSE, TRUE]
426+array
427+ :: [Expression schema relations grouping params ('Null ty)]
428+ -- ^ array elements
429+ -> Expression schema relations grouping params (nullity ('PGvararray ty))
430+array xs = UnsafeExpression $
431+ "ARRAY[" <> commaSeparated (renderExpression <$> xs) <> "]"
310432
311433instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
313− label = UnsafeExpression $ renderSQL (PGlabel @label)
434+ (Expression schema relations grouping params (nullity ('PGenum labels))) where
435+ label = UnsafeExpression $ renderLabel (PGlabel @label)
436+
437+-- | A row constructor is an expression that builds a row value
438+-- (also called a composite value) using values for its member fields.
439+--
440+-- >>> type Complex = PGcomposite '["real" ::: 'PGfloat8, "imaginary" ::: 'PGfloat8]
441+-- >>> let i = row (0 `As` #real :* 1 `As` #imaginary :* Nil) :: Expression '[] '[] 'Ungrouped '[] ('NotNull Complex)
442+-- >>> printSQL i
443+-- ROW(0, 1)
444+row
445+ :: SListI (Nulls fields)
446+ => NP (Aliased (Expression schema relations grouping params)) (Nulls fields)
447+ -- ^ zero or more expressions for the row field values
448+ -> Expression schema relations grouping params (nullity ('PGcomposite fields))
449+row exprs = UnsafeExpression $ "ROW" <> parenthesized
450+ (renderCommaSeparated (\ (expr `As` _) -> renderExpression expr) exprs)
451+
452+instance Has field fields ty => IsLabel field
453+ ( Expression schema relation grouping params (nullity ('PGcomposite fields))
454+ -> Expression schema relation grouping params ('Null ty) ) where
455+ fromLabel expr = UnsafeExpression $
456+ parenthesized (renderExpression expr) <> "." <>
457+ fromString (symbolVal (Proxy @field))
458+
459+instance Semigroup
460+ (Expression schema relations grouping params (nullity ('PGvararray ty))) where
461+ (<>) = unsafeBinaryOp "||"
462+
463+instance Monoid
464+ (Expression schema relations grouping params (nullity ('PGvararray ty))) where
465+ mempty = array []
466+ mappend = (<>)
467+
468+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression sch rels grp '[ 'NotNull 'PGtimestamptz] ('NotNull 'PGtimestamptz)
469+-- >>> printSQL expr
470+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
471+greatest
472+ :: Expression schema relations grouping params (nullty)
473+ -- ^ needs at least 1 argument
474+ -> [Expression schema relations grouping params (nullty)]
475+ -- ^ or more
476+ -> Expression schema relations grouping params (nullty)
477+greatest x xs = UnsafeExpression $ "GREATEST("
478+ <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
479+
480+-- | >>> printSQL $ least currentTimestamp [null_]
481+-- LEAST(CURRENT_TIMESTAMP, NULL)
482+least
483+ :: Expression schema relations grouping params (nullty)
484+ -- ^ needs at least 1 argument
485+ -> [Expression schema relations grouping params (nullty)]
486+ -- ^ or more
487+ -> Expression schema relations grouping params (nullty)
488+least x xs = UnsafeExpression $ "LEAST("
489+ <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
314490
315491-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316492-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
493+unsafeBinaryOp
494+ :: ByteString
495+ -- ^ operator
496+ -> Expression schema relations grouping params (ty0)
497+ -> Expression schema relations grouping params (ty1)
498+ -> Expression schema relations grouping params (ty2)
318499unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319− renderSQL x <+> op <+> renderSQL y
320−
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
500+ renderExpression x <+> op <+> renderExpression y
327501
328−-- | >>> printSQL $ unsafeLeftOp "NOT" true
502+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329503-- (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
504+unsafeUnaryOp
505+ :: ByteString
506+ -- ^ operator
507+ -> Expression schema relations grouping params (ty0)
508+ -> Expression schema relations grouping params (ty1)
509+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
510+ op <+> renderExpression x
351511
352512-- | >>> printSQL $ unsafeFunction "f" true
353513-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
514+unsafeFunction
515+ :: ByteString
516+ -- ^ function
517+ -> Expression schema relations grouping params (xty)
518+ -> Expression schema relations grouping params (yty)
355519unsafeFunction fun x = UnsafeExpression $
356− fun <> parenthesized (renderSQL x)
357−
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
377−
378−instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
520+ fun <> parenthesized (renderExpression x)
521+
522+unsafeVariadicFunction
523+ :: SListI elems
524+ => ByteString
525+ -- ^ function
526+ -> NP (Expression schema relations grouping params) elems
527+ -> Expression schema relations grouping params ret
528+unsafeVariadicFunction fun x = UnsafeExpression $
529+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderExpression) x)))
530+
531+instance PGNum ty
532+ => Num (Expression schema relations grouping params (nullity ty)) where
380533 (+) = unsafeBinaryOp "+"
381534 (-) = unsafeBinaryOp "-"
382535 (*) = unsafeBinaryOp "*"
@@ -387,24 +540,19 @@ instance ty `In` PGNum
387540 . fromString
388541 . show
389542
390−instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
543+instance (PGNum ty, PGFloating ty) => Fractional
544+ (Expression schema relations grouping params (nullity ty)) where
392545 (/) = unsafeBinaryOp "/"
393− fromRational
394− = UnsafeExpression
395− . fromString
396− . ($ "")
397− . showFFloat Nothing
398− . fromRat @Double
546+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
399547
400−instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
548+instance (PGNum ty, PGFloating ty) => Floating
549+ (Expression schema relations grouping params (nullity ty)) where
402550 pi = UnsafeExpression "pi()"
403551 exp = unsafeFunction "exp"
404552 log = unsafeFunction "ln"
405553 sqrt = unsafeFunction "sqrt"
406554 b ** x = UnsafeExpression $
407− "power(" <> renderSQL b <> ", " <> renderSQL x <> ")"
555+ "power(" <> renderExpression b <> ", " <> renderExpression x <> ")"
408556 logBase b y = log y / log b
409557 sin = unsafeFunction "sin"
410558 cos = unsafeFunction "cos"
@@ -419,54 +567,1071 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419567 acosh x = log (x + sqrt (x*x - 1))
420568 atanh x = log ((1 + x) / (1 - x)) / 2
421569
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)
570+-- | >>> :{
571+-- let
572+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
573+-- expression = atan2_ pi 2
574+-- in printSQL expression
575+-- :}
576+-- atan2(pi(), 2)
577+atan2_
578+ :: PGFloating float
579+ => Expression schema relations grouping params (nullity float)
580+ -- ^ numerator
581+ -> Expression schema relations grouping params (nullity float)
582+ -- ^ denominator
583+ -> Expression schema relations grouping params (nullity float)
584+atan2_ y x = UnsafeExpression $
585+ "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
586+
587+-- When a `cast` is applied to an `Expression` of a known type, it
588+-- represents a run-time type conversion. The cast will succeed only if a
589+-- suitable type conversion operation has been defined.
590+--
591+-- | >>> printSQL $ true & cast int4
592+-- (TRUE :: int4)
593+cast
594+ :: TypeExpression schema ty1
595+ -- ^ type to cast as
596+ -> Expression schema relations grouping params (nullity ty0)
597+ -- ^ value to convert
598+ -> Expression schema relations grouping params (nullity ty1)
599+cast ty x = UnsafeExpression $ parenthesized $
600+ renderExpression x <+> "::" <+> renderTypeExpression ty
601+
602+-- | integer division, truncates the result
603+--
604+-- >>> :{
605+-- let
606+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
607+-- expression = 5 `quot_` 2
608+-- in printSQL expression
609+-- :}
610+-- (5 / 2)
611+quot_
612+ :: PGIntegral int
613+ => Expression schema relations grouping params (nullity int)
614+ -- ^ numerator
615+ -> Expression schema relations grouping params (nullity int)
616+ -- ^ denominator
617+ -> Expression schema relations grouping params (nullity int)
618+quot_ = unsafeBinaryOp "/"
619+
620+-- | remainder upon integer division
621+--
622+-- >>> :{
623+-- let
624+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
625+-- expression = 5 `rem_` 2
626+-- in printSQL expression
627+-- :}
628+-- (5 % 2)
629+rem_
630+ :: PGIntegral int
631+ => Expression schema relations grouping params (nullity int)
632+ -- ^ numerator
633+ -> Expression schema relations grouping params (nullity int)
634+ -- ^ denominator
635+ -> Expression schema relations grouping params (nullity int)
636+rem_ = unsafeBinaryOp "%"
637+
638+-- | >>> :{
639+-- let
640+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
641+-- expression = trunc pi
642+-- in printSQL expression
643+-- :}
644+-- trunc(pi())
645+trunc
646+ :: PGFloating frac
647+ => Expression schema relations grouping params (nullity frac)
648+ -- ^ fractional number
649+ -> Expression schema relations grouping params (nullity frac)
650+trunc = unsafeFunction "trunc"
651+
652+-- | >>> :{
653+-- let
654+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
655+-- expression = round_ pi
656+-- in printSQL expression
657+-- :}
658+-- round(pi())
659+round_
660+ :: PGFloating frac
661+ => Expression schema relations grouping params (nullity frac)
662+ -- ^ fractional number
663+ -> Expression schema relations grouping params (nullity frac)
664+round_ = unsafeFunction "round"
665+
666+-- | >>> :{
667+-- let
668+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
669+-- expression = ceiling_ pi
670+-- in printSQL expression
671+-- :}
672+-- ceiling(pi())
673+ceiling_
674+ :: PGFloating frac
675+ => Expression schema relations grouping params (nullity frac)
676+ -- ^ fractional number
677+ -> Expression schema relations grouping params (nullity frac)
678+ceiling_ = unsafeFunction "ceiling"
679+
680+-- | A `Condition` is a boolean valued `Expression`. While SQL allows
681+-- conditions to have @NULL@, Squeal instead chooses to disallow @NULL@,
682+-- forcing one to handle the case of @NULL@ explicitly to produce
683+-- a `Condition`.
684+type Condition schema relations grouping params =
685+ Expression schema relations grouping params ('NotNull 'PGbool)
686+
687+-- | >>> printSQL true
688+-- TRUE
689+true :: Condition schema relations grouping params
690+true = UnsafeExpression "TRUE"
691+
692+-- | >>> printSQL false
693+-- FALSE
694+false :: Condition schema relations grouping params
695+false = UnsafeExpression "FALSE"
696+
697+-- | >>> printSQL $ not_ true
698+-- (NOT TRUE)
699+not_
700+ :: Condition schema relations grouping params
701+ -> Condition schema relations grouping params
702+not_ = unsafeUnaryOp "NOT"
703+
704+-- | >>> printSQL $ true .&& false
705+-- (TRUE AND FALSE)
706+(.&&)
707+ :: Condition schema relations grouping params
708+ -> Condition schema relations grouping params
709+ -> Condition schema relations grouping params
710+(.&&) = unsafeBinaryOp "AND"
711+
712+-- | >>> printSQL $ true .|| false
713+-- (TRUE OR FALSE)
714+(.||)
715+ :: Condition schema relations grouping params
716+ -> Condition schema relations grouping params
717+ -> Condition schema relations grouping params
718+(.||) = unsafeBinaryOp "OR"
719+
720+-- | >>> :{
721+-- let
722+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
723+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
724+-- in printSQL expression
725+-- :}
726+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
727+caseWhenThenElse
728+ :: [ ( Condition schema relations grouping params
729+ , Expression schema relations grouping params (ty)
730+ ) ]
731+ -- ^ whens and thens
732+ -> Expression schema relations grouping params (ty)
733+ -- ^ else
734+ -> Expression schema relations grouping params (ty)
735+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
736+ [ "CASE"
737+ , mconcat
738+ [ mconcat
739+ [ " WHEN ", renderExpression when_
740+ , " THEN ", renderExpression then_
741+ ]
742+ | (when_,then_) <- whenThens
743+ ]
744+ , " ELSE ", renderExpression else_
745+ , " END"
746+ ]
747+
748+-- | >>> :{
749+-- let
750+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
751+-- expression = ifThenElse true 1 0
752+-- in printSQL expression
753+-- :}
754+-- CASE WHEN TRUE THEN 1 ELSE 0 END
755+ifThenElse
756+ :: Condition schema relations grouping params
757+ -> Expression schema relations grouping params (ty) -- ^ then
758+ -> Expression schema relations grouping params (ty) -- ^ else
759+ -> Expression schema relations grouping params (ty)
760+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
761+
762+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
763+-- will produce @NULL@s if one of their arguments is @NULL@.
764+--
765+-- >>> printSQL $ notNull true .== null_
766+-- (TRUE = NULL)
767+(.==)
768+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
769+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
770+ -> Expression schema relations grouping params (nullity 'PGbool)
771+(.==) = unsafeBinaryOp "="
772+infix 4 .==
773+
774+-- | >>> printSQL $ notNull true ./= null_
775+-- (TRUE <> NULL)
776+(./=)
777+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
778+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
779+ -> Expression schema relations grouping params (nullity 'PGbool)
780+(./=) = unsafeBinaryOp "<>"
781+infix 4 ./=
782+
783+-- | >>> printSQL $ notNull true .>= null_
784+-- (TRUE >= NULL)
785+(.>=)
786+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
787+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
788+ -> Expression schema relations grouping params (nullity 'PGbool)
789+(.>=) = unsafeBinaryOp ">="
790+infix 4 .>=
791+
792+-- | >>> printSQL $ notNull true .< null_
793+-- (TRUE < NULL)
794+(.<)
795+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
796+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
797+ -> Expression schema relations grouping params (nullity 'PGbool)
798+(.<) = unsafeBinaryOp "<"
799+infix 4 .<
800+
801+-- | >>> printSQL $ notNull true .<= null_
802+-- (TRUE <= NULL)
803+(.<=)
804+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
805+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
806+ -> Expression schema relations grouping params (nullity 'PGbool)
807+(.<=) = unsafeBinaryOp "<="
808+infix 4 .<=
809+
810+-- | >>> printSQL $ notNull true .> null_
811+-- (TRUE > NULL)
812+(.>)
813+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
814+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
815+ -> Expression schema relations grouping params (nullity 'PGbool)
816+(.>) = unsafeBinaryOp ">"
817+infix 4 .>
818+
819+-- | >>> printSQL currentDate
820+-- CURRENT_DATE
821+currentDate
822+ :: Expression schema relations grouping params (nullity 'PGdate)
823+currentDate = UnsafeExpression "CURRENT_DATE"
824+
825+-- | >>> printSQL currentTime
826+-- CURRENT_TIME
827+currentTime
828+ :: Expression schema relations grouping params (nullity 'PGtimetz)
829+currentTime = UnsafeExpression "CURRENT_TIME"
830+
831+-- | >>> printSQL currentTimestamp
832+-- CURRENT_TIMESTAMP
833+currentTimestamp
834+ :: Expression schema relations grouping params (nullity 'PGtimestamptz)
835+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
836+
837+-- | >>> printSQL localTime
838+-- LOCALTIME
839+localTime
840+ :: Expression schema relations grouping params (nullity 'PGtime)
841+localTime = UnsafeExpression "LOCALTIME"
842+
843+-- | >>> printSQL localTimestamp
844+-- LOCALTIMESTAMP
845+localTimestamp
846+ :: Expression schema relations grouping params (nullity 'PGtimestamp)
847+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
848+
849+{-----------------------------------------
850+text
851+-----------------------------------------}
438852
439853instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
854+ (Expression schema relations grouping params (nullity 'PGtext)) where
441855 fromString str = UnsafeExpression $
442856 "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) <> "\'"
857+ where
858+ escape = \case
859+ '\NUL' -> "\\0"
860+ '\'' -> "''"
861+ '"' -> "\\\""
862+ '\b' -> "\\b"
863+ '\n' -> "\\n"
864+ '\r' -> "\\r"
865+ '\t' -> "\\t"
866+ '\\' -> "\\\\"
867+ c -> [c]
451868
452869instance 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
870+ (Expression schema relations grouping params (nullity 'PGtext)) where
463871 (<>) = unsafeBinaryOp "||"
464872
465873instance 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
874+ (Expression schema relations grouping params (nullity 'PGtext)) where
471875 mempty = fromString ""
472876 mappend = (<>)
877+
878+-- | >>> printSQL $ lower "ARRRGGG"
879+-- lower(E'ARRRGGG')
880+lower
881+ :: Expression schema relations grouping params (nullity 'PGtext)
882+ -- ^ string to lower case
883+ -> Expression schema relations grouping params (nullity 'PGtext)
884+lower = unsafeFunction "lower"
885+
886+-- | >>> printSQL $ upper "eeee"
887+-- upper(E'eeee')
888+upper
889+ :: Expression schema relations grouping params (nullity 'PGtext)
890+ -- ^ string to upper case
891+ -> Expression schema relations grouping params (nullity 'PGtext)
892+upper = unsafeFunction "upper"
893+
894+-- | >>> printSQL $ charLength "four"
895+-- char_length(E'four')
896+charLength
897+ :: Expression schema relations grouping params (nullity 'PGtext)
898+ -- ^ string to measure
899+ -> Expression schema relations grouping params (nullity 'PGint4)
900+charLength = unsafeFunction "char_length"
901+
902+-- | The `like` expression returns true if the @string@ matches
903+-- the supplied @pattern@. If @pattern@ does not contain percent signs
904+-- or underscores, then the pattern only represents the string itself;
905+-- in that case `like` acts like the equals operator. An underscore (_)
906+-- in pattern stands for (matches) any single character; a percent sign (%)
907+-- matches any sequence of zero or more characters.
908+--
909+-- >>> printSQL $ "abc" `like` "a%"
910+-- (E'abc' LIKE E'a%')
911+like
912+ :: Expression schema relations grouping params (nullity 'PGtext)
913+ -- ^ string
914+ -> Expression schema relations grouping params (nullity 'PGtext)
915+ -- ^ pattern
916+ -> Expression schema relations grouping params (nullity 'PGbool)
917+like = unsafeBinaryOp "LIKE"
918+
919+{-----------------------------------------
920+ -- json and jsonb support
921+
922+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
923+comments lifted directly from this page.
924+
925+Table 9.44: json and jsonb operators
926+-----------------------------------------}
927+
928+-- | Get JSON value (object field or array element) at a key.
929+(.->)
930+ :: (PGjson_ json, PGjsonKey key)
931+ => Expression schema relations grouping params (nullity json)
932+ -> Expression schema relations grouping params (nullity key)
933+ -> Expression schema relations grouping params ('Null json)
934+(.->) = unsafeBinaryOp "->"
935+
936+-- | Get JSON value (object field or array element) at a key, as text.
937+(.->>)
938+ :: (PGjson_ json, PGjsonKey key)
939+ => Expression schema relations grouping params (nullity json)
940+ -> Expression schema relations grouping params (nullity key)
941+ -> Expression schema relations grouping params ('Null 'PGtext)
942+(.->>) = unsafeBinaryOp "->>"
943+
944+-- | Get JSON value at a specified path.
945+(.#>)
946+ :: (PGjson_ json, PGtextArray "(.#>)" path)
947+ => Expression schema relations grouping params (nullity json)
948+ -> Expression schema relations grouping params (nullity path)
949+ -> Expression schema relations grouping params ('Null json)
950+(.#>) = unsafeBinaryOp "#>"
951+
952+-- | Get JSON value at a specified path as text.
953+(.#>>)
954+ :: (PGjson_ json, PGtextArray "(.#>>)" path)
955+ => Expression schema relations grouping params (nullity json)
956+ -> Expression schema relations grouping params (nullity path)
957+ -> Expression schema relations grouping params ('Null 'PGtext)
958+(.#>>) = unsafeBinaryOp "#>>"
959+
960+-- Additional jsonb operators
961+
962+-- | Does the left JSON value contain the right JSON path/value entries at the
963+-- top level?
964+(.@>)
965+ :: Expression schema relations grouping params (nullity 'PGjsonb)
966+ -> Expression schema relations grouping params (nullity 'PGjsonb)
967+ -> Expression schema relations grouping params ('NotNull 'PGbool)
968+(.@>) = unsafeBinaryOp "@>"
969+
970+-- | Are the left JSON path/value entries contained at the top level within the
971+-- right JSON value?
972+(.<@)
973+ :: Expression schema relations grouping params (nullity 'PGjsonb)
974+ -> Expression schema relations grouping params (nullity 'PGjsonb)
975+ -> Expression schema relations grouping params ('NotNull 'PGbool)
976+(.<@) = unsafeBinaryOp "<@"
977+
978+-- | Does the string exist as a top-level key within the JSON value?
979+(.?)
980+ :: Expression schema relations grouping params (nullity 'PGjsonb)
981+ -> Expression schema relations grouping params (nullity 'PGtext)
982+ -> Expression schema relations grouping params ('NotNull 'PGbool)
983+(.?) = unsafeBinaryOp "?"
984+
985+-- | Do any of these array strings exist as top-level keys?
986+(.?|)
987+ :: Expression schema relations grouping params (nullity 'PGjsonb)
988+ -> Expression schema relations grouping params (nullity ('PGvararray 'PGtext))
989+ -> Expression schema relations grouping params ('NotNull 'PGbool)
990+(.?|) = unsafeBinaryOp "?|"
991+
992+-- | Do all of these array strings exist as top-level keys?
993+(.?&)
994+ :: Expression schema relations grouping params (nullity 'PGjsonb)
995+ -> Expression schema relations grouping params (nullity ('PGvararray 'PGtext))
996+ -> Expression schema relations grouping params ('NotNull 'PGbool)
997+(.?&) = unsafeBinaryOp "?&"
998+
999+-- | Concatenate two jsonb values into a new jsonb value.
1000+(.||.)
1001+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1002+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1003+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1004+(.||.) = unsafeBinaryOp "||"
1005+
1006+-- | Delete a key or keys from a JSON object, or remove an array element.
1007+--
1008+-- If the right operand is..
1009+--
1010+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1011+-- are matched based on their key value.
1012+--
1013+-- @ text[] @: Delete multiple key/value pairs or string elements
1014+-- from left operand. Key/value pairs are matched based on their key value.
1015+--
1016+-- @ integer @: Delete the array element with specified index (Negative integers
1017+-- count from the end). Throws an error if top level container is not an array.
1018+(.-.)
1019+ :: (key `In` '[ 'PGtext, 'PGvararray 'PGtext, 'PGint4, 'PGint2 ]) -- hlint error without parens here
1020+ => Expression schema relations grouping params (nullity 'PGjsonb)
1021+ -> Expression schema relations grouping params (nullity key)
1022+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1023+(.-.) = unsafeBinaryOp "-"
1024+
1025+-- | Delete the field or element with specified path (for JSON arrays, negative
1026+-- integers count from the end)
1027+(#-.)
1028+ :: PGtextArray "(#-.)" arrayty
1029+ => Expression schema relations grouping params (nullity 'PGjsonb)
1030+ -> Expression schema relations grouping params (nullity arrayty)
1031+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1032+(#-.) = unsafeBinaryOp "#-"
1033+
1034+{-----------------------------------------
1035+Table 9.45: JSON creation functions
1036+-----------------------------------------}
1037+
1038+-- | Returns the value as json. Arrays and composites are converted
1039+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1040+-- type to json, the cast function will be used to perform the conversion;
1041+-- otherwise, a scalar value is produced. For any scalar type other than a
1042+-- number, a Boolean, or a null value, the text representation will be used, in
1043+-- such a fashion that it is a valid json value.
1044+toJson
1045+ :: Expression schema relations grouping params (nullity ty)
1046+ -> Expression schema relations grouping params (nullity 'PGjson)
1047+toJson = unsafeFunction "to_json"
1048+
1049+-- | Returns the value as jsonb. Arrays and composites are converted
1050+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1051+-- type to json, the cast function will be used to perform the conversion;
1052+-- otherwise, a scalar value is produced. For any scalar type other than a
1053+-- number, a Boolean, or a null value, the text representation will be used, in
1054+-- such a fashion that it is a valid jsonb value.
1055+toJsonb
1056+ :: Expression schema relations grouping params (nullity ty)
1057+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1058+toJsonb = unsafeUnaryOp "to_jsonb"
1059+
1060+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1061+-- becomes a JSON array of arrays. Line feeds will be added between dimension-1
1062+-- elements if pretty_bool is true.
1063+arrayToJson
1064+ :: PGarray "arrayToJson" arr
1065+ => Expression schema relations grouping params (nullity arr)
1066+ -> Expression schema relations grouping params (nullity 'PGjson)
1067+arrayToJson = unsafeFunction "array_to_json"
1068+
1069+-- | Returns the row as a JSON object. Line feeds will be added between level-1
1070+-- elements if pretty_bool is true.
1071+rowToJson
1072+ :: Expression schema relations grouping params (nullity ('PGcomposite ty))
1073+ -> Expression schema relations grouping params (nullity 'PGjson)
1074+rowToJson = unsafeFunction "row_to_json"
1075+
1076+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1077+-- argument list.
1078+jsonBuildArray
1079+ :: SListI elems
1080+ => NP (Expression schema relations grouping params) elems
1081+ -> Expression schema relations grouping params (nullity 'PGjson)
1082+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1083+
1084+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1085+-- variadic argument list.
1086+jsonbBuildArray
1087+ :: SListI elems
1088+ => NP (Expression schema relations grouping params) elems
1089+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1090+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1091+
1092+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1093+-- argument list. The elements of the argument list must alternate between text
1094+-- and values.
1095+jsonBuildObject
1096+ :: (PGobjectpairs "jsonBuildObject" elems, SListI elems)
1097+ => NP (Expression schema relations grouping params) elems
1098+ -> Expression schema relations grouping params (nullity 'PGjson)
1099+jsonBuildObject = unsafeVariadicFunction "json_build_object"
1100+
1101+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1102+-- variadic argument list. The elements of the argument list must alternate
1103+-- between text and values.
1104+jsonbBuildObject
1105+ :: (PGobjectpairs "jsonbBuildObject" elems, SListI elems)
1106+ => NP (Expression schema relations grouping params) elems
1107+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1108+jsonbBuildObject = unsafeVariadicFunction "jsonb_build_object"
1109+
1110+-- | Builds a JSON object out of a text array. The array must have either
1111+-- exactly one dimension with an even number of members, in which case they are
1112+-- taken as alternating key/value pairs, or two dimensions such that each inner
1113+-- array has exactly two elements, which are taken as a key/value pair.
1114+jsonObject
1115+ :: PGarrayOf "jsonObject" arr 'PGtext
1116+ => Expression schema relations grouping params (nullity arr)
1117+ -> Expression schema relations grouping params (nullity 'PGjson)
1118+jsonObject = unsafeFunction "json_object"
1119+
1120+-- | Builds a binary JSON object out of a text array. The array must have either
1121+-- exactly one dimension with an even number of members, in which case they are
1122+-- taken as alternating key/value pairs, or two dimensions such that each inner
1123+-- array has exactly two elements, which are taken as a key/value pair.
1124+jsonbObject
1125+ :: PGarrayOf "jsonbObject" arr 'PGtext
1126+ => Expression schema relations grouping params (nullity arr)
1127+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1128+jsonbObject = unsafeFunction "jsonb_object"
1129+
1130+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1131+-- keys and one for values, that are zipped pairwise to create a JSON object.
1132+jsonZipObject
1133+ :: ( PGarrayOf "jsonZipObject" keysArray 'PGtext
1134+ , PGarrayOf "jsonZipObject" valuesArray 'PGtext)
1135+ => Expression schema relations grouping params (nullity keysArray)
1136+ -> Expression schema relations grouping params (nullity valuesArray)
1137+ -> Expression schema relations grouping params (nullity 'PGjson)
1138+jsonZipObject ks vs =
1139+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1140+
1141+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1142+-- keys and one for values, that are zipped pairwise to create a binary JSON
1143+-- object.
1144+jsonbZipObject
1145+ :: ( PGarrayOf "jsonbZipObject" keysArray 'PGtext
1146+ , PGarrayOf "jsonbZipObject" valuesArray 'PGtext)
1147+ => Expression schema relations grouping params (nullity keysArray)
1148+ -> Expression schema relations grouping params (nullity valuesArray)
1149+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1150+jsonbZipObject ks vs =
1151+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1152+
1153+{-----------------------------------------
1154+Table 9.46: JSON processing functions
1155+-----------------------------------------}
1156+
1157+-- | Returns the number of elements in the outermost JSON array.
1158+jsonArrayLength
1159+ :: Expression schema relations grouping params (nullity 'PGjson)
1160+ -> Expression schema relations grouping params (nullity 'PGint4)
1161+jsonArrayLength = unsafeFunction "json_array_length"
1162+
1163+-- | Returns the number of elements in the outermost binary JSON array.
1164+jsonbArrayLength
1165+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1166+ -> Expression schema relations grouping params (nullity 'PGint4)
1167+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1168+
1169+-- | Expands the outermost JSON object into a set of key/value pairs.
1170+--
1171+-- See also 'Squeal.PostgreSQL.Query.jsonEach'.
1172+jsonEachAsComposite
1173+ :: Expression schema relations grouping params (nullity 'PGjson)
1174+ -> Expression schema relations grouping params
1175+ (nullity ('PGcomposite '[ "key" ::: 'PGtext, "value" ::: 'PGjson ]))
1176+jsonEachAsComposite = unsafeFunction "json_each"
1177+
1178+-- | Expands the outermost JSON object into a set of key/value pairs.
1179+--
1180+-- See also 'Squeal.PostgreSQL.Query.jsonbEach'
1181+jsonbEachAsComposite
1182+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1183+ -> Expression schema relations grouping params
1184+ (nullity ('PGcomposite '[ "key" ::: 'PGtext, "value" ::: 'PGjsonb ]))
1185+jsonbEachAsComposite = unsafeFunction "jsonb_each"
1186+
1187+-- | Expands the outermost JSON object into a set of key/value pairs.
1188+--
1189+-- See also 'Squeal.PostgreSQL.Query.jsonEachText'.
1190+jsonEachTextAsComposite
1191+ :: Expression schema relations grouping params (nullity 'PGjson)
1192+ -> Expression schema relations grouping params
1193+ (nullity ('PGcomposite '[ "key" ::: 'PGtext, "value" ::: 'PGtext ]))
1194+jsonEachTextAsComposite = unsafeFunction "json_each_text"
1195+
1196+-- | Expands the outermost JSON object into a set of key/value pairs.
1197+--
1198+-- See also 'Squeal.PostgreSQL.Query.jsonbEachText'
1199+jsonbEachTextAsComposite
1200+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1201+ -> Expression schema relations grouping params
1202+ (nullity ('PGcomposite '[ "key" ::: 'PGtext, "value" ::: 'PGtext ]))
1203+jsonbEachTextAsComposite = unsafeFunction "jsonb_each_text"
1204+
1205+-- | Returns JSON value pointed to by path_elems (equivalent to #> operator).
1206+jsonExtractPath
1207+ :: SListI elems
1208+ => Expression schema relations grouping params (nullity 'PGjson)
1209+ -> NP (Expression schema relations grouping params) elems
1210+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1211+jsonExtractPath x xs =
1212+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1213+
1214+-- | Returns JSON value pointed to by path_elems (equivalent to #> operator).
1215+jsonbExtractPath
1216+ :: SListI elems
1217+ => Expression schema relations grouping params (nullity 'PGjsonb)
1218+ -> NP (Expression schema relations grouping params) elems
1219+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1220+jsonbExtractPath x xs =
1221+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1222+
1223+-- | Returns JSON value pointed to by path_elems (equivalent to #> operator),
1224+-- as text.
1225+jsonExtractPathText
1226+ :: SListI elems
1227+ => Expression schema relations grouping params (nullity 'PGjson)
1228+ -> NP (Expression schema relations grouping params) elems
1229+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1230+jsonExtractPathText x xs =
1231+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1232+
1233+-- | Returns JSON value pointed to by path_elems (equivalent to #> operator),
1234+-- as text.
1235+jsonbExtractPathText
1236+ :: SListI elems
1237+ => Expression schema relations grouping params (nullity 'PGjsonb)
1238+ -> NP (Expression schema relations grouping params) elems
1239+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1240+jsonbExtractPathText x xs =
1241+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1242+
1243+-- | Returns set of keys in the outermost JSON object.
1244+jsonObjectKeys
1245+ :: Expression schema relations grouping params (nullity 'PGjson)
1246+ -> Expression schema relations grouping params (nullity 'PGtext)
1247+jsonObjectKeys = unsafeFunction "json_object_keys"
1248+
1249+-- | Returns set of keys in the outermost JSON object.
1250+jsonbObjectKeys
1251+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1252+ -> Expression schema relations grouping params (nullity 'PGtext)
1253+jsonbObjectKeys = unsafeFunction "jsonb_object_keys"
1254+
1255+{-----------------------------------------
1256+aggregation
1257+-----------------------------------------}
1258+
1259+-- | escape hatch to define aggregate functions
1260+unsafeAggregate
1261+ :: ByteString -- ^ aggregate function
1262+ -> Expression schema relations 'Ungrouped params (xty)
1263+ -> Expression schema relations ('Grouped bys) params (yty)
1264+unsafeAggregate fun x = UnsafeExpression $ mconcat
1265+ [fun, "(", renderExpression x, ")"]
1266+
1267+-- | escape hatch to define aggregate functions over distinct values
1268+unsafeAggregateDistinct
1269+ :: ByteString -- ^ aggregate function
1270+ -> Expression schema relations 'Ungrouped params (xty)
1271+ -> Expression schema relations ('Grouped bys) params (yty)
1272+unsafeAggregateDistinct fun x = UnsafeExpression $ mconcat
1273+ [fun, "(DISTINCT ", renderExpression x, ")"]
1274+
1275+-- | >>> :{
1276+-- let
1277+-- expression :: Expression schema '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Grouped bys) params ('Null 'PGnumeric)
1278+-- expression = sum_ #col
1279+-- in printSQL expression
1280+-- :}
1281+-- sum("col")
1282+sum_
1283+ :: PGNum ty
1284+ => Expression schema relations 'Ungrouped params (nullity ty)
1285+ -- ^ what to sum
1286+ -> Expression schema relations ('Grouped bys) params (nullity ty)
1287+sum_ = unsafeAggregate "sum"
1288+
1289+-- | >>> :{
1290+-- let
1291+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGnumeric]] ('Grouped bys) params (nullity 'PGnumeric)
1292+-- expression = sumDistinct #col
1293+-- in printSQL expression
1294+-- :}
1295+-- sum(DISTINCT "col")
1296+sumDistinct
1297+ :: PGNum ty
1298+ => Expression schema relations 'Ungrouped params (nullity ty)
1299+ -- ^ what to sum
1300+ -> Expression schema relations ('Grouped bys) params (nullity ty)
1301+sumDistinct = unsafeAggregateDistinct "sum"
1302+
1303+-- | A constraint for `PGType`s that you can take averages of and the resulting
1304+-- `PGType`.
1305+class PGAvg ty avg | ty -> avg where
1306+ avg, avgDistinct
1307+ :: Expression schema relations 'Ungrouped params (nullity ty)
1308+ -- ^ what to average
1309+ -> Expression schema relations ('Grouped bys) params (nullity avg)
1310+ avg = unsafeAggregate "avg"
1311+ avgDistinct = unsafeAggregateDistinct "avg"
1312+instance PGAvg 'PGint2 'PGnumeric
1313+instance PGAvg 'PGint4 'PGnumeric
1314+instance PGAvg 'PGint8 'PGnumeric
1315+instance PGAvg 'PGnumeric 'PGnumeric
1316+instance PGAvg 'PGfloat4 'PGfloat8
1317+instance PGAvg 'PGfloat8 'PGfloat8
1318+instance PGAvg 'PGinterval 'PGinterval
1319+
1320+-- | >>> :{
1321+-- let
1322+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1323+-- expression = bitAnd #col
1324+-- in printSQL expression
1325+-- :}
1326+-- bit_and("col")
1327+bitAnd
1328+ :: PGIntegral int
1329+ => Expression schema relations 'Ungrouped params (nullity int)
1330+ -- ^ what to aggregate
1331+ -> Expression schema relations ('Grouped bys) params (nullity int)
1332+bitAnd = unsafeAggregate "bit_and"
1333+
1334+-- | >>> :{
1335+-- let
1336+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1337+-- expression = bitOr #col
1338+-- in printSQL expression
1339+-- :}
1340+-- bit_or("col")
1341+bitOr
1342+ :: PGIntegral int
1343+ => Expression schema relations 'Ungrouped params (nullity int)
1344+ -- ^ what to aggregate
1345+ -> Expression schema relations ('Grouped bys) params (nullity int)
1346+bitOr = unsafeAggregate "bit_or"
1347+
1348+-- | >>> :{
1349+-- let
1350+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1351+-- expression = bitAndDistinct #col
1352+-- in printSQL expression
1353+-- :}
1354+-- bit_and(DISTINCT "col")
1355+bitAndDistinct
1356+ :: PGIntegral int
1357+ => Expression schema relations 'Ungrouped params (nullity int)
1358+ -- ^ what to aggregate
1359+ -> Expression schema relations ('Grouped bys) params (nullity int)
1360+bitAndDistinct = unsafeAggregateDistinct "bit_and"
1361+
1362+-- | >>> :{
1363+-- let
1364+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1365+-- expression = bitOrDistinct #col
1366+-- in printSQL expression
1367+-- :}
1368+-- bit_or(DISTINCT "col")
1369+bitOrDistinct
1370+ :: PGIntegral int
1371+ => Expression schema relations 'Ungrouped params (nullity int)
1372+ -- ^ what to aggregate
1373+ -> Expression schema relations ('Grouped bys) params (nullity int)
1374+bitOrDistinct = unsafeAggregateDistinct "bit_or"
1375+
1376+-- | >>> :{
1377+-- let
1378+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1379+-- expression = boolAnd #col
1380+-- in printSQL expression
1381+-- :}
1382+-- bool_and("col")
1383+boolAnd
1384+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1385+ -- ^ what to aggregate
1386+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1387+boolAnd = unsafeAggregate "bool_and"
1388+
1389+-- | >>> :{
1390+-- let
1391+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1392+-- expression = boolOr #col
1393+-- in printSQL expression
1394+-- :}
1395+-- bool_or("col")
1396+boolOr
1397+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1398+ -- ^ what to aggregate
1399+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1400+boolOr = unsafeAggregate "bool_or"
1401+
1402+-- | >>> :{
1403+-- let
1404+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1405+-- expression = boolAndDistinct #col
1406+-- in printSQL expression
1407+-- :}
1408+-- bool_and(DISTINCT "col")
1409+boolAndDistinct
1410+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1411+ -- ^ what to aggregate
1412+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1413+boolAndDistinct = unsafeAggregateDistinct "bool_and"
1414+
1415+-- | >>> :{
1416+-- let
1417+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1418+-- expression = boolOrDistinct #col
1419+-- in printSQL expression
1420+-- :}
1421+-- bool_or(DISTINCT "col")
1422+boolOrDistinct
1423+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1424+ -- ^ what to aggregate
1425+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1426+boolOrDistinct = unsafeAggregateDistinct "bool_or"
1427+
1428+-- | A special aggregation that does not require an input
1429+--
1430+-- >>> printSQL countStar
1431+-- count(*)
1432+countStar
1433+ :: Expression schema relations ('Grouped bys) params ('NotNull 'PGint8)
1434+countStar = UnsafeExpression $ "count(*)"
1435+
1436+-- | >>> :{
1437+-- let
1438+-- expression :: Expression schema '[tab ::: '["col" ::: nullity ty]] (Grouped bys) params ('NotNull 'PGint8)
1439+-- expression = count #col
1440+-- in printSQL expression
1441+-- :}
1442+-- count("col")
1443+count
1444+ :: Expression schema relations 'Ungrouped params ty
1445+ -- ^ what to count
1446+ -> Expression schema relations ('Grouped bys) params ('NotNull 'PGint8)
1447+count = unsafeAggregate "count"
1448+
1449+-- | >>> :{
1450+-- let
1451+-- expression :: Expression schema '[tab ::: '["col" ::: nullity ty]] (Grouped bys) params ('NotNull 'PGint8)
1452+-- expression = countDistinct #col
1453+-- in printSQL expression
1454+-- :}
1455+-- count(DISTINCT "col")
1456+countDistinct
1457+ :: Expression schema relations 'Ungrouped params ty
1458+ -- ^ what to count
1459+ -> Expression schema relations ('Grouped bys) params ('NotNull 'PGint8)
1460+countDistinct = unsafeAggregateDistinct "count"
1461+
1462+-- | synonym for `boolAnd`
1463+--
1464+-- >>> :{
1465+-- let
1466+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1467+-- expression = every #col
1468+-- in printSQL expression
1469+-- :}
1470+-- every("col")
1471+every
1472+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1473+ -- ^ what to aggregate
1474+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1475+every = unsafeAggregate "every"
1476+
1477+-- | synonym for `boolAndDistinct`
1478+--
1479+-- >>> :{
1480+-- let
1481+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1482+-- expression = everyDistinct #col
1483+-- in printSQL expression
1484+-- :}
1485+-- every(DISTINCT "col")
1486+everyDistinct
1487+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1488+ -- ^ what to aggregate
1489+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1490+everyDistinct = unsafeAggregateDistinct "every"
1491+
1492+-- | minimum and maximum aggregation
1493+max_, min_, maxDistinct, minDistinct
1494+ :: Expression schema relations 'Ungrouped params (nullity ty)
1495+ -- ^ what to aggregate
1496+ -> Expression schema relations ('Grouped bys) params (nullity ty)
1497+max_ = unsafeAggregate "max"
1498+min_ = unsafeAggregate "min"
1499+maxDistinct = unsafeAggregateDistinct "max"
1500+minDistinct = unsafeAggregateDistinct "min"
1501+
1502+{-----------------------------------------
1503+type expressions
1504+-----------------------------------------}
1505+
1506+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1507+newtype TypeExpression (schema :: SchemaType) (ty :: PGType)
1508+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1509+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1510+
1511+instance (Has alias schema ('Typedef ty))
1512+ => IsLabel alias (TypeExpression schema ty) where
1513+ fromLabel = UnsafeTypeExpression (renderAlias (fromLabel @alias))
1514+
1515+-- | logical Boolean (true/false)
1516+bool :: TypeExpression schema 'PGbool
1517+bool = UnsafeTypeExpression "bool"
1518+-- | signed two-byte integer
1519+int2, smallint :: TypeExpression schema 'PGint2
1520+int2 = UnsafeTypeExpression "int2"
1521+smallint = UnsafeTypeExpression "smallint"
1522+-- | signed four-byte integer
1523+int4, int, integer :: TypeExpression schema 'PGint4
1524+int4 = UnsafeTypeExpression "int4"
1525+int = UnsafeTypeExpression "int"
1526+integer = UnsafeTypeExpression "integer"
1527+-- | signed eight-byte integer
1528+int8, bigint :: TypeExpression schema 'PGint8
1529+int8 = UnsafeTypeExpression "int8"
1530+bigint = UnsafeTypeExpression "bigint"
1531+-- | arbitrary precision numeric type
1532+numeric :: TypeExpression schema 'PGnumeric
1533+numeric = UnsafeTypeExpression "numeric"
1534+-- | single precision floating-point number (4 bytes)
1535+float4, real :: TypeExpression schema 'PGfloat4
1536+float4 = UnsafeTypeExpression "float4"
1537+real = UnsafeTypeExpression "real"
1538+-- | double precision floating-point number (8 bytes)
1539+float8, doublePrecision :: TypeExpression schema 'PGfloat8
1540+float8 = UnsafeTypeExpression "float8"
1541+doublePrecision = UnsafeTypeExpression "double precision"
1542+-- | variable-length character string
1543+text :: TypeExpression schema 'PGtext
1544+text = UnsafeTypeExpression "text"
1545+-- | fixed-length character string
1546+char, character
1547+ :: (KnownNat n, 1 <= n)
1548+ => proxy n
1549+ -> TypeExpression schema ('PGchar n)
1550+char p = UnsafeTypeExpression $ "char(" <> renderNat p <> ")"
1551+character p = UnsafeTypeExpression $ "character(" <> renderNat p <> ")"
1552+-- | variable-length character string
1553+varchar, characterVarying
1554+ :: (KnownNat n, 1 <= n)
1555+ => proxy n
1556+ -> TypeExpression schema ('PGvarchar n)
1557+varchar p = UnsafeTypeExpression $ "varchar(" <> renderNat p <> ")"
1558+characterVarying p = UnsafeTypeExpression $
1559+ "character varying(" <> renderNat p <> ")"
1560+-- | binary data ("byte array")
1561+bytea :: TypeExpression schema 'PGbytea
1562+bytea = UnsafeTypeExpression "bytea"
1563+-- | date and time (no time zone)
1564+timestamp :: TypeExpression schema 'PGtimestamp
1565+timestamp = UnsafeTypeExpression "timestamp"
1566+-- | date and time, including time zone
1567+timestampWithTimeZone :: TypeExpression schema 'PGtimestamptz
1568+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1569+-- | calendar date (year, month, day)
1570+date :: TypeExpression schema 'PGdate
1571+date = UnsafeTypeExpression "date"
1572+-- | time of day (no time zone)
1573+time :: TypeExpression schema 'PGtime
1574+time = UnsafeTypeExpression "time"
1575+-- | time of day, including time zone
1576+timeWithTimeZone :: TypeExpression schema 'PGtimetz
1577+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1578+-- | time span
1579+interval :: TypeExpression schema 'PGinterval
1580+interval = UnsafeTypeExpression "interval"
1581+-- | universally unique identifier
1582+uuid :: TypeExpression schema 'PGuuid
1583+uuid = UnsafeTypeExpression "uuid"
1584+-- | IPv4 or IPv6 host address
1585+inet :: TypeExpression schema 'PGinet
1586+inet = UnsafeTypeExpression "inet"
1587+-- | textual JSON data
1588+json :: TypeExpression schema 'PGjson
1589+json = UnsafeTypeExpression "json"
1590+-- | binary JSON data, decomposed
1591+jsonb :: TypeExpression schema 'PGjsonb
1592+jsonb = UnsafeTypeExpression "jsonb"
1593+-- | variable length array
1594+vararray
1595+ :: TypeExpression schema pg
1596+ -> TypeExpression schema ('PGvararray pg)
1597+vararray ty = UnsafeTypeExpression $ renderTypeExpression ty <> "[]"
1598+-- | fixed length array
1599+--
1600+-- >>> renderTypeExpression (fixarray (Proxy @2) json)
1601+-- "json[2]"
1602+fixarray
1603+ :: KnownNat n
1604+ => proxy n
1605+ -> TypeExpression schema pg
1606+ -> TypeExpression schema ('PGfixarray n pg)
1607+fixarray p ty = UnsafeTypeExpression $
1608+ renderTypeExpression ty <> "[" <> renderNat p <> "]"
1609+
1610+-- | `pgtype` is a demoted version of a `PGType`
1611+class PGTyped schema (ty :: PGType) where pgtype :: TypeExpression schema ty
1612+instance PGTyped schema 'PGbool where pgtype = bool
1613+instance PGTyped schema 'PGint2 where pgtype = int2
1614+instance PGTyped schema 'PGint4 where pgtype = int4
1615+instance PGTyped schema 'PGint8 where pgtype = int8
1616+instance PGTyped schema 'PGnumeric where pgtype = numeric
1617+instance PGTyped schema 'PGfloat4 where pgtype = float4
1618+instance PGTyped schema 'PGfloat8 where pgtype = float8
1619+instance PGTyped schema 'PGtext where pgtype = text
1620+instance (KnownNat n, 1 <= n)
1621+ => PGTyped schema ('PGchar n) where pgtype = char (Proxy @n)
1622+instance (KnownNat n, 1 <= n)
1623+ => PGTyped schema ('PGvarchar n) where pgtype = varchar (Proxy @n)
1624+instance PGTyped schema 'PGbytea where pgtype = bytea
1625+instance PGTyped schema 'PGtimestamp where pgtype = timestamp
1626+instance PGTyped schema 'PGtimestamptz where pgtype = timestampWithTimeZone
1627+instance PGTyped schema 'PGdate where pgtype = date
1628+instance PGTyped schema 'PGtime where pgtype = time
1629+instance PGTyped schema 'PGtimetz where pgtype = timeWithTimeZone
1630+instance PGTyped schema 'PGinterval where pgtype = interval
1631+instance PGTyped schema 'PGuuid where pgtype = uuid
1632+instance PGTyped schema 'PGjson where pgtype = json
1633+instance PGTyped schema 'PGjsonb where pgtype = jsonb
1634+instance PGTyped schema ty => PGTyped schema ('PGvararray ty) where
1635+ pgtype = vararray (pgtype @schema @ty)
1636+instance (KnownNat n, PGTyped schema ty) => PGTyped schema ('PGfixarray n ty) where
1637+ pgtype = fixarray (Proxy @n) (pgtype @schema @ty)