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