@@ -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,563 @@ 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+ , Aggregate (..)
138+ , Distinction (..)
139+ , PGAvg
140+ -- * Window Functions
141+ , WindowDefinition (..)
142+ , partitionBy
143+ , WindowFunction (..)
144+ , rank
145+ , rowNumber
146+ , denseRank
147+ , percentRank
148+ , cumeDist
149+ , ntile
150+ , lag
151+ , lead
152+ , firstValue
153+ , lastValue
154+ , nthValue
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 , (&)
197+ , NP (..)
198+ , (:*:) (..)
199+ , I (..)
59200 , K (..)
60− , unK
61201 ) where
62202
63203import Control.Category
64204import Control.DeepSeq
65205import Data.ByteString (ByteString)
206+import Data.ByteString.Lazy (toStrict)
66207import Data.Function ((&))
67208import Data.Semigroup hiding (All)
209+import qualified Data.Aeson as JSON
210+import Data.Ratio
68211import Data.String
69−import Generics.SOP hiding (All, from)
212+import Data.Word
213+import Generics.SOP hiding (from)
214+import GHC.Generics ((:*:) (..))
70215import GHC.OverloadedLabels
71216import GHC.TypeLits
72−import Numeric
73217import Prelude hiding (id, (.))
74218
219+import qualified Data.ByteString as ByteString
75220import qualified GHC.Generics as GHC
76221
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79222import Squeal.PostgreSQL.Render
80223import Squeal.PostgreSQL.Schema
81224
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85225{-----------------------------------------
86226column expressions
87227-----------------------------------------}
88228
89229{- | `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,
230+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92231as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93232`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
233+or in search `Condition`s in a number of commands.
95234
96235The expression syntax allows the calculation of
97236values from primitive expression using arithmetic, logical,
98237and 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`.
113238-}
114239newtype Expression
115− (outer :: FromType)
116− (commons :: FromType)
117240 (grp :: Grouping)
241+ (commons :: FromType)
118242 (schemas :: SchemasType)
119243 (params :: [NullityType])
120244 (from :: FromType)
121245 (ty :: NullityType)
122246 = UnsafeExpression { renderExpression :: ByteString }
123247 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
248+
249+instance RenderSQL (Expression grp commons schemas params from ty) where
125250 renderSQL = renderExpression
126251
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.
252+{- | A `HasParameter` constraint is used to indicate a value that is
253+supplied externally to a SQL statement.
254+`Squeal.PostgreSQL.PQ.manipulateParams`,
255+`Squeal.PostgreSQL.PQ.queryParams` and
256+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
257+separately from the SQL command string, in which case `param`s are used to
258+refer to the out-of-line data values.
198259-}
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)
260+class KnownNat n => HasParameter
261+ (n :: Nat)
262+ (params :: [NullityType])
263+ (ty :: NullityType)
264+ | n params -> ty where
265+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
266+ --
267+ -- >>> let expr = parameter @1 int4 :: Expression grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
268+ -- >>> printSQL expr
269+ -- ($1 :: int4)
270+ parameter
271+ :: TypeExpression schemas ty
272+ -> Expression grp commons schemas params from ty
273+ parameter ty = UnsafeExpression $ parenthesized $
274+ "$" <> renderNat @n <+> "::"
275+ <+> renderSQL ty
276+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
277+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
278+ => HasParameter n (ty' : params) ty
279+
280+-- | `param` takes a `Nat` using type application and for basic types,
281+-- infers a `TypeExpression`.
282+--
283+-- >>> let expr = param @1 :: Expression grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
284+-- >>> printSQL expr
285+-- ($1 :: int4)
286+param
287+ :: forall n commons schemas params from grp ty
288+ . (PGTyped schemas ty, HasParameter n params ty)
289+ => Expression grp commons schemas params from ty -- ^ param
290+param = parameter @n (pgtype @schemas)
214291
215−instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
292+instance (HasUnique tab from row, Has col row ty)
293+ => IsLabel col (Expression 'Ungrouped commons schemas params from ty) where
217294 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))
295+instance (HasUnique tab from row, Has col row ty, column ~ (col ::: ty))
222296 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
297+ (Aliased (Expression 'Ungrouped commons schemas params from) column) where
224298 fromLabel = fromLabel @col `As` Alias
225−instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
299+instance (HasUnique tab from row, Has col row ty, columns ~ '[col ::: ty])
226300 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
301+ (NP (Aliased (Expression 'Ungrouped commons schemas params from)) columns) where
228302 fromLabel = fromLabel @col :* Nil
229303
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
304+instance (Has tab from row, Has col row ty)
305+ => IsQualified tab col (Expression 'Ungrouped commons schemas params from ty) where
232306 tab ! col = UnsafeExpression $
233307 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))
308+instance (Has tab from row, Has col row ty, column ~ (col ::: ty))
238309 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
310+ (Aliased (Expression 'Ungrouped commons schemas params from) column) where
240311 tab ! col = tab ! col `As` col
241−instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
312+instance (Has tab from row, Has col row ty, columns ~ '[col ::: ty])
242313 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
314+ (NP (Aliased (Expression 'Ungrouped commons schemas params from)) columns) where
244315 tab ! col = tab ! col :* Nil
245316
246317instance
247− ( HasUnique tab (Join outer from) row
318+ ( HasUnique tab from row
248319 , Has col row ty
249320 , GroupedBy tab col bys
250321 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
322+ (Expression ('Grouped bys) commons schemas params from ty) where
252323 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253324instance
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
325+ ( HasUnique tab from row
263326 , Has col row ty
264327 , GroupedBy tab col bys
265328 , column ~ (col ::: ty)
266329 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
330+ (Aliased (Expression ('Grouped bys) commons schemas params from) column) where
268331 fromLabel = fromLabel @col `As` Alias
269332instance
270− ( HasUnique tab (Join outer from) row
333+ ( HasUnique tab from row
271334 , Has col row ty
272335 , GroupedBy tab col bys
273336 , columns ~ '[col ::: ty]
274337 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
338+ (NP (Aliased (Expression ('Grouped bys) commons schemas params from)) columns) where
276339 fromLabel = fromLabel @col :* Nil
277340
278341instance
279− ( Has tab (Join outer from) row
342+ ( Has tab from row
280343 , Has col row ty
281344 , GroupedBy tab col bys
282345 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
346+ (Expression ('Grouped bys) commons schemas params from ty) where
284347 tab ! col = UnsafeExpression $
285348 renderSQL tab <> "." <> renderSQL col
286349instance
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
350+ ( Has tab from row
296351 , Has col row ty
297352 , GroupedBy tab col bys
298353 , column ~ (col ::: ty)
299354 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
355+ (Aliased (Expression ('Grouped bys) commons schemas params from) column) where
301356 tab ! col = tab ! col `As` col
302357instance
303− ( Has tab (Join outer from) row
358+ ( Has tab from row
304359 , Has col row ty
305360 , GroupedBy tab col bys
306361 , columns ~ '[col ::: ty]
307362 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
363+ (NP (Aliased (Expression ('Grouped bys) commons schemas params from)) columns) where
309364 tab ! col = tab ! col :* Nil
310365
366+-- | analagous to `Nothing`
367+--
368+-- >>> printSQL null_
369+-- NULL
370+null_ :: Expression commons schemas rels grouping params ('Null ty)
371+null_ = UnsafeExpression "NULL"
372+
373+-- | analagous to `Just`
374+--
375+-- >>> printSQL $ notNull true
376+-- TRUE
377+notNull
378+ :: Expression commons schemas rels grouping params ('NotNull ty)
379+ -> Expression commons schemas rels grouping params ('Null ty)
380+notNull = UnsafeExpression . renderSQL
381+
382+-- | return the leftmost value which is not NULL
383+--
384+-- >>> printSQL $ coalesce [null_, true] false
385+-- COALESCE(NULL, TRUE, FALSE)
386+coalesce
387+ :: [Expression grp commons schemas params from ('Null ty)]
388+ -- ^ @NULL@s may be present
389+ -> Expression grp commons schemas params from ('NotNull ty)
390+ -- ^ @NULL@ is absent
391+ -> Expression grp commons schemas params from ('NotNull ty)
392+coalesce nullxs notNullx = UnsafeExpression $
393+ "COALESCE" <> parenthesized (commaSeparated
394+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
395+
396+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
397+--
398+-- >>> printSQL $ fromNull true null_
399+-- COALESCE(NULL, TRUE)
400+fromNull
401+ :: Expression grp commons schemas params from ('NotNull ty)
402+ -- ^ what to convert @NULL@ to
403+ -> Expression grp commons schemas params from ('Null ty)
404+ -> Expression grp commons schemas params from ('NotNull ty)
405+fromNull notNullx nullx = coalesce [nullx] notNullx
406+
407+-- | >>> printSQL $ null_ & isNull
408+-- NULL IS NULL
409+isNull
410+ :: Expression grp commons schemas params from ('Null ty)
411+ -- ^ possibly @NULL@
412+ -> Condition grp commons schemas params from
413+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
414+
415+-- | >>> printSQL $ null_ & isNotNull
416+-- NULL IS NOT NULL
417+isNotNull
418+ :: Expression grp commons schemas params from ('Null ty)
419+ -- ^ possibly @NULL@
420+ -> Condition grp commons schemas params from
421+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
422+
423+-- | analagous to `maybe` using @IS NULL@
424+--
425+-- >>> printSQL $ matchNull true not_ null_
426+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
427+matchNull
428+ :: Expression grp commons schemas params from (nullty)
429+ -- ^ what to convert @NULL@ to
430+ -> ( Expression grp commons schemas params from ('NotNull ty)
431+ -> Expression grp commons schemas params from (nullty) )
432+ -- ^ function to perform when @NULL@ is absent
433+ -> Expression grp commons schemas params from ('Null ty)
434+ -> Expression grp commons schemas params from (nullty)
435+matchNull y f x = ifThenElse (isNull x) y
436+ (f (UnsafeExpression (renderSQL x)))
437+
438+{-| right inverse to `fromNull`, if its arguments are equal then
439+`nullIf` gives @NULL@.
440+
441+>>> :set -XTypeApplications -XDataKinds
442+>>> let expr = nullIf false (param @1) :: Expression grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
443+>>> printSQL expr
444+NULL IF (FALSE, ($1 :: bool))
445+-}
446+nullIf
447+ :: Expression grp commons schemas params from ('NotNull ty)
448+ -- ^ @NULL@ is absent
449+ -> Expression grp commons schemas params from ('NotNull ty)
450+ -- ^ @NULL@ is absent
451+ -> Expression grp commons schemas params from ('Null ty)
452+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
453+ (renderSQL x <> ", " <> renderSQL y)
454+
455+-- | >>> printSQL $ array [null_, false, true]
456+-- ARRAY[NULL, FALSE, TRUE]
457+array
458+ :: [Expression grp commons schemas params from ty]
459+ -- ^ array elements
460+ -> Expression grp commons schemas params from (nullity ('PGvararray ty))
461+array xs = UnsafeExpression $
462+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
463+
464+-- | >>> printSQL $ array [null_, false, true] & index 2
465+-- (ARRAY[NULL, FALSE, TRUE])[2]
466+index
467+ :: Word64 -- ^ index
468+ -> Expression grp commons schemas params from (nullity ('PGvararray ty)) -- ^ array
469+ -> Expression grp commons schemas params from (NullifyType ty)
470+index n expr = UnsafeExpression $
471+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
472+
311473instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
474+ (Expression grp commons schemas params from (nullity ('PGenum labels))) where
313475 label = UnsafeExpression $ renderSQL (PGlabel @label)
314476
477+-- | A row constructor is an expression that builds a row value
478+-- (also called a composite value) using values for its member fields.
479+--
480+-- >>> :{
481+-- type Complex = 'PGcomposite
482+-- '[ "real" ::: 'NotNull 'PGfloat8
483+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
484+-- :}
485+--
486+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression grp commons schemas params from ('NotNull Complex)
487+-- >>> printSQL i
488+-- ROW(0, 1)
489+row
490+ :: SListI row
491+ => NP (Aliased (Expression grp commons schemas params from)) row
492+ -- ^ zero or more expressions for the row field values
493+ -> Expression grp commons schemas params from (nullity ('PGcomposite row))
494+row exprs = UnsafeExpression $ "ROW" <> parenthesized
495+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
496+
497+-- | >>> :{
498+-- type Complex = 'PGcomposite
499+-- '[ "real" ::: 'NotNull 'PGfloat8
500+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
501+-- type Schema = '["complex" ::: 'Typedef Complex]
502+-- :}
503+--
504+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression grp '[] (Public Schema) from params ('NotNull Complex)
505+-- >>> printSQL $ i & field #complex #imaginary
506+-- (ROW(0, 1)::"complex")."imaginary"
507+field
508+ :: ( Has sch schemas schema
509+ , Has tydef schema ('Typedef ('PGcomposite row))
510+ , Has field row ty)
511+ => QualifiedAlias sch tydef -- ^ row type
512+ -> Alias field -- ^ field name
513+ -> Expression grp commons schemas params from ('NotNull ('PGcomposite row))
514+ -> Expression grp commons schemas params from ty
515+field td fld expr = UnsafeExpression $
516+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
517+ <> "." <> renderSQL fld
518+
519+instance Semigroup
520+ (Expression grp commons schemas params from (nullity ('PGvararray ty))) where
521+ (<>) = unsafeBinaryOp "||"
522+
523+instance Monoid
524+ (Expression grp commons schemas params from (nullity ('PGvararray ty))) where
525+ mempty = array []
526+ mappend = (<>)
527+
528+-- | >>> let expr = greatest currentTimestamp [param @1] :: Expression grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
529+-- >>> printSQL expr
530+-- GREATEST(CURRENT_TIMESTAMP, ($1 :: timestamp with time zone))
531+greatest
532+ :: Expression grp commons schemas params from (nullty)
533+ -- ^ needs at least 1 argument
534+ -> [Expression grp commons schemas params from (nullty)]
535+ -- ^ or more
536+ -> Expression grp commons schemas params from (nullty)
537+greatest x xs = UnsafeExpression $ "GREATEST("
538+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
539+
540+-- | >>> printSQL $ least currentTimestamp [null_]
541+-- LEAST(CURRENT_TIMESTAMP, NULL)
542+least
543+ :: Expression grp commons schemas params from (nullty)
544+ -- ^ needs at least 1 argument
545+ -> [Expression grp commons schemas params from (nullty)]
546+ -- ^ or more
547+ -> Expression grp commons schemas params from (nullty)
548+least x xs = UnsafeExpression $ "LEAST("
549+ <> commaSeparated (renderSQL <$> (x:xs)) <> ")"
550+
315551-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316552-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
553+unsafeBinaryOp
554+ :: ByteString
555+ -- ^ operator
556+ -> Expression grp commons schemas params from (ty0)
557+ -> Expression grp commons schemas params from (ty1)
558+ -> Expression grp commons schemas params from (ty2)
318559unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319560 renderSQL x <+> op <+> renderSQL y
320561
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
562+-- | >>> printSQL $ unsafeUnaryOp "NOT" true
329563-- (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
564+unsafeUnaryOp
565+ :: ByteString
566+ -- ^ operator
567+ -> Expression grp commons schemas params from (ty0)
568+ -> Expression grp commons schemas params from (ty1)
569+unsafeUnaryOp op x = UnsafeExpression $ parenthesized $
570+ op <+> renderSQL x
351571
352572-- | >>> printSQL $ unsafeFunction "f" true
353573-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
574+unsafeFunction
575+ :: ByteString
576+ -- ^ function
577+ -> Expression grp commons schemas params from (xty)
578+ -> Expression grp commons schemas params from (yty)
355579unsafeFunction fun x = UnsafeExpression $
356580 fun <> parenthesized (renderSQL x)
357581
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
582+-- | Helper for defining variadic functions.
583+unsafeVariadicFunction
584+ :: SListI elems
585+ => ByteString
586+ -- ^ function
587+ -> NP (Expression grp commons schemas params from) elems
588+ -> Expression grp commons schemas params from ret
589+unsafeVariadicFunction fun x = UnsafeExpression $
590+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
377591
378592instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
593+ => Num (Expression grp commons schemas params from (nullity ty)) where
380594 (+) = unsafeBinaryOp "+"
381595 (-) = unsafeBinaryOp "-"
382596 (*) = unsafeBinaryOp "*"
@@ -388,17 +602,12 @@ instance ty `In` PGNum
388602 . show
389603
390604instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
605+ (Expression grp commons schemas params from (nullity ty)) where
392606 (/) = unsafeBinaryOp "/"
393− fromRational
394− = UnsafeExpression
395− . fromString
396− . ($ "")
397− . showFFloat Nothing
398− . fromRat @Double
607+ fromRational x = fromInteger (numerator x) / fromInteger (denominator x)
399608
400609instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
610+ (Expression grp commons schemas params from (nullity ty)) where
402611 pi = UnsafeExpression "pi()"
403612 exp = unsafeFunction "exp"
404613 log = unsafeFunction "ln"
@@ -419,54 +628,1542 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419628 acosh x = log (x + sqrt (x*x - 1))
420629 atanh x = log ((1 + x) / (1 - x)) / 2
421630
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)
631+-- | >>> :{
632+-- let
633+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
634+-- expression = atan2_ pi 2
635+-- in printSQL expression
636+-- :}
637+-- atan2(pi(), 2)
638+atan2_
639+ :: float `In` PGFloating
640+ => Expression grp commons schemas params from (nullity float)
641+ -- ^ numerator
642+ -> Expression grp commons schemas params from (nullity float)
643+ -- ^ denominator
644+ -> Expression grp commons schemas params from (nullity float)
645+atan2_ y x = UnsafeExpression $
646+ "atan2(" <> renderSQL y <> ", " <> renderSQL x <> ")"
647+
648+-- When a `cast` is applied to an `Expression` of a known type, it
649+-- represents a run-time type conversion. The cast will succeed only if a
650+-- suitable type conversion operation has been defined.
651+--
652+-- | >>> printSQL $ true & cast int4
653+-- (TRUE :: int4)
654+cast
655+ :: TypeExpression schemas ty1
656+ -- ^ type to cast as
657+ -> Expression grp commons schemas params from ty0
658+ -- ^ value to convert
659+ -> Expression grp commons schemas params from ty1
660+cast ty x = UnsafeExpression $ parenthesized $
661+ renderSQL x <+> "::" <+> renderSQL ty
662+
663+-- | integer division, truncates the result
664+--
665+-- >>> :{
666+-- let
667+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
668+-- expression = 5 `quot_` 2
669+-- in printSQL expression
670+-- :}
671+-- (5 / 2)
672+quot_
673+ :: int `In` PGIntegral
674+ => Expression grp commons schemas params from (nullity int)
675+ -- ^ numerator
676+ -> Expression grp commons schemas params from (nullity int)
677+ -- ^ denominator
678+ -> Expression grp commons schemas params from (nullity int)
679+quot_ = unsafeBinaryOp "/"
680+
681+-- | remainder upon integer division
682+--
683+-- >>> :{
684+-- let
685+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
686+-- expression = 5 `rem_` 2
687+-- in printSQL expression
688+-- :}
689+-- (5 % 2)
690+rem_
691+ :: int `In` PGIntegral
692+ => Expression grp commons schemas params from (nullity int)
693+ -- ^ numerator
694+ -> Expression grp commons schemas params from (nullity int)
695+ -- ^ denominator
696+ -> Expression grp commons schemas params from (nullity int)
697+rem_ = unsafeBinaryOp "%"
698+
699+-- | >>> :{
700+-- let
701+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
702+-- expression = trunc pi
703+-- in printSQL expression
704+-- :}
705+-- trunc(pi())
706+trunc
707+ :: frac `In` PGFloating
708+ => Expression grp commons schemas params from (nullity frac)
709+ -- ^ fractional number
710+ -> Expression grp commons schemas params from (nullity frac)
711+trunc = unsafeFunction "trunc"
712+
713+-- | >>> :{
714+-- let
715+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
716+-- expression = round_ pi
717+-- in printSQL expression
718+-- :}
719+-- round(pi())
720+round_
721+ :: frac `In` PGFloating
722+ => Expression grp commons schemas params from (nullity frac)
723+ -- ^ fractional number
724+ -> Expression grp commons schemas params from (nullity frac)
725+round_ = unsafeFunction "round"
726+
727+-- | >>> :{
728+-- let
729+-- expression :: Expression grp commons schemas params from (nullity 'PGfloat4)
730+-- expression = ceiling_ pi
731+-- in printSQL expression
732+-- :}
733+-- ceiling(pi())
734+ceiling_
735+ :: frac `In` PGFloating
736+ => Expression grp commons schemas params from (nullity frac)
737+ -- ^ fractional number
738+ -> Expression grp commons schemas params from (nullity frac)
739+ceiling_ = unsafeFunction "ceiling"
740+
741+-- | A `Condition` is an `Expression`, which can evaluate
742+-- to `true`, `false` or `null_`. This is because SQL uses
743+-- a three valued logic.
744+type Condition grp commons schemas params from =
745+ Expression grp commons schemas params from ('Null 'PGbool)
746+
747+-- | >>> printSQL true
748+-- TRUE
749+true :: Expression grp commons schemas params from (nullity 'PGbool)
750+true = UnsafeExpression "TRUE"
751+
752+-- | >>> printSQL false
753+-- FALSE
754+false :: Expression grp commons schemas params from (nullity 'PGbool)
755+false = UnsafeExpression "FALSE"
756+
757+-- | >>> printSQL $ not_ true
758+-- (NOT TRUE)
759+not_
760+ :: Expression grp commons schemas params from (nullity 'PGbool)
761+ -> Expression grp commons schemas params from (nullity 'PGbool)
762+not_ = unsafeUnaryOp "NOT"
763+
764+-- | >>> printSQL $ true .&& false
765+-- (TRUE AND FALSE)
766+(.&&)
767+ :: Expression grp commons schemas params from (nullity 'PGbool)
768+ -> Expression grp commons schemas params from (nullity 'PGbool)
769+ -> Expression grp commons schemas params from (nullity 'PGbool)
770+infixr 3 .&&
771+(.&&) = unsafeBinaryOp "AND"
772+
773+-- | >>> printSQL $ true .|| false
774+-- (TRUE OR FALSE)
775+(.||)
776+ :: Expression grp commons schemas params from (nullity 'PGbool)
777+ -> Expression grp commons schemas params from (nullity 'PGbool)
778+ -> Expression grp commons schemas params from (nullity 'PGbool)
779+infixr 2 .||
780+(.||) = unsafeBinaryOp "OR"
781+
782+-- | >>> :{
783+-- let
784+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
785+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
786+-- in printSQL expression
787+-- :}
788+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
789+caseWhenThenElse
790+ :: [ ( Condition grp commons schemas params from
791+ , Expression grp commons schemas params from ty
792+ ) ]
793+ -- ^ whens and thens
794+ -> Expression grp commons schemas params from ty
795+ -- ^ else
796+ -> Expression grp commons schemas params from ty
797+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
798+ [ "CASE"
799+ , mconcat
800+ [ mconcat
801+ [ " WHEN ", renderSQL when_
802+ , " THEN ", renderSQL then_
803+ ]
804+ | (when_,then_) <- whenThens
805+ ]
806+ , " ELSE ", renderSQL else_
807+ , " END"
808+ ]
809+
810+-- | >>> :{
811+-- let
812+-- expression :: Expression grp commons schemas params from (nullity 'PGint2)
813+-- expression = ifThenElse true 1 0
814+-- in printSQL expression
815+-- :}
816+-- CASE WHEN TRUE THEN 1 ELSE 0 END
817+ifThenElse
818+ :: Condition grp commons schemas params from
819+ -> Expression grp commons schemas params from ty -- ^ then
820+ -> Expression grp commons schemas params from ty -- ^ else
821+ -> Expression grp commons schemas params from ty
822+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
823+
824+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
825+-- will produce @NULL@s if one of their arguments is @NULL@.
826+--
827+-- >>> printSQL $ true .== null_
828+-- (TRUE = NULL)
829+(.==)
830+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
831+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
832+ -> Condition grp commons schemas params from
833+(.==) = unsafeBinaryOp "="
834+infix 4 .==
835+
836+-- | >>> printSQL $ true ./= null_
837+-- (TRUE <> NULL)
838+(./=)
839+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
840+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
841+ -> Condition grp commons schemas params from
842+(./=) = unsafeBinaryOp "<>"
843+infix 4 ./=
844+
845+-- | >>> printSQL $ true .>= null_
846+-- (TRUE >= NULL)
847+(.>=)
848+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
849+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
850+ -> Condition grp commons schemas params from
851+(.>=) = unsafeBinaryOp ">="
852+infix 4 .>=
853+
854+-- | >>> printSQL $ true .< null_
855+-- (TRUE < NULL)
856+(.<)
857+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
858+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
859+ -> Condition grp commons schemas params from
860+(.<) = unsafeBinaryOp "<"
861+infix 4 .<
862+
863+-- | >>> printSQL $ true .<= null_
864+-- (TRUE <= NULL)
865+(.<=)
866+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
867+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
868+ -> Condition grp commons schemas params from
869+(.<=) = unsafeBinaryOp "<="
870+infix 4 .<=
871+
872+-- | >>> printSQL $ true .> null_
873+-- (TRUE > NULL)
874+(.>)
875+ :: Expression grp commons schemas params from (nullity0 ty) -- ^ lhs
876+ -> Expression grp commons schemas params from (nullity1 ty) -- ^ rhs
877+ -> Condition grp commons schemas params from
878+(.>) = unsafeBinaryOp ">"
879+infix 4 .>
880+
881+-- | >>> printSQL currentDate
882+-- CURRENT_DATE
883+currentDate
884+ :: Expression grp commons schemas params from (nullity 'PGdate)
885+currentDate = UnsafeExpression "CURRENT_DATE"
886+
887+-- | >>> printSQL currentTime
888+-- CURRENT_TIME
889+currentTime
890+ :: Expression grp commons schemas params from (nullity 'PGtimetz)
891+currentTime = UnsafeExpression "CURRENT_TIME"
892+
893+-- | >>> printSQL currentTimestamp
894+-- CURRENT_TIMESTAMP
895+currentTimestamp
896+ :: Expression grp commons schemas params from (nullity 'PGtimestamptz)
897+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
898+
899+-- | >>> printSQL localTime
900+-- LOCALTIME
901+localTime
902+ :: Expression grp commons schemas params from (nullity 'PGtime)
903+localTime = UnsafeExpression "LOCALTIME"
904+
905+-- | >>> printSQL localTimestamp
906+-- LOCALTIMESTAMP
907+localTimestamp
908+ :: Expression grp commons schemas params from (nullity 'PGtimestamp)
909+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
910+
911+{-----------------------------------------
912+text
913+-----------------------------------------}
438914
439915instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
916+ (Expression grp commons schemas params from (nullity 'PGtext)) where
441917 fromString str = UnsafeExpression $
442918 "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) <> "\'"
919+ where
920+ escape = \case
921+ '\NUL' -> "\\0"
922+ '\'' -> "''"
923+ '"' -> "\\\""
924+ '\b' -> "\\b"
925+ '\n' -> "\\n"
926+ '\r' -> "\\r"
927+ '\t' -> "\\t"
928+ '\\' -> "\\\\"
929+ c -> [c]
451930
452931instance 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
932+ (Expression grp commons schemas params from (nullity 'PGtext)) where
463933 (<>) = unsafeBinaryOp "||"
464934
465935instance 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
936+ (Expression grp commons schemas params from (nullity 'PGtext)) where
471937 mempty = fromString ""
472938 mappend = (<>)
939+
940+-- | >>> printSQL $ lower "ARRRGGG"
941+-- lower(E'ARRRGGG')
942+lower
943+ :: Expression grp commons schemas params from (nullity 'PGtext)
944+ -- ^ string to lower case
945+ -> Expression grp commons schemas params from (nullity 'PGtext)
946+lower = unsafeFunction "lower"
947+
948+-- | >>> printSQL $ upper "eeee"
949+-- upper(E'eeee')
950+upper
951+ :: Expression grp commons schemas params from (nullity 'PGtext)
952+ -- ^ string to upper case
953+ -> Expression grp commons schemas params from (nullity 'PGtext)
954+upper = unsafeFunction "upper"
955+
956+-- | >>> printSQL $ charLength "four"
957+-- char_length(E'four')
958+charLength
959+ :: Expression grp commons schemas params from (nullity 'PGtext)
960+ -- ^ string to measure
961+ -> Expression grp commons schemas params from (nullity 'PGint4)
962+charLength = unsafeFunction "char_length"
963+
964+-- | The `like` expression returns true if the @string@ matches
965+-- the supplied @pattern@. If @pattern@ does not contain percent signs
966+-- or underscores, then the pattern only represents the string itself;
967+-- in that case `like` acts like the equals operator. An underscore (_)
968+-- in pattern stands for (matches) any single character; a percent sign (%)
969+-- matches any sequence of zero or more characters.
970+--
971+-- >>> printSQL $ "abc" `like` "a%"
972+-- (E'abc' LIKE E'a%')
973+like
974+ :: Expression grp commons schemas params from (nullity 'PGtext)
975+ -- ^ string
976+ -> Expression grp commons schemas params from (nullity 'PGtext)
977+ -- ^ pattern
978+ -> Expression grp commons schemas params from (nullity 'PGbool)
979+like = unsafeBinaryOp "LIKE"
980+
981+-- | The key word ILIKE can be used instead of LIKE to make the
982+-- match case-insensitive according to the active locale.
983+--
984+-- >>> printSQL $ "abc" `ilike` "a%"
985+-- (E'abc' ILIKE E'a%')
986+ilike
987+ :: Expression grp commons schemas params from (nullity 'PGtext)
988+ -- ^ string
989+ -> Expression grp commons schemas params from (nullity 'PGtext)
990+ -- ^ pattern
991+ -> Expression grp commons schemas params from (nullity 'PGbool)
992+ilike = unsafeBinaryOp "ILIKE"
993+
994+{-----------------------------------------
995+ -- json and jsonb support
996+
997+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
998+comments lifted directly from this page.
999+
1000+Table 9.44: json and jsonb operators
1001+-----------------------------------------}
1002+
1003+-- | Get JSON value (object field or array element) at a key.
1004+(.->)
1005+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1006+ => Expression grp commons schemas params from (nullity json)
1007+ -> Expression grp commons schemas params from (nullity key)
1008+ -> Expression grp commons schemas params from ('Null json)
1009+infixl 8 .->
1010+(.->) = unsafeBinaryOp "->"
1011+
1012+-- | Get JSON value (object field or array element) at a key, as text.
1013+(.->>)
1014+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1015+ => Expression grp commons schemas params from (nullity json)
1016+ -> Expression grp commons schemas params from (nullity key)
1017+ -> Expression grp commons schemas params from ('Null 'PGtext)
1018+infixl 8 .->>
1019+(.->>) = unsafeBinaryOp "->>"
1020+
1021+-- | Get JSON value at a specified path.
1022+(.#>)
1023+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1024+ => Expression grp commons schemas params from (nullity json)
1025+ -> Expression grp commons schemas params from (nullity path)
1026+ -> Expression grp commons schemas params from ('Null json)
1027+infixl 8 .#>
1028+(.#>) = unsafeBinaryOp "#>"
1029+
1030+-- | Get JSON value at a specified path as text.
1031+(.#>>)
1032+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1033+ => Expression grp commons schemas params from (nullity json)
1034+ -> Expression grp commons schemas params from (nullity path)
1035+ -> Expression grp commons schemas params from ('Null 'PGtext)
1036+infixl 8 .#>>
1037+(.#>>) = unsafeBinaryOp "#>>"
1038+
1039+-- Additional jsonb operators
1040+
1041+-- | Does the left JSON value contain the right JSON path/value entries at the
1042+-- top level?
1043+(.@>)
1044+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1045+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1046+ -> Condition grp commons schemas params from
1047+infixl 9 .@>
1048+(.@>) = unsafeBinaryOp "@>"
1049+
1050+-- | Are the left JSON path/value entries contained at the top level within the
1051+-- right JSON value?
1052+(.<@)
1053+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1054+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1055+ -> Condition grp commons schemas params from
1056+infixl 9 .<@
1057+(.<@) = unsafeBinaryOp "<@"
1058+
1059+-- | Does the string exist as a top-level key within the JSON value?
1060+(.?)
1061+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1062+ -> Expression grp commons schemas params from (nullity 'PGtext)
1063+ -> Condition grp commons schemas params from
1064+infixl 9 .?
1065+(.?) = unsafeBinaryOp "?"
1066+
1067+-- | Do any of these array strings exist as top-level keys?
1068+(.?|)
1069+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1070+ -> Expression grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1071+ -> Condition grp commons schemas params from
1072+infixl 9 .?|
1073+(.?|) = unsafeBinaryOp "?|"
1074+
1075+-- | Do all of these array strings exist as top-level keys?
1076+(.?&)
1077+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1078+ -> Expression grp commons schemas params from (nullity ('PGvararray ('NotNull 'PGtext)))
1079+ -> Condition grp commons schemas params from
1080+infixl 9 .?&
1081+(.?&) = unsafeBinaryOp "?&"
1082+
1083+-- | Concatenate two jsonb values into a new jsonb value.
1084+instance
1085+ Semigroup (Expression commons schemas from grouping param (nullity 'PGjsonb)) where
1086+ (<>) = unsafeBinaryOp "||"
1087+
1088+-- | Delete a key or keys from a JSON object, or remove an array element.
1089+--
1090+-- If the right operand is..
1091+--
1092+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1093+-- are matched based on their key value.
1094+--
1095+-- @ text[] @: Delete multiple key/value pairs or string elements
1096+-- from left operand. Key/value pairs are matched based on their key value.
1097+--
1098+-- @ integer @: Delete the array element with specified index (Negative integers
1099+-- count from the end). Throws an error if top level container is not an array.
1100+(.-.)
1101+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1102+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1103+ -> Expression grp commons schemas params from (nullity key)
1104+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1105+infixl 6 .-.
1106+(.-.) = unsafeBinaryOp "-"
1107+
1108+-- | Delete the field or element with specified path (for JSON arrays, negative
1109+-- integers count from the end)
1110+(#-.)
1111+ :: PGTextArray "(#-.)" arrayty
1112+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1113+ -> Expression grp commons schemas params from (nullity arrayty)
1114+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1115+infixl 6 #-.
1116+(#-.) = unsafeBinaryOp "#-"
1117+
1118+{-----------------------------------------
1119+Table 9.45: JSON creation functions
1120+-----------------------------------------}
1121+
1122+-- | Literal binary JSON
1123+jsonbLit
1124+ :: JSON.ToJSON x
1125+ => x -> Expression grp commons schemas params from (nullity 'PGjsonb)
1126+jsonbLit = cast jsonb . UnsafeExpression
1127+ . singleQuotedUtf8 . toStrict . JSON.encode
1128+
1129+-- | Literal JSON
1130+jsonLit
1131+ :: JSON.ToJSON x
1132+ => x -> Expression grp commons schemas params from (nullity 'PGjson)
1133+jsonLit = cast json . UnsafeExpression
1134+ . singleQuotedUtf8 . toStrict . JSON.encode
1135+
1136+-- | Returns the value as json. Arrays and composites are converted
1137+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1138+-- type to json, the cast function will be used to perform the conversion;
1139+-- otherwise, a scalar value is produced. For any scalar type other than a
1140+-- number, a Boolean, or a null value, the text representation will be used, in
1141+-- such a fashion that it is a valid json value.
1142+toJson
1143+ :: Expression grp commons schemas params from (nullity ty)
1144+ -> Expression grp commons schemas params from (nullity 'PGjson)
1145+toJson = unsafeFunction "to_json"
1146+
1147+-- | Returns the value as jsonb. Arrays and composites are converted
1148+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1149+-- type to json, the cast function will be used to perform the conversion;
1150+-- otherwise, a scalar value is produced. For any scalar type other than a
1151+-- number, a Boolean, or a null value, the text representation will be used, in
1152+-- such a fashion that it is a valid jsonb value.
1153+toJsonb
1154+ :: Expression grp commons schemas params from (nullity ty)
1155+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1156+toJsonb = unsafeFunction "to_jsonb"
1157+
1158+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1159+-- becomes a JSON array of arrays.
1160+arrayToJson
1161+ :: PGArray "arrayToJson" arr
1162+ => Expression grp commons schemas params from (nullity arr)
1163+ -> Expression grp commons schemas params from (nullity 'PGjson)
1164+arrayToJson = unsafeFunction "array_to_json"
1165+
1166+-- | Returns the row as a JSON object.
1167+rowToJson
1168+ :: Expression grp commons schemas params from (nullity ('PGcomposite ty))
1169+ -> Expression grp commons schemas params from (nullity 'PGjson)
1170+rowToJson = unsafeFunction "row_to_json"
1171+
1172+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1173+-- argument list.
1174+jsonBuildArray
1175+ :: SListI elems
1176+ => NP (Expression grp commons schemas params from) elems
1177+ -> Expression grp commons schemas params from (nullity 'PGjson)
1178+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1179+
1180+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1181+-- variadic argument list.
1182+jsonbBuildArray
1183+ :: SListI elems
1184+ => NP (Expression grp commons schemas params from) elems
1185+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1186+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1187+
1188+unsafeRowFunction
1189+ :: All Top elems
1190+ => NP (Aliased (Expression grp commons schemas params from)) elems
1191+ -> [ByteString]
1192+unsafeRowFunction =
1193+ (`appEndo` []) . hcfoldMap (Proxy :: Proxy Top)
1194+ (\(col `As` name) -> Endo $ \xs ->
1195+ renderAliasString name : renderSQL col : xs)
1196+ where
1197+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1198+ renderAliasString = singleQuotedText . fromString . symbolVal
1199+
1200+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1201+-- argument list. The elements of the argument list must alternate between text
1202+-- and values.
1203+jsonBuildObject
1204+ :: All Top elems
1205+ => NP (Aliased (Expression grp commons schemas params from)) elems
1206+ -> Expression grp commons schemas params from (nullity 'PGjson)
1207+jsonBuildObject
1208+ = unsafeFunction "json_build_object"
1209+ . UnsafeExpression
1210+ . commaSeparated
1211+ . unsafeRowFunction
1212+
1213+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1214+-- variadic argument list. The elements of the argument list must alternate
1215+-- between text and values.
1216+jsonbBuildObject
1217+ :: All Top elems
1218+ => NP (Aliased (Expression grp commons schemas params from)) elems
1219+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1220+jsonbBuildObject
1221+ = unsafeFunction "jsonb_build_object"
1222+ . UnsafeExpression
1223+ . commaSeparated
1224+ . unsafeRowFunction
1225+
1226+-- | Builds a JSON object out of a text array. The array must have either
1227+-- exactly one dimension with an even number of members, in which case they are
1228+-- taken as alternating key/value pairs, or two dimensions such that each inner
1229+-- array has exactly two elements, which are taken as a key/value pair.
1230+jsonObject
1231+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1232+ => Expression grp commons schemas params from (nullity arr)
1233+ -> Expression grp commons schemas params from (nullity 'PGjson)
1234+jsonObject = unsafeFunction "json_object"
1235+
1236+-- | Builds a binary JSON object out of a text array. The array must have either
1237+-- exactly one dimension with an even number of members, in which case they are
1238+-- taken as alternating key/value pairs, or two dimensions such that each inner
1239+-- array has exactly two elements, which are taken as a key/value pair.
1240+jsonbObject
1241+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1242+ => Expression grp commons schemas params from (nullity arr)
1243+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1244+jsonbObject = unsafeFunction "jsonb_object"
1245+
1246+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1247+-- keys and one for values, that are zipped pairwise to create a JSON object.
1248+jsonZipObject
1249+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1250+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1251+ => Expression grp commons schemas params from (nullity keysArray)
1252+ -> Expression grp commons schemas params from (nullity valuesArray)
1253+ -> Expression grp commons schemas params from (nullity 'PGjson)
1254+jsonZipObject ks vs =
1255+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1256+
1257+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1258+-- keys and one for values, that are zipped pairwise to create a binary JSON
1259+-- object.
1260+jsonbZipObject
1261+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1262+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1263+ => Expression grp commons schemas params from (nullity keysArray)
1264+ -> Expression grp commons schemas params from (nullity valuesArray)
1265+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1266+jsonbZipObject ks vs =
1267+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1268+
1269+{-----------------------------------------
1270+Table 9.46: JSON processing functions
1271+-----------------------------------------}
1272+
1273+-- | Returns the number of elements in the outermost JSON array.
1274+jsonArrayLength
1275+ :: Expression grp commons schemas params from (nullity 'PGjson)
1276+ -> Expression grp commons schemas params from (nullity 'PGint4)
1277+jsonArrayLength = unsafeFunction "json_array_length"
1278+
1279+-- | Returns the number of elements in the outermost binary JSON array.
1280+jsonbArrayLength
1281+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1282+ -> Expression grp commons schemas params from (nullity 'PGint4)
1283+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1284+
1285+-- | Returns JSON value pointed to by the given path (equivalent to #>
1286+-- operator).
1287+jsonExtractPath
1288+ :: SListI elems
1289+ => Expression grp commons schemas params from (nullity 'PGjson)
1290+ -> NP (Expression grp commons schemas params from) elems
1291+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1292+jsonExtractPath x xs =
1293+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1294+
1295+-- | Returns JSON value pointed to by the given path (equivalent to #>
1296+-- operator).
1297+jsonbExtractPath
1298+ :: SListI elems
1299+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1300+ -> NP (Expression grp commons schemas params from) elems
1301+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1302+jsonbExtractPath x xs =
1303+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1304+
1305+-- | Returns JSON value pointed to by the given path (equivalent to #>
1306+-- operator), as text.
1307+jsonExtractPathAsText
1308+ :: SListI elems
1309+ => Expression grp commons schemas params from (nullity 'PGjson)
1310+ -> NP (Expression grp commons schemas params from) elems
1311+ -> Expression grp commons schemas params from (nullity 'PGjson)
1312+jsonExtractPathAsText x xs =
1313+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1314+
1315+-- | Returns JSON value pointed to by the given path (equivalent to #>
1316+-- operator), as text.
1317+jsonbExtractPathAsText
1318+ :: SListI elems
1319+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1320+ -> NP (Expression grp commons schemas params from) elems
1321+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1322+jsonbExtractPathAsText x xs =
1323+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1324+
1325+-- | Returns the type of the outermost JSON value as a text string. Possible
1326+-- types are object, array, string, number, boolean, and null.
1327+jsonTypeof
1328+ :: Expression grp commons schemas params from (nullity 'PGjson)
1329+ -> Expression grp commons schemas params from (nullity 'PGtext)
1330+jsonTypeof = unsafeFunction "json_typeof"
1331+
1332+-- | Returns the type of the outermost binary JSON value as a text string.
1333+-- Possible types are object, array, string, number, boolean, and null.
1334+jsonbTypeof
1335+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1336+ -> Expression grp commons schemas params from (nullity 'PGtext)
1337+jsonbTypeof = unsafeFunction "jsonb_typeof"
1338+
1339+-- | Returns its argument with all object fields that have null values omitted.
1340+-- Other null values are untouched.
1341+jsonStripNulls
1342+ :: Expression grp commons schemas params from (nullity 'PGjson)
1343+ -> Expression grp commons schemas params from (nullity 'PGjson)
1344+jsonStripNulls = unsafeFunction "json_strip_nulls"
1345+
1346+-- | Returns its argument with all object fields that have null values omitted.
1347+-- Other null values are untouched.
1348+jsonbStripNulls
1349+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1350+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1351+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1352+
1353+-- | @ jsonbSet target path new_value create_missing @
1354+--
1355+-- Returns target with the section designated by path replaced by new_value,
1356+-- or with new_value added if create_missing is true ( default is true) and the
1357+-- item designated by path does not exist. As with the path orientated
1358+-- operators, negative integers that appear in path count from the end of JSON
1359+-- arrays.
1360+jsonbSet
1361+ :: PGTextArray "jsonbSet" arr
1362+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1363+ -> Expression grp commons schemas params from (nullity arr)
1364+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1365+ -> Maybe (Expression grp commons schemas params from (nullity 'PGbool))
1366+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1367+jsonbSet tgt path val createMissing = case createMissing of
1368+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1369+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1370+
1371+-- | @ jsonbInsert target path new_value insert_after @
1372+--
1373+-- Returns target with new_value inserted. If target section designated by
1374+-- path is in a JSONB array, new_value will be inserted before target or after
1375+-- if insert_after is true (default is false). If target section designated by
1376+-- path is in JSONB object, new_value will be inserted only if target does not
1377+-- exist. As with the path orientated operators, negative integers that appear
1378+-- in path count from the end of JSON arrays.
1379+jsonbInsert
1380+ :: PGTextArray "jsonbInsert" arr
1381+ => Expression grp commons schemas params from (nullity 'PGjsonb)
1382+ -> Expression grp commons schemas params from (nullity arr)
1383+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1384+ -> Maybe (Expression grp commons schemas params from (nullity 'PGbool))
1385+ -> Expression grp commons schemas params from (nullity 'PGjsonb)
1386+jsonbInsert tgt path val insertAfter = case insertAfter of
1387+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1388+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1389+
1390+-- | Returns its argument as indented JSON text.
1391+jsonbPretty
1392+ :: Expression grp commons schemas params from (nullity 'PGjsonb)
1393+ -> Expression grp commons schemas params from (nullity 'PGtext)
1394+jsonbPretty = unsafeFunction "jsonb_pretty"
1395+
1396+{-----------------------------------------
1397+aggregation
1398+-----------------------------------------}
1399+
1400+class Aggregate expr1 expr2 aggr
1401+ | aggr -> expr1, aggr -> expr2 where
1402+
1403+ -- | A special aggregation that does not require an input
1404+ --
1405+ -- >>> :{
1406+ -- let
1407+ -- expression :: Expression (Grouped bys) commons schemas params from ('NotNull 'PGint8)
1408+ -- expression = countStar
1409+ -- in printSQL expression
1410+ -- :}
1411+ -- count(*)
1412+ countStar :: aggr ('NotNull 'PGint8)
1413+
1414+ -- | >>> :{
1415+ -- let
1416+ -- expression :: Expression (Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity ty]] ('NotNull 'PGint8)
1417+ -- expression = count (All #col)
1418+ -- in printSQL expression
1419+ -- :}
1420+ -- count(ALL "col")
1421+ count
1422+ :: expr1 ty
1423+ -- ^ what to count
1424+ -> aggr ('NotNull 'PGint8)
1425+
1426+ -- | >>> :{
1427+ -- let
1428+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)
1429+ -- expression = sum_ (Distinct #col)
1430+ -- in printSQL expression
1431+ -- :}
1432+ -- sum(DISTINCT "col")
1433+ sum_
1434+ :: ty `In` PGNum
1435+ => expr1 (nullity ty)
1436+ -> aggr (nullity ty)
1437+
1438+ -- | >>> :{
1439+ -- let
1440+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1441+ -- expression = bitAnd (Distinct #col)
1442+ -- in printSQL expression
1443+ -- :}
1444+ -- bit_and(DISTINCT "col")
1445+ bitAnd
1446+ :: int `In` PGIntegral
1447+ => expr1 (nullity int)
1448+ -- ^ what to aggregate
1449+ -> aggr (nullity int)
1450+
1451+ -- | >>> :{
1452+ -- let
1453+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGint4]] (nullity 'PGint4)
1454+ -- expression = bitOr (All #col)
1455+ -- in printSQL expression
1456+ -- :}
1457+ -- bit_or(ALL "col")
1458+ bitOr
1459+ :: int `In` PGIntegral
1460+ => expr1 (nullity int)
1461+ -- ^ what to aggregate
1462+ -> aggr (nullity int)
1463+
1464+ -- | >>> :{
1465+ -- let
1466+ -- winFun :: WindowFunction 'Ungrouped commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1467+ -- winFun = boolAnd #col
1468+ -- in printSQL winFun
1469+ -- :}
1470+ -- bool_and("col")
1471+ boolAnd
1472+ :: expr1 (nullity 'PGbool)
1473+ -- ^ what to aggregate
1474+ -> aggr (nullity 'PGbool)
1475+
1476+ -- | >>> :{
1477+ -- let
1478+ -- expression :: Expression (Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1479+ -- expression = boolOr (All #col)
1480+ -- in printSQL expression
1481+ -- :}
1482+ -- bool_or(ALL "col")
1483+ boolOr
1484+ :: expr1(nullity 'PGbool)
1485+ -- ^ what to aggregate
1486+ -> aggr (nullity 'PGbool)
1487+
1488+ -- | synonym for `boolAnd`
1489+ --
1490+ -- >>> :{
1491+ -- let
1492+ -- expression :: Expression ('Grouped bys) commons schemas params '[tab ::: '["col" ::: nullity 'PGbool]] (nullity 'PGbool)
1493+ -- expression = every (Distinct #col)
1494+ -- in printSQL expression
1495+ -- :}
1496+ -- every(DISTINCT "col")
1497+ every
1498+ :: expr1 (nullity 'PGbool)
1499+ -- ^ what to aggregate
1500+ -> aggr (nullity 'PGbool)
1501+
1502+ -- | maximum value of expression across all input values
1503+ max_
1504+ :: expr1 (nullity ty)
1505+ -- ^ what to maximize
1506+ -> aggr (nullity ty)
1507+
1508+ -- | minimum value of expression across all input values
1509+ min_
1510+ :: expr1 (nullity ty)
1511+ -- ^ what to minimize
1512+ -> aggr (nullity ty)
1513+
1514+ -- | average aggregation
1515+ avg
1516+ :: expr1 (nullity ty)
1517+ -- ^ what to average
1518+ -> aggr (nullity (PGAvg ty))
1519+
1520+ {- | correlation coefficient
1521+ >>> :{
1522+ let
1523+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1524+ expression = corr (All (#y :*: #x))
1525+ in printSQL expression
1526+ :}
1527+ corr(ALL "y", "x")
1528+ -}
1529+ corr
1530+ :: expr2 (nullity 'PGfloat8)
1531+ -> aggr (nullity 'PGfloat8)
1532+
1533+ {- | population covariance
1534+ >>> :{
1535+ let
1536+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1537+ expression = covarPop (All (#y :*: #x))
1538+ in printSQL expression
1539+ :}
1540+ covar_pop(ALL "y", "x")
1541+ -}
1542+ covarPop
1543+ :: expr2 (nullity 'PGfloat8)
1544+ -> aggr (nullity 'PGfloat8)
1545+
1546+ {- | sample covariance
1547+ >>> :{
1548+ let
1549+ winFun :: WindowFunction 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1550+ winFun = covarSamp (#y :*: #x)
1551+ in printSQL winFun
1552+ :}
1553+ covar_samp("y", "x")
1554+ -}
1555+ covarSamp
1556+ :: expr2 (nullity 'PGfloat8)
1557+ -> aggr (nullity 'PGfloat8)
1558+
1559+ {- | average of the independent variable (sum(X)/N)
1560+ >>> :{
1561+ let
1562+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1563+ expression = regrAvgX (All (#y :*: #x))
1564+ in printSQL expression
1565+ :}
1566+ regr_avgx(ALL "y", "x")
1567+ -}
1568+ regrAvgX
1569+ :: expr2 (nullity 'PGfloat8)
1570+ -> aggr (nullity 'PGfloat8)
1571+
1572+ {- | average of the dependent variable (sum(Y)/N)
1573+ >>> :{
1574+ let
1575+ winFun :: WindowFunction 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1576+ winFun = regrAvgY (#y :*: #x)
1577+ in printSQL winFun
1578+ :}
1579+ regr_avgy("y", "x")
1580+ -}
1581+ regrAvgY
1582+ :: expr2 (nullity 'PGfloat8)
1583+ -> aggr (nullity 'PGfloat8)
1584+
1585+ {- | number of input rows in which both expressions are nonnull
1586+ >>> :{
1587+ let
1588+ winFun :: WindowFunction 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGint8)
1589+ winFun = regrCount (#y :*: #x)
1590+ in printSQL winFun
1591+ :}
1592+ regr_count("y", "x")
1593+ -}
1594+ regrCount
1595+ :: expr2 (nullity 'PGfloat8)
1596+ -> aggr (nullity 'PGint8)
1597+
1598+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1599+ >>> :{
1600+ let
1601+ expression :: Expression ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('NotNull 'PGfloat8)
1602+ expression = regrIntercept (All (#y :*: #x))
1603+ in printSQL expression
1604+ :}
1605+ regr_intercept(ALL "y", "x")
1606+ -}
1607+ regrIntercept
1608+ :: expr2 (nullity 'PGfloat8)
1609+ -> aggr (nullity 'PGfloat8)
1610+
1611+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1612+ regrR2
1613+ :: expr2 (nullity 'PGfloat8)
1614+ -> aggr (nullity 'PGfloat8)
1615+
1616+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1617+ -- determined by the (X, Y) pairs
1618+ regrSlope
1619+ :: expr2 (nullity 'PGfloat8)
1620+ -> aggr (nullity 'PGfloat8)
1621+
1622+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1623+ -- (“sum of squares” of the independent variable)
1624+ regrSxx
1625+ :: expr2 (nullity 'PGfloat8)
1626+ -> aggr (nullity 'PGfloat8)
1627+
1628+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1629+ -- (“sum of products” of independent times dependent variable)
1630+ regrSxy
1631+ :: expr2 (nullity 'PGfloat8)
1632+ -> aggr (nullity 'PGfloat8)
1633+
1634+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1635+ -- (“sum of squares” of the dependent variable)
1636+ regrSyy
1637+ :: expr2 (nullity 'PGfloat8)
1638+ -> aggr (nullity 'PGfloat8)
1639+
1640+ -- | historical alias for `stddevSamp`
1641+ stddev
1642+ :: expr1 (nullity ty)
1643+ -> aggr (nullity (PGAvg ty))
1644+
1645+ -- | population standard deviation of the input values
1646+ stddevPop
1647+ :: expr1 (nullity ty)
1648+ -> aggr (nullity (PGAvg ty))
1649+
1650+ -- | sample standard deviation of the input values
1651+ stddevSamp
1652+ :: expr1 (nullity ty)
1653+ -> aggr (nullity (PGAvg ty))
1654+
1655+ -- | historical alias for `varSamp`
1656+ variance
1657+ :: expr1 (nullity ty)
1658+ -> aggr (nullity (PGAvg ty))
1659+
1660+ -- | population variance of the input values
1661+ -- (square of the population standard deviation)
1662+ varPop
1663+ :: expr1 (nullity ty)
1664+ -> aggr (nullity (PGAvg ty))
1665+
1666+ -- | sample variance of the input values
1667+ -- (square of the sample standard deviation)
1668+ varSamp
1669+ :: expr1 (nullity ty)
1670+ -> aggr (nullity (PGAvg ty))
1671+
1672+data Distinction expr ty
1673+ = All (expr ty)
1674+ | Distinct (expr ty)
1675+ deriving (GHC.Generic,Show,Eq,Ord)
1676+instance NFData (Distinction (Expression grp commons schemas params from) ty)
1677+instance RenderSQL (Distinction (Expression grp commons schemas params from) ty) where
1678+ renderSQL = \case
1679+ All x -> "ALL" <+> renderSQL x
1680+ Distinct x -> "DISTINCT" <+> renderSQL x
1681+instance RenderSQL
1682+ (Distinction
1683+ ( Expression grp commons schemas params from
1684+ :*:
1685+ Expression grp commons schemas params from) xty ) where
1686+ renderSQL = \case
1687+ All (x :*: x') ->
1688+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1689+ Distinct (x :*: x') ->
1690+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1691+
1692+instance Aggregate
1693+ (Distinction (Expression 'Ungrouped commons schemas params from))
1694+ (Distinction (Expression 'Ungrouped commons schemas params from :*: Expression 'Ungrouped commons schemas params from))
1695+ (Expression ('Grouped bys) commons schemas params from) where
1696+ countStar = UnsafeExpression "count(*)"
1697+ count = unsafeAggregate1 "count"
1698+ sum_ = unsafeAggregate1 "sum"
1699+ bitAnd = unsafeAggregate1 "bit_and"
1700+ bitOr = unsafeAggregate1 "bit_or"
1701+ boolAnd = unsafeAggregate1 "bool_and"
1702+ boolOr = unsafeAggregate1 "bool_or"
1703+ every = unsafeAggregate1 "every"
1704+ max_ = unsafeAggregate1 "max"
1705+ min_ = unsafeAggregate1 "min"
1706+ avg = unsafeAggregate1 "avg"
1707+ corr = unsafeAggregate2 "corr"
1708+ covarPop = unsafeAggregate2 "covar_pop"
1709+ covarSamp = unsafeAggregate2 "covar_samp"
1710+ regrAvgX = unsafeAggregate2 "regr_avgx"
1711+ regrAvgY = unsafeAggregate2 "regr_avgy"
1712+ regrCount = unsafeAggregate2 "regr_count"
1713+ regrIntercept = unsafeAggregate2 "regr_intercept"
1714+ regrR2 = unsafeAggregate2 "regr_r2"
1715+ regrSlope = unsafeAggregate2 "regr_slope"
1716+ regrSxx = unsafeAggregate2 "regr_sxx"
1717+ regrSxy = unsafeAggregate2 "regr_sxy"
1718+ regrSyy = unsafeAggregate2 "regr_syy"
1719+ stddev = unsafeAggregate1 "stddev"
1720+ stddevPop = unsafeAggregate1 "stddev_pop"
1721+ stddevSamp = unsafeAggregate1 "stddev_samp"
1722+ variance = unsafeAggregate1 "variance"
1723+ varPop = unsafeAggregate1 "var_pop"
1724+ varSamp = unsafeAggregate1 "var_samp"
1725+instance Aggregate
1726+ (Expression grp commons schemas params from)
1727+ (Expression grp commons schemas params from :*: Expression grp commons schemas params from)
1728+ (WindowFunction grp commons schemas params from) where
1729+ countStar = UnsafeWindowFunction "count(*)"
1730+ count = unsafeWindowFunction1 "count"
1731+ sum_ = unsafeWindowFunction1 "sum"
1732+ bitAnd = unsafeWindowFunction1 "bit_and"
1733+ bitOr = unsafeWindowFunction1 "bit_or"
1734+ boolAnd = unsafeWindowFunction1 "bool_and"
1735+ boolOr = unsafeWindowFunction1 "bool_or"
1736+ every = unsafeWindowFunction1 "every"
1737+ max_ = unsafeWindowFunction1 "max"
1738+ min_ = unsafeWindowFunction1 "min"
1739+ avg = unsafeWindowFunction1 "avg"
1740+ corr = unsafeWindowFunction2 "corr"
1741+ covarPop = unsafeWindowFunction2 "covar_pop"
1742+ covarSamp = unsafeWindowFunction2 "covar_samp"
1743+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1744+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1745+ regrCount = unsafeWindowFunction2 "regr_count"
1746+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1747+ regrR2 = unsafeWindowFunction2 "regr_r2"
1748+ regrSlope = unsafeWindowFunction2 "regr_slope"
1749+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1750+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1751+ regrSyy = unsafeWindowFunction2 "regr_syy"
1752+ stddev = unsafeWindowFunction1 "stddev"
1753+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1754+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1755+ variance = unsafeWindowFunction1 "variance"
1756+ varPop = unsafeWindowFunction1 "var_pop"
1757+ varSamp = unsafeWindowFunction1 "var_samp"
1758+
1759+-- | escape hatch to define aggregate functions
1760+unsafeAggregate1
1761+ :: ByteString -- ^ aggregate function
1762+ -> Distinction (Expression 'Ungrouped commons schemas params from) xty
1763+ -> Expression ('Grouped bys) commons schemas params from yty
1764+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1765+ [fun, "(", renderSQL x, ")"]
1766+
1767+-- | escape hatch to define aggregate binary functions
1768+unsafeAggregate2
1769+ :: ByteString -- ^ aggregate function
1770+ -> Distinction (Expression 'Ungrouped commons schemas params from :*: Expression 'Ungrouped commons schemas params from) xty
1771+ -> Expression ('Grouped bys) commons schemas params from yty
1772+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1773+ [fun, "(", renderSQL xx, ")"]
1774+
1775+-- | A type family that calculates `PGAvg` type of a `PGType`.
1776+type family PGAvg ty where
1777+ PGAvg 'PGint2 = 'PGnumeric
1778+ PGAvg 'PGint4 = 'PGnumeric
1779+ PGAvg 'PGint8 = 'PGnumeric
1780+ PGAvg 'PGnumeric = 'PGnumeric
1781+ PGAvg 'PGfloat4 = 'PGfloat8
1782+ PGAvg 'PGfloat8 = 'PGfloat8
1783+ PGAvg 'PGinterval = 'PGinterval
1784+ PGAvg pg = TypeError
1785+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1786+
1787+{-----------------------------------------
1788+type expressions
1789+-----------------------------------------}
1790+
1791+-- | `TypeExpression`s are used in `cast`s and `createTable` commands.
1792+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1793+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1794+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1795+instance RenderSQL (TypeExpression schemas ty) where
1796+ renderSQL = renderTypeExpression
1797+
1798+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1799+typedef
1800+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1801+ => QualifiedAlias sch td
1802+ -> TypeExpression schemas (nullity ty)
1803+typedef = UnsafeTypeExpression . renderSQL
1804+
1805+-- | The composite type corresponding to a `Table` definition can be expressed
1806+-- by its alias.
1807+typetable
1808+ :: (Has sch schemas schema, Has tab schema ('Table table))
1809+ => QualifiedAlias sch tab
1810+ -> TypeExpression schemas (nullity ('PGcomposite (TableToRow table)))
1811+typetable = UnsafeTypeExpression . renderSQL
1812+
1813+-- | The composite type corresponding to a `View` definition can be expressed
1814+-- by its alias.
1815+typeview
1816+ :: (Has sch schemas schema, Has vw schema ('View view))
1817+ => QualifiedAlias sch vw
1818+ -> TypeExpression schemas (nullity ('PGcomposite view))
1819+typeview = UnsafeTypeExpression . renderSQL
1820+
1821+-- | logical Boolean (true/false)
1822+bool :: TypeExpression schemas (nullity 'PGbool)
1823+bool = UnsafeTypeExpression "bool"
1824+-- | signed two-byte integer
1825+int2, smallint :: TypeExpression schemas (nullity 'PGint2)
1826+int2 = UnsafeTypeExpression "int2"
1827+smallint = UnsafeTypeExpression "smallint"
1828+-- | signed four-byte integer
1829+int4, int, integer :: TypeExpression schemas (nullity 'PGint4)
1830+int4 = UnsafeTypeExpression "int4"
1831+int = UnsafeTypeExpression "int"
1832+integer = UnsafeTypeExpression "integer"
1833+-- | signed eight-byte integer
1834+int8, bigint :: TypeExpression schemas (nullity 'PGint8)
1835+int8 = UnsafeTypeExpression "int8"
1836+bigint = UnsafeTypeExpression "bigint"
1837+-- | arbitrary precision numeric type
1838+numeric :: TypeExpression schemas (nullity 'PGnumeric)
1839+numeric = UnsafeTypeExpression "numeric"
1840+-- | single precision floating-point number (4 bytes)
1841+float4, real :: TypeExpression schemas (nullity 'PGfloat4)
1842+float4 = UnsafeTypeExpression "float4"
1843+real = UnsafeTypeExpression "real"
1844+-- | double precision floating-point number (8 bytes)
1845+float8, doublePrecision :: TypeExpression schemas (nullity 'PGfloat8)
1846+float8 = UnsafeTypeExpression "float8"
1847+doublePrecision = UnsafeTypeExpression "double precision"
1848+-- | variable-length character string
1849+text :: TypeExpression schemas (nullity 'PGtext)
1850+text = UnsafeTypeExpression "text"
1851+-- | fixed-length character string
1852+char, character
1853+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1854+ => TypeExpression schemas (nullity ('PGchar n))
1855+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
1856+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
1857+-- | variable-length character string
1858+varchar, characterVarying
1859+ :: forall n schemas nullity. (KnownNat n, 1 <= n)
1860+ => TypeExpression schemas (nullity ('PGvarchar n))
1861+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
1862+characterVarying = UnsafeTypeExpression $
1863+ "character varying(" <> renderNat @n <> ")"
1864+-- | binary data ("byte array")
1865+bytea :: TypeExpression schemas (nullity 'PGbytea)
1866+bytea = UnsafeTypeExpression "bytea"
1867+-- | date and time (no time zone)
1868+timestamp :: TypeExpression schemas (nullity 'PGtimestamp)
1869+timestamp = UnsafeTypeExpression "timestamp"
1870+-- | date and time, including time zone
1871+timestampWithTimeZone :: TypeExpression schemas (nullity 'PGtimestamptz)
1872+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
1873+-- | calendar date (year, month, day)
1874+date :: TypeExpression schemas (nullity 'PGdate)
1875+date = UnsafeTypeExpression "date"
1876+-- | time of day (no time zone)
1877+time :: TypeExpression schemas (nullity 'PGtime)
1878+time = UnsafeTypeExpression "time"
1879+-- | time of day, including time zone
1880+timeWithTimeZone :: TypeExpression schemas (nullity 'PGtimetz)
1881+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
1882+-- | time span
1883+interval :: TypeExpression schemas (nullity 'PGinterval)
1884+interval = UnsafeTypeExpression "interval"
1885+-- | universally unique identifier
1886+uuid :: TypeExpression schemas (nullity 'PGuuid)
1887+uuid = UnsafeTypeExpression "uuid"
1888+-- | IPv4 or IPv6 host address
1889+inet :: TypeExpression schemas (nullity 'PGinet)
1890+inet = UnsafeTypeExpression "inet"
1891+-- | textual JSON data
1892+json :: TypeExpression schemas (nullity 'PGjson)
1893+json = UnsafeTypeExpression "json"
1894+-- | binary JSON data, decomposed
1895+jsonb :: TypeExpression schemas (nullity 'PGjsonb)
1896+jsonb = UnsafeTypeExpression "jsonb"
1897+-- | variable length array
1898+vararray
1899+ :: TypeExpression schemas pg
1900+ -> TypeExpression schemas (nullity ('PGvararray pg))
1901+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
1902+-- | fixed length array
1903+--
1904+-- >>> renderSQL (fixarray @'[2] json)
1905+-- "json[2]"
1906+fixarray
1907+ :: forall dims schemas nullity pg. All KnownNat dims
1908+ => TypeExpression schemas pg
1909+ -> TypeExpression schemas (nullity ('PGfixarray dims pg))
1910+fixarray ty = UnsafeTypeExpression $
1911+ renderSQL ty <> renderDims @dims
1912+ where
1913+ renderDims :: forall ns. All KnownNat ns => ByteString
1914+ renderDims =
1915+ ("[" <>)
1916+ . (<> "]")
1917+ . ByteString.intercalate "]["
1918+ . hcollapse
1919+ $ hcmap (Proxy @KnownNat)
1920+ (K . fromString . show . natVal)
1921+ (hpure Proxy :: NP Proxy ns)
1922+
1923+-- | `pgtype` is a demoted version of a `PGType`
1924+class PGTyped schemas (ty :: NullityType) where
1925+ pgtype :: TypeExpression schemas ty
1926+instance PGTyped schemas (nullity 'PGbool) where pgtype = bool
1927+instance PGTyped schemas (nullity 'PGint2) where pgtype = int2
1928+instance PGTyped schemas (nullity 'PGint4) where pgtype = int4
1929+instance PGTyped schemas (nullity 'PGint8) where pgtype = int8
1930+instance PGTyped schemas (nullity 'PGnumeric) where pgtype = numeric
1931+instance PGTyped schemas (nullity 'PGfloat4) where pgtype = float4
1932+instance PGTyped schemas (nullity 'PGfloat8) where pgtype = float8
1933+instance PGTyped schemas (nullity 'PGtext) where pgtype = text
1934+instance (KnownNat n, 1 <= n)
1935+ => PGTyped schemas (nullity ('PGchar n)) where pgtype = char @n
1936+instance (KnownNat n, 1 <= n)
1937+ => PGTyped schemas (nullity ('PGvarchar n)) where pgtype = varchar @n
1938+instance PGTyped schemas (nullity 'PGbytea) where pgtype = bytea
1939+instance PGTyped schemas (nullity 'PGtimestamp) where pgtype = timestamp
1940+instance PGTyped schemas (nullity 'PGtimestamptz) where pgtype = timestampWithTimeZone
1941+instance PGTyped schemas (nullity 'PGdate) where pgtype = date
1942+instance PGTyped schemas (nullity 'PGtime) where pgtype = time
1943+instance PGTyped schemas (nullity 'PGtimetz) where pgtype = timeWithTimeZone
1944+instance PGTyped schemas (nullity 'PGinterval) where pgtype = interval
1945+instance PGTyped schemas (nullity 'PGuuid) where pgtype = uuid
1946+instance PGTyped schemas (nullity 'PGjson) where pgtype = json
1947+instance PGTyped schemas (nullity 'PGjsonb) where pgtype = jsonb
1948+instance PGTyped schemas ty
1949+ => PGTyped schemas (nullity ('PGvararray ty)) where
1950+ pgtype = vararray (pgtype @schemas @ty)
1951+instance (All KnownNat dims, PGTyped schemas ty)
1952+ => PGTyped schemas (nullity ('PGfixarray dims ty)) where
1953+ pgtype = fixarray @dims (pgtype @schemas @ty)
1954+
1955+{-----------------------------------------
1956+Sorting
1957+-----------------------------------------}
1958+
1959+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1960+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1961+-- column to ascending or descending. Ascending order puts smaller values
1962+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1963+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1964+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1965+-- determine whether nulls appear before or after non-null values in the sort
1966+-- ordering of a `Null` result column.
1967+data SortExpression grp commons schemas params from where
1968+ Asc
1969+ :: Expression grp commons schemas params from ('NotNull ty)
1970+ -> SortExpression grp commons schemas params from
1971+ Desc
1972+ :: Expression grp commons schemas params from ('NotNull ty)
1973+ -> SortExpression grp commons schemas params from
1974+ AscNullsFirst
1975+ :: Expression grp commons schemas params from ('Null ty)
1976+ -> SortExpression grp commons schemas params from
1977+ AscNullsLast
1978+ :: Expression grp commons schemas params from ('Null ty)
1979+ -> SortExpression grp commons schemas params from
1980+ DescNullsFirst
1981+ :: Expression grp commons schemas params from ('Null ty)
1982+ -> SortExpression grp commons schemas params from
1983+ DescNullsLast
1984+ :: Expression grp commons schemas params from ('Null ty)
1985+ -> SortExpression grp commons schemas params from
1986+deriving instance Show (SortExpression grp commons schemas params from)
1987+
1988+class OrderBy expr where
1989+ orderBy
1990+ :: [SortExpression grp commons schemas params from]
1991+ -> expr grp commons schemas params from
1992+ -> expr grp commons schemas params from
1993+
1994+-- | Render a `SortExpression`.
1995+instance RenderSQL (SortExpression grp commons schemas params from) where
1996+ renderSQL = \case
1997+ Asc expression -> renderSQL expression <+> "ASC"
1998+ Desc expression -> renderSQL expression <+> "DESC"
1999+ AscNullsFirst expression -> renderSQL expression
2000+ <+> "ASC NULLS FIRST"
2001+ DescNullsFirst expression -> renderSQL expression
2002+ <+> "DESC NULLS FIRST"
2003+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2004+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2005+
2006+data WindowDefinition grp commons schemas params from where
2007+ WindowDefinition
2008+ :: SListI bys
2009+ => NP (Expression grp commons schemas params from) bys
2010+ -> [SortExpression grp commons schemas params from]
2011+ -> WindowDefinition grp commons schemas params from
2012+
2013+instance OrderBy WindowDefinition where
2014+ orderBy sortsR (WindowDefinition parts sortsL)
2015+ = WindowDefinition parts (sortsL ++ sortsR)
2016+
2017+instance RenderSQL (WindowDefinition commons schemas from grp params) where
2018+ renderSQL (WindowDefinition part ord) =
2019+ renderPartitionByClause part <> renderOrderByClause ord
2020+ where
2021+ renderPartitionByClause = \case
2022+ Nil -> ""
2023+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2024+ renderOrderByClause = \case
2025+ [] -> ""
2026+ srts -> " ORDER" <+> "BY"
2027+ <+> commaSeparated (renderSQL <$> srts)
2028+
2029+partitionBy
2030+ :: SListI bys
2031+ => NP (Expression grp commons schemas params from) bys
2032+ -> WindowDefinition grp commons schemas params from
2033+partitionBy bys = WindowDefinition bys []
2034+
2035+newtype WindowFunction
2036+ (grp :: Grouping)
2037+ (commons :: FromType)
2038+ (schemas :: SchemasType)
2039+ (params :: [NullityType])
2040+ (from :: FromType)
2041+ (ty :: NullityType)
2042+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2043+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2044+
2045+instance RenderSQL (WindowFunction grp commons schemas params from ty) where
2046+ renderSQL = renderWindowFunction
2047+
2048+unsafeWindowFunction1
2049+ :: ByteString
2050+ -> Expression grp commons schemas params from ty0
2051+ -> WindowFunction grp commons schemas params from ty1
2052+unsafeWindowFunction1 fun x
2053+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2054+
2055+unsafeWindowFunction2
2056+ :: ByteString
2057+ -> (Expression grp commons schemas params from :*: Expression grp commons schemas params from) ty0
2058+ -> WindowFunction grp commons schemas params from ty1
2059+unsafeWindowFunction2 fun (x :*: x')
2060+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2061+
2062+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2063+>>> printSQL rank
2064+rank()
2065+-}
2066+rank :: WindowFunction grp commons schemas params from ('NotNull 'PGint8)
2067+rank = UnsafeWindowFunction "rank()"
2068+
2069+{- | number of the current row within its partition, counting from 1
2070+>>> printSQL rowNumber
2071+row_number()
2072+-}
2073+rowNumber :: WindowFunction grp commons schemas params from ('NotNull 'PGint8)
2074+rowNumber = UnsafeWindowFunction "row_number()"
2075+
2076+{- | rank of the current row without gaps; this function counts peer groups
2077+>>> printSQL denseRank
2078+dense_rank()
2079+-}
2080+denseRank :: WindowFunction grp commons schemas params from ('NotNull 'PGint8)
2081+denseRank = UnsafeWindowFunction "dense_rank()"
2082+
2083+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2084+>>> printSQL percentRank
2085+percent_rank()
2086+-}
2087+percentRank :: WindowFunction grp commons schemas params from ('NotNull 'PGfloat8)
2088+percentRank = UnsafeWindowFunction "percent_rank()"
2089+
2090+{- | cumulative distribution: (number of partition rows
2091+preceding or peer with current row) / total partition rows
2092+>>> printSQL cumeDist
2093+cume_dist()
2094+-}
2095+cumeDist :: WindowFunction grp commons schemas params from ('NotNull 'PGfloat8)
2096+cumeDist = UnsafeWindowFunction "cume_dist()"
2097+
2098+{- | integer ranging from 1 to the argument value,
2099+dividing the partition as equally as possible
2100+-}
2101+ntile
2102+ :: Expression grp commons schemas params from ('NotNull 'PGint4)
2103+ -- ^ num buckets
2104+ -> WindowFunction grp commons schemas params from ('NotNull 'PGint4)
2105+ntile = unsafeWindowFunction1 "ntile"
2106+
2107+{- | returns value evaluated at the row that is offset rows before the current
2108+row within the partition; if there is no such row, instead return default
2109+(which must be of the same type as value). Both offset and default are
2110+evaluated with respect to the current row.
2111+-}
2112+lag
2113+ :: Expression grp commons schemas params from ty
2114+ -- ^ value
2115+ -> Expression grp commons schemas params from ('NotNull 'PGint4)
2116+ -- ^ offset
2117+ -> Expression grp commons schemas params from ty
2118+ -- ^ default
2119+ -> WindowFunction grp commons schemas params from ty
2120+lag value offset def = UnsafeWindowFunction $ "lag"
2121+ <> parenthesized
2122+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2123+
2124+{- | returns value evaluated at the row that is offset rows after the current
2125+row within the partition; if there is no such row, instead return default
2126+(which must be of the same type as value). Both offset and default are
2127+evaluated with respect to the current row.
2128+-}
2129+lead
2130+ :: Expression grp commons schemas params from ty
2131+ -- ^ value
2132+ -> Expression grp commons schemas params from ('NotNull 'PGint4)
2133+ -- ^ offset
2134+ -> Expression grp commons schemas params from ty
2135+ -- ^ default
2136+ -> WindowFunction grp commons schemas params from ty
2137+lead value offset def = UnsafeWindowFunction $ "lag"
2138+ <> parenthesized
2139+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2140+
2141+{- | returns value evaluated at the row that is the
2142+first row of the window frame
2143+-}
2144+firstValue
2145+ :: Expression grp commons schemas params from ty
2146+ -- ^ value
2147+ -> WindowFunction grp commons schemas params from ty
2148+firstValue = unsafeWindowFunction1 "first_value"
2149+
2150+{- | returns value evaluated at the row that is the
2151+last row of the window frame
2152+-}
2153+lastValue
2154+ :: Expression grp commons schemas params from ty
2155+ -- ^ value
2156+ -> WindowFunction grp commons schemas params from ty
2157+lastValue = unsafeWindowFunction1 "last_value"
2158+
2159+{- | returns value evaluated at the row that is the nth
2160+row of the window frame (counting from 1); null if no such row
2161+-}
2162+nthValue
2163+ :: Expression grp commons schemas params from (nullity ty)
2164+ -- ^ value
2165+ -> Expression grp commons schemas params from ('NotNull 'PGint4)
2166+ -- ^ nth
2167+ -> WindowFunction grp commons schemas params from ('Null ty)
2168+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2169+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])