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