@@ -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,521 @@ 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+ , (.->)
95+ , (.->>)
96+ , (.#>)
97+ , (.#>>)
98+ -- *** jsonb only operators
99+ , (.@>)
100+ , (.<@)
101+ , (.?)
102+ , (.?|)
103+ , (.?&)
104+ , (.-.)
105+ , (#-.)
106+ -- *** Functions
107+ , jsonLit
108+ , jsonbLit
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+ , jsonExtractPath
124+ , jsonbExtractPath
125+ , jsonExtractPathAsText
126+ , jsonbExtractPathAsText
127+ , jsonObjectKeys
128+ , jsonbObjectKeys
129+ , jsonTypeof
130+ , jsonbTypeof
131+ , jsonStripNulls
132+ , jsonbStripNulls
133+ , jsonbSet
134+ , jsonbInsert
135+ , jsonbPretty
136+ -- ** Aggregation
137+ , unsafeAggregate, unsafeAggregateDistinct
138+ , sum_, sumDistinct
139+ , PGAvg (avg, avgDistinct)
140+ , bitAnd, bitOr, boolAnd, boolOr
141+ , bitAndDistinct, bitOrDistinct, boolAndDistinct, boolOrDistinct
142+ , countStar
143+ , count, countDistinct
144+ , every, everyDistinct
145+ , max_, maxDistinct, min_, minDistinct
146+ -- * Types
147+ , TypeExpression (UnsafeTypeExpression, renderTypeExpression)
148+ , PGTyped (pgtype)
149+ , bool
150+ , int2
151+ , smallint
152+ , int4
153+ , int
154+ , integer
155+ , int8
156+ , bigint
157+ , numeric
158+ , float4
159+ , real
160+ , float8
161+ , doublePrecision
162+ , text
163+ , char
164+ , character
165+ , varchar
166+ , characterVarying
167+ , bytea
168+ , timestamp
169+ , timestampWithTimeZone
170+ , date
171+ , time
172+ , timeWithTimeZone
173+ , interval
174+ , uuid
175+ , inet
176+ , json
177+ , jsonb
178+ , vararray
179+ , fixarray
57180 -- * Re-export
58181 , (&)
59− , K (..)
60− , unK
182+ , NP ((:*), Nil)
61183 ) where
62184
63185import Control.Category
64186import Control.DeepSeq
65187import Data.ByteString (ByteString)
188+import Data.ByteString.Lazy (toStrict)
66189import Data.Function ((&))
67190import Data.Semigroup hiding (All)
191+import qualified Data.Aeson as JSON
192+import Data.Ratio
68193import Data.String
69−import Generics.SOP hiding (All, from)
194+import Generics.SOP hiding (from)
70195import GHC.OverloadedLabels
71196import GHC.TypeLits
72−import Numeric
73197import Prelude hiding (id, (.))
74198
75199import qualified GHC.Generics as GHC
76200
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79201import Squeal.PostgreSQL.Render
80202import Squeal.PostgreSQL.Schema
81203
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85204{-----------------------------------------
86205column expressions
87206-----------------------------------------}
88207
89208{- | `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,
209+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92210as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93211`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
212+or in search `Condition`s in a number of commands.
95213
96214The expression syntax allows the calculation of
97215values from primitive expression using arithmetic, logical,
98216and 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`.
113217-}
114218newtype Expression
115− (outer :: FromType)
116− (commons :: FromType)
117− (grp :: Grouping)
118− (schemas :: SchemasType)
219+ (schema :: SchemaType)
220+ (relations :: RelationsType)
221+ (grouping :: Grouping)
119222 (params :: [NullityType])
120− (from :: FromType)
121223 (ty :: NullityType)
122224 = UnsafeExpression { renderExpression :: ByteString }
123225 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
226+
227+instance RenderSQL (Expression schema relations grouping params ty) where
125228 renderSQL = renderExpression
126229
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.
230+{- | A `HasParameter` constraint is used to indicate a value that is
231+supplied externally to a SQL statement.
232+`Squeal.PostgreSQL.PQ.manipulateParams`,
233+`Squeal.PostgreSQL.PQ.queryParams` and
234+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
235+separately from the SQL command string, in which case `param`s are used to
236+refer to the out-of-line data values.
198237-}
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
238+class KnownNat n => HasParameter
239+ (n :: Nat)
240+ (schema :: SchemaType)
241+ (params :: [NullityType])
242+ (ty :: NullityType)
243+ | n params -> ty where
244+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
245+ --
246+ -- >>> let expr = parameter @1 int4 :: Expression sch rels grp '[ 'Null 'PGint4] ('Null 'PGint4)
247+ -- >>> printSQL expr
248+ -- ($1 :: int4)
249+ parameter
250+ :: TypeExpression schema ty
251+ -> Expression schema relations grouping params ty
252+ parameter ty = UnsafeExpression $ parenthesized $
253+ "$" <> renderNat @n <+> "::"
254+ <+> renderTypeExpression ty
255+instance {-# OVERLAPPING #-} HasParameter 1 schema (ty1:tys) ty1
256+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) schema params ty)
257+ => HasParameter n schema (ty' : params) ty
258+
259+-- | `param` takes a `Nat` using type application and for basic types,
260+-- infers a `TypeExpression`.
261+--
262+-- >>> let expr = param @1 :: Expression sch rels grp '[ 'Null 'PGint4] ('Null 'PGint4)
263+-- >>> printSQL expr
264+-- ($1 :: int4)
265+param
266+ :: forall n schema params relations grouping ty
267+ . (PGTyped schema ty, HasParameter n schema params ty)
268+ => Expression schema relations grouping params ty -- ^ param
269+param = parameter @n pgtype
270+
271+instance (HasUnique relation relations columns, Has column columns ty)
272+ => IsLabel column (Expression schema relations 'Ungrouped params ty) where
273+ fromLabel = UnsafeExpression $ renderAlias (Alias @column)
274+instance (HasUnique relation relations columns, Has column columns ty)
275+ => IsLabel column
276+ (Aliased (Expression schema relations 'Ungrouped params) (column ::: ty)) where
277+ fromLabel = fromLabel @column `As` Alias @column
278+instance (HasUnique relation relations columns, Has column columns ty)
279+ => IsLabel column
280+ (NP (Aliased (Expression schema relations 'Ungrouped params)) '[column ::: ty]) where
281+ fromLabel = fromLabel @column :* Nil
282+
283+instance (Has relation relations columns, Has column columns ty)
284+ => IsQualified relation column (Expression schema relations 'Ungrouped params ty) where
285+ relation ! column = UnsafeExpression $
286+ renderAlias relation <> "." <> renderAlias column
287+instance (Has relation relations columns, Has column columns ty)
288+ => IsQualified relation column
289+ (Aliased (Expression schema relations 'Ungrouped params) (column ::: ty)) where
290+ relation ! column = relation ! column `As` column
291+instance (Has relation relations columns, Has column columns ty)
292+ => IsQualified relation column
293+ (NP (Aliased (Expression schema relations 'Ungrouped params)) '[column ::: ty]) where
294+ relation ! column = relation ! column :* Nil
245295
246296instance
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
297+ ( HasUnique relation relations columns
298+ , Has column columns ty
299+ , GroupedBy relation column bys
300+ ) => IsLabel column
301+ (Expression schema relations ('Grouped bys) params ty) where
302+ fromLabel = UnsafeExpression $ renderAlias (Alias @column)
261303instance
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
304+ ( HasUnique relation relations columns
305+ , Has column columns ty
306+ , GroupedBy relation column bys
307+ ) => IsLabel column
308+ ( Aliased (Expression schema relations ('Grouped bys) params)
309+ (column ::: ty) ) where
310+ fromLabel = fromLabel @column `As` Alias @column
269311instance
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
312+ ( HasUnique relation relations columns
313+ , Has column columns ty
314+ , GroupedBy relation column bys
315+ ) => IsLabel column
316+ ( NP (Aliased (Expression schema relations ('Grouped bys) params))
317+ '[column ::: ty] ) where
318+ fromLabel = fromLabel @column :* Nil
277319
278320instance
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
321+ ( Has relation relations columns
322+ , Has column columns ty
323+ , GroupedBy relation column bys
324+ ) => IsQualified relation column
325+ (Expression schema relations ('Grouped bys) params ty) where
326+ relation ! column = UnsafeExpression $
327+ renderAlias relation <> "." <> renderAlias column
294328instance
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
329+ ( Has relation relations columns
330+ , Has column columns ty
331+ , GroupedBy relation column bys
332+ ) => IsQualified relation column
333+ (Aliased (Expression schema relations ('Grouped bys) params)
334+ (column ::: ty)) where
335+ relation ! column = relation ! column `As` column
302336instance
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
337+ ( Has relation relations columns
338+ , Has column columns ty
339+ , GroupedBy relation column bys
340+ ) => IsQualified relation column
341+ ( NP (Aliased (Expression schema relations ('Grouped bys) params))
342+ '[column ::: ty]) where
343+ relation ! column = relation ! column :* Nil
344+
345+-- | analagous to `Nothing`
346+--
347+-- >>> printSQL null_
348+-- NULL
349+null_ :: Expression schema rels grouping params ('Null ty)
350+null_ = UnsafeExpression "NULL"
351+
352+-- | analagous to `Just`
353+--
354+-- >>> printSQL $ notNull true
355+-- TRUE
356+notNull
357+ :: Expression schema rels grouping params ('NotNull ty)
358+ -> Expression schema rels grouping params ('Null ty)
359+notNull = UnsafeExpression . renderExpression
360+
361+-- | return the leftmost value which is not NULL
362+--
363+-- >>> printSQL $ coalesce [null_, notNull true] false
364+-- COALESCE(NULL, TRUE, FALSE)
365+coalesce
366+ :: [Expression schema relations grouping params ('Null ty)]
367+ -- ^ @NULL@s may be present
368+ -> Expression schema relations grouping params ('NotNull ty)
369+ -- ^ @NULL@ is absent
370+ -> Expression schema relations grouping params ('NotNull ty)
371+coalesce nullxs notNullx = UnsafeExpression $
372+ "COALESCE" <> parenthesized (commaSeparated
373+ ((renderExpression <$> nullxs) <> [renderExpression notNullx]))
374+
375+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
376+--
377+-- >>> printSQL $ fromNull true null_
378+-- COALESCE(NULL, TRUE)
379+fromNull
380+ :: Expression schema relations grouping params ('NotNull ty)
381+ -- ^ what to convert @NULL@ to
382+ -> Expression schema relations grouping params ('Null ty)
383+ -> Expression schema relations grouping params ('NotNull ty)
384+fromNull notNullx nullx = coalesce [nullx] notNullx
385+
386+-- | >>> printSQL $ null_ & isNull
387+-- NULL IS NULL
388+isNull
389+ :: Expression schema relations grouping params ('Null ty)
390+ -- ^ possibly @NULL@
391+ -> Condition schema relations grouping params
392+isNull x = UnsafeExpression $ renderExpression x <+> "IS NULL"
393+
394+-- | >>> printSQL $ null_ & isNotNull
395+-- NULL IS NOT NULL
396+isNotNull
397+ :: Expression schema relations grouping params ('Null ty)
398+ -- ^ possibly @NULL@
399+ -> Condition schema relations grouping params
400+isNotNull x = UnsafeExpression $ renderExpression x <+> "IS NOT NULL"
401+
402+-- | analagous to `maybe` using @IS NULL@
403+--
404+-- >>> printSQL $ matchNull true not_ null_
405+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
406+matchNull
407+ :: Expression schema relations grouping params (nullty)
408+ -- ^ what to convert @NULL@ to
409+ -> ( Expression schema relations grouping params ('NotNull ty)
410+ -> Expression schema relations grouping params (nullty) )
411+ -- ^ function to perform when @NULL@ is absent
412+ -> Expression schema relations grouping params ('Null ty)
413+ -> Expression schema relations grouping params (nullty)
414+matchNull y f x = ifThenElse (isNull x) y
415+ (f (UnsafeExpression (renderExpression x)))
416+
417+{-| right inverse to `fromNull`, if its arguments are equal then
418+`nullIf` gives @NULL@.
419+
420+>>> :set -XTypeApplications -XDataKinds
421+>>> let expr = nullIf false (param @1) :: Expression schema rels grp '[ 'NotNull 'PGbool] ('Null 'PGbool)
422+>>> printSQL expr
423+NULL IF (FALSE, ($1 :: bool))
424+-}
425+nullIf
426+ :: Expression schema relations grouping params ('NotNull ty)
427+ -- ^ @NULL@ is absent
428+ -> Expression schema relations grouping params ('NotNull ty)
429+ -- ^ @NULL@ is absent
430+ -> Expression schema relations grouping params ('Null ty)
431+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
432+ (renderExpression x <> ", " <> renderExpression y)
433+
434+-- | >>> printSQL $ array [null_, notNull false, notNull true]
435+-- ARRAY[NULL, FALSE, TRUE]
436+array
437+ :: [Expression schema relations grouping params ty]
438+ -- ^ array elements
439+ -> Expression schema relations grouping params (nullity ('PGvararray ty))
440+array xs = UnsafeExpression $
441+ "ARRAY[" <> commaSeparated (renderExpression <$> xs) <> "]"
310442
311443instance (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)
444+ (Expression schema relations grouping params (nullity ('PGenum labels))) where
445+ label = UnsafeExpression $ renderLabel (PGlabel @label)
446+
447+-- | A row constructor is an expression that builds a row value
448+-- (also called a composite value) using values for its member fields.
449+--
450+-- >>> :{
451+-- type Complex = 'PGcomposite
452+-- '[ "real" ::: 'NotNull 'PGfloat8
453+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
454+-- :}
455+--
456+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression '[] '[] 'Ungrouped '[] ('NotNull Complex)
457+-- >>> printSQL i
458+-- ROW(0, 1)
459+row
460+ :: SListI fields
461+ => NP (Aliased (Expression schema relations grouping params)) fields
462+ -- ^ zero or more expressions for the row field values
463+ -> Expression schema relations grouping params (nullity ('PGcomposite fields))
464+row exprs = UnsafeExpression $ "ROW" <> parenthesized
465+ (renderCommaSeparated (\ (expr `As` _) -> renderExpression expr) exprs)
466+
467+instance Has field fields ty => IsLabel field
468+ ( Expression schema relation grouping params ('NotNull ('PGcomposite fields))
469+ -> Expression schema relation grouping params ty ) where
470+ fromLabel expr = UnsafeExpression $
471+ parenthesized (renderExpression expr) <> "." <>
472+ renderSymbol @field
473+
474+instance Semigroup
475+ (Expression schema relations grouping params (nullity ('PGvararray ty))) where
476+ (<>) = unsafeBinaryOp "||"
477+
478+instance Monoid
479+ (Expression schema relations grouping params (nullity ('PGvararray ty))) where
480+ mempty = array []
481+ mappend = (<>)
482+
483+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression sch rels grp '[ 'NotNull 'PGtimestamptz] ('NotNull 'PGtimestamptz)
484+-- >>> printSQL expr
485+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
486+greatest
487+ :: Expression schema relations grouping params (nullty)
488+ -- ^ needs at least 1 argument
489+ -> [Expression schema relations grouping params (nullty)]
490+ -- ^ or more
491+ -> Expression schema relations grouping params (nullty)
492+greatest x xs = UnsafeExpression $ "GREATEST("
493+ <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
494+
495+-- | >>> printSQL $ least currentTimestamp [null_]
496+-- LEAST(CURRENT_TIMESTAMP, NULL)
497+least
498+ :: Expression schema relations grouping params (nullty)
499+ -- ^ needs at least 1 argument
500+ -> [Expression schema relations grouping params (nullty)]
501+ -- ^ or more
502+ -> Expression schema relations grouping params (nullty)
503+least x xs = UnsafeExpression $ "LEAST("
504+ <> commaSeparated (renderExpression <$> (x:xs)) <> ")"
314505
315506-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316507-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
508+unsafeBinaryOp
509+ :: ByteString
510+ -- ^ operator
511+ -> Expression schema relations grouping params (ty0)
512+ -> Expression schema relations grouping params (ty1)
513+ -> Expression schema relations grouping params (ty2)
318514unsafeBinaryOp 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
515+ renderExpression x <+> op <+> renderExpression y
327516
328−-- | >>> printSQL $ unsafeLeftOp "NOT" true
517+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329518-- (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
519+unsafeUnaryOp
520+ :: ByteString
521+ -- ^ operator
522+ -> Expression schema relations grouping params (ty0)
523+ -> Expression schema relations grouping params (ty1)
524+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
525+ op <+> renderExpression x
351526
352527-- | >>> printSQL $ unsafeFunction "f" true
353528-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
529+unsafeFunction
530+ :: ByteString
531+ -- ^ function
532+ -> Expression schema relations grouping params (xty)
533+ -> Expression schema relations grouping params (yty)
355534unsafeFunction 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
535+ fun <> parenthesized (renderExpression x)
536+
537+-- | Helper for defining variadic functions.
538+unsafeVariadicFunction
539+ :: SListI elems
540+ => ByteString
541+ -- ^ function
542+ -> NP (Expression schema relations grouping params) elems
543+ -> Expression schema relations grouping params ret
544+unsafeVariadicFunction fun x = UnsafeExpression $
545+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderExpression) x)))
546+
547+instance PGNum ty
548+ => Num (Expression schema relations grouping params (nullity ty)) where
380549 (+) = unsafeBinaryOp "+"
381550 (-) = unsafeBinaryOp "-"
382551 (*) = unsafeBinaryOp "*"
@@ -387,24 +556,19 @@ instance ty `In` PGNum
387556 . fromString
388557 . show
389558
390−instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
559+instance (PGNum ty, PGFloating ty) => Fractional
560+ (Expression schema relations grouping params (nullity ty)) where
392561 (/) = unsafeBinaryOp "/"
393− fromRational
394− = UnsafeExpression
395− . fromString
396− . ($ "")
397− . showFFloat Nothing
398− . fromRat @Double
562+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
399563
400−instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
564+instance (PGNum ty, PGFloating ty) => Floating
565+ (Expression schema relations grouping params (nullity ty)) where
402566 pi = UnsafeExpression "pi()"
403567 exp = unsafeFunction "exp"
404568 log = unsafeFunction "ln"
405569 sqrt = unsafeFunction "sqrt"
406570 b ** x = UnsafeExpression $
407− "power(" <> renderSQL b <> ", " <> renderSQL x <> ")"
571+ "power(" <> renderExpression b <> ", " <> renderExpression x <> ")"
408572 logBase b y = log y / log b
409573 sin = unsafeFunction "sin"
410574 cos = unsafeFunction "cos"
@@ -419,54 +583,1129 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419583 acosh x = log (x + sqrt (x*x - 1))
420584 atanh x = log ((1 + x) / (1 - x)) / 2
421585
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)
586+-- | >>> :{
587+-- let
588+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
589+-- expression = atan2_ pi 2
590+-- in printSQL expression
591+-- :}
592+-- atan2(pi(), 2)
593+atan2_
594+ :: PGFloating float
595+ => Expression schema relations grouping params (nullity float)
596+ -- ^ numerator
597+ -> Expression schema relations grouping params (nullity float)
598+ -- ^ denominator
599+ -> Expression schema relations grouping params (nullity float)
600+atan2_ y x = UnsafeExpression $
601+ "atan2(" <> renderExpression y <> ", " <> renderExpression x <> ")"
602+
603+-- When a `cast` is applied to an `Expression` of a known type, it
604+-- represents a run-time type conversion. The cast will succeed only if a
605+-- suitable type conversion operation has been defined.
606+--
607+-- | >>> printSQL $ true & cast int4
608+-- (TRUE :: int4)
609+cast
610+ :: TypeExpression schema ty1
611+ -- ^ type to cast as
612+ -> Expression schema relations grouping params ty0
613+ -- ^ value to convert
614+ -> Expression schema relations grouping params ty1
615+cast ty x = UnsafeExpression $ parenthesized $
616+ renderExpression x <+> "::" <+> renderTypeExpression ty
617+
618+-- | integer division, truncates the result
619+--
620+-- >>> :{
621+-- let
622+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
623+-- expression = 5 `quot_` 2
624+-- in printSQL expression
625+-- :}
626+-- (5 / 2)
627+quot_
628+ :: PGIntegral int
629+ => Expression schema relations grouping params (nullity int)
630+ -- ^ numerator
631+ -> Expression schema relations grouping params (nullity int)
632+ -- ^ denominator
633+ -> Expression schema relations grouping params (nullity int)
634+quot_ = unsafeBinaryOp "/"
635+
636+-- | remainder upon integer division
637+--
638+-- >>> :{
639+-- let
640+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
641+-- expression = 5 `rem_` 2
642+-- in printSQL expression
643+-- :}
644+-- (5 % 2)
645+rem_
646+ :: PGIntegral int
647+ => Expression schema relations grouping params (nullity int)
648+ -- ^ numerator
649+ -> Expression schema relations grouping params (nullity int)
650+ -- ^ denominator
651+ -> Expression schema relations grouping params (nullity int)
652+rem_ = unsafeBinaryOp "%"
653+
654+-- | >>> :{
655+-- let
656+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
657+-- expression = trunc pi
658+-- in printSQL expression
659+-- :}
660+-- trunc(pi())
661+trunc
662+ :: PGFloating frac
663+ => Expression schema relations grouping params (nullity frac)
664+ -- ^ fractional number
665+ -> Expression schema relations grouping params (nullity frac)
666+trunc = unsafeFunction "trunc"
667+
668+-- | >>> :{
669+-- let
670+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
671+-- expression = round_ pi
672+-- in printSQL expression
673+-- :}
674+-- round(pi())
675+round_
676+ :: PGFloating frac
677+ => Expression schema relations grouping params (nullity frac)
678+ -- ^ fractional number
679+ -> Expression schema relations grouping params (nullity frac)
680+round_ = unsafeFunction "round"
681+
682+-- | >>> :{
683+-- let
684+-- expression :: Expression schema relations grouping params (nullity 'PGfloat4)
685+-- expression = ceiling_ pi
686+-- in printSQL expression
687+-- :}
688+-- ceiling(pi())
689+ceiling_
690+ :: PGFloating frac
691+ => Expression schema relations grouping params (nullity frac)
692+ -- ^ fractional number
693+ -> Expression schema relations grouping params (nullity frac)
694+ceiling_ = unsafeFunction "ceiling"
695+
696+-- | A `Condition` is a boolean valued `Expression`. While SQL allows
697+-- conditions to have @NULL@, Squeal instead chooses to disallow @NULL@,
698+-- forcing one to handle the case of @NULL@ explicitly to produce
699+-- a `Condition`.
700+type Condition schema relations grouping params =
701+ Expression schema relations grouping params ('NotNull 'PGbool)
702+
703+-- | >>> printSQL true
704+-- TRUE
705+true :: Condition schema relations grouping params
706+true = UnsafeExpression "TRUE"
707+
708+-- | >>> printSQL false
709+-- FALSE
710+false :: Condition schema relations grouping params
711+false = UnsafeExpression "FALSE"
712+
713+-- | >>> printSQL $ not_ true
714+-- (NOT TRUE)
715+not_
716+ :: Condition schema relations grouping params
717+ -> Condition schema relations grouping params
718+not_ = unsafeUnaryOp "NOT"
719+
720+-- | >>> printSQL $ true .&& false
721+-- (TRUE AND FALSE)
722+(.&&)
723+ :: Condition schema relations grouping params
724+ -> Condition schema relations grouping params
725+ -> Condition schema relations grouping params
726+(.&&) = unsafeBinaryOp "AND"
727+
728+-- | >>> printSQL $ true .|| false
729+-- (TRUE OR FALSE)
730+(.||)
731+ :: Condition schema relations grouping params
732+ -> Condition schema relations grouping params
733+ -> Condition schema relations grouping params
734+(.||) = unsafeBinaryOp "OR"
735+
736+-- | >>> :{
737+-- let
738+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
739+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
740+-- in printSQL expression
741+-- :}
742+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
743+caseWhenThenElse
744+ :: [ ( Condition schema relations grouping params
745+ , Expression schema relations grouping params (ty)
746+ ) ]
747+ -- ^ whens and thens
748+ -> Expression schema relations grouping params (ty)
749+ -- ^ else
750+ -> Expression schema relations grouping params (ty)
751+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
752+ [ "CASE"
753+ , mconcat
754+ [ mconcat
755+ [ " WHEN ", renderExpression when_
756+ , " THEN ", renderExpression then_
757+ ]
758+ | (when_,then_) <- whenThens
759+ ]
760+ , " ELSE ", renderExpression else_
761+ , " END"
762+ ]
763+
764+-- | >>> :{
765+-- let
766+-- expression :: Expression schema relations grouping params (nullity 'PGint2)
767+-- expression = ifThenElse true 1 0
768+-- in printSQL expression
769+-- :}
770+-- CASE WHEN TRUE THEN 1 ELSE 0 END
771+ifThenElse
772+ :: Condition schema relations grouping params
773+ -> Expression schema relations grouping params (ty) -- ^ then
774+ -> Expression schema relations grouping params (ty) -- ^ else
775+ -> Expression schema relations grouping params (ty)
776+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
777+
778+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
779+-- will produce @NULL@s if one of their arguments is @NULL@.
780+--
781+-- >>> printSQL $ notNull true .== null_
782+-- (TRUE = NULL)
783+(.==)
784+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
785+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
786+ -> Expression schema relations grouping params (nullity 'PGbool)
787+(.==) = unsafeBinaryOp "="
788+infix 4 .==
789+
790+-- | >>> printSQL $ notNull true ./= null_
791+-- (TRUE <> NULL)
792+(./=)
793+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
794+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
795+ -> Expression schema relations grouping params (nullity 'PGbool)
796+(./=) = unsafeBinaryOp "<>"
797+infix 4 ./=
798+
799+-- | >>> printSQL $ notNull true .>= null_
800+-- (TRUE >= NULL)
801+(.>=)
802+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
803+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
804+ -> Expression schema relations grouping params (nullity 'PGbool)
805+(.>=) = unsafeBinaryOp ">="
806+infix 4 .>=
807+
808+-- | >>> printSQL $ notNull true .< null_
809+-- (TRUE < NULL)
810+(.<)
811+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
812+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
813+ -> Expression schema relations grouping params (nullity 'PGbool)
814+(.<) = unsafeBinaryOp "<"
815+infix 4 .<
816+
817+-- | >>> printSQL $ notNull true .<= null_
818+-- (TRUE <= NULL)
819+(.<=)
820+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
821+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
822+ -> Expression schema relations grouping params (nullity 'PGbool)
823+(.<=) = unsafeBinaryOp "<="
824+infix 4 .<=
825+
826+-- | >>> printSQL $ notNull true .> null_
827+-- (TRUE > NULL)
828+(.>)
829+ :: Expression schema relations grouping params (nullity ty) -- ^ lhs
830+ -> Expression schema relations grouping params (nullity ty) -- ^ rhs
831+ -> Expression schema relations grouping params (nullity 'PGbool)
832+(.>) = unsafeBinaryOp ">"
833+infix 4 .>
834+
835+-- | >>> printSQL currentDate
836+-- CURRENT_DATE
837+currentDate
838+ :: Expression schema relations grouping params (nullity 'PGdate)
839+currentDate = UnsafeExpression "CURRENT_DATE"
840+
841+-- | >>> printSQL currentTime
842+-- CURRENT_TIME
843+currentTime
844+ :: Expression schema relations grouping params (nullity 'PGtimetz)
845+currentTime = UnsafeExpression "CURRENT_TIME"
846+
847+-- | >>> printSQL currentTimestamp
848+-- CURRENT_TIMESTAMP
849+currentTimestamp
850+ :: Expression schema relations grouping params (nullity 'PGtimestamptz)
851+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
852+
853+-- | >>> printSQL localTime
854+-- LOCALTIME
855+localTime
856+ :: Expression schema relations grouping params (nullity 'PGtime)
857+localTime = UnsafeExpression "LOCALTIME"
858+
859+-- | >>> printSQL localTimestamp
860+-- LOCALTIMESTAMP
861+localTimestamp
862+ :: Expression schema relations grouping params (nullity 'PGtimestamp)
863+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
864+
865+{-----------------------------------------
866+text
867+-----------------------------------------}
438868
439869instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
870+ (Expression schema relations grouping params (nullity 'PGtext)) where
441871 fromString str = UnsafeExpression $
442872 "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) <> "\'"
873+ where
874+ escape = \case
875+ '\NUL' -> "\\0"
876+ '\'' -> "''"
877+ '"' -> "\\\""
878+ '\b' -> "\\b"
879+ '\n' -> "\\n"
880+ '\r' -> "\\r"
881+ '\t' -> "\\t"
882+ '\\' -> "\\\\"
883+ c -> [c]
451884
452885instance 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
886+ (Expression schema relations grouping params (nullity 'PGtext)) where
463887 (<>) = unsafeBinaryOp "||"
464888
465889instance 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
890+ (Expression schema relations grouping params (nullity 'PGtext)) where
471891 mempty = fromString ""
472892 mappend = (<>)
893+
894+-- | >>> printSQL $ lower "ARRRGGG"
895+-- lower(E'ARRRGGG')
896+lower
897+ :: Expression schema relations grouping params (nullity 'PGtext)
898+ -- ^ string to lower case
899+ -> Expression schema relations grouping params (nullity 'PGtext)
900+lower = unsafeFunction "lower"
901+
902+-- | >>> printSQL $ upper "eeee"
903+-- upper(E'eeee')
904+upper
905+ :: Expression schema relations grouping params (nullity 'PGtext)
906+ -- ^ string to upper case
907+ -> Expression schema relations grouping params (nullity 'PGtext)
908+upper = unsafeFunction "upper"
909+
910+-- | >>> printSQL $ charLength "four"
911+-- char_length(E'four')
912+charLength
913+ :: Expression schema relations grouping params (nullity 'PGtext)
914+ -- ^ string to measure
915+ -> Expression schema relations grouping params (nullity 'PGint4)
916+charLength = unsafeFunction "char_length"
917+
918+-- | The `like` expression returns true if the @string@ matches
919+-- the supplied @pattern@. If @pattern@ does not contain percent signs
920+-- or underscores, then the pattern only represents the string itself;
921+-- in that case `like` acts like the equals operator. An underscore (_)
922+-- in pattern stands for (matches) any single character; a percent sign (%)
923+-- matches any sequence of zero or more characters.
924+--
925+-- >>> printSQL $ "abc" `like` "a%"
926+-- (E'abc' LIKE E'a%')
927+like
928+ :: Expression schema relations grouping params (nullity 'PGtext)
929+ -- ^ string
930+ -> Expression schema relations grouping params (nullity 'PGtext)
931+ -- ^ pattern
932+ -> Expression schema relations grouping params (nullity 'PGbool)
933+like = unsafeBinaryOp "LIKE"
934+
935+{-----------------------------------------
936+ -- json and jsonb support
937+
938+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
939+comments lifted directly from this page.
940+
941+Table 9.44: json and jsonb operators
942+-----------------------------------------}
943+
944+-- | Get JSON value (object field or array element) at a key.
945+(.->)
946+ :: (PGjson_ json, PGjsonKey key)
947+ => Expression schema relations grouping params (nullity json)
948+ -> Expression schema relations grouping params (nullity key)
949+ -> Expression schema relations grouping params ('Null json)
950+(.->) = unsafeBinaryOp "->"
951+
952+-- | Get JSON value (object field or array element) at a key, as text.
953+(.->>)
954+ :: (PGjson_ json, PGjsonKey key)
955+ => Expression schema relations grouping params (nullity json)
956+ -> Expression schema relations grouping params (nullity key)
957+ -> Expression schema relations grouping params ('Null 'PGtext)
958+(.->>) = unsafeBinaryOp "->>"
959+
960+-- | Get JSON value at a specified path.
961+(.#>)
962+ :: (PGjson_ json, PGtextArray "(.#>)" path)
963+ => Expression schema relations grouping params (nullity json)
964+ -> Expression schema relations grouping params (nullity path)
965+ -> Expression schema relations grouping params ('Null json)
966+(.#>) = unsafeBinaryOp "#>"
967+
968+-- | Get JSON value at a specified path as text.
969+(.#>>)
970+ :: (PGjson_ json, PGtextArray "(.#>>)" path)
971+ => Expression schema relations grouping params (nullity json)
972+ -> Expression schema relations grouping params (nullity path)
973+ -> Expression schema relations grouping params ('Null 'PGtext)
974+(.#>>) = unsafeBinaryOp "#>>"
975+
976+-- Additional jsonb operators
977+
978+-- | Does the left JSON value contain the right JSON path/value entries at the
979+-- top level?
980+(.@>)
981+ :: Expression schema relations grouping params (nullity 'PGjsonb)
982+ -> Expression schema relations grouping params (nullity 'PGjsonb)
983+ -> Condition schema relations grouping params
984+(.@>) = unsafeBinaryOp "@>"
985+
986+-- | Are the left JSON path/value entries contained at the top level within the
987+-- right JSON value?
988+(.<@)
989+ :: Expression schema relations grouping params (nullity 'PGjsonb)
990+ -> Expression schema relations grouping params (nullity 'PGjsonb)
991+ -> Condition schema relations grouping params
992+(.<@) = unsafeBinaryOp "<@"
993+
994+-- | Does the string exist as a top-level key within the JSON value?
995+(.?)
996+ :: Expression schema relations grouping params (nullity 'PGjsonb)
997+ -> Expression schema relations grouping params (nullity 'PGtext)
998+ -> Condition schema relations grouping params
999+(.?) = unsafeBinaryOp "?"
1000+
1001+-- | Do any of these array strings exist as top-level keys?
1002+(.?|)
1003+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1004+ -> Expression schema relations grouping params (nullity ('PGvararray ('NotNull 'PGtext)))
1005+ -> Condition schema relations grouping params
1006+(.?|) = unsafeBinaryOp "?|"
1007+
1008+-- | Do all of these array strings exist as top-level keys?
1009+(.?&)
1010+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1011+ -> Expression schema relations grouping params (nullity ('PGvararray ('NotNull 'PGtext)))
1012+ -> Condition schema relations grouping params
1013+(.?&) = unsafeBinaryOp "?&"
1014+
1015+-- | Concatenate two jsonb values into a new jsonb value.
1016+instance
1017+ Semigroup (Expression schema relations grouping param (nullity 'PGjsonb)) where
1018+ (<>) = unsafeBinaryOp "||"
1019+
1020+-- | Delete a key or keys from a JSON object, or remove an array element.
1021+--
1022+-- If the right operand is..
1023+--
1024+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1025+-- are matched based on their key value.
1026+--
1027+-- @ text[] @: Delete multiple key/value pairs or string elements
1028+-- from left operand. Key/value pairs are matched based on their key value.
1029+--
1030+-- @ integer @: Delete the array element with specified index (Negative integers
1031+-- count from the end). Throws an error if top level container is not an array.
1032+(.-.)
1033+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1034+ => Expression schema relations grouping params (nullity 'PGjsonb)
1035+ -> Expression schema relations grouping params (nullity key)
1036+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1037+(.-.) = unsafeBinaryOp "-"
1038+
1039+-- | Delete the field or element with specified path (for JSON arrays, negative
1040+-- integers count from the end)
1041+(#-.)
1042+ :: PGtextArray "(#-.)" arrayty
1043+ => Expression schema relations grouping params (nullity 'PGjsonb)
1044+ -> Expression schema relations grouping params (nullity arrayty)
1045+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1046+(#-.) = unsafeBinaryOp "#-"
1047+
1048+{-----------------------------------------
1049+Table 9.45: JSON creation functions
1050+-----------------------------------------}
1051+
1052+-- | Literal binary JSON
1053+jsonbLit :: JSON.Value -> Expression schema relations grouping params (nullity 'PGjsonb)
1054+jsonbLit = cast jsonb . UnsafeExpression . singleQuotedUtf8 . toStrict . JSON.encode
1055+
1056+-- | Literal JSON
1057+jsonLit :: JSON.Value -> Expression schema relations grouping params (nullity 'PGjson)
1058+jsonLit = cast json . UnsafeExpression . singleQuotedUtf8 . toStrict . JSON.encode
1059+
1060+-- | Returns the value as json. Arrays and composites are converted
1061+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1062+-- type to json, the cast function will be used to perform the conversion;
1063+-- otherwise, a scalar value is produced. For any scalar type other than a
1064+-- number, a Boolean, or a null value, the text representation will be used, in
1065+-- such a fashion that it is a valid json value.
1066+toJson
1067+ :: Expression schema relations grouping params (nullity ty)
1068+ -> Expression schema relations grouping params (nullity 'PGjson)
1069+toJson = unsafeFunction "to_json"
1070+
1071+-- | Returns the value as jsonb. Arrays and composites are converted
1072+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1073+-- type to json, the cast function will be used to perform the conversion;
1074+-- otherwise, a scalar value is produced. For any scalar type other than a
1075+-- number, a Boolean, or a null value, the text representation will be used, in
1076+-- such a fashion that it is a valid jsonb value.
1077+toJsonb
1078+ :: Expression schema relations grouping params (nullity ty)
1079+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1080+toJsonb = unsafeFunction "to_jsonb"
1081+
1082+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1083+-- becomes a JSON array of arrays.
1084+arrayToJson
1085+ :: PGarray "arrayToJson" arr
1086+ => Expression schema relations grouping params (nullity arr)
1087+ -> Expression schema relations grouping params (nullity 'PGjson)
1088+arrayToJson = unsafeFunction "array_to_json"
1089+
1090+-- | Returns the row as a JSON object.
1091+rowToJson
1092+ :: Expression schema relations grouping params (nullity ('PGcomposite ty))
1093+ -> Expression schema relations grouping params (nullity 'PGjson)
1094+rowToJson = unsafeFunction "row_to_json"
1095+
1096+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1097+-- argument list.
1098+jsonBuildArray
1099+ :: SListI elems
1100+ => NP (Expression schema relations grouping params) elems
1101+ -> Expression schema relations grouping params (nullity 'PGjson)
1102+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1103+
1104+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1105+-- variadic argument list.
1106+jsonbBuildArray
1107+ :: SListI elems
1108+ => NP (Expression schema relations grouping params) elems
1109+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1110+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1111+
1112+unsafeRowFunction
1113+ :: All Top elems
1114+ => NP (Aliased (Expression schema relations grouping params)) elems
1115+ -> [ByteString]
1116+unsafeRowFunction =
1117+ (`appEndo` []) . hcfoldMap (Proxy :: Proxy Top)
1118+ (\(col `As` name) -> Endo $ \xs ->
1119+ renderAliasString name : renderExpression col : xs)
1120+
1121+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1122+-- argument list. The elements of the argument list must alternate between text
1123+-- and values.
1124+jsonBuildObject
1125+ :: All Top elems
1126+ => NP (Aliased (Expression schema relations grouping params)) elems
1127+ -> Expression schema relations grouping params (nullity 'PGjson)
1128+jsonBuildObject
1129+ = unsafeFunction "json_build_object"
1130+ . UnsafeExpression
1131+ . commaSeparated
1132+ . unsafeRowFunction
1133+
1134+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1135+-- variadic argument list. The elements of the argument list must alternate
1136+-- between text and values.
1137+jsonbBuildObject
1138+ :: All Top elems
1139+ => NP (Aliased (Expression schema relations grouping params)) elems
1140+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1141+jsonbBuildObject
1142+ = unsafeFunction "jsonb_build_object"
1143+ . UnsafeExpression
1144+ . commaSeparated
1145+ . unsafeRowFunction
1146+
1147+-- | Builds a JSON object out of a text array. The array must have either
1148+-- exactly one dimension with an even number of members, in which case they are
1149+-- taken as alternating key/value pairs, or two dimensions such that each inner
1150+-- array has exactly two elements, which are taken as a key/value pair.
1151+jsonObject
1152+ :: PGarrayOf "jsonObject" arr ('NotNull 'PGtext)
1153+ => Expression schema relations grouping params (nullity arr)
1154+ -> Expression schema relations grouping params (nullity 'PGjson)
1155+jsonObject = unsafeFunction "json_object"
1156+
1157+-- | Builds a binary JSON object out of a text array. The array must have either
1158+-- exactly one dimension with an even number of members, in which case they are
1159+-- taken as alternating key/value pairs, or two dimensions such that each inner
1160+-- array has exactly two elements, which are taken as a key/value pair.
1161+jsonbObject
1162+ :: PGarrayOf "jsonbObject" arr ('NotNull 'PGtext)
1163+ => Expression schema relations grouping params (nullity arr)
1164+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1165+jsonbObject = unsafeFunction "jsonb_object"
1166+
1167+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1168+-- keys and one for values, that are zipped pairwise to create a JSON object.
1169+jsonZipObject
1170+ :: ( PGarrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1171+ , PGarrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1172+ => Expression schema relations grouping params (nullity keysArray)
1173+ -> Expression schema relations grouping params (nullity valuesArray)
1174+ -> Expression schema relations grouping params (nullity 'PGjson)
1175+jsonZipObject ks vs =
1176+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1177+
1178+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1179+-- keys and one for values, that are zipped pairwise to create a binary JSON
1180+-- object.
1181+jsonbZipObject
1182+ :: ( PGarrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1183+ , PGarrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1184+ => Expression schema relations grouping params (nullity keysArray)
1185+ -> Expression schema relations grouping params (nullity valuesArray)
1186+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1187+jsonbZipObject ks vs =
1188+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1189+
1190+{-----------------------------------------
1191+Table 9.46: JSON processing functions
1192+-----------------------------------------}
1193+
1194+-- | Returns the number of elements in the outermost JSON array.
1195+jsonArrayLength
1196+ :: Expression schema relations grouping params (nullity 'PGjson)
1197+ -> Expression schema relations grouping params (nullity 'PGint4)
1198+jsonArrayLength = unsafeFunction "json_array_length"
1199+
1200+-- | Returns the number of elements in the outermost binary JSON array.
1201+jsonbArrayLength
1202+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1203+ -> Expression schema relations grouping params (nullity 'PGint4)
1204+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1205+
1206+-- | Returns JSON value pointed to by the given path (equivalent to #>
1207+-- operator).
1208+jsonExtractPath
1209+ :: SListI elems
1210+ => Expression schema relations grouping params (nullity 'PGjson)
1211+ -> NP (Expression schema relations grouping params) elems
1212+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1213+jsonExtractPath x xs =
1214+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1215+
1216+-- | Returns JSON value pointed to by the given path (equivalent to #>
1217+-- operator).
1218+jsonbExtractPath
1219+ :: SListI elems
1220+ => Expression schema relations grouping params (nullity 'PGjsonb)
1221+ -> NP (Expression schema relations grouping params) elems
1222+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1223+jsonbExtractPath x xs =
1224+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1225+
1226+-- | Returns JSON value pointed to by the given path (equivalent to #>
1227+-- operator), as text.
1228+jsonExtractPathAsText
1229+ :: SListI elems
1230+ => Expression schema relations grouping params (nullity 'PGjson)
1231+ -> NP (Expression schema relations grouping params) elems
1232+ -> Expression schema relations grouping params (nullity 'PGjson)
1233+jsonExtractPathAsText x xs =
1234+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1235+
1236+-- | Returns JSON value pointed to by the given path (equivalent to #>
1237+-- operator), as text.
1238+jsonbExtractPathAsText
1239+ :: SListI elems
1240+ => Expression schema relations grouping params (nullity 'PGjsonb)
1241+ -> NP (Expression schema relations grouping params) elems
1242+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1243+jsonbExtractPathAsText x xs =
1244+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1245+
1246+-- | Returns set of keys in the outermost JSON object.
1247+jsonObjectKeys
1248+ :: Expression schema relations grouping params (nullity 'PGjson)
1249+ -> Expression schema relations grouping params (nullity 'PGtext)
1250+jsonObjectKeys = unsafeFunction "json_object_keys"
1251+
1252+-- | Returns set of keys in the outermost JSON object.
1253+jsonbObjectKeys
1254+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1255+ -> Expression schema relations grouping params (nullity 'PGtext)
1256+jsonbObjectKeys = unsafeFunction "jsonb_object_keys"
1257+
1258+-- | Returns the type of the outermost JSON value as a text string. Possible
1259+-- types are object, array, string, number, boolean, and null.
1260+jsonTypeof
1261+ :: Expression schema relations grouping params (nullity 'PGjson)
1262+ -> Expression schema relations grouping params (nullity 'PGtext)
1263+jsonTypeof = unsafeFunction "json_typeof"
1264+
1265+-- | Returns the type of the outermost binary JSON value as a text string.
1266+-- Possible types are object, array, string, number, boolean, and null.
1267+jsonbTypeof
1268+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1269+ -> Expression schema relations grouping params (nullity 'PGtext)
1270+jsonbTypeof = unsafeFunction "jsonb_typeof"
1271+
1272+-- | Returns its argument with all object fields that have null values omitted.
1273+-- Other null values are untouched.
1274+jsonStripNulls
1275+ :: Expression schema relations grouping params (nullity 'PGjson)
1276+ -> Expression schema relations grouping params (nullity 'PGjson)
1277+jsonStripNulls = unsafeFunction "json_strip_nulls"
1278+
1279+-- | Returns its argument with all object fields that have null values omitted.
1280+-- Other null values are untouched.
1281+jsonbStripNulls
1282+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1283+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1284+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1285+
1286+-- | @ jsonbSet target path new_value create_missing @
1287+--
1288+-- Returns target with the section designated by path replaced by new_value,
1289+-- or with new_value added if create_missing is true ( default is true) and the
1290+-- item designated by path does not exist. As with the path orientated
1291+-- operators, negative integers that appear in path count from the end of JSON
1292+-- arrays.
1293+jsonbSet
1294+ :: PGtextArray "jsonbSet" arr
1295+ => Expression schema relations grouping params (nullity 'PGjsonb)
1296+ -> Expression schema relations grouping params (nullity arr)
1297+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1298+ -> Maybe (Expression schema relations grouping params (nullity 'PGbool))
1299+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1300+jsonbSet tgt path val createMissing = case createMissing of
1301+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1302+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1303+
1304+-- | @ jsonbInsert target path new_value insert_after @
1305+--
1306+-- Returns target with new_value inserted. If target section designated by
1307+-- path is in a JSONB array, new_value will be inserted before target or after
1308+-- if insert_after is true (default is false). If target section designated by
1309+-- path is in JSONB object, new_value will be inserted only if target does not
1310+-- exist. As with the path orientated operators, negative integers that appear
1311+-- in path count from the end of JSON arrays.
1312+jsonbInsert
1313+ :: PGtextArray "jsonbInsert" arr
1314+ => Expression schema relations grouping params (nullity 'PGjsonb)
1315+ -> Expression schema relations grouping params (nullity arr)
1316+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1317+ -> Maybe (Expression schema relations grouping params (nullity 'PGbool))
1318+ -> Expression schema relations grouping params (nullity 'PGjsonb)
1319+jsonbInsert tgt path val insertAfter = case insertAfter of
1320+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1321+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1322+
1323+-- | Returns its argument as indented JSON text.
1324+jsonbPretty
1325+ :: Expression schema relations grouping params (nullity 'PGjsonb)
1326+ -> Expression schema relations grouping params (nullity 'PGtext)
1327+jsonbPretty = unsafeFunction "jsonb_pretty"
1328+
1329+{-----------------------------------------
1330+aggregation
1331+-----------------------------------------}
1332+
1333+-- | escape hatch to define aggregate functions
1334+unsafeAggregate
1335+ :: ByteString -- ^ aggregate function
1336+ -> Expression schema relations 'Ungrouped params (xty)
1337+ -> Expression schema relations ('Grouped bys) params (yty)
1338+unsafeAggregate fun x = UnsafeExpression $ mconcat
1339+ [fun, "(", renderExpression x, ")"]
1340+
1341+-- | escape hatch to define aggregate functions over distinct values
1342+unsafeAggregateDistinct
1343+ :: ByteString -- ^ aggregate function
1344+ -> Expression schema relations 'Ungrouped params (xty)
1345+ -> Expression schema relations ('Grouped bys) params (yty)
1346+unsafeAggregateDistinct fun x = UnsafeExpression $ mconcat
1347+ [fun, "(DISTINCT ", renderExpression x, ")"]
1348+
1349+-- | >>> :{
1350+-- let
1351+-- expression :: Expression schema '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Grouped bys) params ('Null 'PGnumeric)
1352+-- expression = sum_ #col
1353+-- in printSQL expression
1354+-- :}
1355+-- sum("col")
1356+sum_
1357+ :: PGNum ty
1358+ => Expression schema relations 'Ungrouped params (nullity ty)
1359+ -- ^ what to sum
1360+ -> Expression schema relations ('Grouped bys) params (nullity ty)
1361+sum_ = unsafeAggregate "sum"
1362+
1363+-- | >>> :{
1364+-- let
1365+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGnumeric]] ('Grouped bys) params (nullity 'PGnumeric)
1366+-- expression = sumDistinct #col
1367+-- in printSQL expression
1368+-- :}
1369+-- sum(DISTINCT "col")
1370+sumDistinct
1371+ :: PGNum ty
1372+ => Expression schema relations 'Ungrouped params (nullity ty)
1373+ -- ^ what to sum
1374+ -> Expression schema relations ('Grouped bys) params (nullity ty)
1375+sumDistinct = unsafeAggregateDistinct "sum"
1376+
1377+-- | A constraint for `PGType`s that you can take averages of and the resulting
1378+-- `PGType`.
1379+class PGAvg ty avg | ty -> avg where
1380+ avg, avgDistinct
1381+ :: Expression schema relations 'Ungrouped params (nullity ty)
1382+ -- ^ what to average
1383+ -> Expression schema relations ('Grouped bys) params (nullity avg)
1384+ avg = unsafeAggregate "avg"
1385+ avgDistinct = unsafeAggregateDistinct "avg"
1386+instance PGAvg 'PGint2 'PGnumeric
1387+instance PGAvg 'PGint4 'PGnumeric
1388+instance PGAvg 'PGint8 'PGnumeric
1389+instance PGAvg 'PGnumeric 'PGnumeric
1390+instance PGAvg 'PGfloat4 'PGfloat8
1391+instance PGAvg 'PGfloat8 'PGfloat8
1392+instance PGAvg 'PGinterval 'PGinterval
1393+
1394+-- | >>> :{
1395+-- let
1396+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1397+-- expression = bitAnd #col
1398+-- in printSQL expression
1399+-- :}
1400+-- bit_and("col")
1401+bitAnd
1402+ :: PGIntegral int
1403+ => Expression schema relations 'Ungrouped params (nullity int)
1404+ -- ^ what to aggregate
1405+ -> Expression schema relations ('Grouped bys) params (nullity int)
1406+bitAnd = unsafeAggregate "bit_and"
1407+
1408+-- | >>> :{
1409+-- let
1410+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1411+-- expression = bitOr #col
1412+-- in printSQL expression
1413+-- :}
1414+-- bit_or("col")
1415+bitOr
1416+ :: PGIntegral int
1417+ => Expression schema relations 'Ungrouped params (nullity int)
1418+ -- ^ what to aggregate
1419+ -> Expression schema relations ('Grouped bys) params (nullity int)
1420+bitOr = unsafeAggregate "bit_or"
1421+
1422+-- | >>> :{
1423+-- let
1424+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1425+-- expression = bitAndDistinct #col
1426+-- in printSQL expression
1427+-- :}
1428+-- bit_and(DISTINCT "col")
1429+bitAndDistinct
1430+ :: PGIntegral int
1431+ => Expression schema relations 'Ungrouped params (nullity int)
1432+ -- ^ what to aggregate
1433+ -> Expression schema relations ('Grouped bys) params (nullity int)
1434+bitAndDistinct = unsafeAggregateDistinct "bit_and"
1435+
1436+-- | >>> :{
1437+-- let
1438+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGint4]] (Grouped bys) params (nullity 'PGint4)
1439+-- expression = bitOrDistinct #col
1440+-- in printSQL expression
1441+-- :}
1442+-- bit_or(DISTINCT "col")
1443+bitOrDistinct
1444+ :: PGIntegral int
1445+ => Expression schema relations 'Ungrouped params (nullity int)
1446+ -- ^ what to aggregate
1447+ -> Expression schema relations ('Grouped bys) params (nullity int)
1448+bitOrDistinct = unsafeAggregateDistinct "bit_or"
1449+
1450+-- | >>> :{
1451+-- let
1452+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1453+-- expression = boolAnd #col
1454+-- in printSQL expression
1455+-- :}
1456+-- bool_and("col")
1457+boolAnd
1458+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1459+ -- ^ what to aggregate
1460+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1461+boolAnd = unsafeAggregate "bool_and"
1462+
1463+-- | >>> :{
1464+-- let
1465+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1466+-- expression = boolOr #col
1467+-- in printSQL expression
1468+-- :}
1469+-- bool_or("col")
1470+boolOr
1471+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1472+ -- ^ what to aggregate
1473+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1474+boolOr = unsafeAggregate "bool_or"
1475+
1476+-- | >>> :{
1477+-- let
1478+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1479+-- expression = boolAndDistinct #col
1480+-- in printSQL expression
1481+-- :}
1482+-- bool_and(DISTINCT "col")
1483+boolAndDistinct
1484+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1485+ -- ^ what to aggregate
1486+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1487+boolAndDistinct = unsafeAggregateDistinct "bool_and"
1488+
1489+-- | >>> :{
1490+-- let
1491+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1492+-- expression = boolOrDistinct #col
1493+-- in printSQL expression
1494+-- :}
1495+-- bool_or(DISTINCT "col")
1496+boolOrDistinct
1497+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1498+ -- ^ what to aggregate
1499+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1500+boolOrDistinct = unsafeAggregateDistinct "bool_or"
1501+
1502+-- | A special aggregation that does not require an input
1503+--
1504+-- >>> printSQL countStar
1505+-- count(*)
1506+countStar
1507+ :: Expression schema relations ('Grouped bys) params ('NotNull 'PGint8)
1508+countStar = UnsafeExpression $ "count(*)"
1509+
1510+-- | >>> :{
1511+-- let
1512+-- expression :: Expression schema '[tab ::: '["col" ::: nullity ty]] (Grouped bys) params ('NotNull 'PGint8)
1513+-- expression = count #col
1514+-- in printSQL expression
1515+-- :}
1516+-- count("col")
1517+count
1518+ :: Expression schema relations 'Ungrouped params ty
1519+ -- ^ what to count
1520+ -> Expression schema relations ('Grouped bys) params ('NotNull 'PGint8)
1521+count = unsafeAggregate "count"
1522+
1523+-- | >>> :{
1524+-- let
1525+-- expression :: Expression schema '[tab ::: '["col" ::: nullity ty]] (Grouped bys) params ('NotNull 'PGint8)
1526+-- expression = countDistinct #col
1527+-- in printSQL expression
1528+-- :}
1529+-- count(DISTINCT "col")
1530+countDistinct
1531+ :: Expression schema relations 'Ungrouped params ty
1532+ -- ^ what to count
1533+ -> Expression schema relations ('Grouped bys) params ('NotNull 'PGint8)
1534+countDistinct = unsafeAggregateDistinct "count"
1535+
1536+-- | synonym for `boolAnd`
1537+--
1538+-- >>> :{
1539+-- let
1540+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1541+-- expression = every #col
1542+-- in printSQL expression
1543+-- :}
1544+-- every("col")
1545+every
1546+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1547+ -- ^ what to aggregate
1548+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1549+every = unsafeAggregate "every"
1550+
1551+-- | synonym for `boolAndDistinct`
1552+--
1553+-- >>> :{
1554+-- let
1555+-- expression :: Expression schema '[tab ::: '["col" ::: nullity 'PGbool]] (Grouped bys) params (nullity 'PGbool)
1556+-- expression = everyDistinct #col
1557+-- in printSQL expression
1558+-- :}
1559+-- every(DISTINCT "col")
1560+everyDistinct
1561+ :: Expression schema relations 'Ungrouped params (nullity 'PGbool)
1562+ -- ^ what to aggregate
1563+ -> Expression schema relations ('Grouped bys) params (nullity 'PGbool)
1564+everyDistinct = unsafeAggregateDistinct "every"
1565+
1566+-- | minimum and maximum aggregation
1567+max_, min_, maxDistinct, minDistinct
1568+ :: Expression schema relations 'Ungrouped params (nullity ty)
1569+ -- ^ what to aggregate
1570+ -> Expression schema relations ('Grouped bys) params (nullity ty)
1571+max_ = unsafeAggregate "max"
1572+min_ = unsafeAggregate "min"
1573+maxDistinct = unsafeAggregateDistinct "max"
1574+minDistinct = unsafeAggregateDistinct "min"
1575+
1576+{-----------------------------------------
1577+type expressions
1578+-----------------------------------------}
1579+
1580+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1581+newtype TypeExpression (schema :: SchemaType) (ty :: NullityType)
1582+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1583+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1584+
1585+instance (Has alias schema ('Typedef ty))
1586+ => IsLabel alias (TypeExpression schema (nullity ty)) where
1587+ fromLabel = UnsafeTypeExpression (renderAlias (fromLabel @alias))
1588+
1589+-- | logical Boolean (true/false)
1590+bool :: TypeExpression schema (nullity 'PGbool)
1591+bool = UnsafeTypeExpression "bool"
1592+-- | signed two-byte integer
1593+int2, smallint :: TypeExpression schema (nullity 'PGint2)
1594+int2 = UnsafeTypeExpression "int2"
1595+smallint = UnsafeTypeExpression "smallint"
1596+-- | signed four-byte integer
1597+int4, int, integer :: TypeExpression schema (nullity 'PGint4)
1598+int4 = UnsafeTypeExpression "int4"
1599+int = UnsafeTypeExpression "int"
1600+integer = UnsafeTypeExpression "integer"
1601+-- | signed eight-byte integer
1602+int8, bigint :: TypeExpression schema (nullity 'PGint8)
1603+int8 = UnsafeTypeExpression "int8"
1604+bigint = UnsafeTypeExpression "bigint"
1605+-- | arbitrary precision numeric type
1606+numeric :: TypeExpression schema (nullity 'PGnumeric)
1607+numeric = UnsafeTypeExpression "numeric"
1608+-- | single precision floating-point number (4 bytes)
1609+float4, real :: TypeExpression schema (nullity 'PGfloat4)
1610+float4 = UnsafeTypeExpression "float4"
1611+real = UnsafeTypeExpression "real"
1612+-- | double precision floating-point number (8 bytes)
1613+float8, doublePrecision :: TypeExpression schema (nullity 'PGfloat8)
1614+float8 = UnsafeTypeExpression "float8"
1615+doublePrecision = UnsafeTypeExpression "double precision"
1616+-- | variable-length character string
1617+text :: TypeExpression schema (nullity 'PGtext)
1618+text = UnsafeTypeExpression "text"
1619+-- | fixed-length character string
1620+char, character
1621+ :: forall n schema nullity. (KnownNat n, 1 <= n)
1622+ => TypeExpression schema (nullity ('PGchar n))
1623+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1624+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1625+-- | variable-length character string
1626+varchar, characterVarying
1627+ :: forall n schema nullity. (KnownNat n, 1 <= n)
1628+ => TypeExpression schema (nullity ('PGvarchar n))
1629+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1630+characterVarying = UnsafeTypeExpression $
1631+ "character varying(" <> renderNat @n <> ")"
1632+-- | binary data ("byte array")
1633+bytea :: TypeExpression schema (nullity 'PGbytea)
1634+bytea = UnsafeTypeExpression "bytea"
1635+-- | date and time (no time zone)
1636+timestamp :: TypeExpression schema (nullity 'PGtimestamp)
1637+timestamp = UnsafeTypeExpression "timestamp"
1638+-- | date and time, including time zone
1639+timestampWithTimeZone :: TypeExpression schema (nullity 'PGtimestamptz)
1640+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1641+-- | calendar date (year, month, day)
1642+date :: TypeExpression schema (nullity 'PGdate)
1643+date = UnsafeTypeExpression "date"
1644+-- | time of day (no time zone)
1645+time :: TypeExpression schema (nullity 'PGtime)
1646+time = UnsafeTypeExpression "time"
1647+-- | time of day, including time zone
1648+timeWithTimeZone :: TypeExpression schema (nullity 'PGtimetz)
1649+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1650+-- | time span
1651+interval :: TypeExpression schema (nullity 'PGinterval)
1652+interval = UnsafeTypeExpression "interval"
1653+-- | universally unique identifier
1654+uuid :: TypeExpression schema (nullity 'PGuuid)
1655+uuid = UnsafeTypeExpression "uuid"
1656+-- | IPv4 or IPv6 host address
1657+inet :: TypeExpression schema (nullity 'PGinet)
1658+inet = UnsafeTypeExpression "inet"
1659+-- | textual JSON data
1660+json :: TypeExpression schema (nullity 'PGjson)
1661+json = UnsafeTypeExpression "json"
1662+-- | binary JSON data, decomposed
1663+jsonb :: TypeExpression schema (nullity 'PGjsonb)
1664+jsonb = UnsafeTypeExpression "jsonb"
1665+-- | variable length array
1666+vararray
1667+ :: TypeExpression schema pg
1668+ -> TypeExpression schema (nullity ('PGvararray pg))
1669+vararray ty = UnsafeTypeExpression $ renderTypeExpression ty <> "[]"
1670+-- | fixed length array
1671+--
1672+-- >>> renderTypeExpression (fixarray @2 json)
1673+-- "json[2]"
1674+fixarray
1675+ :: forall n schema nullity pg. KnownNat n
1676+ => TypeExpression schema pg
1677+ -> TypeExpression schema (nullity ('PGfixarray n pg))
1678+fixarray ty = UnsafeTypeExpression $
1679+ renderTypeExpression ty <> "[" <> renderNat @n <> "]"
1680+
1681+-- | `pgtype` is a demoted version of a `PGType`
1682+class PGTyped schema (ty :: NullityType) where
1683+ pgtype :: TypeExpression schema ty
1684+instance PGTyped schema (nullity 'PGbool) where pgtype = bool
1685+instance PGTyped schema (nullity 'PGint2) where pgtype = int2
1686+instance PGTyped schema (nullity 'PGint4) where pgtype = int4
1687+instance PGTyped schema (nullity 'PGint8) where pgtype = int8
1688+instance PGTyped schema (nullity 'PGnumeric) where pgtype = numeric
1689+instance PGTyped schema (nullity 'PGfloat4) where pgtype = float4
1690+instance PGTyped schema (nullity 'PGfloat8) where pgtype = float8
1691+instance PGTyped schema (nullity 'PGtext) where pgtype = text
1692+instance (KnownNat n, 1 <= n)
1693+ => PGTyped schema (nullity ('PGchar n)) where pgtype = char @n
1694+instance (KnownNat n, 1 <= n)
1695+ => PGTyped schema (nullity ('PGvarchar n)) where pgtype = varchar @n
1696+instance PGTyped schema (nullity 'PGbytea) where pgtype = bytea
1697+instance PGTyped schema (nullity 'PGtimestamp) where pgtype = timestamp
1698+instance PGTyped schema (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
1699+instance PGTyped schema (nullity 'PGdate) where pgtype = date
1700+instance PGTyped schema (nullity 'PGtime) where pgtype = time
1701+instance PGTyped schema (nullity 'PGtimetz) where pgtype = timeWithTimeZone
1702+instance PGTyped schema (nullity 'PGinterval) where pgtype = interval
1703+instance PGTyped schema (nullity 'PGuuid) where pgtype = uuid
1704+instance PGTyped schema (nullity 'PGjson) where pgtype = json
1705+instance PGTyped schema (nullity 'PGjsonb) where pgtype = jsonb
1706+instance PGTyped schema ty
1707+ => PGTyped schema (nullity ('PGvararray ty)) where
1708+ pgtype = vararray (pgtype @schema @ty)
1709+instance (KnownNat n, PGTyped schema ty)
1710+ => PGTyped schema (nullity ('PGfixarray n ty)) where
1711+ pgtype = fixarray @n (pgtype @schema @ty)