@@ -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
@@ -33,350 +32,546 @@ Squeal expressions are the atoms used to build statements.
3332module Squeal.PostgreSQL.Expression
3433 ( -- * Expression
3534 Expression (..)
36− , Expr
37− , type (-->)
38− , FunctionDB
39− , unsafeFunction
40− , function
41− , unsafeLeftOp
42− , leftOp
43− , unsafeRightOp
44− , rightOp
45− , Operator
46− , OperatorDB
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+ , index
49+ , row
50+ , field
51+ -- ** Functions
4752 , unsafeBinaryOp
48− , binaryOp
49− , FunctionVar
50− , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
53− , unsafeFunctionN
54− , functionN
55− , PGSubset (..)
56− , PGIntersect (..)
53+ , unsafeUnaryOp
54+ , unsafeFunction
55+ , unsafeVariadicFunction
56+ , atan2_
57+ , cast
58+ , quot_
59+ , rem_
60+ , trunc
61+ , round_
62+ , ceiling_
63+ , greatest
64+ , least
65+ -- ** Conditions
66+ , true
67+ , false
68+ , not_
69+ , (.&&)
70+ , (.||)
71+ , Condition
72+ , caseWhenThenElse
73+ , ifThenElse
74+ , (.==)
75+ , (./=)
76+ , (.>=)
77+ , (.<)
78+ , (.<=)
79+ , (.>)
80+ -- ** Time
81+ , currentDate
82+ , currentTime
83+ , currentTimestamp
84+ , localTime
85+ , localTimestamp
86+ -- ** Text
87+ , lower
88+ , upper
89+ , charLength
90+ , like
91+ , ilike
92+ -- ** Json
93+ -- *** Json and Jsonb operators
94+ , (.->)
95+ , (.->>)
96+ , (.#>)
97+ , (.#>>)
98+ -- *** Jsonb 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+ , jsonTypeof
128+ , jsonbTypeof
129+ , jsonStripNulls
130+ , jsonbStripNulls
131+ , jsonbSet
132+ , jsonbInsert
133+ , jsonbPretty
134+ -- ** Aggregation
135+ , unsafeAggregate, unsafeAggregateDistinct
136+ , sum_, sumDistinct
137+ , PGAvg (avg, avgDistinct)
138+ , bitAnd, bitOr, boolAnd, boolOr
139+ , bitAndDistinct, bitOrDistinct, boolAndDistinct, boolOrDistinct
140+ , countStar
141+ , count, countDistinct
142+ , every, everyDistinct
143+ , max_, maxDistinct, min_, minDistinct
144+ -- * Types
145+ , TypeExpression (..)
146+ , PGTyped (..)
147+ , typedef
148+ , typetable
149+ , typeview
150+ , bool
151+ , int2
152+ , smallint
153+ , int4
154+ , int
155+ , integer
156+ , int8
157+ , bigint
158+ , numeric
159+ , float4
160+ , real
161+ , float8
162+ , doublePrecision
163+ , text
164+ , char
165+ , character
166+ , varchar
167+ , characterVarying
168+ , bytea
169+ , timestamp
170+ , timestampWithTimeZone
171+ , date
172+ , time
173+ , timeWithTimeZone
174+ , interval
175+ , uuid
176+ , inet
177+ , json
178+ , jsonb
179+ , vararray
180+ , fixarray
57181 -- * Re-export
58182 , (&)
59− , K (..)
60− , unK
183+ , NP ((:*), Nil)
61184 ) where
62185
63186import Control.Category
64187import Control.DeepSeq
65188import Data.ByteString (ByteString)
189+import Data.ByteString.Lazy (toStrict)
66190import Data.Function ((&))
67191import Data.Semigroup hiding (All)
192+import qualified Data.Aeson as JSON
193+import Data.Ratio
68194import Data.String
69−import Generics.SOP hiding (All, from)
195+import Data.Word
196+import Generics.SOP hiding (from)
70197import GHC.OverloadedLabels
71198import GHC.TypeLits
72−import Numeric
73199import Prelude hiding (id, (.))
74200
75201import qualified GHC.Generics as GHC
76202
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79203import Squeal.PostgreSQL.Render
80204import Squeal.PostgreSQL.Schema
81205
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85206{-----------------------------------------
86207column expressions
87208-----------------------------------------}
88209
89210{- | `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,
211+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92212as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93213`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
214+or in search `Condition`s in a number of commands.
95215
96216The expression syntax allows the calculation of
97217values from primitive expression using arithmetic, logical,
98218and 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`.
113219-}
114220newtype Expression
115− (outer :: FromType)
116221 (commons :: FromType)
117− (grp :: Grouping)
118222 (schemas :: SchemasType)
119223 (params :: [NullityType])
224+ (grp :: Grouping)
120225 (from :: FromType)
121226 (ty :: NullityType)
122227 = UnsafeExpression { renderExpression :: ByteString }
123228 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
229+
230+instance RenderSQL (Expression commons schemas params grp from ty) where
125231 renderSQL = renderExpression
126232
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.
198−-}
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)
233+{- | A `HasParameter` constraint is used to indicate a value that is
234+supplied externally to a SQL statement.
235+`Squeal.PostgreSQL.PQ.manipulateParams`,
236+`Squeal.PostgreSQL.PQ.queryParams` and
237+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
238+separately from the SQL command string, in which case `param`s are used to
239+refer to the out-of-line data values.
210240-}
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
213− (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
241+class KnownNat n => HasParameter
242+ (n :: Nat)
243+ (params :: [NullityType])
244+ (ty :: NullityType)
245+ | n params -> ty where
246+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
247+ --
248+ -- >>> let expr = parameter @1 int4 :: Expression '[] schemas '[ 'Null 'PGint4] grp from ('Null 'PGint4)
249+ -- >>> printSQL expr
250+ -- ($1 :: int4)
251+ parameter
252+ :: TypeExpression schemas ty
253+ -> Expression commons schemas params grp from ty
254+ parameter ty = UnsafeExpression $ parenthesized $
255+ "$" <> renderNat @n <+> "::"
256+ <+> renderSQL ty
257+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
258+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
259+ => HasParameter n (ty' : params) ty
260+
261+-- | `param` takes a `Nat` using type application and for basic types,
262+-- infers a `TypeExpression`.
263+--
264+-- >>> let expr = param @1 :: Expression commons schemas '[ 'Null 'PGint4] grp from ('Null 'PGint4)
265+-- >>> printSQL expr
266+-- ($1 :: int4)
267+param
268+ :: forall n commons schemas params from grp ty
269+ . (PGTyped schemas ty, HasParameter n params ty)
270+ => Expression commons schemas params grp from ty -- ^ param
271+param = parameter @n (pgtype @schemas)
214272
215−instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
273+instance (HasUnique tab from row, Has col row ty)
274+ => IsLabel col (Expression commons schemas params 'Ungrouped from ty) where
217275 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))
276+instance (HasUnique tab from row, Has col row ty, column ~ (col ::: ty))
222277 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
278+ (Aliased (Expression commons schemas params 'Ungrouped from) column) where
224279 fromLabel = fromLabel @col `As` Alias
225−instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
280+instance (HasUnique tab from row, Has col row ty, columns ~ '[col ::: ty])
226281 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
282+ (NP (Aliased (Expression commons schemas params 'Ungrouped from)) columns) where
228283 fromLabel = fromLabel @col :* Nil
229284
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
285+instance (Has tab from row, Has col row ty)
286+ => IsQualified tab col (Expression commons schemas params 'Ungrouped from ty) where
232287 tab ! col = UnsafeExpression $
233288 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))
289+instance (Has tab from row, Has col row ty, column ~ (col ::: ty))
238290 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
291+ (Aliased (Expression commons schemas params 'Ungrouped from) column) where
240292 tab ! col = tab ! col `As` col
241−instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
293+instance (Has tab from row, Has col row ty, columns ~ '[col ::: ty])
242294 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
295+ (NP (Aliased (Expression commons schemas params 'Ungrouped from)) columns) where
244296 tab ! col = tab ! col :* Nil
245297
246298instance
247− ( HasUnique tab (Join outer from) row
299+ ( HasUnique tab from row
248300 , Has col row ty
249301 , GroupedBy tab col bys
250302 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
303+ (Expression commons schemas params ('Grouped bys) from ty) where
252304 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253305instance
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
261−instance
262− ( HasUnique tab (Join outer from) row
306+ ( HasUnique tab from row
263307 , Has col row ty
264308 , GroupedBy tab col bys
265309 , column ~ (col ::: ty)
266310 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
311+ (Aliased (Expression commons schemas params ('Grouped bys) from) column) where
268312 fromLabel = fromLabel @col `As` Alias
269313instance
270− ( HasUnique tab (Join outer from) row
314+ ( HasUnique tab from row
271315 , Has col row ty
272316 , GroupedBy tab col bys
273317 , columns ~ '[col ::: ty]
274318 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
319+ (NP (Aliased (Expression commons schemas params ('Grouped bys) from)) columns) where
276320 fromLabel = fromLabel @col :* Nil
277321
278322instance
279− ( Has tab (Join outer from) row
323+ ( Has tab from row
280324 , Has col row ty
281325 , GroupedBy tab col bys
282326 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
327+ (Expression commons schemas params ('Grouped bys) from ty) where
284328 tab ! col = UnsafeExpression $
285329 renderSQL tab <> "." <> renderSQL col
286330instance
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
294−instance
295− ( Has tab (Join outer from) row
331+ ( Has tab from row
296332 , Has col row ty
297333 , GroupedBy tab col bys
298334 , column ~ (col ::: ty)
299335 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
336+ (Aliased (Expression commons schemas params ('Grouped bys) from) column) where
301337 tab ! col = tab ! col `As` col
302338instance
303− ( Has tab (Join outer from) row
339+ ( Has tab from row
304340 , Has col row ty
305341 , GroupedBy tab col bys
306342 , columns ~ '[col ::: ty]
307343 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
344+ (NP (Aliased (Expression commons schemas params ('Grouped bys) from)) columns) where
309345 tab ! col = tab ! col :* Nil
310346
347+-- | analagous to `Nothing`
348+--
349+-- >>> printSQL null_
350+-- NULL
351+null_ :: Expression commons schemas rels grouping params ('Null ty)
352+null_ = UnsafeExpression "NULL"
353+
354+-- | analagous to `Just`
355+--
356+-- >>> printSQL $ notNull true
357+-- TRUE
358+notNull
359+ :: Expression commons schemas rels grouping params ('NotNull ty)
360+ -> Expression commons schemas rels grouping params ('Null ty)
361+notNull = UnsafeExpression . renderSQL
362+
363+-- | return the leftmost value which is not NULL
364+--
365+-- >>> printSQL $ coalesce [null_, true] false
366+-- COALESCE(NULL, TRUE, FALSE)
367+coalesce
368+ :: [Expression commons schemas params grp from ('Null ty)]
369+ -- ^ @NULL@s may be present
370+ -> Expression commons schemas params grp from ('NotNull ty)
371+ -- ^ @NULL@ is absent
372+ -> Expression commons schemas params grp from ('NotNull ty)
373+coalesce nullxs notNullx = UnsafeExpression $
374+ "COALESCE" <> parenthesized (commaSeparated
375+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
376+
377+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
378+--
379+-- >>> printSQL $ fromNull true null_
380+-- COALESCE(NULL, TRUE)
381+fromNull
382+ :: Expression commons schemas params grp from ('NotNull ty)
383+ -- ^ what to convert @NULL@ to
384+ -> Expression commons schemas params grp from ('Null ty)
385+ -> Expression commons schemas params grp from ('NotNull ty)
386+fromNull notNullx nullx = coalesce [nullx] notNullx
387+
388+-- | >>> printSQL $ null_ & isNull
389+-- NULL IS NULL
390+isNull
391+ :: Expression commons schemas params grp from ('Null ty)
392+ -- ^ possibly @NULL@
393+ -> Condition commons schemas params grp from
394+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
395+
396+-- | >>> printSQL $ null_ & isNotNull
397+-- NULL IS NOT NULL
398+isNotNull
399+ :: Expression commons schemas params grp from ('Null ty)
400+ -- ^ possibly @NULL@
401+ -> Condition commons schemas params grp from
402+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
403+
404+-- | analagous to `maybe` using @IS NULL@
405+--
406+-- >>> printSQL $ matchNull true not_ null_
407+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
408+matchNull
409+ :: Expression commons schemas params grp from (nullty)
410+ -- ^ what to convert @NULL@ to
411+ -> ( Expression commons schemas params grp from ('NotNull ty)
412+ -> Expression commons schemas params grp from (nullty) )
413+ -- ^ function to perform when @NULL@ is absent
414+ -> Expression commons schemas params grp from ('Null ty)
415+ -> Expression commons schemas params grp from (nullty)
416+matchNull y f x = ifThenElse (isNull x) y
417+ (f (UnsafeExpression (renderSQL x)))
418+
419+{-| right inverse to `fromNull`, if its arguments are equal then
420+`nullIf` gives @NULL@.
421+
422+>>> :set -XTypeApplications -XDataKinds
423+>>> let expr = nullIf false (param @1) :: Expression commons schemas '[ 'NotNull 'PGbool] grp from ('Null 'PGbool)
424+>>> printSQL expr
425+NULL IF (FALSE, ($1 :: bool))
426+-}
427+nullIf
428+ :: Expression commons schemas params grp from ('NotNull ty)
429+ -- ^ @NULL@ is absent
430+ -> Expression commons schemas params grp from ('NotNull ty)
431+ -- ^ @NULL@ is absent
432+ -> Expression commons schemas params grp from ('Null ty)
433+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
434+ (renderSQL x <> ", " <> renderSQL y)
435+
436+-- | >>> printSQL $ array [null_, false, true]
437+-- ARRAY[NULL, FALSE, TRUE]
438+array
439+ :: [Expression commons schemas params grp from ty]
440+ -- ^ array elements
441+ -> Expression commons schemas params grp from (nullity ('PGvararray ty))
442+array xs = UnsafeExpression $
443+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
444+
445+-- | >>> printSQL $ array [null_, false, true] & index 2
446+-- (ARRAY[NULL, FALSE, TRUE])[2]
447+index
448+ :: Word64 -- ^ index
449+ -> Expression commons schemas params grp from (nullity ('PGvararray ty)) -- ^ array
450+ -> Expression commons schemas params grp from (NullifyType ty)
451+index n expr = UnsafeExpression $
452+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
453+
311454instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
455+ (Expression commons schemas params grp from (nullity ('PGenum labels))) where
313456 label = UnsafeExpression $ renderSQL (PGlabel @label)
314457
458+-- | A row constructor is an expression that builds a row value
459+-- (also called a composite value) using values for its member fields.
460+--
461+-- >>> :{
462+-- type Complex = 'PGcomposite
463+-- '[ "real" ::: 'NotNull 'PGfloat8
464+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
465+-- :}
466+--
467+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression commons schemas from grp params ('NotNull Complex)
468+-- >>> printSQL i
469+-- ROW(0, 1)
470+row
471+ :: SListI row
472+ => NP (Aliased (Expression commons schemas params grp from)) row
473+ -- ^ zero or more expressions for the row field values
474+ -> Expression commons schemas params grp from (nullity ('PGcomposite row))
475+row exprs = UnsafeExpression $ "ROW" <> parenthesized
476+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
477+
478+-- | >>> :{
479+-- type Complex = 'PGcomposite
480+-- '[ "real" ::: 'NotNull 'PGfloat8
481+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
482+-- type Schema = '["complex" ::: 'Typedef Complex]
483+-- :}
484+--
485+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression '[] (Public Schema) from grp params ('NotNull Complex)
486+-- >>> printSQL $ i & field #complex #imaginary
487+-- (ROW(0, 1)::"complex")."imaginary"
488+field
489+ :: ( Has sch schemas schema
490+ , Has tydef schema ('Typedef ('PGcomposite row))
491+ , Has field row ty)
492+ => QualifiedAlias sch tydef -- ^ row type
493+ -> Alias field -- ^ field name
494+ -> Expression commons schemas params grp from ('NotNull ('PGcomposite row))
495+ -> Expression commons schemas params grp from ty
496+field td fld expr = UnsafeExpression $
497+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
498+ <> "." <> renderSQL fld
499+
500+instance Semigroup
501+ (Expression commons schemas params grp from (nullity ('PGvararray ty))) where
502+ (<>) = unsafeBinaryOp "||"
503+
504+instance Monoid
505+ (Expression commons schemas params grp from (nullity ('PGvararray ty))) where
506+ mempty = array []
507+ mappend = (<>)
508+
509+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression commons schemas '[ 'NotNull 'PGtimestamptz] grp from ('NotNull 'PGtimestamptz)
510+-- >>> printSQL expr
511+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
512+greatest
513+ :: Expression commons schemas params grp from (nullty)
514+ -- ^ needs at least 1 argument
515+ -> [Expression commons schemas params grp from (nullty)]
516+ -- ^ or more
517+ -> Expression commons schemas params grp from (nullty)
518+greatest x xs = UnsafeExpression $ "GREATEST("
519+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
520+
521+-- | >>> printSQL $ least currentTimestamp [null_]
522+-- LEAST(CURRENT_TIMESTAMP, NULL)
523+least
524+ :: Expression commons schemas params grp from (nullty)
525+ -- ^ needs at least 1 argument
526+ -> [Expression commons schemas params grp from (nullty)]
527+ -- ^ or more
528+ -> Expression commons schemas params grp from (nullty)
529+least x xs = UnsafeExpression $ "LEAST("
530+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
531+
315532-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316533-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
534+unsafeBinaryOp
535+ :: ByteString
536+ -- ^ operator
537+ -> Expression commons schemas params grp from (ty0)
538+ -> Expression commons schemas params grp from (ty1)
539+ -> Expression commons schemas params grp from (ty2)
318540unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319541 renderSQL x <+> op <+> renderSQL y
320542
321−binaryOp
322− :: forall op sch schemas schema x y z.
323− ( Has sch schemas schema
324− , Has op schema ('Operator ('BinaryOp x y z)) )
325− => OperatorDB schemas x y z
326−binaryOp = unsafeBinaryOp $ renderSymbol @op
327−
328−-- | >>> printSQL $ unsafeLeftOp "NOT" true
543+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329544-- (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
545+unsafeUnaryOp
546+ :: ByteString
547+ -- ^ operator
548+ -> Expression commons schemas params grp from (ty0)
549+ -> Expression commons schemas params grp from (ty1)
550+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
551+ op <+> renderSQL x
351552
352553-- | >>> printSQL $ unsafeFunction "f" true
353554-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
555+unsafeFunction
556+ :: ByteString
557+ -- ^ function
558+ -> Expression commons schemas params grp from (xty)
559+ -> Expression commons schemas params grp from (yty)
355560unsafeFunction fun x = UnsafeExpression $
356561 fun <> parenthesized (renderSQL x)
357562
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
563+-- | Helper for defining variadic functions.
564+unsafeVariadicFunction
565+ :: SListI elems
566+ => ByteString
567+ -- ^ function
568+ -> NP (Expression commons schemas params grp from) elems
569+ -> Expression commons schemas params grp from ret
570+unsafeVariadicFunction fun x = UnsafeExpression $
571+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
377572
378573instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
574+ => Num (Expression commons schemas params grp from (nullity ty)) where
380575 (+) = unsafeBinaryOp "+"
381576 (-) = unsafeBinaryOp "-"
382577 (*) = unsafeBinaryOp "*"
@@ -388,17 +583,12 @@ instance ty `In` PGNum
388583 . show
389584
390585instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
586+ (Expression commons schemas params grp from (nullity ty)) where
392587 (/) = unsafeBinaryOp "/"
393− fromRational
394− = UnsafeExpression
395− . fromString
396− . ($ "")
397− . showFFloat Nothing
398− . fromRat @Double
588+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
399589
400590instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
591+ (Expression commons schemas params grp from (nullity ty)) where
402592 pi = UnsafeExpression "pi()"
403593 exp = unsafeFunction "exp"
404594 log = unsafeFunction "ln"
@@ -419,54 +609,1172 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419609 acosh x = log (x + sqrt (x*x - 1))
420610 atanh x = log ((1 + x) / (1 - x)) / 2
421611
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)
612+-- | >>> :{
613+-- let
614+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
615+-- expression = atan2_ pi 2
616+-- in printSQL expression
617+-- :}
618+-- atan2(pi(), 2)
619+atan2_
620+ :: float `In` PGFloating
621+ => Expression commons schemas params grp from (nullity float)
622+ -- ^ numerator
623+ -> Expression commons schemas params grp from (nullity float)
624+ -- ^ denominator
625+ -> Expression commons schemas params grp from (nullity float)
626+atan2_ y x = UnsafeExpression $
627+ "atan2(" <> renderSQL y <> ", " <> renderSQL x <> ")"
628+
629+-- When a `cast` is applied to an `Expression` of a known type, it
630+-- represents a run-time type conversion. The cast will succeed only if a
631+-- suitable type conversion operation has been defined.
632+--
633+-- | >>> printSQL $ true & cast int4
634+-- (TRUE :: int4)
635+cast
636+ :: TypeExpression schemas ty1
637+ -- ^ type to cast as
638+ -> Expression commons schemas params grp from ty0
639+ -- ^ value to convert
640+ -> Expression commons schemas params grp from ty1
641+cast ty x = UnsafeExpression $ parenthesized $
642+ renderSQL x <+> "::" <+> renderSQL ty
643+
644+-- | integer division, truncates the result
645+--
646+-- >>> :{
647+-- let
648+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
649+-- expression = 5 `quot_` 2
650+-- in printSQL expression
651+-- :}
652+-- (5 / 2)
653+quot_
654+ :: int `In` PGIntegral
655+ => Expression commons schemas params grp from (nullity int)
656+ -- ^ numerator
657+ -> Expression commons schemas params grp from (nullity int)
658+ -- ^ denominator
659+ -> Expression commons schemas params grp from (nullity int)
660+quot_ = unsafeBinaryOp "/"
661+
662+-- | remainder upon integer division
663+--
664+-- >>> :{
665+-- let
666+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
667+-- expression = 5 `rem_` 2
668+-- in printSQL expression
669+-- :}
670+-- (5 % 2)
671+rem_
672+ :: int `In` PGIntegral
673+ => Expression commons schemas params grp from (nullity int)
674+ -- ^ numerator
675+ -> Expression commons schemas params grp from (nullity int)
676+ -- ^ denominator
677+ -> Expression commons schemas params grp from (nullity int)
678+rem_ = unsafeBinaryOp "%"
679+
680+-- | >>> :{
681+-- let
682+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
683+-- expression = trunc pi
684+-- in printSQL expression
685+-- :}
686+-- trunc(pi())
687+trunc
688+ :: frac `In` PGFloating
689+ => Expression commons schemas params grp from (nullity frac)
690+ -- ^ fractional number
691+ -> Expression commons schemas params grp from (nullity frac)
692+trunc = unsafeFunction "trunc"
693+
694+-- | >>> :{
695+-- let
696+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
697+-- expression = round_ pi
698+-- in printSQL expression
699+-- :}
700+-- round(pi())
701+round_
702+ :: frac `In` PGFloating
703+ => Expression commons schemas params grp from (nullity frac)
704+ -- ^ fractional number
705+ -> Expression commons schemas params grp from (nullity frac)
706+round_ = unsafeFunction "round"
707+
708+-- | >>> :{
709+-- let
710+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
711+-- expression = ceiling_ pi
712+-- in printSQL expression
713+-- :}
714+-- ceiling(pi())
715+ceiling_
716+ :: frac `In` PGFloating
717+ => Expression commons schemas params grp from (nullity frac)
718+ -- ^ fractional number
719+ -> Expression commons schemas params grp from (nullity frac)
720+ceiling_ = unsafeFunction "ceiling"
721+
722+-- | A `Condition` is an `Expression`, which can evaluate
723+-- to `true`, `false` or `null_`. This is because SQL uses
724+-- a three valued logic.
725+type Condition commons schemas params grp from =
726+ Expression commons schemas params grp from ('Null 'PGbool)
727+
728+-- | >>> printSQL true
729+-- TRUE
730+true :: Expression commons schemas params grp from (nullity 'PGbool)
731+true = UnsafeExpression "TRUE"
732+
733+-- | >>> printSQL false
734+-- FALSE
735+false :: Expression commons schemas params grp from (nullity 'PGbool)
736+false = UnsafeExpression "FALSE"
737+
738+-- | >>> printSQL $ not_ true
739+-- (NOT TRUE)
740+not_
741+ :: Expression commons schemas params grp from (nullity 'PGbool)
742+ -> Expression commons schemas params grp from (nullity 'PGbool)
743+not_ = unsafeUnaryOp "NOT"
744+
745+-- | >>> printSQL $ true .&& false
746+-- (TRUE AND FALSE)
747+(.&&)
748+ :: Expression commons schemas params grp from (nullity 'PGbool)
749+ -> Expression commons schemas params grp from (nullity 'PGbool)
750+ -> Expression commons schemas params grp from (nullity 'PGbool)
751+infixr 3 .&&
752+(.&&) = unsafeBinaryOp "AND"
753+
754+-- | >>> printSQL $ true .|| false
755+-- (TRUE OR FALSE)
756+(.||)
757+ :: Expression commons schemas params grp from (nullity 'PGbool)
758+ -> Expression commons schemas params grp from (nullity 'PGbool)
759+ -> Expression commons schemas params grp from (nullity 'PGbool)
760+infixr 2 .||
761+(.||) = unsafeBinaryOp "OR"
762+
763+-- | >>> :{
764+-- let
765+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
766+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
767+-- in printSQL expression
768+-- :}
769+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
770+caseWhenThenElse
771+ :: [ ( Condition commons schemas params grp from
772+ , Expression commons schemas params grp from ty
773+ ) ]
774+ -- ^ whens and thens
775+ -> Expression commons schemas params grp from ty
776+ -- ^ else
777+ -> Expression commons schemas params grp from ty
778+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
779+ [ "CASE"
780+ , mconcat
781+ [ mconcat
782+ [ " WHEN ", renderSQL when_
783+ , " THEN ", renderSQL then_
784+ ]
785+ | (when_,then_) <- whenThens
786+ ]
787+ , " ELSE ", renderSQL else_
788+ , " END"
789+ ]
790+
791+-- | >>> :{
792+-- let
793+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
794+-- expression = ifThenElse true 1 0
795+-- in printSQL expression
796+-- :}
797+-- CASE WHEN TRUE THEN 1 ELSE 0 END
798+ifThenElse
799+ :: Condition commons schemas params grp from
800+ -> Expression commons schemas params grp from ty -- ^ then
801+ -> Expression commons schemas params grp from ty -- ^ else
802+ -> Expression commons schemas params grp from ty
803+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
804+
805+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
806+-- will produce @NULL@s if one of their arguments is @NULL@.
807+--
808+-- >>> printSQL $ true .== null_
809+-- (TRUE = NULL)
810+(.==)
811+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
812+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
813+ -> Condition commons schemas params grp from
814+(.==) = unsafeBinaryOp "="
815+infix 4 .==
816+
817+-- | >>> printSQL $ true ./= null_
818+-- (TRUE <> NULL)
819+(./=)
820+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
821+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
822+ -> Condition commons schemas params grp from
823+(./=) = unsafeBinaryOp "<>"
824+infix 4 ./=
825+
826+-- | >>> printSQL $ true .>= null_
827+-- (TRUE >= NULL)
828+(.>=)
829+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
830+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
831+ -> Condition commons schemas params grp from
832+(.>=) = unsafeBinaryOp ">="
833+infix 4 .>=
834+
835+-- | >>> printSQL $ true .< null_
836+-- (TRUE < NULL)
837+(.<)
838+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
839+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
840+ -> Condition commons schemas params grp from
841+(.<) = unsafeBinaryOp "<"
842+infix 4 .<
843+
844+-- | >>> printSQL $ true .<= null_
845+-- (TRUE <= NULL)
846+(.<=)
847+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
848+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
849+ -> Condition commons schemas params grp from
850+(.<=) = unsafeBinaryOp "<="
851+infix 4 .<=
852+
853+-- | >>> printSQL $ true .> null_
854+-- (TRUE > NULL)
855+(.>)
856+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
857+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
858+ -> Condition commons schemas params grp from
859+(.>) = unsafeBinaryOp ">"
860+infix 4 .>
861+
862+-- | >>> printSQL currentDate
863+-- CURRENT_DATE
864+currentDate
865+ :: Expression commons schemas params grp from (nullity 'PGdate)
866+currentDate = UnsafeExpression "CURRENT_DATE"
867+
868+-- | >>> printSQL currentTime
869+-- CURRENT_TIME
870+currentTime
871+ :: Expression commons schemas params grp from (nullity 'PGtimetz)
872+currentTime = UnsafeExpression "CURRENT_TIME"
873+
874+-- | >>> printSQL currentTimestamp
875+-- CURRENT_TIMESTAMP
876+currentTimestamp
877+ :: Expression commons schemas params grp from (nullity 'PGtimestamptz)
878+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
879+
880+-- | >>> printSQL localTime
881+-- LOCALTIME
882+localTime
883+ :: Expression commons schemas params grp from (nullity 'PGtime)
884+localTime = UnsafeExpression "LOCALTIME"
885+
886+-- | >>> printSQL localTimestamp
887+-- LOCALTIMESTAMP
888+localTimestamp
889+ :: Expression commons schemas params grp from (nullity 'PGtimestamp)
890+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
891+
892+{-----------------------------------------
893+text
894+-----------------------------------------}
438895
439896instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
897+ (Expression commons schemas params grp from (nullity 'PGtext)) where
441898 fromString str = UnsafeExpression $
442899 "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) <> "\'"
900+ where
901+ escape = \case
902+ '\NUL' -> "\\0"
903+ '\'' -> "''"
904+ '"' -> "\\\""
905+ '\b' -> "\\b"
906+ '\n' -> "\\n"
907+ '\r' -> "\\r"
908+ '\t' -> "\\t"
909+ '\\' -> "\\\\"
910+ c -> [c]
451911
452912instance 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
913+ (Expression commons schemas params grp from (nullity 'PGtext)) where
463914 (<>) = unsafeBinaryOp "||"
464915
465916instance 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
917+ (Expression commons schemas params grp from (nullity 'PGtext)) where
471918 mempty = fromString ""
472919 mappend = (<>)
920+
921+-- | >>> printSQL $ lower "ARRRGGG"
922+-- lower(E'ARRRGGG')
923+lower
924+ :: Expression commons schemas params grp from (nullity 'PGtext)
925+ -- ^ string to lower case
926+ -> Expression commons schemas params grp from (nullity 'PGtext)
927+lower = unsafeFunction "lower"
928+
929+-- | >>> printSQL $ upper "eeee"
930+-- upper(E'eeee')
931+upper
932+ :: Expression commons schemas params grp from (nullity 'PGtext)
933+ -- ^ string to upper case
934+ -> Expression commons schemas params grp from (nullity 'PGtext)
935+upper = unsafeFunction "upper"
936+
937+-- | >>> printSQL $ charLength "four"
938+-- char_length(E'four')
939+charLength
940+ :: Expression commons schemas params grp from (nullity 'PGtext)
941+ -- ^ string to measure
942+ -> Expression commons schemas params grp from (nullity 'PGint4)
943+charLength = unsafeFunction "char_length"
944+
945+-- | The `like` expression returns true if the @string@ matches
946+-- the supplied @pattern@. If @pattern@ does not contain percent signs
947+-- or underscores, then the pattern only represents the string itself;
948+-- in that case `like` acts like the equals operator. An underscore (_)
949+-- in pattern stands for (matches) any single character; a percent sign (%)
950+-- matches any sequence of zero or more characters.
951+--
952+-- >>> printSQL $ "abc" `like` "a%"
953+-- (E'abc' LIKE E'a%')
954+like
955+ :: Expression commons schemas params grp from (nullity 'PGtext)
956+ -- ^ string
957+ -> Expression commons schemas params grp from (nullity 'PGtext)
958+ -- ^ pattern
959+ -> Expression commons schemas params grp from (nullity 'PGbool)
960+like = unsafeBinaryOp "LIKE"
961+
962+-- | The key word ILIKE can be used instead of LIKE to make the
963+-- match case-insensitive according to the active locale.
964+--
965+-- >>> printSQL $ "abc" `ilike` "a%"
966+-- (E'abc' ILIKE E'a%')
967+ilike
968+ :: Expression commons schemas params grp from (nullity 'PGtext)
969+ -- ^ string
970+ -> Expression commons schemas params grp from (nullity 'PGtext)
971+ -- ^ pattern
972+ -> Expression commons schemas params grp from (nullity 'PGbool)
973+ilike = unsafeBinaryOp "ILIKE"
974+
975+{-----------------------------------------
976+ -- json and jsonb support
977+
978+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
979+comments lifted directly from this page.
980+
981+Table 9.44: json and jsonb operators
982+-----------------------------------------}
983+
984+-- | Get JSON value (object field or array element) at a key.
985+(.->)
986+ :: (json `In` PGJsonType, key `In` PGJsonKey)
987+ => Expression commons schemas params grp from (nullity json)
988+ -> Expression commons schemas params grp from (nullity key)
989+ -> Expression commons schemas params grp from ('Null json)
990+infixl 8 .->
991+(.->) = unsafeBinaryOp "->"
992+
993+-- | Get JSON value (object field or array element) at a key, as text.
994+(.->>)
995+ :: (json `In` PGJsonType, key `In` PGJsonKey)
996+ => Expression commons schemas params grp from (nullity json)
997+ -> Expression commons schemas params grp from (nullity key)
998+ -> Expression commons schemas params grp from ('Null 'PGtext)
999+infixl 8 .->>
1000+(.->>) = unsafeBinaryOp "->>"
1001+
1002+-- | Get JSON value at a specified path.
1003+(.#>)
1004+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1005+ => Expression commons schemas params grp from (nullity json)
1006+ -> Expression commons schemas params grp from (nullity path)
1007+ -> Expression commons schemas params grp from ('Null json)
1008+infixl 8 .#>
1009+(.#>) = unsafeBinaryOp "#>"
1010+
1011+-- | Get JSON value at a specified path as text.
1012+(.#>>)
1013+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1014+ => Expression commons schemas params grp from (nullity json)
1015+ -> Expression commons schemas params grp from (nullity path)
1016+ -> Expression commons schemas params grp from ('Null 'PGtext)
1017+infixl 8 .#>>
1018+(.#>>) = unsafeBinaryOp "#>>"
1019+
1020+-- Additional jsonb operators
1021+
1022+-- | Does the left JSON value contain the right JSON path/value entries at the
1023+-- top level?
1024+(.@>)
1025+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1026+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1027+ -> Condition commons schemas params grp from
1028+infixl 9 .@>
1029+(.@>) = unsafeBinaryOp "@>"
1030+
1031+-- | Are the left JSON path/value entries contained at the top level within the
1032+-- right JSON value?
1033+(.<@)
1034+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1035+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1036+ -> Condition commons schemas params grp from
1037+infixl 9 .<@
1038+(.<@) = unsafeBinaryOp "<@"
1039+
1040+-- | Does the string exist as a top-level key within the JSON value?
1041+(.?)
1042+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1043+ -> Expression commons schemas params grp from (nullity 'PGtext)
1044+ -> Condition commons schemas params grp from
1045+infixl 9 .?
1046+(.?) = unsafeBinaryOp "?"
1047+
1048+-- | Do any of these array strings exist as top-level keys?
1049+(.?|)
1050+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1051+ -> Expression commons schemas params grp from (nullity ('PGvararray ('NotNull 'PGtext)))
1052+ -> Condition commons schemas params grp from
1053+infixl 9 .?|
1054+(.?|) = unsafeBinaryOp "?|"
1055+
1056+-- | Do all of these array strings exist as top-level keys?
1057+(.?&)
1058+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1059+ -> Expression commons schemas params grp from (nullity ('PGvararray ('NotNull 'PGtext)))
1060+ -> Condition commons schemas params grp from
1061+infixl 9 .?&
1062+(.?&) = unsafeBinaryOp "?&"
1063+
1064+-- | Concatenate two jsonb values into a new jsonb value.
1065+instance
1066+ Semigroup (Expression commons schemas from grouping param (nullity 'PGjsonb)) where
1067+ (<>) = unsafeBinaryOp "||"
1068+
1069+-- | Delete a key or keys from a JSON object, or remove an array element.
1070+--
1071+-- If the right operand is..
1072+--
1073+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1074+-- are matched based on their key value.
1075+--
1076+-- @ text[] @: Delete multiple key/value pairs or string elements
1077+-- from left operand. Key/value pairs are matched based on their key value.
1078+--
1079+-- @ integer @: Delete the array element with specified index (Negative integers
1080+-- count from the end). Throws an error if top level container is not an array.
1081+(.-.)
1082+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1083+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1084+ -> Expression commons schemas params grp from (nullity key)
1085+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1086+infixl 6 .-.
1087+(.-.) = unsafeBinaryOp "-"
1088+
1089+-- | Delete the field or element with specified path (for JSON arrays, negative
1090+-- integers count from the end)
1091+(#-.)
1092+ :: PGTextArray "(#-.)" arrayty
1093+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1094+ -> Expression commons schemas params grp from (nullity arrayty)
1095+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1096+infixl 6 #-.
1097+(#-.) = unsafeBinaryOp "#-"
1098+
1099+{-----------------------------------------
1100+Table 9.45: JSON creation functions
1101+-----------------------------------------}
1102+
1103+-- | Literal binary JSON
1104+jsonbLit
1105+ :: JSON.ToJSON x
1106+ => x -> Expression commons schemas params grp from (nullity 'PGjsonb)
1107+jsonbLit = cast jsonb . UnsafeExpression
1108+ . singleQuotedUtf8 . toStrict . JSON.encode
1109+
1110+-- | Literal JSON
1111+jsonLit
1112+ :: JSON.ToJSON x
1113+ => x -> Expression commons schemas params grp from (nullity 'PGjson)
1114+jsonLit = cast json . UnsafeExpression
1115+ . singleQuotedUtf8 . toStrict . JSON.encode
1116+
1117+-- | Returns the value as json. Arrays and composites are converted
1118+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1119+-- type to json, the cast function will be used to perform the conversion;
1120+-- otherwise, a scalar value is produced. For any scalar type other than a
1121+-- number, a Boolean, or a null value, the text representation will be used, in
1122+-- such a fashion that it is a valid json value.
1123+toJson
1124+ :: Expression commons schemas params grp from (nullity ty)
1125+ -> Expression commons schemas params grp from (nullity 'PGjson)
1126+toJson = unsafeFunction "to_json"
1127+
1128+-- | Returns the value as jsonb. Arrays and composites are converted
1129+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1130+-- type to json, the cast function will be used to perform the conversion;
1131+-- otherwise, a scalar value is produced. For any scalar type other than a
1132+-- number, a Boolean, or a null value, the text representation will be used, in
1133+-- such a fashion that it is a valid jsonb value.
1134+toJsonb
1135+ :: Expression commons schemas params grp from (nullity ty)
1136+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1137+toJsonb = unsafeFunction "to_jsonb"
1138+
1139+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1140+-- becomes a JSON array of arrays.
1141+arrayToJson
1142+ :: PGArray "arrayToJson" arr
1143+ => Expression commons schemas params grp from (nullity arr)
1144+ -> Expression commons schemas params grp from (nullity 'PGjson)
1145+arrayToJson = unsafeFunction "array_to_json"
1146+
1147+-- | Returns the row as a JSON object.
1148+rowToJson
1149+ :: Expression commons schemas params grp from (nullity ('PGcomposite ty))
1150+ -> Expression commons schemas params grp from (nullity 'PGjson)
1151+rowToJson = unsafeFunction "row_to_json"
1152+
1153+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1154+-- argument list.
1155+jsonBuildArray
1156+ :: SListI elems
1157+ => NP (Expression commons schemas params grp from) elems
1158+ -> Expression commons schemas params grp from (nullity 'PGjson)
1159+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1160+
1161+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1162+-- variadic argument list.
1163+jsonbBuildArray
1164+ :: SListI elems
1165+ => NP (Expression commons schemas params grp from) elems
1166+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1167+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1168+
1169+unsafeRowFunction
1170+ :: All Top elems
1171+ => NP (Aliased (Expression commons schemas params grp from)) elems
1172+ -> [ByteString]
1173+unsafeRowFunction =
1174+ (`appEndo` []) . hcfoldMap (Proxy :: Proxy Top)
1175+ (\(col `As` name) -> Endo $ \xs ->
1176+ renderAliasString name : renderSQL col : xs)
1177+ where
1178+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1179+ renderAliasString = singleQuotedText . fromString . symbolVal
1180+
1181+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1182+-- argument list. The elements of the argument list must alternate between text
1183+-- and values.
1184+jsonBuildObject
1185+ :: All Top elems
1186+ => NP (Aliased (Expression commons schemas params grp from)) elems
1187+ -> Expression commons schemas params grp from (nullity 'PGjson)
1188+jsonBuildObject
1189+ = unsafeFunction "json_build_object"
1190+ . UnsafeExpression
1191+ . commaSeparated
1192+ . unsafeRowFunction
1193+
1194+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1195+-- variadic argument list. The elements of the argument list must alternate
1196+-- between text and values.
1197+jsonbBuildObject
1198+ :: All Top elems
1199+ => NP (Aliased (Expression commons schemas params grp from)) elems
1200+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1201+jsonbBuildObject
1202+ = unsafeFunction "jsonb_build_object"
1203+ . UnsafeExpression
1204+ . commaSeparated
1205+ . unsafeRowFunction
1206+
1207+-- | Builds a JSON object out of a text array. The array must have either
1208+-- exactly one dimension with an even number of members, in which case they are
1209+-- taken as alternating key/value pairs, or two dimensions such that each inner
1210+-- array has exactly two elements, which are taken as a key/value pair.
1211+jsonObject
1212+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1213+ => Expression commons schemas params grp from (nullity arr)
1214+ -> Expression commons schemas params grp from (nullity 'PGjson)
1215+jsonObject = unsafeFunction "json_object"
1216+
1217+-- | Builds a binary JSON object out of a text array. The array must have either
1218+-- exactly one dimension with an even number of members, in which case they are
1219+-- taken as alternating key/value pairs, or two dimensions such that each inner
1220+-- array has exactly two elements, which are taken as a key/value pair.
1221+jsonbObject
1222+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1223+ => Expression commons schemas params grp from (nullity arr)
1224+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1225+jsonbObject = unsafeFunction "jsonb_object"
1226+
1227+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1228+-- keys and one for values, that are zipped pairwise to create a JSON object.
1229+jsonZipObject
1230+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1231+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1232+ => Expression commons schemas params grp from (nullity keysArray)
1233+ -> Expression commons schemas params grp from (nullity valuesArray)
1234+ -> Expression commons schemas params grp from (nullity 'PGjson)
1235+jsonZipObject ks vs =
1236+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1237+
1238+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1239+-- keys and one for values, that are zipped pairwise to create a binary JSON
1240+-- object.
1241+jsonbZipObject
1242+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1243+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1244+ => Expression commons schemas params grp from (nullity keysArray)
1245+ -> Expression commons schemas params grp from (nullity valuesArray)
1246+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1247+jsonbZipObject ks vs =
1248+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1249+
1250+{-----------------------------------------
1251+Table 9.46: JSON processing functions
1252+-----------------------------------------}
1253+
1254+-- | Returns the number of elements in the outermost JSON array.
1255+jsonArrayLength
1256+ :: Expression commons schemas params grp from (nullity 'PGjson)
1257+ -> Expression commons schemas params grp from (nullity 'PGint4)
1258+jsonArrayLength = unsafeFunction "json_array_length"
1259+
1260+-- | Returns the number of elements in the outermost binary JSON array.
1261+jsonbArrayLength
1262+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1263+ -> Expression commons schemas params grp from (nullity 'PGint4)
1264+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1265+
1266+-- | Returns JSON value pointed to by the given path (equivalent to #>
1267+-- operator).
1268+jsonExtractPath
1269+ :: SListI elems
1270+ => Expression commons schemas params grp from (nullity 'PGjson)
1271+ -> NP (Expression commons schemas params grp from) elems
1272+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1273+jsonExtractPath x xs =
1274+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1275+
1276+-- | Returns JSON value pointed to by the given path (equivalent to #>
1277+-- operator).
1278+jsonbExtractPath
1279+ :: SListI elems
1280+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1281+ -> NP (Expression commons schemas params grp from) elems
1282+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1283+jsonbExtractPath x xs =
1284+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1285+
1286+-- | Returns JSON value pointed to by the given path (equivalent to #>
1287+-- operator), as text.
1288+jsonExtractPathAsText
1289+ :: SListI elems
1290+ => Expression commons schemas params grp from (nullity 'PGjson)
1291+ -> NP (Expression commons schemas params grp from) elems
1292+ -> Expression commons schemas params grp from (nullity 'PGjson)
1293+jsonExtractPathAsText x xs =
1294+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1295+
1296+-- | Returns JSON value pointed to by the given path (equivalent to #>
1297+-- operator), as text.
1298+jsonbExtractPathAsText
1299+ :: SListI elems
1300+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1301+ -> NP (Expression commons schemas params grp from) elems
1302+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1303+jsonbExtractPathAsText x xs =
1304+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1305+
1306+-- | Returns the type of the outermost JSON value as a text string. Possible
1307+-- types are object, array, string, number, boolean, and null.
1308+jsonTypeof
1309+ :: Expression commons schemas params grp from (nullity 'PGjson)
1310+ -> Expression commons schemas params grp from (nullity 'PGtext)
1311+jsonTypeof = unsafeFunction "json_typeof"
1312+
1313+-- | Returns the type of the outermost binary JSON value as a text string.
1314+-- Possible types are object, array, string, number, boolean, and null.
1315+jsonbTypeof
1316+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1317+ -> Expression commons schemas params grp from (nullity 'PGtext)
1318+jsonbTypeof = unsafeFunction "jsonb_typeof"
1319+
1320+-- | Returns its argument with all object fields that have null values omitted.
1321+-- Other null values are untouched.
1322+jsonStripNulls
1323+ :: Expression commons schemas params grp from (nullity 'PGjson)
1324+ -> Expression commons schemas params grp from (nullity 'PGjson)
1325+jsonStripNulls = unsafeFunction "json_strip_nulls"
1326+
1327+-- | Returns its argument with all object fields that have null values omitted.
1328+-- Other null values are untouched.
1329+jsonbStripNulls
1330+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1331+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1332+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1333+
1334+-- | @ jsonbSet target path new_value create_missing @
1335+--
1336+-- Returns target with the section designated by path replaced by new_value,
1337+-- or with new_value added if create_missing is true ( default is true) and the
1338+-- item designated by path does not exist. As with the path orientated
1339+-- operators, negative integers that appear in path count from the end of JSON
1340+-- arrays.
1341+jsonbSet
1342+ :: PGTextArray "jsonbSet" arr
1343+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1344+ -> Expression commons schemas params grp from (nullity arr)
1345+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1346+ -> Maybe (Expression commons schemas params grp from (nullity 'PGbool))
1347+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1348+jsonbSet tgt path val createMissing = case createMissing of
1349+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1350+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1351+
1352+-- | @ jsonbInsert target path new_value insert_after @
1353+--
1354+-- Returns target with new_value inserted. If target section designated by
1355+-- path is in a JSONB array, new_value will be inserted before target or after
1356+-- if insert_after is true (default is false). If target section designated by
1357+-- path is in JSONB object, new_value will be inserted only if target does not
1358+-- exist. As with the path orientated operators, negative integers that appear
1359+-- in path count from the end of JSON arrays.
1360+jsonbInsert
1361+ :: PGTextArray "jsonbInsert" arr
1362+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1363+ -> Expression commons schemas params grp from (nullity arr)
1364+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1365+ -> Maybe (Expression commons schemas params grp from (nullity 'PGbool))
1366+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1367+jsonbInsert tgt path val insertAfter = case insertAfter of
1368+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1369+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1370+
1371+-- | Returns its argument as indented JSON text.
1372+jsonbPretty
1373+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1374+ -> Expression commons schemas params grp from (nullity 'PGtext)
1375+jsonbPretty = unsafeFunction "jsonb_pretty"
1376+
1377+{-----------------------------------------
1378+aggregation
1379+-----------------------------------------}
1380+
1381+-- | escape hatch to define aggregate functions
1382+unsafeAggregate
1383+ :: ByteString -- ^ aggregate function
1384+ -> Expression commons schemas from 'Ungrouped params (xty)
1385+ -> Expression commons schemas from ('Grouped bys) params (yty)
1386+unsafeAggregate fun x = UnsafeExpression $ mconcat
1387+ [fun, "(", renderSQL x, ")"]
1388+
1389+-- | escape hatch to define aggregate functions over distinct values
1390+unsafeAggregateDistinct
1391+ :: ByteString -- ^ aggregate function
1392+ -> Expression commons schemas from 'Ungrouped params (xty)
1393+ -> Expression commons schemas from ('Grouped bys) params (yty)
1394+unsafeAggregateDistinct fun x = UnsafeExpression $ mconcat
1395+ [fun, "(DISTINCT ", renderSQL x, ")"]
1396+
1397+-- | >>> :{
1398+-- let
1399+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)
1400+-- expression = sum_ #col
1401+-- in printSQL expression
1402+-- :}
1403+-- sum("col")
1404+sum_
1405+ :: ty `In` PGNum
1406+ => Expression commons schemas from 'Ungrouped params (nullity ty)
1407+ -- ^ what to sum
1408+ -> Expression commons schemas from ('Grouped bys) params (nullity ty)
1409+sum_ = unsafeAggregate "sum"
1410+
1411+-- | >>> :{
1412+-- let
1413+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: nullity 'PGnumeric]] (nullity 'PGnumeric)
1414+-- expression = sumDistinct #col
1415+-- in printSQL expression
1416+-- :}
1417+-- sum(DISTINCT "col")
1418+sumDistinct
1419+ :: ty `In` PGNum
1420+ => Expression commons schemas from 'Ungrouped params (nullity ty)
1421+ -- ^ what to sum
1422+ -> Expression commons schemas from ('Grouped bys) params (nullity ty)
1423+sumDistinct = unsafeAggregateDistinct "sum"
1424+
1425+-- | A constraint for `PGType`s that you can take averages of and the resulting
1426+-- `PGType`.
1427+class PGAvg ty avg | ty -> avg where
1428+ avg, avgDistinct
1429+ :: Expression commons schemas from 'Ungrouped params (nullity ty)
1430+ -- ^ what to average
1431+ -> Expression commons schemas from ('Grouped bys) params (nullity avg)
1432+ avg = unsafeAggregate "avg"
1433+ avgDistinct = unsafeAggregateDistinct "avg"
1434+instance PGAvg 'PGint2 'PGnumeric
1435+instance PGAvg 'PGint4 'PGnumeric
1436+instance PGAvg 'PGint8 'PGnumeric
1437+instance PGAvg 'PGnumeric 'PGnumeric
1438+instance PGAvg 'PGfloat4 'PGfloat8
1439+instance PGAvg 'PGfloat8 'PGfloat8
1440+instance PGAvg 'PGinterval 'PGinterval
1441+
1442+-- | >>> :{
1443+-- let
1444+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1445+-- expression = bitAnd #col
1446+-- in printSQL expression
1447+-- :}
1448+-- bit_and("col")
1449+bitAnd
1450+ :: int `In` PGIntegral
1451+ => Expression commons schemas from 'Ungrouped params (nullity int)
1452+ -- ^ what to aggregate
1453+ -> Expression commons schemas from ('Grouped bys) params (nullity int)
1454+bitAnd = unsafeAggregate "bit_and"
1455+
1456+-- | >>> :{
1457+-- let
1458+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1459+-- expression = bitOr #col
1460+-- in printSQL expression
1461+-- :}
1462+-- bit_or("col")
1463+bitOr
1464+ :: int `In` PGIntegral
1465+ => Expression commons schemas from 'Ungrouped params (nullity int)
1466+ -- ^ what to aggregate
1467+ -> Expression commons schemas from ('Grouped bys) params (nullity int)
1468+bitOr = unsafeAggregate "bit_or"
1469+
1470+-- | >>> :{
1471+-- let
1472+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1473+-- expression = bitAndDistinct #col
1474+-- in printSQL expression
1475+-- :}
1476+-- bit_and(DISTINCT "col")
1477+bitAndDistinct
1478+ :: int `In` PGIntegral
1479+ => Expression commons schemas from 'Ungrouped params (nullity int)
1480+ -- ^ what to aggregate
1481+ -> Expression commons schemas from ('Grouped bys) params (nullity int)
1482+bitAndDistinct = unsafeAggregateDistinct "bit_and"
1483+
1484+-- | >>> :{
1485+-- let
1486+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1487+-- expression = bitOrDistinct #col
1488+-- in printSQL expression
1489+-- :}
1490+-- bit_or(DISTINCT "col")
1491+bitOrDistinct
1492+ :: int `In` PGIntegral
1493+ => Expression commons schemas from 'Ungrouped params (nullity int)
1494+ -- ^ what to aggregate
1495+ -> Expression commons schemas from ('Grouped bys) params (nullity int)
1496+bitOrDistinct = unsafeAggregateDistinct "bit_or"
1497+
1498+-- | >>> :{
1499+-- let
1500+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1501+-- expression = boolAnd #col
1502+-- in printSQL expression
1503+-- :}
1504+-- bool_and("col")
1505+boolAnd
1506+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1507+ -- ^ what to aggregate
1508+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1509+boolAnd = unsafeAggregate "bool_and"
1510+
1511+-- | >>> :{
1512+-- let
1513+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1514+-- expression = boolOr #col
1515+-- in printSQL expression
1516+-- :}
1517+-- bool_or("col")
1518+boolOr
1519+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1520+ -- ^ what to aggregate
1521+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1522+boolOr = unsafeAggregate "bool_or"
1523+
1524+-- | >>> :{
1525+-- let
1526+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1527+-- expression = boolAndDistinct #col
1528+-- in printSQL expression
1529+-- :}
1530+-- bool_and(DISTINCT "col")
1531+boolAndDistinct
1532+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1533+ -- ^ what to aggregate
1534+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1535+boolAndDistinct = unsafeAggregateDistinct "bool_and"
1536+
1537+-- | >>> :{
1538+-- let
1539+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1540+-- expression = boolOrDistinct #col
1541+-- in printSQL expression
1542+-- :}
1543+-- bool_or(DISTINCT "col")
1544+boolOrDistinct
1545+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1546+ -- ^ what to aggregate
1547+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1548+boolOrDistinct = unsafeAggregateDistinct "bool_or"
1549+
1550+-- | A special aggregation that does not require an input
1551+--
1552+-- >>> printSQL countStar
1553+-- count(*)
1554+countStar
1555+ :: Expression commons schemas from ('Grouped bys) params ('NotNull 'PGint8)
1556+countStar = UnsafeExpression $ "count(*)"
1557+
1558+-- | >>> :{
1559+-- let
1560+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1561+-- expression = count #col
1562+-- in printSQL expression
1563+-- :}
1564+-- count("col")
1565+count
1566+ :: Expression commons schemas from 'Ungrouped params ty
1567+ -- ^ what to count
1568+ -> Expression commons schemas from ('Grouped bys) params ('NotNull 'PGint8)
1569+count = unsafeAggregate "count"
1570+
1571+-- | >>> :{
1572+-- let
1573+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1574+-- expression = countDistinct #col
1575+-- in printSQL expression
1576+-- :}
1577+-- count(DISTINCT "col")
1578+countDistinct
1579+ :: Expression commons schemas from 'Ungrouped params ty
1580+ -- ^ what to count
1581+ -> Expression commons schemas from ('Grouped bys) params ('NotNull 'PGint8)
1582+countDistinct = unsafeAggregateDistinct "count"
1583+
1584+-- | synonym for `boolAnd`
1585+--
1586+-- >>> :{
1587+-- let
1588+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1589+-- expression = every #col
1590+-- in printSQL expression
1591+-- :}
1592+-- every("col")
1593+every
1594+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1595+ -- ^ what to aggregate
1596+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1597+every = unsafeAggregate "every"
1598+
1599+-- | synonym for `boolAndDistinct`
1600+--
1601+-- >>> :{
1602+-- let
1603+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1604+-- expression = everyDistinct #col
1605+-- in printSQL expression
1606+-- :}
1607+-- every(DISTINCT "col")
1608+everyDistinct
1609+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1610+ -- ^ what to aggregate
1611+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1612+everyDistinct = unsafeAggregateDistinct "every"
1613+
1614+-- | minimum and maximum aggregation
1615+max_, min_, maxDistinct, minDistinct
1616+ :: Expression commons schemas from 'Ungrouped params (nullity ty)
1617+ -- ^ what to aggregate
1618+ -> Expression commons schemas from ('Grouped bys) params (nullity ty)
1619+max_ = unsafeAggregate "max"
1620+min_ = unsafeAggregate "min"
1621+maxDistinct = unsafeAggregateDistinct "max"
1622+minDistinct = unsafeAggregateDistinct "min"
1623+
1624+{-----------------------------------------
1625+type expressions
1626+-----------------------------------------}
1627+
1628+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1629+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1630+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1631+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1632+instance RenderSQL (TypeExpression schemas ty) where
1633+ renderSQL = renderTypeExpression
1634+
1635+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1636+typedef
1637+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1638+ => QualifiedAlias sch td
1639+ -> TypeExpression schemas (nullity ty)
1640+typedef = UnsafeTypeExpression . renderSQL
1641+
1642+-- | The composite type corresponding to a `Table` definition can be expressed
1643+-- by its alias.
1644+typetable
1645+ :: (Has sch schemas schema, Has tab schema ('Table table))
1646+ => QualifiedAlias sch tab
1647+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1648+typetable = UnsafeTypeExpression . renderSQL
1649+
1650+-- | The composite type corresponding to a `View` definition can be expressed
1651+-- by its alias.
1652+typeview
1653+ :: (Has sch schemas schema, Has vw schema ('View view))
1654+ => QualifiedAlias sch vw
1655+ -> TypeExpression schemas (nullity ('PGcomposite view))
1656+typeview = UnsafeTypeExpression . renderSQL
1657+
1658+-- | logical Boolean (true/false)
1659+bool :: TypeExpression schemas (nullity 'PGbool)
1660+bool = UnsafeTypeExpression "bool"
1661+-- | signed two-byte integer
1662+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1663+int2 = UnsafeTypeExpression "int2"
1664+smallint = UnsafeTypeExpression "smallint"
1665+-- | signed four-byte integer
1666+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1667+int4 = UnsafeTypeExpression "int4"
1668+int = UnsafeTypeExpression "int"
1669+integer = UnsafeTypeExpression "integer"
1670+-- | signed eight-byte integer
1671+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1672+int8 = UnsafeTypeExpression "int8"
1673+bigint = UnsafeTypeExpression "bigint"
1674+-- | arbitrary precision numeric type
1675+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1676+numeric = UnsafeTypeExpression "numeric"
1677+-- | single precision floating-point number (4 bytes)
1678+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1679+float4 = UnsafeTypeExpression "float4"
1680+real = UnsafeTypeExpression "real"
1681+-- | double precision floating-point number (8 bytes)
1682+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1683+float8 = UnsafeTypeExpression "float8"
1684+doublePrecision = UnsafeTypeExpression "double precision"
1685+-- | variable-length character string
1686+text :: TypeExpression schemas (nullity 'PGtext)
1687+text = UnsafeTypeExpression "text"
1688+-- | fixed-length character string
1689+char, character
1690+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1691+ => TypeExpression schemas (nullity ('PGchar n))
1692+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1693+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1694+-- | variable-length character string
1695+varchar, characterVarying
1696+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1697+ => TypeExpression schemas (nullity ('PGvarchar n))
1698+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1699+characterVarying = UnsafeTypeExpression $
1700+ "character varying(" <> renderNat @n <> ")"
1701+-- | binary data ("byte array")
1702+bytea :: TypeExpression schemas (nullity 'PGbytea)
1703+bytea = UnsafeTypeExpression "bytea"
1704+-- | date and time (no time zone)
1705+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1706+timestamp = UnsafeTypeExpression "timestamp"
1707+-- | date and time, including time zone
1708+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1709+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1710+-- | calendar date (year, month, day)
1711+date :: TypeExpression schemas (nullity 'PGdate)
1712+date = UnsafeTypeExpression "date"
1713+-- | time of day (no time zone)
1714+time :: TypeExpression schemas (nullity 'PGtime)
1715+time = UnsafeTypeExpression "time"
1716+-- | time of day, including time zone
1717+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1718+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1719+-- | time span
1720+interval :: TypeExpression schemas (nullity 'PGinterval)
1721+interval = UnsafeTypeExpression "interval"
1722+-- | universally unique identifier
1723+uuid :: TypeExpression schemas (nullity 'PGuuid)
1724+uuid = UnsafeTypeExpression "uuid"
1725+-- | IPv4 or IPv6 host address
1726+inet :: TypeExpression schemas (nullity 'PGinet)
1727+inet = UnsafeTypeExpression "inet"
1728+-- | textual JSON data
1729+json :: TypeExpression schemas (nullity 'PGjson)
1730+json = UnsafeTypeExpression "json"
1731+-- | binary JSON data, decomposed
1732+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1733+jsonb = UnsafeTypeExpression "jsonb"
1734+-- | variable length array
1735+vararray
1736+ :: TypeExpression schemas pg
1737+ -> TypeExpression schemas (nullity ('PGvararray pg))
1738+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1739+-- | fixed length array
1740+--
1741+-- >>> renderSQL (fixarray @2 json)
1742+-- "json[2]"
1743+fixarray
1744+ :: forall n schemas nullity pg. KnownNat n
1745+ => TypeExpression schemas pg
1746+ -> TypeExpression schemas (nullity ('PGfixarray n pg))
1747+fixarray ty = UnsafeTypeExpression $
1748+ renderSQL ty <> "[" <> renderNat @n <> "]"
1749+
1750+-- | `pgtype` is a demoted version of a `PGType`
1751+class PGTyped schemas (ty :: NullityType) where
1752+ pgtype :: TypeExpression schemas ty
1753+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
1754+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
1755+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
1756+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
1757+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
1758+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
1759+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
1760+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
1761+instance (KnownNat n, 1 <= n)
1762+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
1763+instance (KnownNat n, 1 <= n)
1764+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
1765+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
1766+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
1767+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
1768+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
1769+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
1770+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
1771+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
1772+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
1773+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
1774+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
1775+instance PGTyped schemas ty
1776+ => PGTyped schemas (nullity ('PGvararray ty)) where
1777+ pgtype = vararray (pgtype @schemas @ty)
1778+instance (KnownNat n, PGTyped schemas ty)
1779+ => PGTyped schemas (nullity ('PGfixarray n ty)) where
1780+ pgtype = fixarray @n (pgtype @schemas @ty)