@@ -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
@@ -33,350 +34,558 @@ Squeal expressions are the atoms used to build statements.
3334module Squeal.PostgreSQL.Expression
3435 ( -- * Expression
3536 Expression (..)
36− , Expr
37− , type (-->)
38− , FunctionDB
39− , unsafeFunction
40− , function
41− , unsafeLeftOp
42− , leftOp
43− , unsafeRightOp
44− , rightOp
45− , Operator
46− , OperatorDB
37+ , HasParameter (parameter)
38+ , param
39+ -- ** Null
40+ , null_
41+ , notNull
42+ , coalesce
43+ , fromNull
44+ , isNull
45+ , isNotNull
46+ , matchNull
47+ , nullIf
48+ -- ** Collections
49+ , array
50+ , index
51+ , row
52+ , field
53+ -- ** Functions
4754 , unsafeBinaryOp
48− , binaryOp
49− , FunctionVar
50− , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
53− , unsafeFunctionN
54− , functionN
55− , PGSubset (..)
56− , PGIntersect (..)
55+ , unsafeUnaryOp
56+ , unsafeFunction
57+ , unsafeVariadicFunction
58+ , atan2_
59+ , cast
60+ , quot_
61+ , rem_
62+ , trunc
63+ , round_
64+ , ceiling_
65+ , greatest
66+ , least
67+ -- ** Conditions
68+ , true
69+ , false
70+ , not_
71+ , (.&&)
72+ , (.||)
73+ , Condition
74+ , caseWhenThenElse
75+ , ifThenElse
76+ , (.==)
77+ , (./=)
78+ , (.>=)
79+ , (.<)
80+ , (.<=)
81+ , (.>)
82+ -- ** Time
83+ , currentDate
84+ , currentTime
85+ , currentTimestamp
86+ , localTime
87+ , localTimestamp
88+ -- ** Text
89+ , lower
90+ , upper
91+ , charLength
92+ , like
93+ , ilike
94+ -- ** Json
95+ -- *** Json and Jsonb operators
96+ , (.->)
97+ , (.->>)
98+ , (.#>)
99+ , (.#>>)
100+ -- *** Jsonb operators
101+ , (.@>)
102+ , (.<@)
103+ , (.?)
104+ , (.?|)
105+ , (.?&)
106+ , (.-.)
107+ , (#-.)
108+ -- *** Functions
109+ , jsonLit
110+ , jsonbLit
111+ , toJson
112+ , toJsonb
113+ , arrayToJson
114+ , rowToJson
115+ , jsonBuildArray
116+ , jsonbBuildArray
117+ , jsonBuildObject
118+ , jsonbBuildObject
119+ , jsonObject
120+ , jsonbObject
121+ , jsonZipObject
122+ , jsonbZipObject
123+ , jsonArrayLength
124+ , jsonbArrayLength
125+ , jsonExtractPath
126+ , jsonbExtractPath
127+ , jsonExtractPathAsText
128+ , jsonbExtractPathAsText
129+ , jsonTypeof
130+ , jsonbTypeof
131+ , jsonStripNulls
132+ , jsonbStripNulls
133+ , jsonbSet
134+ , jsonbInsert
135+ , jsonbPretty
136+ -- ** Aggregation
137+ , unsafeAggregate, unsafeAggregateDistinct
138+ , sum_, sumDistinct
139+ , PGAvg (avg, avgDistinct)
140+ , bitAnd, bitOr, boolAnd, boolOr
141+ , bitAndDistinct, bitOrDistinct, boolAndDistinct, boolOrDistinct
142+ , countStar
143+ , count, countDistinct
144+ , every, everyDistinct
145+ , max_, maxDistinct, min_, minDistinct
146+ -- * Window Functions
147+ , WindowDefinition (..)
148+ , partitionBy
149+ , WindowFunction (..)
150+ , rank
151+ , rowNumber
152+ , denseRank
153+ , percentRank
154+ , cumeDist
155+ -- * Sorting
156+ , SortExpression (..)
157+ , OrderBy (..)
158+ -- * Types
159+ , TypeExpression (..)
160+ , PGTyped (..)
161+ , typedef
162+ , typetable
163+ , typeview
164+ , bool
165+ , int2
166+ , smallint
167+ , int4
168+ , int
169+ , integer
170+ , int8
171+ , bigint
172+ , numeric
173+ , float4
174+ , real
175+ , float8
176+ , doublePrecision
177+ , text
178+ , char
179+ , character
180+ , varchar
181+ , characterVarying
182+ , bytea
183+ , timestamp
184+ , timestampWithTimeZone
185+ , date
186+ , time
187+ , timeWithTimeZone
188+ , interval
189+ , uuid
190+ , inet
191+ , json
192+ , jsonb
193+ , vararray
194+ , fixarray
57195 -- * Re-export
58196 , (&)
59− , K (..)
60− , unK
197+ , NP ((:*), Nil)
61198 ) where
62199
63200import Control.Category
64201import Control.DeepSeq
65202import Data.ByteString (ByteString)
203+import Data.ByteString.Lazy (toStrict)
66204import Data.Function ((&))
67205import Data.Semigroup hiding (All)
206+import qualified Data.Aeson as JSON
207+import Data.Ratio
68208import Data.String
69−import Generics.SOP hiding (All, from)
209+import Data.Word
210+import Generics.SOP hiding (from)
70211import GHC.OverloadedLabels
71212import GHC.TypeLits
72−import Numeric
73213import Prelude hiding (id, (.))
74214
75215import qualified GHC.Generics as GHC
76216
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79217import Squeal.PostgreSQL.Render
80218import Squeal.PostgreSQL.Schema
81219
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85220{-----------------------------------------
86221column expressions
87222-----------------------------------------}
88223
89224{- | `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,
225+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92226as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93227`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
228+or in search `Condition`s in a number of commands.
95229
96230The expression syntax allows the calculation of
97231values from primitive expression using arithmetic, logical,
98232and 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`.
113233-}
114234newtype Expression
115− (outer :: FromType)
116235 (commons :: FromType)
117− (grp :: Grouping)
118236 (schemas :: SchemasType)
119237 (params :: [NullityType])
238+ (grp :: Grouping)
120239 (from :: FromType)
121240 (ty :: NullityType)
122241 = UnsafeExpression { renderExpression :: ByteString }
123242 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
243+
244+instance RenderSQL (Expression commons schemas params grp from ty) where
125245 renderSQL = renderExpression
126246
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)
247+{- | A `HasParameter` constraint is used to indicate a value that is
248+supplied externally to a SQL statement.
249+`Squeal.PostgreSQL.PQ.manipulateParams`,
250+`Squeal.PostgreSQL.PQ.queryParams` and
251+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
252+separately from the SQL command string, in which case `param`s are used to
253+refer to the out-of-line data values.
181254-}
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)
210−-}
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
213− (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
255+class KnownNat n => HasParameter
256+ (n :: Nat)
257+ (params :: [NullityType])
258+ (ty :: NullityType)
259+ | n params -> ty where
260+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
261+ --
262+ -- >>> let expr = parameter @1 int4 :: Expression '[] schemas '[ 'Null 'PGint4] grp from ('Null 'PGint4)
263+ -- >>> printSQL expr
264+ -- ($1 :: int4)
265+ parameter
266+ :: TypeExpression schemas ty
267+ -> Expression commons schemas params grp from ty
268+ parameter ty = UnsafeExpression $ parenthesized $
269+ "$" <> renderNat @n <+> "::"
270+ <+> renderSQL ty
271+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
272+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
273+ => HasParameter n (ty' : params) ty
214274
215−instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
275+-- | `param` takes a `Nat` using type application and for basic types,
276+-- infers a `TypeExpression`.
277+--
278+-- >>> let expr = param @1 :: Expression commons schemas '[ 'Null 'PGint4] grp from ('Null 'PGint4)
279+-- >>> printSQL expr
280+-- ($1 :: int4)
281+param
282+ :: forall n commons schemas params from grp ty
283+ . (PGTyped schemas ty, HasParameter n params ty)
284+ => Expression commons schemas params grp from ty -- ^ param
285+param = parameter @n (pgtype @schemas)
286+
287+instance (HasUnique tab from row, Has col row ty)
288+ => IsLabel col (Expression commons schemas params 'Ungrouped from ty) where
217289 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))
290+instance (HasUnique tab from row, Has col row ty, column ~ (col ::: ty))
222291 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
292+ (Aliased (Expression commons schemas params 'Ungrouped from) column) where
224293 fromLabel = fromLabel @col `As` Alias
225−instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
294+instance (HasUnique tab from row, Has col row ty, columns ~ '[col ::: ty])
226295 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
296+ (NP (Aliased (Expression commons schemas params 'Ungrouped from)) columns) where
228297 fromLabel = fromLabel @col :* Nil
229298
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
299+instance (Has tab from row, Has col row ty)
300+ => IsQualified tab col (Expression commons schemas params 'Ungrouped from ty) where
232301 tab ! col = UnsafeExpression $
233302 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))
303+instance (Has tab from row, Has col row ty, column ~ (col ::: ty))
238304 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
305+ (Aliased (Expression commons schemas params 'Ungrouped from) column) where
240306 tab ! col = tab ! col `As` col
241−instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
307+instance (Has tab from row, Has col row ty, columns ~ '[col ::: ty])
242308 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
309+ (NP (Aliased (Expression commons schemas params 'Ungrouped from)) columns) where
244310 tab ! col = tab ! col :* Nil
245311
246312instance
247− ( HasUnique tab (Join outer from) row
313+ ( HasUnique tab from row
248314 , Has col row ty
249315 , GroupedBy tab col bys
250316 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
317+ (Expression commons schemas params ('Grouped bys) from ty) where
252318 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253319instance
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
320+ ( HasUnique tab from row
263321 , Has col row ty
264322 , GroupedBy tab col bys
265323 , column ~ (col ::: ty)
266324 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
325+ (Aliased (Expression commons schemas params ('Grouped bys) from) column) where
268326 fromLabel = fromLabel @col `As` Alias
269327instance
270− ( HasUnique tab (Join outer from) row
328+ ( HasUnique tab from row
271329 , Has col row ty
272330 , GroupedBy tab col bys
273331 , columns ~ '[col ::: ty]
274332 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
333+ (NP (Aliased (Expression commons schemas params ('Grouped bys) from)) columns) where
276334 fromLabel = fromLabel @col :* Nil
277335
278336instance
279− ( Has tab (Join outer from) row
337+ ( Has tab from row
280338 , Has col row ty
281339 , GroupedBy tab col bys
282340 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
341+ (Expression commons schemas params ('Grouped bys) from ty) where
284342 tab ! col = UnsafeExpression $
285343 renderSQL tab <> "." <> renderSQL col
286344instance
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
345+ ( Has tab from row
296346 , Has col row ty
297347 , GroupedBy tab col bys
298348 , column ~ (col ::: ty)
299349 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
350+ (Aliased (Expression commons schemas params ('Grouped bys) from) column) where
301351 tab ! col = tab ! col `As` col
302352instance
303− ( Has tab (Join outer from) row
353+ ( Has tab from row
304354 , Has col row ty
305355 , GroupedBy tab col bys
306356 , columns ~ '[col ::: ty]
307357 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
358+ (NP (Aliased (Expression commons schemas params ('Grouped bys) from)) columns) where
309359 tab ! col = tab ! col :* Nil
310360
361+-- | analagous to `Nothing`
362+--
363+-- >>> printSQL null_
364+-- NULL
365+null_ :: Expression commons schemas rels grouping params ('Null ty)
366+null_ = UnsafeExpression "NULL"
367+
368+-- | analagous to `Just`
369+--
370+-- >>> printSQL $ notNull true
371+-- TRUE
372+notNull
373+ :: Expression commons schemas rels grouping params ('NotNull ty)
374+ -> Expression commons schemas rels grouping params ('Null ty)
375+notNull = UnsafeExpression . renderSQL
376+
377+-- | return the leftmost value which is not NULL
378+--
379+-- >>> printSQL $ coalesce [null_, true] false
380+-- COALESCE(NULL, TRUE, FALSE)
381+coalesce
382+ :: [Expression commons schemas params grp from ('Null ty)]
383+ -- ^ @NULL@s may be present
384+ -> Expression commons schemas params grp from ('NotNull ty)
385+ -- ^ @NULL@ is absent
386+ -> Expression commons schemas params grp from ('NotNull ty)
387+coalesce nullxs notNullx = UnsafeExpression $
388+ "COALESCE" <> parenthesized (commaSeparated
389+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
390+
391+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
392+--
393+-- >>> printSQL $ fromNull true null_
394+-- COALESCE(NULL, TRUE)
395+fromNull
396+ :: Expression commons schemas params grp from ('NotNull ty)
397+ -- ^ what to convert @NULL@ to
398+ -> Expression commons schemas params grp from ('Null ty)
399+ -> Expression commons schemas params grp from ('NotNull ty)
400+fromNull notNullx nullx = coalesce [nullx] notNullx
401+
402+-- | >>> printSQL $ null_ & isNull
403+-- NULL IS NULL
404+isNull
405+ :: Expression commons schemas params grp from ('Null ty)
406+ -- ^ possibly @NULL@
407+ -> Condition commons schemas params grp from
408+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
409+
410+-- | >>> printSQL $ null_ & isNotNull
411+-- NULL IS NOT NULL
412+isNotNull
413+ :: Expression commons schemas params grp from ('Null ty)
414+ -- ^ possibly @NULL@
415+ -> Condition commons schemas params grp from
416+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
417+
418+-- | analagous to `maybe` using @IS NULL@
419+--
420+-- >>> printSQL $ matchNull true not_ null_
421+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
422+matchNull
423+ :: Expression commons schemas params grp from (nullty)
424+ -- ^ what to convert @NULL@ to
425+ -> ( Expression commons schemas params grp from ('NotNull ty)
426+ -> Expression commons schemas params grp from (nullty) )
427+ -- ^ function to perform when @NULL@ is absent
428+ -> Expression commons schemas params grp from ('Null ty)
429+ -> Expression commons schemas params grp from (nullty)
430+matchNull y f x = ifThenElse (isNull x) y
431+ (f (UnsafeExpression (renderSQL x)))
432+
433+{-| right inverse to `fromNull`, if its arguments are equal then
434+`nullIf` gives @NULL@.
435+
436+>>> :set -XTypeApplications -XDataKinds
437+>>> let expr = nullIf false (param @1) :: Expression commons schemas '[ 'NotNull 'PGbool] grp from ('Null 'PGbool)
438+>>> printSQL expr
439+NULL IF (FALSE, ($1 :: bool))
440+-}
441+nullIf
442+ :: Expression commons schemas params grp from ('NotNull ty)
443+ -- ^ @NULL@ is absent
444+ -> Expression commons schemas params grp from ('NotNull ty)
445+ -- ^ @NULL@ is absent
446+ -> Expression commons schemas params grp from ('Null ty)
447+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
448+ (renderSQL x <> ", " <> renderSQL y)
449+
450+-- | >>> printSQL $ array [null_, false, true]
451+-- ARRAY[NULL, FALSE, TRUE]
452+array
453+ :: [Expression commons schemas params grp from ty]
454+ -- ^ array elements
455+ -> Expression commons schemas params grp from (nullity ('PGvararray ty))
456+array xs = UnsafeExpression $
457+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
458+
459+-- | >>> printSQL $ array [null_, false, true] & index 2
460+-- (ARRAY[NULL, FALSE, TRUE])[2]
461+index
462+ :: Word64 -- ^ index
463+ -> Expression commons schemas params grp from (nullity ('PGvararray ty)) -- ^ array
464+ -> Expression commons schemas params grp from (NullifyType ty)
465+index n expr = UnsafeExpression $
466+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
467+
311468instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
469+ (Expression commons schemas params grp from (nullity ('PGenum labels))) where
313470 label = UnsafeExpression $ renderSQL (PGlabel @label)
314471
472+-- | A row constructor is an expression that builds a row value
473+-- (also called a composite value) using values for its member fields.
474+--
475+-- >>> :{
476+-- type Complex = 'PGcomposite
477+-- '[ "real" ::: 'NotNull 'PGfloat8
478+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
479+-- :}
480+--
481+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression commons schemas from grp params ('NotNull Complex)
482+-- >>> printSQL i
483+-- ROW(0, 1)
484+row
485+ :: SListI row
486+ => NP (Aliased (Expression commons schemas params grp from)) row
487+ -- ^ zero or more expressions for the row field values
488+ -> Expression commons schemas params grp from (nullity ('PGcomposite row))
489+row exprs = UnsafeExpression $ "ROW" <> parenthesized
490+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
491+
492+-- | >>> :{
493+-- type Complex = 'PGcomposite
494+-- '[ "real" ::: 'NotNull 'PGfloat8
495+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
496+-- type Schema = '["complex" ::: 'Typedef Complex]
497+-- :}
498+--
499+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression '[] (Public Schema) from grp params ('NotNull Complex)
500+-- >>> printSQL $ i & field #complex #imaginary
501+-- (ROW(0, 1)::"complex")."imaginary"
502+field
503+ :: ( Has sch schemas schema
504+ , Has tydef schema ('Typedef ('PGcomposite row))
505+ , Has field row ty)
506+ => QualifiedAlias sch tydef -- ^ row type
507+ -> Alias field -- ^ field name
508+ -> Expression commons schemas params grp from ('NotNull ('PGcomposite row))
509+ -> Expression commons schemas params grp from ty
510+field td fld expr = UnsafeExpression $
511+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
512+ <> "." <> renderSQL fld
513+
514+instance Semigroup
515+ (Expression commons schemas params grp from (nullity ('PGvararray ty))) where
516+ (<>) = unsafeBinaryOp "||"
517+
518+instance Monoid
519+ (Expression commons schemas params grp from (nullity ('PGvararray ty))) where
520+ mempty = array []
521+ mappend = (<>)
522+
523+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression commons schemas '[ 'NotNull 'PGtimestamptz] grp from ('NotNull 'PGtimestamptz)
524+-- >>> printSQL expr
525+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
526+greatest
527+ :: Expression commons schemas params grp from (nullty)
528+ -- ^ needs at least 1 argument
529+ -> [Expression commons schemas params grp from (nullty)]
530+ -- ^ or more
531+ -> Expression commons schemas params grp from (nullty)
532+greatest x xs = UnsafeExpression $ "GREATEST("
533+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
534+
535+-- | >>> printSQL $ least currentTimestamp [null_]
536+-- LEAST(CURRENT_TIMESTAMP, NULL)
537+least
538+ :: Expression commons schemas params grp from (nullty)
539+ -- ^ needs at least 1 argument
540+ -> [Expression commons schemas params grp from (nullty)]
541+ -- ^ or more
542+ -> Expression commons schemas params grp from (nullty)
543+least x xs = UnsafeExpression $ "LEAST("
544+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
545+
315546-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316547-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
548+unsafeBinaryOp
549+ :: ByteString
550+ -- ^ operator
551+ -> Expression commons schemas params grp from (ty0)
552+ -> Expression commons schemas params grp from (ty1)
553+ -> Expression commons schemas params grp from (ty2)
318554unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319555 renderSQL x <+> op <+> renderSQL y
320556
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
557+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329558-- (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
559+unsafeUnaryOp
560+ :: ByteString
561+ -- ^ operator
562+ -> Expression commons schemas params grp from (ty0)
563+ -> Expression commons schemas params grp from (ty1)
564+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
565+ op <+> renderSQL x
351566
352567-- | >>> printSQL $ unsafeFunction "f" true
353568-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
569+unsafeFunction
570+ :: ByteString
571+ -- ^ function
572+ -> Expression commons schemas params grp from (xty)
573+ -> Expression commons schemas params grp from (yty)
355574unsafeFunction fun x = UnsafeExpression $
356575 fun <> parenthesized (renderSQL x)
357576
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
577+-- | Helper for defining variadic functions.
578+unsafeVariadicFunction
579+ :: SListI elems
580+ => ByteString
581+ -- ^ function
582+ -> NP (Expression commons schemas params grp from) elems
583+ -> Expression commons schemas params grp from ret
584+unsafeVariadicFunction fun x = UnsafeExpression $
585+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
377586
378587instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
588+ => Num (Expression commons schemas params grp from (nullity ty)) where
380589 (+) = unsafeBinaryOp "+"
381590 (-) = unsafeBinaryOp "-"
382591 (*) = unsafeBinaryOp "*"
@@ -388,17 +597,12 @@ instance ty `In` PGNum
388597 . show
389598
390599instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
600+ (Expression commons schemas params grp from (nullity ty)) where
392601 (/) = unsafeBinaryOp "/"
393− fromRational
394− = UnsafeExpression
395− . fromString
396− . ($ "")
397− . showFFloat Nothing
398− . fromRat @Double
602+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
399603
400604instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
605+ (Expression commons schemas params grp from (nullity ty)) where
402606 pi = UnsafeExpression "pi()"
403607 exp = unsafeFunction "exp"
404608 log = unsafeFunction "ln"
@@ -419,54 +623,1301 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419623 acosh x = log (x + sqrt (x*x - 1))
420624 atanh x = log ((1 + x) / (1 - x)) / 2
421625
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)
626+-- | >>> :{
627+-- let
628+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
629+-- expression = atan2_ pi 2
630+-- in printSQL expression
631+-- :}
632+-- atan2(pi(), 2)
633+atan2_
634+ :: float `In` PGFloating
635+ => Expression commons schemas params grp from (nullity float)
636+ -- ^ numerator
637+ -> Expression commons schemas params grp from (nullity float)
638+ -- ^ denominator
639+ -> Expression commons schemas params grp from (nullity float)
640+atan2_ y x = UnsafeExpression $
641+ "atan2(" <> renderSQL y <> ", " <> renderSQL x <> ")"
642+
643+-- When a `cast` is applied to an `Expression` of a known type, it
644+-- represents a run-time type conversion. The cast will succeed only if a
645+-- suitable type conversion operation has been defined.
646+--
647+-- | >>> printSQL $ true & cast int4
648+-- (TRUE :: int4)
649+cast
650+ :: TypeExpression schemas ty1
651+ -- ^ type to cast as
652+ -> Expression commons schemas params grp from ty0
653+ -- ^ value to convert
654+ -> Expression commons schemas params grp from ty1
655+cast ty x = UnsafeExpression $ parenthesized $
656+ renderSQL x <+> "::" <+> renderSQL ty
657+
658+-- | integer division, truncates the result
659+--
660+-- >>> :{
661+-- let
662+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
663+-- expression = 5 `quot_` 2
664+-- in printSQL expression
665+-- :}
666+-- (5 / 2)
667+quot_
668+ :: int `In` PGIntegral
669+ => Expression commons schemas params grp from (nullity int)
670+ -- ^ numerator
671+ -> Expression commons schemas params grp from (nullity int)
672+ -- ^ denominator
673+ -> Expression commons schemas params grp from (nullity int)
674+quot_ = unsafeBinaryOp "/"
675+
676+-- | remainder upon integer division
677+--
678+-- >>> :{
679+-- let
680+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
681+-- expression = 5 `rem_` 2
682+-- in printSQL expression
683+-- :}
684+-- (5 % 2)
685+rem_
686+ :: int `In` PGIntegral
687+ => Expression commons schemas params grp from (nullity int)
688+ -- ^ numerator
689+ -> Expression commons schemas params grp from (nullity int)
690+ -- ^ denominator
691+ -> Expression commons schemas params grp from (nullity int)
692+rem_ = unsafeBinaryOp "%"
693+
694+-- | >>> :{
695+-- let
696+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
697+-- expression = trunc pi
698+-- in printSQL expression
699+-- :}
700+-- trunc(pi())
701+trunc
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+trunc = unsafeFunction "trunc"
707+
708+-- | >>> :{
709+-- let
710+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
711+-- expression = round_ pi
712+-- in printSQL expression
713+-- :}
714+-- round(pi())
715+round_
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+round_ = unsafeFunction "round"
721+
722+-- | >>> :{
723+-- let
724+-- expression :: Expression commons schemas params grp from (nullity 'PGfloat4)
725+-- expression = ceiling_ pi
726+-- in printSQL expression
727+-- :}
728+-- ceiling(pi())
729+ceiling_
730+ :: frac `In` PGFloating
731+ => Expression commons schemas params grp from (nullity frac)
732+ -- ^ fractional number
733+ -> Expression commons schemas params grp from (nullity frac)
734+ceiling_ = unsafeFunction "ceiling"
735+
736+-- | A `Condition` is an `Expression`, which can evaluate
737+-- to `true`, `false` or `null_`. This is because SQL uses
738+-- a three valued logic.
739+type Condition commons schemas params grp from =
740+ Expression commons schemas params grp from ('Null 'PGbool)
741+
742+-- | >>> printSQL true
743+-- TRUE
744+true :: Expression commons schemas params grp from (nullity 'PGbool)
745+true = UnsafeExpression "TRUE"
746+
747+-- | >>> printSQL false
748+-- FALSE
749+false :: Expression commons schemas params grp from (nullity 'PGbool)
750+false = UnsafeExpression "FALSE"
751+
752+-- | >>> printSQL $ not_ true
753+-- (NOT TRUE)
754+not_
755+ :: Expression commons schemas params grp from (nullity 'PGbool)
756+ -> Expression commons schemas params grp from (nullity 'PGbool)
757+not_ = unsafeUnaryOp "NOT"
758+
759+-- | >>> printSQL $ true .&& false
760+-- (TRUE AND FALSE)
761+(.&&)
762+ :: Expression commons schemas params grp from (nullity 'PGbool)
763+ -> Expression commons schemas params grp from (nullity 'PGbool)
764+ -> Expression commons schemas params grp from (nullity 'PGbool)
765+infixr 3 .&&
766+(.&&) = unsafeBinaryOp "AND"
767+
768+-- | >>> printSQL $ true .|| false
769+-- (TRUE OR FALSE)
770+(.||)
771+ :: Expression commons schemas params grp from (nullity 'PGbool)
772+ -> Expression commons schemas params grp from (nullity 'PGbool)
773+ -> Expression commons schemas params grp from (nullity 'PGbool)
774+infixr 2 .||
775+(.||) = unsafeBinaryOp "OR"
776+
777+-- | >>> :{
778+-- let
779+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
780+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
781+-- in printSQL expression
782+-- :}
783+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
784+caseWhenThenElse
785+ :: [ ( Condition commons schemas params grp from
786+ , Expression commons schemas params grp from ty
787+ ) ]
788+ -- ^ whens and thens
789+ -> Expression commons schemas params grp from ty
790+ -- ^ else
791+ -> Expression commons schemas params grp from ty
792+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
793+ [ "CASE"
794+ , mconcat
795+ [ mconcat
796+ [ " WHEN ", renderSQL when_
797+ , " THEN ", renderSQL then_
798+ ]
799+ | (when_,then_) <- whenThens
800+ ]
801+ , " ELSE ", renderSQL else_
802+ , " END"
803+ ]
804+
805+-- | >>> :{
806+-- let
807+-- expression :: Expression commons schemas params grp from (nullity 'PGint2)
808+-- expression = ifThenElse true 1 0
809+-- in printSQL expression
810+-- :}
811+-- CASE WHEN TRUE THEN 1 ELSE 0 END
812+ifThenElse
813+ :: Condition commons schemas params grp from
814+ -> Expression commons schemas params grp from ty -- ^ then
815+ -> Expression commons schemas params grp from ty -- ^ else
816+ -> Expression commons schemas params grp from ty
817+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
818+
819+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
820+-- will produce @NULL@s if one of their arguments is @NULL@.
821+--
822+-- >>> printSQL $ true .== null_
823+-- (TRUE = NULL)
824+(.==)
825+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
826+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
827+ -> Condition commons schemas params grp from
828+(.==) = unsafeBinaryOp "="
829+infix 4 .==
830+
831+-- | >>> printSQL $ true ./= null_
832+-- (TRUE <> NULL)
833+(./=)
834+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
835+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
836+ -> Condition commons schemas params grp from
837+(./=) = unsafeBinaryOp "<>"
838+infix 4 ./=
839+
840+-- | >>> printSQL $ true .>= null_
841+-- (TRUE >= NULL)
842+(.>=)
843+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
844+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
845+ -> Condition commons schemas params grp from
846+(.>=) = unsafeBinaryOp ">="
847+infix 4 .>=
848+
849+-- | >>> printSQL $ true .< null_
850+-- (TRUE < NULL)
851+(.<)
852+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
853+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
854+ -> Condition commons schemas params grp from
855+(.<) = unsafeBinaryOp "<"
856+infix 4 .<
857+
858+-- | >>> printSQL $ true .<= null_
859+-- (TRUE <= NULL)
860+(.<=)
861+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
862+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
863+ -> Condition commons schemas params grp from
864+(.<=) = unsafeBinaryOp "<="
865+infix 4 .<=
866+
867+-- | >>> printSQL $ true .> null_
868+-- (TRUE > NULL)
869+(.>)
870+ :: Expression commons schemas params grp from (nullity0 ty) -- ^ lhs
871+ -> Expression commons schemas params grp from (nullity1 ty) -- ^ rhs
872+ -> Condition commons schemas params grp from
873+(.>) = unsafeBinaryOp ">"
874+infix 4 .>
875+
876+-- | >>> printSQL currentDate
877+-- CURRENT_DATE
878+currentDate
879+ :: Expression commons schemas params grp from (nullity 'PGdate)
880+currentDate = UnsafeExpression "CURRENT_DATE"
881+
882+-- | >>> printSQL currentTime
883+-- CURRENT_TIME
884+currentTime
885+ :: Expression commons schemas params grp from (nullity 'PGtimetz)
886+currentTime = UnsafeExpression "CURRENT_TIME"
887+
888+-- | >>> printSQL currentTimestamp
889+-- CURRENT_TIMESTAMP
890+currentTimestamp
891+ :: Expression commons schemas params grp from (nullity 'PGtimestamptz)
892+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
893+
894+-- | >>> printSQL localTime
895+-- LOCALTIME
896+localTime
897+ :: Expression commons schemas params grp from (nullity 'PGtime)
898+localTime = UnsafeExpression "LOCALTIME"
899+
900+-- | >>> printSQL localTimestamp
901+-- LOCALTIMESTAMP
902+localTimestamp
903+ :: Expression commons schemas params grp from (nullity 'PGtimestamp)
904+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
905+
906+{-----------------------------------------
907+text
908+-----------------------------------------}
438909
439910instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
911+ (Expression commons schemas params grp from (nullity 'PGtext)) where
441912 fromString str = UnsafeExpression $
442913 "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) <> "\'"
914+ where
915+ escape = \case
916+ '\NUL' -> "\\0"
917+ '\'' -> "''"
918+ '"' -> "\\\""
919+ '\b' -> "\\b"
920+ '\n' -> "\\n"
921+ '\r' -> "\\r"
922+ '\t' -> "\\t"
923+ '\\' -> "\\\\"
924+ c -> [c]
451925
452926instance 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
927+ (Expression commons schemas params grp from (nullity 'PGtext)) where
463928 (<>) = unsafeBinaryOp "||"
464929
465930instance 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
931+ (Expression commons schemas params grp from (nullity 'PGtext)) where
471932 mempty = fromString ""
472933 mappend = (<>)
934+
935+-- | >>> printSQL $ lower "ARRRGGG"
936+-- lower(E'ARRRGGG')
937+lower
938+ :: Expression commons schemas params grp from (nullity 'PGtext)
939+ -- ^ string to lower case
940+ -> Expression commons schemas params grp from (nullity 'PGtext)
941+lower = unsafeFunction "lower"
942+
943+-- | >>> printSQL $ upper "eeee"
944+-- upper(E'eeee')
945+upper
946+ :: Expression commons schemas params grp from (nullity 'PGtext)
947+ -- ^ string to upper case
948+ -> Expression commons schemas params grp from (nullity 'PGtext)
949+upper = unsafeFunction "upper"
950+
951+-- | >>> printSQL $ charLength "four"
952+-- char_length(E'four')
953+charLength
954+ :: Expression commons schemas params grp from (nullity 'PGtext)
955+ -- ^ string to measure
956+ -> Expression commons schemas params grp from (nullity 'PGint4)
957+charLength = unsafeFunction "char_length"
958+
959+-- | The `like` expression returns true if the @string@ matches
960+-- the supplied @pattern@. If @pattern@ does not contain percent signs
961+-- or underscores, then the pattern only represents the string itself;
962+-- in that case `like` acts like the equals operator. An underscore (_)
963+-- in pattern stands for (matches) any single character; a percent sign (%)
964+-- matches any sequence of zero or more characters.
965+--
966+-- >>> printSQL $ "abc" `like` "a%"
967+-- (E'abc' LIKE E'a%')
968+like
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+like = unsafeBinaryOp "LIKE"
975+
976+-- | The key word ILIKE can be used instead of LIKE to make the
977+-- match case-insensitive according to the active locale.
978+--
979+-- >>> printSQL $ "abc" `ilike` "a%"
980+-- (E'abc' ILIKE E'a%')
981+ilike
982+ :: Expression commons schemas params grp from (nullity 'PGtext)
983+ -- ^ string
984+ -> Expression commons schemas params grp from (nullity 'PGtext)
985+ -- ^ pattern
986+ -> Expression commons schemas params grp from (nullity 'PGbool)
987+ilike = unsafeBinaryOp "ILIKE"
988+
989+{-----------------------------------------
990+ -- json and jsonb support
991+
992+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
993+comments lifted directly from this page.
994+
995+Table 9.44: json and jsonb operators
996+-----------------------------------------}
997+
998+-- | Get JSON value (object field or array element) at a key.
999+(.->)
1000+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1001+ => Expression commons schemas params grp from (nullity json)
1002+ -> Expression commons schemas params grp from (nullity key)
1003+ -> Expression commons schemas params grp from ('Null json)
1004+infixl 8 .->
1005+(.->) = unsafeBinaryOp "->"
1006+
1007+-- | Get JSON value (object field or array element) at a key, as text.
1008+(.->>)
1009+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1010+ => Expression commons schemas params grp from (nullity json)
1011+ -> Expression commons schemas params grp from (nullity key)
1012+ -> Expression commons schemas params grp from ('Null 'PGtext)
1013+infixl 8 .->>
1014+(.->>) = unsafeBinaryOp "->>"
1015+
1016+-- | Get JSON value at a specified path.
1017+(.#>)
1018+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1019+ => Expression commons schemas params grp from (nullity json)
1020+ -> Expression commons schemas params grp from (nullity path)
1021+ -> Expression commons schemas params grp from ('Null json)
1022+infixl 8 .#>
1023+(.#>) = unsafeBinaryOp "#>"
1024+
1025+-- | Get JSON value at a specified path as text.
1026+(.#>>)
1027+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1028+ => Expression commons schemas params grp from (nullity json)
1029+ -> Expression commons schemas params grp from (nullity path)
1030+ -> Expression commons schemas params grp from ('Null 'PGtext)
1031+infixl 8 .#>>
1032+(.#>>) = unsafeBinaryOp "#>>"
1033+
1034+-- Additional jsonb operators
1035+
1036+-- | Does the left JSON value contain the right JSON path/value entries at the
1037+-- top level?
1038+(.@>)
1039+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1040+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1041+ -> Condition commons schemas params grp from
1042+infixl 9 .@>
1043+(.@>) = unsafeBinaryOp "@>"
1044+
1045+-- | Are the left JSON path/value entries contained at the top level within the
1046+-- right JSON value?
1047+(.<@)
1048+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1049+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1050+ -> Condition commons schemas params grp from
1051+infixl 9 .<@
1052+(.<@) = unsafeBinaryOp "<@"
1053+
1054+-- | Does the string exist as a top-level key within the JSON value?
1055+(.?)
1056+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1057+ -> Expression commons schemas params grp from (nullity 'PGtext)
1058+ -> Condition commons schemas params grp from
1059+infixl 9 .?
1060+(.?) = unsafeBinaryOp "?"
1061+
1062+-- | Do any of these array strings exist as top-level keys?
1063+(.?|)
1064+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1065+ -> Expression commons schemas params grp from (nullity ('PGvararray ('NotNull 'PGtext)))
1066+ -> Condition commons schemas params grp from
1067+infixl 9 .?|
1068+(.?|) = unsafeBinaryOp "?|"
1069+
1070+-- | Do all of these array strings exist as top-level keys?
1071+(.?&)
1072+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1073+ -> Expression commons schemas params grp from (nullity ('PGvararray ('NotNull 'PGtext)))
1074+ -> Condition commons schemas params grp from
1075+infixl 9 .?&
1076+(.?&) = unsafeBinaryOp "?&"
1077+
1078+-- | Concatenate two jsonb values into a new jsonb value.
1079+instance
1080+ Semigroup (Expression commons schemas from grouping param (nullity 'PGjsonb)) where
1081+ (<>) = unsafeBinaryOp "||"
1082+
1083+-- | Delete a key or keys from a JSON object, or remove an array element.
1084+--
1085+-- If the right operand is..
1086+--
1087+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1088+-- are matched based on their key value.
1089+--
1090+-- @ text[] @: Delete multiple key/value pairs or string elements
1091+-- from left operand. Key/value pairs are matched based on their key value.
1092+--
1093+-- @ integer @: Delete the array element with specified index (Negative integers
1094+-- count from the end). Throws an error if top level container is not an array.
1095+(.-.)
1096+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1097+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1098+ -> Expression commons schemas params grp from (nullity key)
1099+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1100+infixl 6 .-.
1101+(.-.) = unsafeBinaryOp "-"
1102+
1103+-- | Delete the field or element with specified path (for JSON arrays, negative
1104+-- integers count from the end)
1105+(#-.)
1106+ :: PGTextArray "(#-.)" arrayty
1107+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1108+ -> Expression commons schemas params grp from (nullity arrayty)
1109+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1110+infixl 6 #-.
1111+(#-.) = unsafeBinaryOp "#-"
1112+
1113+{-----------------------------------------
1114+Table 9.45: JSON creation functions
1115+-----------------------------------------}
1116+
1117+-- | Literal binary JSON
1118+jsonbLit
1119+ :: JSON.ToJSON x
1120+ => x -> Expression commons schemas params grp from (nullity 'PGjsonb)
1121+jsonbLit = cast jsonb . UnsafeExpression
1122+ . singleQuotedUtf8 . toStrict . JSON.encode
1123+
1124+-- | Literal JSON
1125+jsonLit
1126+ :: JSON.ToJSON x
1127+ => x -> Expression commons schemas params grp from (nullity 'PGjson)
1128+jsonLit = cast json . UnsafeExpression
1129+ . singleQuotedUtf8 . toStrict . JSON.encode
1130+
1131+-- | Returns the value as json. Arrays and composites are converted
1132+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1133+-- type to json, the cast function will be used to perform the conversion;
1134+-- otherwise, a scalar value is produced. For any scalar type other than a
1135+-- number, a Boolean, or a null value, the text representation will be used, in
1136+-- such a fashion that it is a valid json value.
1137+toJson
1138+ :: Expression commons schemas params grp from (nullity ty)
1139+ -> Expression commons schemas params grp from (nullity 'PGjson)
1140+toJson = unsafeFunction "to_json"
1141+
1142+-- | Returns the value as jsonb. Arrays and composites are converted
1143+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1144+-- type to json, the cast function will be used to perform the conversion;
1145+-- otherwise, a scalar value is produced. For any scalar type other than a
1146+-- number, a Boolean, or a null value, the text representation will be used, in
1147+-- such a fashion that it is a valid jsonb value.
1148+toJsonb
1149+ :: Expression commons schemas params grp from (nullity ty)
1150+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1151+toJsonb = unsafeFunction "to_jsonb"
1152+
1153+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1154+-- becomes a JSON array of arrays.
1155+arrayToJson
1156+ :: PGArray "arrayToJson" arr
1157+ => Expression commons schemas params grp from (nullity arr)
1158+ -> Expression commons schemas params grp from (nullity 'PGjson)
1159+arrayToJson = unsafeFunction "array_to_json"
1160+
1161+-- | Returns the row as a JSON object.
1162+rowToJson
1163+ :: Expression commons schemas params grp from (nullity ('PGcomposite ty))
1164+ -> Expression commons schemas params grp from (nullity 'PGjson)
1165+rowToJson = unsafeFunction "row_to_json"
1166+
1167+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1168+-- argument list.
1169+jsonBuildArray
1170+ :: SListI elems
1171+ => NP (Expression commons schemas params grp from) elems
1172+ -> Expression commons schemas params grp from (nullity 'PGjson)
1173+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1174+
1175+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1176+-- variadic argument list.
1177+jsonbBuildArray
1178+ :: SListI elems
1179+ => NP (Expression commons schemas params grp from) elems
1180+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1181+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1182+
1183+unsafeRowFunction
1184+ :: All Top elems
1185+ => NP (Aliased (Expression commons schemas params grp from)) elems
1186+ -> [ByteString]
1187+unsafeRowFunction =
1188+ (`appEndo` []) . hcfoldMap (Proxy :: Proxy Top)
1189+ (\(col `As` name) -> Endo $ \xs ->
1190+ renderAliasString name : renderSQL col : xs)
1191+ where
1192+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1193+ renderAliasString = singleQuotedText . fromString . symbolVal
1194+
1195+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1196+-- argument list. The elements of the argument list must alternate between text
1197+-- and values.
1198+jsonBuildObject
1199+ :: All Top elems
1200+ => NP (Aliased (Expression commons schemas params grp from)) elems
1201+ -> Expression commons schemas params grp from (nullity 'PGjson)
1202+jsonBuildObject
1203+ = unsafeFunction "json_build_object"
1204+ . UnsafeExpression
1205+ . commaSeparated
1206+ . unsafeRowFunction
1207+
1208+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1209+-- variadic argument list. The elements of the argument list must alternate
1210+-- between text and values.
1211+jsonbBuildObject
1212+ :: All Top elems
1213+ => NP (Aliased (Expression commons schemas params grp from)) elems
1214+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1215+jsonbBuildObject
1216+ = unsafeFunction "jsonb_build_object"
1217+ . UnsafeExpression
1218+ . commaSeparated
1219+ . unsafeRowFunction
1220+
1221+-- | Builds a JSON object out of a text array. The array must have either
1222+-- exactly one dimension with an even number of members, in which case they are
1223+-- taken as alternating key/value pairs, or two dimensions such that each inner
1224+-- array has exactly two elements, which are taken as a key/value pair.
1225+jsonObject
1226+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1227+ => Expression commons schemas params grp from (nullity arr)
1228+ -> Expression commons schemas params grp from (nullity 'PGjson)
1229+jsonObject = unsafeFunction "json_object"
1230+
1231+-- | Builds a binary JSON object out of a text array. The array must have either
1232+-- exactly one dimension with an even number of members, in which case they are
1233+-- taken as alternating key/value pairs, or two dimensions such that each inner
1234+-- array has exactly two elements, which are taken as a key/value pair.
1235+jsonbObject
1236+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1237+ => Expression commons schemas params grp from (nullity arr)
1238+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1239+jsonbObject = unsafeFunction "jsonb_object"
1240+
1241+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1242+-- keys and one for values, that are zipped pairwise to create a JSON object.
1243+jsonZipObject
1244+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1245+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1246+ => Expression commons schemas params grp from (nullity keysArray)
1247+ -> Expression commons schemas params grp from (nullity valuesArray)
1248+ -> Expression commons schemas params grp from (nullity 'PGjson)
1249+jsonZipObject ks vs =
1250+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1251+
1252+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1253+-- keys and one for values, that are zipped pairwise to create a binary JSON
1254+-- object.
1255+jsonbZipObject
1256+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1257+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1258+ => Expression commons schemas params grp from (nullity keysArray)
1259+ -> Expression commons schemas params grp from (nullity valuesArray)
1260+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1261+jsonbZipObject ks vs =
1262+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1263+
1264+{-----------------------------------------
1265+Table 9.46: JSON processing functions
1266+-----------------------------------------}
1267+
1268+-- | Returns the number of elements in the outermost JSON array.
1269+jsonArrayLength
1270+ :: Expression commons schemas params grp from (nullity 'PGjson)
1271+ -> Expression commons schemas params grp from (nullity 'PGint4)
1272+jsonArrayLength = unsafeFunction "json_array_length"
1273+
1274+-- | Returns the number of elements in the outermost binary JSON array.
1275+jsonbArrayLength
1276+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1277+ -> Expression commons schemas params grp from (nullity 'PGint4)
1278+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1279+
1280+-- | Returns JSON value pointed to by the given path (equivalent to #>
1281+-- operator).
1282+jsonExtractPath
1283+ :: SListI elems
1284+ => Expression commons schemas params grp from (nullity 'PGjson)
1285+ -> NP (Expression commons schemas params grp from) elems
1286+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1287+jsonExtractPath x xs =
1288+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1289+
1290+-- | Returns JSON value pointed to by the given path (equivalent to #>
1291+-- operator).
1292+jsonbExtractPath
1293+ :: SListI elems
1294+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1295+ -> NP (Expression commons schemas params grp from) elems
1296+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1297+jsonbExtractPath x xs =
1298+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1299+
1300+-- | Returns JSON value pointed to by the given path (equivalent to #>
1301+-- operator), as text.
1302+jsonExtractPathAsText
1303+ :: SListI elems
1304+ => Expression commons schemas params grp from (nullity 'PGjson)
1305+ -> NP (Expression commons schemas params grp from) elems
1306+ -> Expression commons schemas params grp from (nullity 'PGjson)
1307+jsonExtractPathAsText x xs =
1308+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1309+
1310+-- | Returns JSON value pointed to by the given path (equivalent to #>
1311+-- operator), as text.
1312+jsonbExtractPathAsText
1313+ :: SListI elems
1314+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1315+ -> NP (Expression commons schemas params grp from) elems
1316+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1317+jsonbExtractPathAsText x xs =
1318+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1319+
1320+-- | Returns the type of the outermost JSON value as a text string. Possible
1321+-- types are object, array, string, number, boolean, and null.
1322+jsonTypeof
1323+ :: Expression commons schemas params grp from (nullity 'PGjson)
1324+ -> Expression commons schemas params grp from (nullity 'PGtext)
1325+jsonTypeof = unsafeFunction "json_typeof"
1326+
1327+-- | Returns the type of the outermost binary JSON value as a text string.
1328+-- Possible types are object, array, string, number, boolean, and null.
1329+jsonbTypeof
1330+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1331+ -> Expression commons schemas params grp from (nullity 'PGtext)
1332+jsonbTypeof = unsafeFunction "jsonb_typeof"
1333+
1334+-- | Returns its argument with all object fields that have null values omitted.
1335+-- Other null values are untouched.
1336+jsonStripNulls
1337+ :: Expression commons schemas params grp from (nullity 'PGjson)
1338+ -> Expression commons schemas params grp from (nullity 'PGjson)
1339+jsonStripNulls = unsafeFunction "json_strip_nulls"
1340+
1341+-- | Returns its argument with all object fields that have null values omitted.
1342+-- Other null values are untouched.
1343+jsonbStripNulls
1344+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1345+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1346+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1347+
1348+-- | @ jsonbSet target path new_value create_missing @
1349+--
1350+-- Returns target with the section designated by path replaced by new_value,
1351+-- or with new_value added if create_missing is true ( default is true) and the
1352+-- item designated by path does not exist. As with the path orientated
1353+-- operators, negative integers that appear in path count from the end of JSON
1354+-- arrays.
1355+jsonbSet
1356+ :: PGTextArray "jsonbSet" arr
1357+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1358+ -> Expression commons schemas params grp from (nullity arr)
1359+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1360+ -> Maybe (Expression commons schemas params grp from (nullity 'PGbool))
1361+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1362+jsonbSet tgt path val createMissing = case createMissing of
1363+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1364+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1365+
1366+-- | @ jsonbInsert target path new_value insert_after @
1367+--
1368+-- Returns target with new_value inserted. If target section designated by
1369+-- path is in a JSONB array, new_value will be inserted before target or after
1370+-- if insert_after is true (default is false). If target section designated by
1371+-- path is in JSONB object, new_value will be inserted only if target does not
1372+-- exist. As with the path orientated operators, negative integers that appear
1373+-- in path count from the end of JSON arrays.
1374+jsonbInsert
1375+ :: PGTextArray "jsonbInsert" arr
1376+ => Expression commons schemas params grp from (nullity 'PGjsonb)
1377+ -> Expression commons schemas params grp from (nullity arr)
1378+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1379+ -> Maybe (Expression commons schemas params grp from (nullity 'PGbool))
1380+ -> Expression commons schemas params grp from (nullity 'PGjsonb)
1381+jsonbInsert tgt path val insertAfter = case insertAfter of
1382+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1383+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1384+
1385+-- | Returns its argument as indented JSON text.
1386+jsonbPretty
1387+ :: Expression commons schemas params grp from (nullity 'PGjsonb)
1388+ -> Expression commons schemas params grp from (nullity 'PGtext)
1389+jsonbPretty = unsafeFunction "jsonb_pretty"
1390+
1391+{-----------------------------------------
1392+aggregation
1393+-----------------------------------------}
1394+
1395+-- | escape hatch to define aggregate functions
1396+unsafeAggregate
1397+ :: ByteString -- ^ aggregate function
1398+ -> Expression commons schemas from 'Ungrouped params (xty)
1399+ -> Expression commons schemas from ('Grouped bys) params (yty)
1400+unsafeAggregate fun x = UnsafeExpression $ mconcat
1401+ [fun, "(", renderSQL x, ")"]
1402+
1403+-- | escape hatch to define aggregate functions over distinct values
1404+unsafeAggregateDistinct
1405+ :: ByteString -- ^ aggregate function
1406+ -> Expression commons schemas from 'Ungrouped params (xty)
1407+ -> Expression commons schemas from ('Grouped bys) params (yty)
1408+unsafeAggregateDistinct fun x = UnsafeExpression $ mconcat
1409+ [fun, "(DISTINCT ", renderSQL x, ")"]
1410+
1411+-- | >>> :{
1412+-- let
1413+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)
1414+-- expression = sum_ #col
1415+-- in printSQL expression
1416+-- :}
1417+-- sum("col")
1418+sum_
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+sum_ = unsafeAggregate "sum"
1424+
1425+-- | >>> :{
1426+-- let
1427+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: nullity 'PGnumeric]] (nullity 'PGnumeric)
1428+-- expression = sumDistinct #col
1429+-- in printSQL expression
1430+-- :}
1431+-- sum(DISTINCT "col")
1432+sumDistinct
1433+ :: ty `In` PGNum
1434+ => Expression commons schemas from 'Ungrouped params (nullity ty)
1435+ -- ^ what to sum
1436+ -> Expression commons schemas from ('Grouped bys) params (nullity ty)
1437+sumDistinct = unsafeAggregateDistinct "sum"
1438+
1439+-- | A constraint for `PGType`s that you can take averages of and the resulting
1440+-- `PGType`.
1441+class PGAvg ty avg | ty -> avg where
1442+ avg, avgDistinct
1443+ :: Expression commons schemas from 'Ungrouped params (nullity ty)
1444+ -- ^ what to average
1445+ -> Expression commons schemas from ('Grouped bys) params (nullity avg)
1446+ avg = unsafeAggregate "avg"
1447+ avgDistinct = unsafeAggregateDistinct "avg"
1448+instance PGAvg 'PGint2 'PGnumeric
1449+instance PGAvg 'PGint4 'PGnumeric
1450+instance PGAvg 'PGint8 'PGnumeric
1451+instance PGAvg 'PGnumeric 'PGnumeric
1452+instance PGAvg 'PGfloat4 'PGfloat8
1453+instance PGAvg 'PGfloat8 'PGfloat8
1454+instance PGAvg 'PGinterval 'PGinterval
1455+
1456+-- | >>> :{
1457+-- let
1458+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1459+-- expression = bitAnd #col
1460+-- in printSQL expression
1461+-- :}
1462+-- bit_and("col")
1463+bitAnd
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+bitAnd = unsafeAggregate "bit_and"
1469+
1470+-- | >>> :{
1471+-- let
1472+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1473+-- expression = bitOr #col
1474+-- in printSQL expression
1475+-- :}
1476+-- bit_or("col")
1477+bitOr
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+bitOr = unsafeAggregate "bit_or"
1483+
1484+-- | >>> :{
1485+-- let
1486+-- expression :: Expression commons schemas params ('Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1487+-- expression = bitAndDistinct #col
1488+-- in printSQL expression
1489+-- :}
1490+-- bit_and(DISTINCT "col")
1491+bitAndDistinct
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+bitAndDistinct = unsafeAggregateDistinct "bit_and"
1497+
1498+-- | >>> :{
1499+-- let
1500+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1501+-- expression = bitOrDistinct #col
1502+-- in printSQL expression
1503+-- :}
1504+-- bit_or(DISTINCT "col")
1505+bitOrDistinct
1506+ :: int `In` PGIntegral
1507+ => Expression commons schemas from 'Ungrouped params (nullity int)
1508+ -- ^ what to aggregate
1509+ -> Expression commons schemas from ('Grouped bys) params (nullity int)
1510+bitOrDistinct = unsafeAggregateDistinct "bit_or"
1511+
1512+-- | >>> :{
1513+-- let
1514+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1515+-- expression = boolAnd #col
1516+-- in printSQL expression
1517+-- :}
1518+-- bool_and("col")
1519+boolAnd
1520+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1521+ -- ^ what to aggregate
1522+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1523+boolAnd = unsafeAggregate "bool_and"
1524+
1525+-- | >>> :{
1526+-- let
1527+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1528+-- expression = boolOr #col
1529+-- in printSQL expression
1530+-- :}
1531+-- bool_or("col")
1532+boolOr
1533+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1534+ -- ^ what to aggregate
1535+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1536+boolOr = unsafeAggregate "bool_or"
1537+
1538+-- | >>> :{
1539+-- let
1540+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1541+-- expression = boolAndDistinct #col
1542+-- in printSQL expression
1543+-- :}
1544+-- bool_and(DISTINCT "col")
1545+boolAndDistinct
1546+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1547+ -- ^ what to aggregate
1548+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1549+boolAndDistinct = unsafeAggregateDistinct "bool_and"
1550+
1551+-- | >>> :{
1552+-- let
1553+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1554+-- expression = boolOrDistinct #col
1555+-- in printSQL expression
1556+-- :}
1557+-- bool_or(DISTINCT "col")
1558+boolOrDistinct
1559+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1560+ -- ^ what to aggregate
1561+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1562+boolOrDistinct = unsafeAggregateDistinct "bool_or"
1563+
1564+-- | A special aggregation that does not require an input
1565+--
1566+-- >>> printSQL countStar
1567+-- count(*)
1568+countStar
1569+ :: Expression commons schemas from ('Grouped bys) params ('NotNull 'PGint8)
1570+countStar = UnsafeExpression $ "count(*)"
1571+
1572+-- | >>> :{
1573+-- let
1574+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1575+-- expression = count #col
1576+-- in printSQL expression
1577+-- :}
1578+-- count("col")
1579+count
1580+ :: Expression commons schemas from 'Ungrouped params ty
1581+ -- ^ what to count
1582+ -> Expression commons schemas from ('Grouped bys) params ('NotNull 'PGint8)
1583+count = unsafeAggregate "count"
1584+
1585+-- | >>> :{
1586+-- let
1587+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1588+-- expression = countDistinct #col
1589+-- in printSQL expression
1590+-- :}
1591+-- count(DISTINCT "col")
1592+countDistinct
1593+ :: Expression commons schemas from 'Ungrouped params ty
1594+ -- ^ what to count
1595+ -> Expression commons schemas from ('Grouped bys) params ('NotNull 'PGint8)
1596+countDistinct = unsafeAggregateDistinct "count"
1597+
1598+-- | synonym for `boolAnd`
1599+--
1600+-- >>> :{
1601+-- let
1602+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1603+-- expression = every #col
1604+-- in printSQL expression
1605+-- :}
1606+-- every("col")
1607+every
1608+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1609+ -- ^ what to aggregate
1610+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1611+every = unsafeAggregate "every"
1612+
1613+-- | synonym for `boolAndDistinct`
1614+--
1615+-- >>> :{
1616+-- let
1617+-- expression :: Expression commons schemas params (Grouped bys) '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1618+-- expression = everyDistinct #col
1619+-- in printSQL expression
1620+-- :}
1621+-- every(DISTINCT "col")
1622+everyDistinct
1623+ :: Expression commons schemas from 'Ungrouped params (nullity 'PGbool)
1624+ -- ^ what to aggregate
1625+ -> Expression commons schemas from ('Grouped bys) params (nullity 'PGbool)
1626+everyDistinct = unsafeAggregateDistinct "every"
1627+
1628+-- | minimum and maximum aggregation
1629+max_, min_, maxDistinct, minDistinct
1630+ :: Expression commons schemas from 'Ungrouped params (nullity ty)
1631+ -- ^ what to aggregate
1632+ -> Expression commons schemas from ('Grouped bys) params (nullity ty)
1633+max_ = unsafeAggregate "max"
1634+min_ = unsafeAggregate "min"
1635+maxDistinct = unsafeAggregateDistinct "max"
1636+minDistinct = unsafeAggregateDistinct "min"
1637+
1638+{-----------------------------------------
1639+type expressions
1640+-----------------------------------------}
1641+
1642+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1643+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1644+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1645+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1646+instance RenderSQL (TypeExpression schemas ty) where
1647+ renderSQL = renderTypeExpression
1648+
1649+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1650+typedef
1651+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1652+ => QualifiedAlias sch td
1653+ -> TypeExpression schemas (nullity ty)
1654+typedef = UnsafeTypeExpression . renderSQL
1655+
1656+-- | The composite type corresponding to a `Table` definition can be expressed
1657+-- by its alias.
1658+typetable
1659+ :: (Has sch schemas schema, Has tab schema ('Table table))
1660+ => QualifiedAlias sch tab
1661+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1662+typetable = UnsafeTypeExpression . renderSQL
1663+
1664+-- | The composite type corresponding to a `View` definition can be expressed
1665+-- by its alias.
1666+typeview
1667+ :: (Has sch schemas schema, Has vw schema ('View view))
1668+ => QualifiedAlias sch vw
1669+ -> TypeExpression schemas (nullity ('PGcomposite view))
1670+typeview = UnsafeTypeExpression . renderSQL
1671+
1672+-- | logical Boolean (true/false)
1673+bool :: TypeExpression schemas (nullity 'PGbool)
1674+bool = UnsafeTypeExpression "bool"
1675+-- | signed two-byte integer
1676+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1677+int2 = UnsafeTypeExpression "int2"
1678+smallint = UnsafeTypeExpression "smallint"
1679+-- | signed four-byte integer
1680+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1681+int4 = UnsafeTypeExpression "int4"
1682+int = UnsafeTypeExpression "int"
1683+integer = UnsafeTypeExpression "integer"
1684+-- | signed eight-byte integer
1685+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1686+int8 = UnsafeTypeExpression "int8"
1687+bigint = UnsafeTypeExpression "bigint"
1688+-- | arbitrary precision numeric type
1689+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1690+numeric = UnsafeTypeExpression "numeric"
1691+-- | single precision floating-point number (4 bytes)
1692+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1693+float4 = UnsafeTypeExpression "float4"
1694+real = UnsafeTypeExpression "real"
1695+-- | double precision floating-point number (8 bytes)
1696+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1697+float8 = UnsafeTypeExpression "float8"
1698+doublePrecision = UnsafeTypeExpression "double precision"
1699+-- | variable-length character string
1700+text :: TypeExpression schemas (nullity 'PGtext)
1701+text = UnsafeTypeExpression "text"
1702+-- | fixed-length character string
1703+char, character
1704+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1705+ => TypeExpression schemas (nullity ('PGchar n))
1706+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1707+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1708+-- | variable-length character string
1709+varchar, characterVarying
1710+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1711+ => TypeExpression schemas (nullity ('PGvarchar n))
1712+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1713+characterVarying = UnsafeTypeExpression $
1714+ "character varying(" <> renderNat @n <> ")"
1715+-- | binary data ("byte array")
1716+bytea :: TypeExpression schemas (nullity 'PGbytea)
1717+bytea = UnsafeTypeExpression "bytea"
1718+-- | date and time (no time zone)
1719+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1720+timestamp = UnsafeTypeExpression "timestamp"
1721+-- | date and time, including time zone
1722+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1723+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1724+-- | calendar date (year, month, day)
1725+date :: TypeExpression schemas (nullity 'PGdate)
1726+date = UnsafeTypeExpression "date"
1727+-- | time of day (no time zone)
1728+time :: TypeExpression schemas (nullity 'PGtime)
1729+time = UnsafeTypeExpression "time"
1730+-- | time of day, including time zone
1731+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1732+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1733+-- | time span
1734+interval :: TypeExpression schemas (nullity 'PGinterval)
1735+interval = UnsafeTypeExpression "interval"
1736+-- | universally unique identifier
1737+uuid :: TypeExpression schemas (nullity 'PGuuid)
1738+uuid = UnsafeTypeExpression "uuid"
1739+-- | IPv4 or IPv6 host address
1740+inet :: TypeExpression schemas (nullity 'PGinet)
1741+inet = UnsafeTypeExpression "inet"
1742+-- | textual JSON data
1743+json :: TypeExpression schemas (nullity 'PGjson)
1744+json = UnsafeTypeExpression "json"
1745+-- | binary JSON data, decomposed
1746+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1747+jsonb = UnsafeTypeExpression "jsonb"
1748+-- | variable length array
1749+vararray
1750+ :: TypeExpression schemas pg
1751+ -> TypeExpression schemas (nullity ('PGvararray pg))
1752+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1753+-- | fixed length array
1754+--
1755+-- >>> renderSQL (fixarray @2 json)
1756+-- "json[2]"
1757+fixarray
1758+ :: forall n schemas nullity pg. KnownNat n
1759+ => TypeExpression schemas pg
1760+ -> TypeExpression schemas (nullity ('PGfixarray n pg))
1761+fixarray ty = UnsafeTypeExpression $
1762+ renderSQL ty <> "[" <> renderNat @n <> "]"
1763+
1764+-- | `pgtype` is a demoted version of a `PGType`
1765+class PGTyped schemas (ty :: NullityType) where
1766+ pgtype :: TypeExpression schemas ty
1767+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
1768+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
1769+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
1770+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
1771+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
1772+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
1773+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
1774+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
1775+instance (KnownNat n, 1 <= n)
1776+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
1777+instance (KnownNat n, 1 <= n)
1778+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
1779+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
1780+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
1781+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
1782+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
1783+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
1784+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
1785+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
1786+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
1787+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
1788+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
1789+instance PGTyped schemas ty
1790+ => PGTyped schemas (nullity ('PGvararray ty)) where
1791+ pgtype = vararray (pgtype @schemas @ty)
1792+instance (KnownNat n, PGTyped schemas ty)
1793+ => PGTyped schemas (nullity ('PGfixarray n ty)) where
1794+ pgtype = fixarray @n (pgtype @schemas @ty)
1795+
1796+{-----------------------------------------
1797+Sorting
1798+-----------------------------------------}
1799+
1800+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1801+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1802+-- column to ascending or descending. Ascending order puts smaller values
1803+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1804+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1805+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1806+-- determine whether nulls appear before or after non-null values in the sort
1807+-- ordering of a `Null` result column.
1808+data SortExpression commons schemas params grp from where
1809+ Asc
1810+ :: Expression commons schemas params grp from ('NotNull ty)
1811+ -> SortExpression commons schemas params grp from
1812+ Desc
1813+ :: Expression commons schemas params grp from ('NotNull ty)
1814+ -> SortExpression commons schemas params grp from
1815+ AscNullsFirst
1816+ :: Expression commons schemas params grp from ('Null ty)
1817+ -> SortExpression commons schemas params grp from
1818+ AscNullsLast
1819+ :: Expression commons schemas params grp from ('Null ty)
1820+ -> SortExpression commons schemas params grp from
1821+ DescNullsFirst
1822+ :: Expression commons schemas params grp from ('Null ty)
1823+ -> SortExpression commons schemas params grp from
1824+ DescNullsLast
1825+ :: Expression commons schemas params grp from ('Null ty)
1826+ -> SortExpression commons schemas params grp from
1827+deriving instance Show (SortExpression commons schemas params grp from)
1828+
1829+class OrderBy expr where
1830+ orderBy
1831+ :: [SortExpression commons schemas params grp from]
1832+ -> expr commons schemas params grp from
1833+ -> expr commons schemas params grp from
1834+
1835+-- | Render a `SortExpression`.
1836+instance RenderSQL (SortExpression commons schemas params grp from) where
1837+ renderSQL = \case
1838+ Asc expression -> renderSQL expression <+> "ASC"
1839+ Desc expression -> renderSQL expression <+> "DESC"
1840+ AscNullsFirst expression -> renderSQL expression
1841+ <+> "ASC NULLS FIRST"
1842+ DescNullsFirst expression -> renderSQL expression
1843+ <+> "DESC NULLS FIRST"
1844+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
1845+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
1846+
1847+data WindowDefinition commons schemas params grp from where
1848+ WindowDefinition
1849+ :: SListI bys
1850+ => NP (Expression commons schemas params grp from) bys
1851+ -> [SortExpression commons schemas params grp from]
1852+ -> WindowDefinition commons schemas params grp from
1853+
1854+instance OrderBy WindowDefinition where
1855+ orderBy sortsR (WindowDefinition parts sortsL)
1856+ = WindowDefinition parts (sortsL ++ sortsR)
1857+
1858+instance RenderSQL (WindowDefinition commons schemas from grp params) where
1859+ renderSQL (WindowDefinition part ord) =
1860+ renderPartitionByClause part <> renderOrderByClause ord
1861+ where
1862+ renderPartitionByClause = \case
1863+ Nil -> ""
1864+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
1865+ renderOrderByClause = \case
1866+ [] -> ""
1867+ srts -> " ORDER" <+> "BY"
1868+ <+> commaSeparated (renderSQL <$> srts)
1869+
1870+partitionBy
1871+ :: SListI bys
1872+ => NP (Expression commons schemas params grp from) bys
1873+ -> WindowDefinition commons schemas params grp from
1874+partitionBy bys = WindowDefinition bys []
1875+
1876+newtype WindowFunction
1877+ (commons :: FromType)
1878+ (schemas :: SchemasType)
1879+ (params :: [NullityType])
1880+ (grp :: Grouping)
1881+ (from :: FromType)
1882+ (ty :: NullityType)
1883+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
1884+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1885+
1886+instance RenderSQL (WindowFunction commons schemas params grp from ty) where
1887+ renderSQL = renderWindowFunction
1888+
1889+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
1890+>>> printSQL rank
1891+rank()
1892+-}
1893+rank :: WindowFunction commons schemas from grp params ('NotNull 'PGint8)
1894+rank = UnsafeWindowFunction "rank()"
1895+
1896+{- | number of the current row within its partition, counting from 1
1897+>>> printSQL rowNumber
1898+row_number()
1899+-}
1900+rowNumber :: WindowFunction commons schemas from grp params ('NotNull 'PGint8)
1901+rowNumber = UnsafeWindowFunction "row_number()"
1902+
1903+{- | rank of the current row without gaps; this function counts peer groups
1904+>>> printSQL denseRank
1905+dense_rank()
1906+-}
1907+denseRank :: WindowFunction commons schemas from grp params ('NotNull 'PGint8)
1908+denseRank = UnsafeWindowFunction "dense_rank()"
1909+
1910+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
1911+>>> printSQL percentRank
1912+percent_rank()
1913+-}
1914+percentRank :: WindowFunction commons schemas from grp params ('NotNull 'PGfloat8)
1915+percentRank = UnsafeWindowFunction "percent_rank()"
1916+
1917+{- | cumulative distribution: (number of partition rows
1918+preceding or peer with current row) / total partition rows
1919+>>> printSQL cumeDist
1920+cume_dist()
1921+-}
1922+cumeDist :: WindowFunction commons schemas from grp params ('NotNull 'PGfloat8)
1923+cumeDist = UnsafeWindowFunction "cume_dist()"