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