@@ -1,13 +1,14 @@
11{-|
22Module: Squeal.PostgreSQL.Expression
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
@@ -34,213 +35,357 @@ module Squeal.PostgreSQL.Expression
3435 ( -- * Expression
3536 Expression (..)
3637 , Expr
37− , type (-->)
38− , FunctionDB
39− , unsafeFunction
40− , function
41− , unsafeLeftOp
42− , leftOp
43− , unsafeRightOp
44− , rightOp
4538 , Operator
46− , OperatorDB
47− , unsafeBinaryOp
48− , binaryOp
49− , FunctionVar
50− , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
53− , unsafeFunctionN
54− , functionN
39+ , (:-->)
40+ , HasParameter (parameter)
41+ , param
42+ -- ** Null
43+ , null_
44+ , notNull
45+ , coalesce
46+ , fromNull
47+ , isNull
48+ , isNotNull
49+ , matchNull
50+ , nullIf
51+ -- ** Collections
52+ , array
53+ , cardinality
54+ , index
55+ , row
56+ , field
5557 , PGSubset (..)
56− , PGIntersect (..)
58+ -- ** Functions
59+ , unsafeBinaryOp
60+ , unsafeUnaryOpL
61+ , unsafeFunction
62+ , unsafeVariadicFunction
63+ , atan2_
64+ , cast
65+ , quot_
66+ , rem_
67+ , trunc
68+ , round_
69+ , ceiling_
70+ , greatest
71+ , least
72+ -- ** Conditions
73+ , true
74+ , false
75+ , not_
76+ , (.&&)
77+ , (.||)
78+ , Condition
79+ , caseWhenThenElse
80+ , ifThenElse
81+ , (.==)
82+ , (./=)
83+ , (.>=)
84+ , (.<)
85+ , (.<=)
86+ , (.>)
87+ , between
88+ , notBetween
89+ , betweenSymmetric
90+ , notBetweenSymmetric
91+ , isDistinctFrom
92+ , isNotDistinctFrom
93+ , isTrue
94+ , isNotTrue
95+ , isFalse
96+ , isNotFalse
97+ , isUnknown
98+ , isNotUnknown
99+ -- ** Time
100+ , currentDate
101+ , currentTime
102+ , currentTimestamp
103+ , localTime
104+ , localTimestamp
105+ , TimeOp (..)
106+ , makeDate
107+ , makeTime
108+ , makeTimestamp
109+ , makeTimestamptz
110+ -- ** Text
111+ , lower
112+ , upper
113+ , charLength
114+ , like
115+ , ilike
116+ -- ** Json
117+ -- *** Json and Jsonb operators
118+ , (.->)
119+ , (.->>)
120+ , (.#>)
121+ , (.#>>)
122+ -- *** Jsonb operators
123+ , (.?)
124+ , (.?|)
125+ , (.?&)
126+ , (.-.)
127+ , (#-.)
128+ -- *** Functions
129+ , jsonLit
130+ , jsonbLit
131+ , toJson
132+ , toJsonb
133+ , arrayToJson
134+ , rowToJson
135+ , jsonBuildArray
136+ , jsonbBuildArray
137+ , jsonBuildObject
138+ , jsonbBuildObject
139+ , jsonObject
140+ , jsonbObject
141+ , jsonZipObject
142+ , jsonbZipObject
143+ , jsonArrayLength
144+ , jsonbArrayLength
145+ , jsonExtractPath
146+ , jsonbExtractPath
147+ , jsonExtractPathAsText
148+ , jsonbExtractPathAsText
149+ , jsonTypeof
150+ , jsonbTypeof
151+ , jsonStripNulls
152+ , jsonbStripNulls
153+ , jsonbSet
154+ , jsonbInsert
155+ , jsonbPretty
156+ -- ** Text Search
157+ , (@@)
158+ , (.&)
159+ , (.|)
160+ , (.!)
161+ , (<->)
162+ , arrayToTSvector
163+ , tsvectorLength
164+ , numnode
165+ , plainToTSquery
166+ , phraseToTSquery
167+ , websearchToTSquery
168+ , queryTree
169+ , toTSquery
170+ , toTSvector
171+ -- ** Aggregation
172+ , Aggregate (..)
173+ , Distinction (..)
174+ , PGAvg
175+ -- * Window Functions
176+ , WindowDefinition (..)
177+ , partitionBy
178+ , WindowFunction (..)
179+ , rank
180+ , rowNumber
181+ , denseRank
182+ , percentRank
183+ , cumeDist
184+ , ntile
185+ , lag
186+ , lead
187+ , firstValue
188+ , lastValue
189+ , nthValue
190+ -- * Sorting
191+ , SortExpression (..)
192+ , OrderBy (..)
193+ -- * Types
194+ , TypeExpression (..)
195+ , PGTyped (..)
196+ , typedef
197+ , typetable
198+ , typeview
199+ , bool
200+ , int2
201+ , smallint
202+ , int4
203+ , int
204+ , integer
205+ , int8
206+ , bigint
207+ , numeric
208+ , float4
209+ , real
210+ , float8
211+ , doublePrecision
212+ , money
213+ , text
214+ , char
215+ , character
216+ , varchar
217+ , characterVarying
218+ , bytea
219+ , timestamp
220+ , timestampWithTimeZone
221+ , date
222+ , time
223+ , timeWithTimeZone
224+ , interval
225+ , uuid
226+ , inet
227+ , json
228+ , jsonb
229+ , vararray
230+ , fixarray
231+ , tsvector
232+ , tsquery
57233 -- * Re-export
58234 , (&)
235+ , NP (..)
236+ , (:*:) (..)
59237 , K (..)
60− , unK
61238 ) where
62239
63240import Control.Category
64241import Control.DeepSeq
65242import Data.ByteString (ByteString)
243+import Data.ByteString.Lazy (toStrict)
66244import Data.Function ((&))
67245import Data.Semigroup hiding (All)
246+import qualified Data.Aeson as JSON
68247import Data.String
248+import Data.Word
69249import Generics.SOP hiding (All, from)
250+import GHC.Generics ((:*:) (..))
70251import GHC.OverloadedLabels
71252import GHC.TypeLits
72253import Numeric
73254import Prelude hiding (id, (.))
74255
256+import qualified Data.ByteString as ByteString
75257import qualified GHC.Generics as GHC
258+import qualified Generics.SOP as SOP
76259
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
79260import Squeal.PostgreSQL.Render
80261import Squeal.PostgreSQL.Schema
81262
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85263{-----------------------------------------
86264column expressions
87265-----------------------------------------}
88266
89267{- | `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,
268+such as in the target list of the `Squeal.PostgreSQL.Query.select` command,
92269as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93270`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
271+or in search `Condition`s in a number of commands.
95272
96273The expression syntax allows the calculation of
97274values from primitive expression using arithmetic, logical,
98275and 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`.
113276-}
114277newtype Expression
115278 (outer :: FromType)
116− (commons :: FromType)
117279 (grp :: Grouping)
280+ (commons :: FromType)
118281 (schemas :: SchemasType)
119282 (params :: [NullityType])
120283 (from :: FromType)
121284 (ty :: NullityType)
122285 = UnsafeExpression { renderExpression :: ByteString }
123286 deriving (GHC.Generic,Show,Eq,Ord,NFData)
124−instance RenderSQL (Expression outer commons grp schemas params from ty) where
287+instance RenderSQL (Expression outer grp commons schemas params from ty) where
125288 renderSQL = renderExpression
126289
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.
133290type Expr x
134− = forall outer commons grp schemas params from
135− . Expression outer commons grp schemas params from x
136− -- ^ cannot reference aliases
291+ = forall outer grp commons schemas params from
292+ . Expression outer grp commons schemas params from x
137293
138−-- | A @RankNType@ for binary operators.
139294type Operator x1 x2 y
140− = forall outer commons grp schemas params from
141− . Expression outer commons grp schemas params from x1
142− -- ^ left input
143− -> Expression outer commons grp schemas params from x2
144− -- ^ right input
145− -> Expression outer commons grp schemas params from y
146− -- ^ output
147−
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
150− . Expression outer commons grp schemas params from x1
151− -- ^ left input
152− -> Expression outer commons grp schemas params from x2
153− -- ^ right input
154− -> Expression outer commons grp schemas params from y
155− -- ^ output
156−
157−-- | A @RankNType@ for functions with a single argument.
158−-- These could be either function calls or unary operators.
159−-- This is a subtype of the usual Haskell function type `Prelude.->`,
160−-- indeed a subcategory as it is closed under the usual
161−-- `Prelude..` and `Prelude.id`.
162−type (-->) x y
163− = forall outer commons grp schemas params from
164− . Expression outer commons grp schemas params from x
165− -- ^ input
166− -> Expression outer commons grp schemas params from y
167− -- ^ output
168−
169−type FunctionDB schemas x y
170− = forall outer commons grp params from
171− . Expression outer commons grp schemas params from x
172− -- ^ input
173− -> Expression outer commons grp schemas params from y
174− -- ^ output
175−
176−{- | A @RankNType@ for functions with a fixed-length list of heterogeneous arguments.
177−Use the `*:` operator to end your argument lists, like so.
178−
179−>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
180−fun(TRUE, FALSE, LOCALTIME, TRUE)
181−-}
182−type (--->) xs y
183− = forall outer commons grp schemas params from
184− . NP (Expression outer commons grp schemas params from) xs
185− -- ^ inputs
186− -> Expression outer commons grp schemas params from y
187− -- ^ output
188−
189−type FunctionNDB schemas xs y
190− = forall outer commons grp params from
191− . NP (Expression outer commons grp schemas params from) xs
192− -- ^ inputs
193− -> Expression outer commons grp schemas params from y
194− -- ^ output
195−
196−{- | A @RankNType@ for functions with a variable-length list of
197−homogeneous arguments and at least 1 more argument.
198−-}
199−type FunctionVar x0 x1 y
200− = forall outer commons grp schemas params from
201− . [Expression outer commons grp schemas params from x0]
202− -- ^ inputs
203− -> Expression outer commons grp schemas params from x1
204− -- ^ must have at least 1 input
205− -> Expression outer commons grp schemas params from y
206− -- ^ output
207−
208−{- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)
209−greatest(TRUE, NULL, FALSE)
210−-}
211−unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212−unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
295+ = forall outer grp commons schemas params from
296+ . Expression outer grp commons schemas params from x1
297+ -> Expression outer grp commons schemas params from x2
298+ -> Expression outer grp commons schemas params from y
299+
300+type (:-->) x y
301+ = forall outer grp commons schemas params from
302+ . Expression outer grp commons schemas params from x
303+ -> Expression outer grp commons schemas params from y
304+
305+type FunctionHet xs y
306+ = forall outer grp commons schemas params from
307+ . NP (Expression outer grp commons schemas params from) xs
308+ -> Expression outer grp commons schemas params from y
309+
310+type FunctionHom x y
311+ = forall outer grp commons schemas params from
312+ . [Expression outer grp commons schemas params from x]
313+ -> Expression outer grp commons schemas params from x
314+ -> Expression outer grp commons schemas params from y
315+
316+unsafeFunctionHom :: ByteString -> FunctionHom x y
317+unsafeFunctionHom fun xs x = UnsafeExpression $ fun <> parenthesized
213318 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
214319
320+{- | A `HasParameter` constraint is used to indicate a value that is
321+supplied externally to a SQL statement.
322+`Squeal.PostgreSQL.PQ.manipulateParams`,
323+`Squeal.PostgreSQL.PQ.queryParams` and
324+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
325+separately from the SQL command string, in which case `param`s are used to
326+refer to the out-of-line data values.
327+-}
328+class KnownNat n => HasParameter
329+ (n :: Nat)
330+ (params :: [NullityType])
331+ (ty :: NullityType)
332+ | n params -> ty where
333+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
334+ --
335+ -- >>> let expr = parameter @1 int4 :: Expression outer grp '[] schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
336+ -- >>> printSQL expr
337+ -- ($1 :: int4)
338+ parameter
339+ :: TypeExpression schemas ty
340+ -> Expression outer grp commons schemas params from ty
341+ parameter ty = UnsafeExpression $ parenthesized $
342+ "$" <> renderNat @n <+> "::"
343+ <+> renderSQL ty
344+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
345+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
346+ => HasParameter n (ty' : params) ty
347+
348+-- | `param` takes a `Nat` using type application and for basic types,
349+-- infers a `TypeExpression`.
350+--
351+-- >>> let expr = param @1 :: Expression outer grp commons schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
352+-- >>> printSQL expr
353+-- ($1 :: int4)
354+param
355+ :: forall n outer commons schemas params from grp ty
356+ . (PGTyped schemas ty, HasParameter n params ty)
357+ => Expression outer grp commons schemas params from ty -- ^ param
358+param = parameter @n (pgtype @schemas)
359+
215360instance (HasUnique tab (Join outer from) row, Has col row ty)
216− => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
361+ => IsLabel col (Expression outer 'Ungrouped commons schemas params from ty) where
217362 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
218363instance (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
364+ => IsLabel col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
220365 fromLabel = fromLabel @col :* Nil
221366instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
222367 => IsLabel col
223− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
368+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
224369 fromLabel = fromLabel @col `As` Alias
225370instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
226371 => IsLabel col
227− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
372+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
228373 fromLabel = fromLabel @col :* Nil
229374
230375instance (Has tab (Join outer from) row, Has col row ty)
231− => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where
376+ => IsQualified tab col (Expression outer 'Ungrouped commons schemas params from ty) where
232377 tab ! col = UnsafeExpression $
233378 renderSQL tab <> "." <> renderSQL col
234379instance (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
380+ => IsQualified tab col (NP (Expression outer 'Ungrouped commons schemas params from) tys) where
236381 tab ! col = tab ! col :* Nil
237382instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))
238383 => IsQualified tab col
239− (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where
384+ (Aliased (Expression outer 'Ungrouped commons schemas params from) column) where
240385 tab ! col = tab ! col `As` col
241386instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])
242387 => IsQualified tab col
243− (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where
388+ (NP (Aliased (Expression outer 'Ungrouped commons schemas params from)) columns) where
244389 tab ! col = tab ! col :* Nil
245390
246391instance
@@ -248,7 +393,7 @@ instance
248393 , Has col row ty
249394 , GroupedBy tab col bys
250395 ) => IsLabel col
251− (Expression outer commons ('Grouped bys) schemas params from ty) where
396+ (Expression outer ('Grouped bys) commons schemas params from ty) where
252397 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
253398instance
254399 ( HasUnique tab (Join outer from) row
@@ -256,7 +401,7 @@ instance
256401 , GroupedBy tab col bys
257402 , tys ~ '[ty]
258403 ) => IsLabel col
259− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
404+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
260405 fromLabel = fromLabel @col :* Nil
261406instance
262407 ( HasUnique tab (Join outer from) row
@@ -264,7 +409,7 @@ instance
264409 , GroupedBy tab col bys
265410 , column ~ (col ::: ty)
266411 ) => IsLabel col
267− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
412+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
268413 fromLabel = fromLabel @col `As` Alias
269414instance
270415 ( HasUnique tab (Join outer from) row
@@ -272,7 +417,7 @@ instance
272417 , GroupedBy tab col bys
273418 , columns ~ '[col ::: ty]
274419 ) => IsLabel col
275− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
420+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
276421 fromLabel = fromLabel @col :* Nil
277422
278423instance
@@ -280,7 +425,7 @@ instance
280425 , Has col row ty
281426 , GroupedBy tab col bys
282427 ) => IsQualified tab col
283− (Expression outer commons ('Grouped bys) schemas params from ty) where
428+ (Expression outer ('Grouped bys) commons schemas params from ty) where
284429 tab ! col = UnsafeExpression $
285430 renderSQL tab <> "." <> renderSQL col
286431instance
@@ -289,7 +434,7 @@ instance
289434 , GroupedBy tab col bys
290435 , tys ~ '[ty]
291436 ) => IsQualified tab col
292− (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where
437+ (NP (Expression outer ('Grouped bys) commons schemas params from) tys) where
293438 tab ! col = tab ! col :* Nil
294439instance
295440 ( Has tab (Join outer from) row
@@ -297,7 +442,7 @@ instance
297442 , GroupedBy tab col bys
298443 , column ~ (col ::: ty)
299444 ) => IsQualified tab col
300− (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where
445+ (Aliased (Expression outer ('Grouped bys) commons schemas params from) column) where
301446 tab ! col = tab ! col `As` col
302447instance
303448 ( Has tab (Join outer from) row
@@ -305,78 +450,223 @@ instance
305450 , GroupedBy tab col bys
306451 , columns ~ '[col ::: ty]
307452 ) => IsQualified tab col
308− (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
453+ (NP (Aliased (Expression outer ('Grouped bys) commons schemas params from)) columns) where
309454 tab ! col = tab ! col :* Nil
310455
456+-- | analagous to `Nothing`
457+--
458+-- >>> printSQL null_
459+-- NULL
460+null_ :: Expr ('Null ty)
461+null_ = UnsafeExpression "NULL"
462+
463+-- | analagous to `Just`
464+--
465+-- >>> printSQL $ notNull true
466+-- TRUE
467+notNull :: 'NotNull ty :--> 'Null ty
468+notNull = UnsafeExpression . renderSQL
469+
470+-- | return the leftmost value which is not NULL
471+--
472+-- >>> printSQL $ coalesce [null_, true] false
473+-- COALESCE(NULL, TRUE, FALSE)
474+coalesce
475+ :: [Expression outer grp commons schemas params from ('Null ty)]
476+ -- ^ @NULL@s may be present
477+ -> Expression outer grp commons schemas params from ('NotNull ty)
478+ -- ^ @NULL@ is absent
479+ -> Expression outer grp commons schemas params from ('NotNull ty)
480+coalesce nullxs notNullx = UnsafeExpression $
481+ "COALESCE" <> parenthesized (commaSeparated
482+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
483+
484+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
485+--
486+-- >>> printSQL $ fromNull true null_
487+-- COALESCE(NULL, TRUE)
488+fromNull
489+ :: Expression outer grp commons schemas params from ('NotNull ty)
490+ -- ^ what to convert @NULL@ to
491+ -> Expression outer grp commons schemas params from ('Null ty)
492+ -> Expression outer grp commons schemas params from ('NotNull ty)
493+fromNull notNullx nullx = coalesce [nullx] notNullx
494+
495+-- | >>> printSQL $ null_ & isNull
496+-- NULL IS NULL
497+isNull
498+ :: Expression outer grp commons schemas params from ('Null ty)
499+ -- ^ possibly @NULL@
500+ -> Condition outer grp commons schemas params from
501+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
502+
503+-- | >>> printSQL $ null_ & isNotNull
504+-- NULL IS NOT NULL
505+isNotNull
506+ :: Expression outer grp commons schemas params from ('Null ty)
507+ -- ^ possibly @NULL@
508+ -> Condition outer grp commons schemas params from
509+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
510+
511+-- | analagous to `maybe` using @IS NULL@
512+--
513+-- >>> printSQL $ matchNull true not_ null_
514+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
515+matchNull
516+ :: Expression outer grp commons schemas params from (nullty)
517+ -- ^ what to convert @NULL@ to
518+ -> ( Expression outer grp commons schemas params from ('NotNull ty)
519+ -> Expression outer grp commons schemas params from (nullty) )
520+ -- ^ function to perform when @NULL@ is absent
521+ -> Expression outer grp commons schemas params from ('Null ty)
522+ -> Expression outer grp commons schemas params from (nullty)
523+matchNull y f x = ifThenElse (isNull x) y
524+ (f (UnsafeExpression (renderSQL x)))
525+
526+{-| right inverse to `fromNull`, if its arguments are equal then
527+`nullIf` gives @NULL@.
528+
529+>>> :set -XTypeApplications -XDataKinds
530+>>> let expr = nullIf false (param @1) :: Expression outer grp commons schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
531+>>> printSQL expr
532+NULL IF (FALSE, ($1 :: bool))
533+-}
534+nullIf
535+ :: Expression outer grp commons schemas params from ('NotNull ty)
536+ -- ^ @NULL@ is absent
537+ -> Expression outer grp commons schemas params from ('NotNull ty)
538+ -- ^ @NULL@ is absent
539+ -> Expression outer grp commons schemas params from ('Null ty)
540+nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
541+ (renderSQL x <> ", " <> renderSQL y)
542+
543+-- | >>> printSQL $ array [null_, false, true]
544+-- ARRAY[NULL, FALSE, TRUE]
545+array
546+ :: [Expression outer grp commons schemas params from ty]
547+ -- ^ array elements
548+ -> Expression outer grp commons schemas params from (null ('PGvararray ty))
549+array xs = UnsafeExpression $
550+ "ARRAY[" <> commaSeparated (renderSQL <$> xs) <> "]"
551+
552+-- | >>> printSQL $ cardinality (array [null_, false, true])
553+-- cardinality(ARRAY[NULL, FALSE, TRUE])
554+cardinality :: null ('PGvararray ty) :--> null 'PGint8
555+cardinality = unsafeFunction "cardinality"
556+
557+-- | >>> printSQL $ array [null_, false, true] & index 2
558+-- (ARRAY[NULL, FALSE, TRUE])[2]
559+index
560+ :: Word64 -- ^ index
561+ -> null ('PGvararray ty) :--> NullifyType ty
562+index n expr = UnsafeExpression $
563+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
564+
311565instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312− (Expression outer commons grp schemas params from (null ('PGenum labels))) where
566+ (Expression outer grp commons schemas params from (null ('PGenum labels))) where
313567 label = UnsafeExpression $ renderSQL (PGlabel @label)
314568
569+-- | A row constructor is an expression that builds a row value
570+-- (also called a composite value) using values for its member fields.
571+--
572+-- >>> :{
573+-- type Complex = 'PGcomposite
574+-- '[ "real" ::: 'NotNull 'PGfloat8
575+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
576+-- :}
577+--
578+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp commons schemas params from ('NotNull Complex)
579+-- >>> printSQL i
580+-- ROW(0, 1)
581+row
582+ :: SListI row
583+ => NP (Aliased (Expression outer grp commons schemas params from)) row
584+ -- ^ zero or more expressions for the row field values
585+ -> Expression outer grp commons schemas params from (null ('PGcomposite row))
586+row exprs = UnsafeExpression $ "ROW" <> parenthesized
587+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
588+
589+-- | >>> :{
590+-- type Complex = 'PGcomposite
591+-- '[ "real" ::: 'NotNull 'PGfloat8
592+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
593+-- type Schema = '["complex" ::: 'Typedef Complex]
594+-- :}
595+--
596+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer grp '[] (Public Schema) from params ('NotNull Complex)
597+-- >>> printSQL $ i & field #complex #imaginary
598+-- (ROW(0, 1)::"complex")."imaginary"
599+field
600+ :: ( Has sch schemas schema
601+ , Has tydef schema ('Typedef ('PGcomposite row))
602+ , Has field row ty)
603+ => QualifiedAlias sch tydef -- ^ row type
604+ -> Alias field -- ^ field name
605+ -> Expression outer grp commons schemas params from ('NotNull ('PGcomposite row))
606+ -> Expression outer grp commons schemas params from ty
607+field td fld expr = UnsafeExpression $
608+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
609+ <> "." <> renderSQL fld
610+
611+instance Semigroup
612+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
613+ (<>) = unsafeBinaryOp "||"
614+
615+instance Monoid
616+ (Expression outer grp commons schemas params from (null ('PGvararray ty))) where
617+ mempty = array []
618+ mappend = (<>)
619+
620+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer grp commons schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
621+-- >>> printSQL expr
622+-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
623+greatest :: FunctionHom ty ty
624+greatest = unsafeFunctionHom "GREATEST"
625+
626+-- | >>> printSQL $ least [null_] currentTimestamp
627+-- LEAST(NULL, CURRENT_TIMESTAMP)
628+least :: FunctionHom ty ty
629+least = unsafeFunctionHom "LEAST"
630+
315631-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316632-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
633+unsafeBinaryOp :: ByteString {- ^ operator -} -> Operator ty0 ty1 ty2
318634unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319635 renderSQL x <+> op <+> renderSQL y
320636
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
637+-- | >>> printSQL $ unsafeUnaryOpL "NOT" true
329638-- (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
639+unsafeUnaryOpL :: ByteString {- ^ operator -} -> x :--> y
640+unsafeUnaryOpL op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
641+
642+unsafeUnaryOpR :: ByteString {- ^ operator -} -> x :--> y
643+unsafeUnaryOpR op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
351644
352645-- | >>> printSQL $ unsafeFunction "f" true
353646-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
647+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355648unsafeFunction fun x = UnsafeExpression $
356649 fun <> parenthesized (renderSQL x)
357650
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 $
651+unsafeFunctionHet
652+ :: SListI xs
653+ => ByteString {- ^ function -}
654+ -> FunctionHet xs y
655+unsafeFunctionHet fun xs = UnsafeExpression $
368656 fun <> parenthesized (renderCommaSeparated renderSQL xs)
369657
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
658+-- | Helper for defining variadic functions.
659+unsafeVariadicFunction
660+ :: SListI elems
661+ => ByteString
662+ -- ^ function
663+ -> NP (Expression outer grp commons schemas params from) elems
664+ -> Expression outer grp commons schemas params from ret
665+unsafeVariadicFunction fun x = UnsafeExpression $
666+ fun <> parenthesized (commaSeparated (hcollapse (hmap (K . renderSQL) x)))
377667
378668instance ty `In` PGNum
379− => Num (Expression outer commons grp schemas params from (null ty)) where
669+ => Num (Expression outer grp commons schemas params from (null ty)) where
380670 (+) = unsafeBinaryOp "+"
381671 (-) = unsafeBinaryOp "-"
382672 (*) = unsafeBinaryOp "*"
@@ -388,7 +678,7 @@ instance ty `In` PGNum
388678 . show
389679
390680instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
391− (Expression outer commons grp schemas params from (null ty)) where
681+ (Expression outer grp commons schemas params from (null ty)) where
392682 (/) = unsafeBinaryOp "/"
393683 fromRational
394684 = UnsafeExpression
@@ -398,7 +688,7 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Fractional
398688 . fromRat @Double
399689
400690instance (ty `In` PGNum, ty `In` PGFloating) => Floating
401− (Expression outer commons grp schemas params from (null ty)) where
691+ (Expression outer grp commons schemas params from (null ty)) where
402692 pi = UnsafeExpression "pi()"
403693 exp = unsafeFunction "exp"
404694 log = unsafeFunction "ln"
@@ -419,54 +709,1764 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419709 acosh x = log (x + sqrt (x*x - 1))
420710 atanh x = log ((1 + x) / (1 - x)) / 2
421711
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)
712+-- | >>> :{
713+-- let
714+-- expression :: Expr (null 'PGfloat4)
715+-- expression = atan2_ (pi *: 2)
716+-- in printSQL expression
717+-- :}
718+-- atan2(pi(), 2)
719+atan2_
720+ :: float `In` PGFloating
721+ => FunctionHet '[ null float, null float] (null float)
722+atan2_ = unsafeFunctionHet "atan2"
723+
724+-- When a `cast` is applied to an `Expression` of a known type, it
725+-- represents a run-time type conversion. The cast will succeed only if a
726+-- suitable type conversion operation has been defined.
727+--
728+-- | >>> printSQL $ true & cast int4
729+-- (TRUE :: int4)
730+cast
731+ :: TypeExpression schemas ty1
732+ -- ^ type to cast as
733+ -> Expression outer grp commons schemas params from ty0
734+ -- ^ value to convert
735+ -> Expression outer grp commons schemas params from ty1
736+cast ty x = UnsafeExpression $ parenthesized $
737+ renderSQL x <+> "::" <+> renderSQL ty
738+
739+-- | integer division, truncates the result
740+--
741+-- >>> :{
742+-- let
743+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
744+-- expression = 5 `quot_` 2
745+-- in printSQL expression
746+-- :}
747+-- (5 / 2)
748+quot_
749+ :: int `In` PGIntegral
750+ => Operator (null int) (null int) (null int)
751+quot_ = unsafeBinaryOp "/"
752+
753+-- | remainder upon integer division
754+--
755+-- >>> :{
756+-- let
757+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
758+-- expression = 5 `rem_` 2
759+-- in printSQL expression
760+-- :}
761+-- (5 % 2)
762+rem_
763+ :: int `In` PGIntegral
764+ => Operator (null int) (null int) (null int)
765+rem_ = unsafeBinaryOp "%"
766+
767+-- | >>> :{
768+-- let
769+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
770+-- expression = trunc pi
771+-- in printSQL expression
772+-- :}
773+-- trunc(pi())
774+trunc :: frac `In` PGFloating => null frac :--> null frac
775+trunc = unsafeFunction "trunc"
776+
777+-- | >>> :{
778+-- let
779+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
780+-- expression = round_ pi
781+-- in printSQL expression
782+-- :}
783+-- round(pi())
784+round_ :: frac `In` PGFloating => null frac :--> null frac
785+round_ = unsafeFunction "round"
786+
787+-- | >>> :{
788+-- let
789+-- expression :: Expression outer grp commons schemas params from (null 'PGfloat4)
790+-- expression = ceiling_ pi
791+-- in printSQL expression
792+-- :}
793+-- ceiling(pi())
794+ceiling_ :: frac `In` PGFloating => null frac :--> null frac
795+ceiling_ = unsafeFunction "ceiling"
796+
797+-- | A `Condition` is an `Expression`, which can evaluate
798+-- to `true`, `false` or `null_`. This is because SQL uses
799+-- a three valued logic.
800+type Condition outer grp commons schemas params from =
801+ Expression outer grp commons schemas params from ('Null 'PGbool)
802+
803+-- | >>> printSQL true
804+-- TRUE
805+true :: Expr (null 'PGbool)
806+true = UnsafeExpression "TRUE"
432807
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)
808+-- | >>> printSQL false
809+-- FALSE
810+false :: Expr (null 'PGbool)
811+false = UnsafeExpression "FALSE"
812+
813+-- | >>> printSQL $ not_ true
814+-- (NOT TRUE)
815+not_ :: null 'PGbool :--> null 'PGbool
816+not_ = unsafeUnaryOpL "NOT"
817+
818+-- | >>> printSQL $ true .&& false
819+-- (TRUE AND FALSE)
820+(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
821+infixr 3 .&&
822+(.&&) = unsafeBinaryOp "AND"
823+
824+-- | >>> printSQL $ true .|| false
825+-- (TRUE OR FALSE)
826+(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
827+infixr 2 .||
828+(.||) = unsafeBinaryOp "OR"
829+
830+-- | >>> :{
831+-- let
832+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
833+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
834+-- in printSQL expression
835+-- :}
836+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
837+caseWhenThenElse
838+ :: [ ( Condition outer grp commons schemas params from
839+ , Expression outer grp commons schemas params from ty
840+ ) ]
841+ -- ^ whens and thens
842+ -> Expression outer grp commons schemas params from ty
843+ -- ^ else
844+ -> Expression outer grp commons schemas params from ty
845+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
846+ [ "CASE"
847+ , mconcat
848+ [ mconcat
849+ [ " WHEN ", renderSQL when_
850+ , " THEN ", renderSQL then_
851+ ]
852+ | (when_,then_) <- whenThens
853+ ]
854+ , " ELSE ", renderSQL else_
855+ , " END"
856+ ]
857+
858+-- | >>> :{
859+-- let
860+-- expression :: Expression outer grp commons schemas params from (null 'PGint2)
861+-- expression = ifThenElse true 1 0
862+-- in printSQL expression
863+-- :}
864+-- CASE WHEN TRUE THEN 1 ELSE 0 END
865+ifThenElse
866+ :: Condition outer grp commons schemas params from
867+ -> Expression outer grp commons schemas params from ty -- ^ then
868+ -> Expression outer grp commons schemas params from ty -- ^ else
869+ -> Expression outer grp commons schemas params from ty
870+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
871+
872+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
873+-- will produce @NULL@s if one of their arguments is @NULL@.
874+--
875+-- >>> printSQL $ true .== null_
876+-- (TRUE = NULL)
877+(.==) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
878+(.==) = unsafeBinaryOp "="
879+infix 4 .==
880+
881+-- | >>> printSQL $ true ./= null_
882+-- (TRUE <> NULL)
883+(./=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
884+(./=) = unsafeBinaryOp "<>"
885+infix 4 ./=
886+
887+-- | >>> printSQL $ true .>= null_
888+-- (TRUE >= NULL)
889+(.>=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
890+(.>=) = unsafeBinaryOp ">="
891+infix 4 .>=
892+
893+-- | >>> printSQL $ true .< null_
894+-- (TRUE < NULL)
895+(.<) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
896+(.<) = unsafeBinaryOp "<"
897+infix 4 .<
898+
899+-- | >>> printSQL $ true .<= null_
900+-- (TRUE <= NULL)
901+(.<=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
902+(.<=) = unsafeBinaryOp "<="
903+infix 4 .<=
904+
905+-- | >>> printSQL $ true .> null_
906+-- (TRUE > NULL)
907+(.>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
908+(.>) = unsafeBinaryOp ">"
909+infix 4 .>
910+
911+{- | between
912+>>> printSQL $ true `between` (null_, false)
913+TRUE BETWEEN NULL AND FALSE
914+-}
915+between
916+ :: Expression outer grp commons schemas params from (null ty)
917+ -> ( Expression outer grp commons schemas params from (null ty)
918+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
919+ -> Condition outer grp commons schemas params from
920+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
921+ <+> renderSQL x <+> "AND" <+> renderSQL y
922+
923+{- | not between
924+>>> printSQL $ true `notBetween` (null_, false)
925+TRUE NOT BETWEEN NULL AND FALSE
926+-}
927+notBetween
928+ :: Expression outer grp commons schemas params from (null ty)
929+ -> ( Expression outer grp commons schemas params from (null ty)
930+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
931+ -> Condition outer grp commons schemas params from
932+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
933+ <+> renderSQL x <+> "AND" <+> renderSQL y
934+
935+{- | between, after sorting the comparison values
936+>>> printSQL $ true `betweenSymmetric` (null_, false)
937+TRUE BETWEEN SYMMETRIC NULL AND FALSE
938+-}
939+betweenSymmetric
940+ :: Expression outer grp commons schemas params from (null ty)
941+ -> ( Expression outer grp commons schemas params from (null ty)
942+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
943+ -> Condition outer grp commons schemas params from
944+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
945+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
946+
947+{- | not between, after sorting the comparison values
948+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
949+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
950+-}
951+notBetweenSymmetric
952+ :: Expression outer grp commons schemas params from (null ty)
953+ -> ( Expression outer grp commons schemas params from (null ty)
954+ , Expression outer grp commons schemas params from (null ty) ) -- ^ bounds
955+ -> Condition outer grp commons schemas params from
956+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
957+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
958+
959+{- | not equal, treating null like an ordinary value
960+>>> printSQL $ true `isDistinctFrom` null_
961+(TRUE IS DISTINCT FROM NULL)
962+-}
963+isDistinctFrom :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
964+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
965+
966+{- | equal, treating null like an ordinary value
967+>>> printSQL $ true `isNotDistinctFrom` null_
968+(TRUE IS NOT DISTINCT FROM NULL)
969+-}
970+isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ('NotNull 'PGbool)
971+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
972+
973+{- | is true
974+>>> printSQL $ true & isTrue
975+(TRUE IS TRUE)
976+-}
977+isTrue :: null 'PGbool :--> 'NotNull 'PGbool
978+isTrue = unsafeUnaryOpR "IS TRUE"
979+
980+{- | is false or unknown
981+>>> printSQL $ true & isNotTrue
982+(TRUE IS NOT TRUE)
983+-}
984+isNotTrue :: null 'PGbool :--> 'NotNull 'PGbool
985+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
986+
987+{- | is false
988+>>> printSQL $ true & isFalse
989+(TRUE IS FALSE)
990+-}
991+isFalse :: null 'PGbool :--> 'NotNull 'PGbool
992+isFalse = unsafeUnaryOpR "IS FALSE"
993+
994+{- | is true or unknown
995+>>> printSQL $ true & isNotFalse
996+(TRUE IS NOT FALSE)
997+-}
998+isNotFalse :: null 'PGbool :--> 'NotNull 'PGbool
999+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1000+
1001+{- | is unknown
1002+>>> printSQL $ true & isUnknown
1003+(TRUE IS UNKNOWN)
1004+-}
1005+isUnknown :: null 'PGbool :--> 'NotNull 'PGbool
1006+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1007+
1008+{- | is true or false
1009+>>> printSQL $ true & isNotUnknown
1010+(TRUE IS NOT UNKNOWN)
1011+-}
1012+isNotUnknown :: null 'PGbool :--> 'NotNull 'PGbool
1013+isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"
1014+
1015+-- | >>> printSQL currentDate
1016+-- CURRENT_DATE
1017+currentDate :: Expr (null 'PGdate)
1018+currentDate = UnsafeExpression "CURRENT_DATE"
1019+
1020+-- | >>> printSQL currentTime
1021+-- CURRENT_TIME
1022+currentTime :: Expr (null 'PGtimetz)
1023+currentTime = UnsafeExpression "CURRENT_TIME"
1024+
1025+-- | >>> printSQL currentTimestamp
1026+-- CURRENT_TIMESTAMP
1027+currentTimestamp :: Expr (null 'PGtimestamptz)
1028+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1029+
1030+-- | >>> printSQL localTime
1031+-- LOCALTIME
1032+localTime :: Expr (null 'PGtime)
1033+localTime = UnsafeExpression "LOCALTIME"
1034+
1035+-- | >>> printSQL localTimestamp
1036+-- LOCALTIMESTAMP
1037+localTimestamp :: Expr (null 'PGtimestamp)
1038+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1039+
1040+{-----------------------------------------
1041+text
1042+-----------------------------------------}
1043+
1044+escape :: Char -> String
1045+escape = \case
1046+ '\NUL' -> "\\0"
1047+ '\'' -> "''"
1048+ '"' -> "\\\""
1049+ '\b' -> "\\b"
1050+ '\n' -> "\\n"
1051+ '\r' -> "\\r"
1052+ '\t' -> "\\t"
1053+ '\\' -> "\\\\"
1054+ c -> [c]
4381055
4391056instance IsString
440− (Expression outer commons grp schemas params from (null 'PGtext)) where
1057+ (Expression outer grp commons schemas params from (null 'PGtext)) where
4411058 fromString str = UnsafeExpression $
4421059 "E\'" <> fromString (escape =<< str) <> "\'"
4431060instance IsString
444− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1061+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
1062+ fromString str = cast tsvector . UnsafeExpression $
4461063 "E\'" <> fromString (escape =<< str) <> "\'"
4471064instance IsString
448− (Expression outer commons grp schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1065+ (Expression outer grp commons schemas params from (null 'PGtsquery)) where
1066+ fromString str = cast tsquery . UnsafeExpression $
4501067 "E\'" <> fromString (escape =<< str) <> "\'"
4511068
4521069instance Semigroup
453− (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
1070+ (Expression outer grp commons schemas params from (null 'PGtext)) where
4541071 (<>) = unsafeBinaryOp "||"
4551072instance 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
1073+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
4631074 (<>) = unsafeBinaryOp "||"
4641075
4651076instance Monoid
466− (Expression outer commons grp schemas params from (null 'PGtext)) where
1077+ (Expression outer grp commons schemas params from (null 'PGtext)) where
4671078 mempty = fromString ""
4681079 mappend = (<>)
4691080instance Monoid
470− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
1081+ (Expression outer grp commons schemas params from (null 'PGtsvector)) where
4711082 mempty = fromString ""
4721083 mappend = (<>)
1084+
1085+-- | >>> printSQL $ lower "ARRRGGG"
1086+-- lower(E'ARRRGGG')
1087+lower :: null 'PGtext :--> null 'PGtext
1088+lower = unsafeFunction "lower"
1089+
1090+-- | >>> printSQL $ upper "eeee"
1091+-- upper(E'eeee')
1092+upper :: null 'PGtext :--> null 'PGtext
1093+upper = unsafeFunction "upper"
1094+
1095+-- | >>> printSQL $ charLength "four"
1096+-- char_length(E'four')
1097+charLength :: null 'PGtext :--> null 'PGint4
1098+charLength = unsafeFunction "char_length"
1099+
1100+-- | The `like` expression returns true if the @string@ matches
1101+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1102+-- or underscores, then the pattern only represents the string itself;
1103+-- in that case `like` acts like the equals operator. An underscore (_)
1104+-- in pattern stands for (matches) any single character; a percent sign (%)
1105+-- matches any sequence of zero or more characters.
1106+--
1107+-- >>> printSQL $ "abc" `like` "a%"
1108+-- (E'abc' LIKE E'a%')
1109+like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1110+like = unsafeBinaryOp "LIKE"
1111+
1112+-- | The key word ILIKE can be used instead of LIKE to make the
1113+-- match case-insensitive according to the active locale.
1114+--
1115+-- >>> printSQL $ "abc" `ilike` "a%"
1116+-- (E'abc' ILIKE E'a%')
1117+ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1118+ilike = unsafeBinaryOp "ILIKE"
1119+
1120+{-----------------------------------------
1121+ -- json and jsonb support
1122+
1123+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1124+comments lifted directly from this page.
1125+
1126+Table 9.44: json and jsonb operators
1127+-----------------------------------------}
1128+
1129+-- | Get JSON value (object field or array element) at a key.
1130+(.->)
1131+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1132+ => Operator (null json) (null key) ('Null json)
1133+infixl 8 .->
1134+(.->) = unsafeBinaryOp "->"
1135+
1136+-- | Get JSON value (object field or array element) at a key, as text.
1137+(.->>)
1138+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1139+ => Operator (null json) (null key) ('Null 'PGtext)
1140+infixl 8 .->>
1141+(.->>) = unsafeBinaryOp "->>"
1142+
1143+-- | Get JSON value at a specified path.
1144+(.#>)
1145+ :: (json `In` PGJsonType, PGTextArray "(.#>)" path)
1146+ => Operator (null json) (null path) ('Null json)
1147+infixl 8 .#>
1148+(.#>) = unsafeBinaryOp "#>"
1149+
1150+-- | Get JSON value at a specified path as text.
1151+(.#>>)
1152+ :: (json `In` PGJsonType, PGTextArray "(.#>>)" path)
1153+ => Operator (null json) (null path) ('Null 'PGtext)
1154+infixl 8 .#>>
1155+(.#>>) = unsafeBinaryOp "#>>"
1156+
1157+-- Additional jsonb operators
1158+
1159+class PGSubset container where
1160+ (@>) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1161+ (@>) = unsafeBinaryOp "@>"
1162+ (<@) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1163+ (<@) = unsafeBinaryOp "<@"
1164+instance PGSubset 'PGjsonb
1165+instance PGSubset 'PGtsquery
1166+instance PGSubset ('PGvararray ty)
1167+
1168+-- | Does the string exist as a top-level key within the JSON value?
1169+(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ('Null 'PGbool)
1170+infixl 9 .?
1171+(.?) = unsafeBinaryOp "?"
1172+
1173+-- | Do any of these array strings exist as top-level keys?
1174+(.?|) :: Operator
1175+ (null 'PGjsonb)
1176+ (null ('PGvararray ('NotNull 'PGtext)))
1177+ ('Null 'PGbool)
1178+infixl 9 .?|
1179+(.?|) = unsafeBinaryOp "?|"
1180+
1181+-- | Do all of these array strings exist as top-level keys?
1182+(.?&) :: Operator
1183+ (null 'PGjsonb)
1184+ (null ('PGvararray ('NotNull 'PGtext)))
1185+ ('Null 'PGbool)
1186+infixl 9 .?&
1187+(.?&) = unsafeBinaryOp "?&"
1188+
1189+-- | Concatenate two jsonb values into a new jsonb value.
1190+instance Semigroup
1191+ (Expression outer grp commons schemas params from (null 'PGjsonb)) where
1192+ (<>) = unsafeBinaryOp "||"
1193+
1194+-- | Delete a key or keys from a JSON object, or remove an array element.
1195+--
1196+-- If the right operand is..
1197+--
1198+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1199+-- are matched based on their key value.
1200+--
1201+-- @ text[] @: Delete multiple key/value pairs or string elements
1202+-- from left operand. Key/value pairs are matched based on their key value.
1203+--
1204+-- @ integer @: Delete the array element with specified index (Negative integers
1205+-- count from the end). Throws an error if top level container is not an array.
1206+(.-.)
1207+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1208+ => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
1209+infixl 6 .-.
1210+(.-.) = unsafeBinaryOp "-"
1211+
1212+-- | Delete the field or element with specified path (for JSON arrays, negative
1213+-- integers count from the end)
1214+(#-.)
1215+ :: PGTextArray "(#-.)" arrayty
1216+ => Operator (null 'PGjsonb) (null arrayty)(null 'PGjsonb)
1217+infixl 6 #-.
1218+(#-.) = unsafeBinaryOp "#-"
1219+
1220+{-----------------------------------------
1221+Table 9.45: JSON creation functions
1222+-----------------------------------------}
1223+
1224+-- | Literal binary JSON
1225+jsonbLit :: JSON.ToJSON x => x -> Expr (null 'PGjsonb)
1226+jsonbLit = cast jsonb . UnsafeExpression
1227+ . singleQuotedUtf8 . toStrict . JSON.encode
1228+
1229+-- | Literal JSON
1230+jsonLit :: JSON.ToJSON x => x -> Expr (null 'PGjson)
1231+jsonLit = cast json . UnsafeExpression
1232+ . singleQuotedUtf8 . toStrict . JSON.encode
1233+
1234+-- | Returns the value as json. Arrays and composites are converted
1235+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1236+-- type to json, the cast function will be used to perform the conversion;
1237+-- otherwise, a scalar value is produced. For any scalar type other than a
1238+-- number, a Boolean, or a null value, the text representation will be used, in
1239+-- such a fashion that it is a valid json value.
1240+toJson :: null ty :--> null 'PGjson
1241+toJson = unsafeFunction "to_json"
1242+
1243+-- | Returns the value as jsonb. Arrays and composites are converted
1244+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1245+-- type to json, the cast function will be used to perform the conversion;
1246+-- otherwise, a scalar value is produced. For any scalar type other than a
1247+-- number, a Boolean, or a null value, the text representation will be used, in
1248+-- such a fashion that it is a valid jsonb value.
1249+toJsonb :: null ty :--> null 'PGjsonb
1250+toJsonb = unsafeFunction "to_jsonb"
1251+
1252+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1253+-- becomes a JSON array of arrays.
1254+arrayToJson
1255+ :: PGArray "arrayToJson" arr
1256+ => null arr :--> null 'PGjson
1257+arrayToJson = unsafeFunction "array_to_json"
1258+
1259+-- | Returns the row as a JSON object.
1260+rowToJson :: null ('PGcomposite ty) :--> null 'PGjson
1261+rowToJson = unsafeFunction "row_to_json"
1262+
1263+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1264+-- argument list.
1265+jsonBuildArray
1266+ :: SListI elems
1267+ => NP (Expression outer grp commons schemas params from) elems
1268+ -> Expression outer grp commons schemas params from (null 'PGjson)
1269+jsonBuildArray = unsafeVariadicFunction "json_build_array"
1270+
1271+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1272+-- variadic argument list.
1273+jsonbBuildArray
1274+ :: SListI elems
1275+ => NP (Expression outer grp commons schemas params from) elems
1276+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1277+jsonbBuildArray = unsafeVariadicFunction "jsonb_build_array"
1278+
1279+unsafeRowFunction
1280+ :: SOP.SListI elems
1281+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1282+ -> [ByteString]
1283+unsafeRowFunction =
1284+ (`appEndo` []) . hcfoldMap (Proxy :: SOP.Proxy SOP.Top)
1285+ (\(col `As` name) -> Endo $ \xs ->
1286+ renderAliasString name : renderSQL col : xs)
1287+ where
1288+ renderAliasString :: KnownSymbol alias => Alias alias -> ByteString
1289+ renderAliasString = singleQuotedText . fromString . symbolVal
1290+
1291+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1292+-- argument list. The elements of the argument list must alternate between text
1293+-- and values.
1294+jsonBuildObject
1295+ :: SOP.SListI elems
1296+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1297+ -> Expression outer grp commons schemas params from (null 'PGjson)
1298+jsonBuildObject
1299+ = unsafeFunction "json_build_object"
1300+ . UnsafeExpression
1301+ . commaSeparated
1302+ . unsafeRowFunction
1303+
1304+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1305+-- variadic argument list. The elements of the argument list must alternate
1306+-- between text and values.
1307+jsonbBuildObject
1308+ :: SOP.SListI elems
1309+ => NP (Aliased (Expression outer grp commons schemas params from)) elems
1310+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1311+jsonbBuildObject
1312+ = unsafeFunction "jsonb_build_object"
1313+ . UnsafeExpression
1314+ . commaSeparated
1315+ . unsafeRowFunction
1316+
1317+-- | Builds a JSON object out of a text array. The array must have either
1318+-- exactly one dimension with an even number of members, in which case they are
1319+-- taken as alternating key/value pairs, or two dimensions such that each inner
1320+-- array has exactly two elements, which are taken as a key/value pair.
1321+jsonObject
1322+ :: PGArrayOf "jsonObject" arr ('NotNull 'PGtext)
1323+ => null arr :--> null 'PGjson
1324+jsonObject = unsafeFunction "json_object"
1325+
1326+-- | Builds a binary JSON object out of a text array. The array must have either
1327+-- exactly one dimension with an even number of members, in which case they are
1328+-- taken as alternating key/value pairs, or two dimensions such that each inner
1329+-- array has exactly two elements, which are taken as a key/value pair.
1330+jsonbObject
1331+ :: PGArrayOf "jsonbObject" arr ('NotNull 'PGtext)
1332+ => null arr :--> null 'PGjsonb
1333+jsonbObject = unsafeFunction "jsonb_object"
1334+
1335+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1336+-- keys and one for values, that are zipped pairwise to create a JSON object.
1337+jsonZipObject
1338+ :: ( PGArrayOf "jsonZipObject" keysArray ('NotNull 'PGtext)
1339+ , PGArrayOf "jsonZipObject" valuesArray ('NotNull 'PGtext))
1340+ => Expression outer grp commons schemas params from (null keysArray)
1341+ -> Expression outer grp commons schemas params from (null valuesArray)
1342+ -> Expression outer grp commons schemas params from (null 'PGjson)
1343+jsonZipObject ks vs =
1344+ unsafeVariadicFunction "json_object" (ks :* vs :* Nil)
1345+
1346+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1347+-- keys and one for values, that are zipped pairwise to create a binary JSON
1348+-- object.
1349+jsonbZipObject
1350+ :: ( PGArrayOf "jsonbZipObject" keysArray ('NotNull 'PGtext)
1351+ , PGArrayOf "jsonbZipObject" valuesArray ('NotNull 'PGtext))
1352+ => Expression outer grp commons schemas params from (null keysArray)
1353+ -> Expression outer grp commons schemas params from (null valuesArray)
1354+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1355+jsonbZipObject ks vs =
1356+ unsafeVariadicFunction "jsonb_object" (ks :* vs :* Nil)
1357+
1358+{-----------------------------------------
1359+Table 9.46: JSON processing functions
1360+-----------------------------------------}
1361+
1362+-- | Returns the number of elements in the outermost JSON array.
1363+jsonArrayLength :: null 'PGjson :--> null 'PGint4
1364+jsonArrayLength = unsafeFunction "json_array_length"
1365+
1366+-- | Returns the number of elements in the outermost binary JSON array.
1367+jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
1368+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1369+
1370+-- | Returns JSON value pointed to by the given path (equivalent to #>
1371+-- operator).
1372+jsonExtractPath
1373+ :: SListI elems
1374+ => Expression outer grp commons schemas params from (null 'PGjson)
1375+ -> NP (Expression outer grp commons schemas params from) elems
1376+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1377+jsonExtractPath x xs =
1378+ unsafeVariadicFunction "json_extract_path" (x :* xs)
1379+
1380+-- | Returns JSON value pointed to by the given path (equivalent to #>
1381+-- operator).
1382+jsonbExtractPath
1383+ :: SListI elems
1384+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1385+ -> NP (Expression outer grp commons schemas params from) elems
1386+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1387+jsonbExtractPath x xs =
1388+ unsafeVariadicFunction "jsonb_extract_path" (x :* xs)
1389+
1390+-- | Returns JSON value pointed to by the given path (equivalent to #>
1391+-- operator), as text.
1392+jsonExtractPathAsText
1393+ :: SListI elems
1394+ => Expression outer grp commons schemas params from (null 'PGjson)
1395+ -> NP (Expression outer grp commons schemas params from) elems
1396+ -> Expression outer grp commons schemas params from (null 'PGjson)
1397+jsonExtractPathAsText x xs =
1398+ unsafeVariadicFunction "json_extract_path_text" (x :* xs)
1399+
1400+-- | Returns JSON value pointed to by the given path (equivalent to #>
1401+-- operator), as text.
1402+jsonbExtractPathAsText
1403+ :: SListI elems
1404+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1405+ -> NP (Expression outer grp commons schemas params from) elems
1406+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1407+jsonbExtractPathAsText x xs =
1408+ unsafeVariadicFunction "jsonb_extract_path_text" (x :* xs)
1409+
1410+-- | Returns the type of the outermost JSON value as a text string. Possible
1411+-- types are object, array, string, number, boolean, and null.
1412+jsonTypeof :: null 'PGjson :--> null 'PGtext
1413+jsonTypeof = unsafeFunction "json_typeof"
1414+
1415+-- | Returns the type of the outermost binary JSON value as a text string.
1416+-- Possible types are object, array, string, number, boolean, and null.
1417+jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
1418+jsonbTypeof = unsafeFunction "jsonb_typeof"
1419+
1420+-- | Returns its argument with all object fields that have null values omitted.
1421+-- Other null values are untouched.
1422+jsonStripNulls :: null 'PGjson :--> null 'PGjson
1423+jsonStripNulls = unsafeFunction "json_strip_nulls"
1424+
1425+-- | Returns its argument with all object fields that have null values omitted.
1426+-- Other null values are untouched.
1427+jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
1428+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1429+
1430+-- | @ jsonbSet target path new_value create_missing @
1431+--
1432+-- Returns target with the section designated by path replaced by new_value,
1433+-- or with new_value added if create_missing is true ( default is true) and the
1434+-- item designated by path does not exist. As with the path orientated
1435+-- operators, negative integers that appear in path count from the end of JSON
1436+-- arrays.
1437+jsonbSet
1438+ :: PGTextArray "jsonbSet" arr
1439+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1440+ -> Expression outer grp commons schemas params from (null arr)
1441+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1442+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1443+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1444+jsonbSet tgt path val createMissing = case createMissing of
1445+ Just m -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* m :* Nil)
1446+ Nothing -> unsafeVariadicFunction "jsonb_set" (tgt :* path :* val :* Nil)
1447+
1448+-- | @ jsonbInsert target path new_value insert_after @
1449+--
1450+-- Returns target with new_value inserted. If target section designated by
1451+-- path is in a JSONB array, new_value will be inserted before target or after
1452+-- if insert_after is true (default is false). If target section designated by
1453+-- path is in JSONB object, new_value will be inserted only if target does not
1454+-- exist. As with the path orientated operators, negative integers that appear
1455+-- in path count from the end of JSON arrays.
1456+jsonbInsert
1457+ :: PGTextArray "jsonbInsert" arr
1458+ => Expression outer grp commons schemas params from (null 'PGjsonb)
1459+ -> Expression outer grp commons schemas params from (null arr)
1460+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1461+ -> Maybe (Expression outer grp commons schemas params from (null 'PGbool))
1462+ -> Expression outer grp commons schemas params from (null 'PGjsonb)
1463+jsonbInsert tgt path val insertAfter = case insertAfter of
1464+ Just i -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1465+ Nothing -> unsafeVariadicFunction "jsonb_insert" (tgt :* path :* val :* Nil)
1466+
1467+-- | Returns its argument as indented JSON text.
1468+jsonbPretty :: null 'PGjsonb :--> null 'PGtext
1469+jsonbPretty = unsafeFunction "jsonb_pretty"
1470+
1471+(@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)
1472+(@@) = unsafeBinaryOp "@@"
1473+
1474+(.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1475+(.&) = unsafeBinaryOp "&&"
1476+
1477+(.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1478+(.|) = unsafeBinaryOp "||"
1479+
1480+(.!) :: null 'PGtsquery :--> null 'PGtsquery
1481+(.!) = unsafeUnaryOpL "!!"
1482+
1483+(<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1484+(<->) = unsafeBinaryOp "<->"
1485+
1486+arrayToTSvector
1487+ :: null ('PGvararray ('NotNull 'PGtext))
1488+ :--> null 'PGtsvector
1489+arrayToTSvector = unsafeFunction "array_to_tsvector"
1490+
1491+tsvectorLength :: null 'PGtsvector :--> null 'PGint4
1492+tsvectorLength = unsafeFunction "length"
1493+
1494+numnode :: null 'PGtsquery :--> null 'PGint4
1495+numnode = unsafeFunction "numnode"
1496+
1497+plainToTSquery
1498+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1499+plainToTSquery = unsafeFunctionHet "plainto_tsquery"
1500+
1501+phraseToTSquery
1502+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1503+phraseToTSquery = unsafeFunctionHet "phraseto_tsquery"
1504+
1505+websearchToTSquery
1506+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1507+websearchToTSquery = unsafeFunctionHet "websearch_to_tsquery"
1508+
1509+queryTree :: null 'PGtsquery :--> null 'PGtext
1510+queryTree = unsafeFunction "query_tree"
1511+
1512+toTSquery
1513+ :: FunctionHet '[null 'PGtext, null 'PGtext] (null 'PGtsquery)
1514+toTSquery = unsafeFunctionHet "to_tsquery"
1515+
1516+toTSvector
1517+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1518+ => FunctionHet '[null 'PGtext, null ty] (null 'PGtsquery)
1519+toTSvector = unsafeFunctionHet "to_tsvector"
1520+
1521+{-----------------------------------------
1522+aggregation
1523+-----------------------------------------}
1524+
1525+{- |
1526+`Aggregate` functions compute a single result from a set of input values.
1527+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1528+as `WindowFunction`s.
1529+-}
1530+class Aggregate expr1 expr2 aggr
1531+ | aggr -> expr1, aggr -> expr2 where
1532+
1533+ -- | A special aggregation that does not require an input
1534+ --
1535+ -- >>> :{
1536+ -- let
1537+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1538+ -- expression = countStar
1539+ -- in printSQL expression
1540+ -- :}
1541+ -- count(*)
1542+ countStar :: aggr ('NotNull 'PGint8)
1543+
1544+ -- | >>> :{
1545+ -- let
1546+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1547+ -- expression = count (All #col)
1548+ -- in printSQL expression
1549+ -- :}
1550+ -- count(ALL "col")
1551+ count
1552+ :: expr1 ty
1553+ -- ^ what to count
1554+ -> aggr ('NotNull 'PGint8)
1555+
1556+ -- | >>> :{
1557+ -- let
1558+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1559+ -- expression = sum_ (Distinct #col)
1560+ -- in printSQL expression
1561+ -- :}
1562+ -- sum(DISTINCT "col")
1563+ sum_
1564+ :: ty `In` PGNum
1565+ => expr1 (null ty)
1566+ -> aggr ('NotNull ty)
1567+
1568+ -- | input values, including nulls, concatenated into an array
1569+ arrayAgg
1570+ :: expr1 ty
1571+ -> aggr ('Null ('PGvararray ty))
1572+
1573+ -- | aggregates values as a JSON array
1574+ jsonAgg
1575+ :: expr1 ty
1576+ -> aggr ('Null 'PGjson)
1577+
1578+ -- | aggregates values as a JSON array
1579+ jsonbAgg
1580+ :: expr1 ty
1581+ -> aggr ('Null 'PGjsonb)
1582+
1583+ {- |
1584+ the bitwise AND of all non-null input values, or null if none
1585+ >>> :{
1586+ let
1587+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1588+ expression = bitAnd (Distinct #col)
1589+ in printSQL expression
1590+ :}
1591+ bit_and(DISTINCT "col")
1592+ -}
1593+ bitAnd
1594+ :: int `In` PGIntegral
1595+ => expr1 (null int)
1596+ -- ^ what to aggregate
1597+ -> aggr ('Null int)
1598+
1599+ {- |
1600+ the bitwise OR of all non-null input values, or null if none
1601+
1602+ >>> :{
1603+ let
1604+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1605+ expression = bitOr (All #col)
1606+ in printSQL expression
1607+ :}
1608+ bit_or(ALL "col")
1609+ -}
1610+ bitOr
1611+ :: int `In` PGIntegral
1612+ => expr1 (null int)
1613+ -- ^ what to aggregate
1614+ -> aggr ('Null int)
1615+
1616+ {- |
1617+ true if all input values are true, otherwise false
1618+
1619+ >>> :{
1620+ let
1621+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1622+ winFun = boolAnd #col
1623+ in printSQL winFun
1624+ :}
1625+ bool_and("col")
1626+ -}
1627+ boolAnd
1628+ :: expr1 (null 'PGbool)
1629+ -- ^ what to aggregate
1630+ -> aggr ('Null 'PGbool)
1631+
1632+ {- |
1633+ true if at least one input value is true, otherwise false
1634+
1635+ >>> :{
1636+ let
1637+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1638+ expression = boolOr (All #col)
1639+ in printSQL expression
1640+ :}
1641+ bool_or(ALL "col")
1642+ -}
1643+ boolOr
1644+ :: expr1(null 'PGbool)
1645+ -- ^ what to aggregate
1646+ -> aggr ('Null 'PGbool)
1647+
1648+ {- |
1649+ equivalent to `boolAnd`
1650+
1651+ >>> :{
1652+ let
1653+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1654+ expression = every (Distinct #col)
1655+ in printSQL expression
1656+ :}
1657+ every(DISTINCT "col")
1658+ -}
1659+ every
1660+ :: expr1 (null 'PGbool)
1661+ -- ^ what to aggregate
1662+ -> aggr ('Null 'PGbool)
1663+
1664+ {- |maximum value of expression across all input values-}
1665+ max_
1666+ :: expr1 (null ty)
1667+ -- ^ what to maximize
1668+ -> aggr ('Null ty)
1669+
1670+ -- | minimum value of expression across all input values
1671+ min_
1672+ :: expr1 (null ty)
1673+ -- ^ what to minimize
1674+ -> aggr ('Null ty)
1675+
1676+ -- | the average (arithmetic mean) of all input values
1677+ avg
1678+ :: expr1 (null ty)
1679+ -- ^ what to average
1680+ -> aggr ('Null (PGAvg ty))
1681+
1682+ {- | correlation coefficient
1683+ >>> :{
1684+ let
1685+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1686+ expression = corr (All (#y :*: #x))
1687+ in printSQL expression
1688+ :}
1689+ corr(ALL "y", "x")
1690+ -}
1691+ corr
1692+ :: expr2 (null 'PGfloat8)
1693+ -> aggr ('Null 'PGfloat8)
1694+
1695+ {- | population covariance
1696+ >>> :{
1697+ let
1698+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1699+ expression = covarPop (All (#y :*: #x))
1700+ in printSQL expression
1701+ :}
1702+ covar_pop(ALL "y", "x")
1703+ -}
1704+ covarPop
1705+ :: expr2 (null 'PGfloat8)
1706+ -> aggr ('Null 'PGfloat8)
1707+
1708+ {- | sample covariance
1709+ >>> :{
1710+ let
1711+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1712+ winFun = covarSamp (#y :*: #x)
1713+ in printSQL winFun
1714+ :}
1715+ covar_samp("y", "x")
1716+ -}
1717+ covarSamp
1718+ :: expr2 (null 'PGfloat8)
1719+ -> aggr ('Null 'PGfloat8)
1720+
1721+ {- | average of the independent variable (sum(X)/N)
1722+ >>> :{
1723+ let
1724+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1725+ expression = regrAvgX (All (#y :*: #x))
1726+ in printSQL expression
1727+ :}
1728+ regr_avgx(ALL "y", "x")
1729+ -}
1730+ regrAvgX
1731+ :: expr2 (null 'PGfloat8)
1732+ -> aggr ('Null 'PGfloat8)
1733+
1734+ {- | average of the dependent variable (sum(Y)/N)
1735+ >>> :{
1736+ let
1737+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1738+ winFun = regrAvgY (#y :*: #x)
1739+ in printSQL winFun
1740+ :}
1741+ regr_avgy("y", "x")
1742+ -}
1743+ regrAvgY
1744+ :: expr2 (null 'PGfloat8)
1745+ -> aggr ('Null 'PGfloat8)
1746+
1747+ {- | number of input rows in which both expressions are nonnull
1748+ >>> :{
1749+ let
1750+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1751+ winFun = regrCount (#y :*: #x)
1752+ in printSQL winFun
1753+ :}
1754+ regr_count("y", "x")
1755+ -}
1756+ regrCount
1757+ :: expr2 (null 'PGfloat8)
1758+ -> aggr ('Null 'PGint8)
1759+
1760+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1761+ >>> :{
1762+ let
1763+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1764+ expression = regrIntercept (All (#y :*: #x))
1765+ in printSQL expression
1766+ :}
1767+ regr_intercept(ALL "y", "x")
1768+ -}
1769+ regrIntercept
1770+ :: expr2 (null 'PGfloat8)
1771+ -> aggr ('Null 'PGfloat8)
1772+
1773+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1774+ regrR2
1775+ :: expr2 (null 'PGfloat8)
1776+ -> aggr ('Null 'PGfloat8)
1777+
1778+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1779+ -- determined by the (X, Y) pairs
1780+ regrSlope
1781+ :: expr2 (null 'PGfloat8)
1782+ -> aggr ('Null 'PGfloat8)
1783+
1784+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1785+ -- (“sum of squares” of the independent variable)
1786+ regrSxx
1787+ :: expr2 (null 'PGfloat8)
1788+ -> aggr ('Null 'PGfloat8)
1789+
1790+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1791+ -- (“sum of products” of independent times dependent variable)
1792+ regrSxy
1793+ :: expr2 (null 'PGfloat8)
1794+ -> aggr ('Null 'PGfloat8)
1795+
1796+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1797+ -- (“sum of squares” of the dependent variable)
1798+ regrSyy
1799+ :: expr2 (null 'PGfloat8)
1800+ -> aggr ('Null 'PGfloat8)
1801+
1802+ -- | historical alias for `stddevSamp`
1803+ stddev
1804+ :: expr1 (null ty)
1805+ -> aggr ('Null (PGAvg ty))
1806+
1807+ -- | population standard deviation of the input values
1808+ stddevPop
1809+ :: expr1 (null ty)
1810+ -> aggr ('Null (PGAvg ty))
1811+
1812+ -- | sample standard deviation of the input values
1813+ stddevSamp
1814+ :: expr1 (null ty)
1815+ -> aggr ('Null (PGAvg ty))
1816+
1817+ -- | historical alias for `varSamp`
1818+ variance
1819+ :: expr1 (null ty)
1820+ -> aggr ('Null (PGAvg ty))
1821+
1822+ -- | population variance of the input values
1823+ -- (square of the population standard deviation)
1824+ varPop
1825+ :: expr1 (null ty)
1826+ -> aggr ('Null (PGAvg ty))
1827+
1828+ -- | sample variance of the input values
1829+ -- (square of the sample standard deviation)
1830+ varSamp
1831+ :: expr1 (null ty)
1832+ -> aggr ('Null (PGAvg ty))
1833+
1834+{- |
1835+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1836+`All` invokes the aggregate once for each input row.
1837+`Distinct` invokes the aggregate once for each distinct value of the expression
1838+(or distinct set of values, for multiple expressions) found in the input
1839+-}
1840+data Distinction expr ty
1841+ = All (expr ty)
1842+ | Distinct (expr ty)
1843+ deriving (GHC.Generic,Show,Eq,Ord)
1844+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1845+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1846+ renderSQL = \case
1847+ All x -> "ALL" <+> renderSQL x
1848+ Distinct x -> "DISTINCT" <+> renderSQL x
1849+instance RenderSQL
1850+ (Distinction
1851+ ( Expression outer grp commons schemas params from
1852+ :*:
1853+ Expression outer grp commons schemas params from) xty ) where
1854+ renderSQL = \case
1855+ All (x :*: x') ->
1856+ "ALL" <+> renderSQL x <> ", " <> renderSQL x'
1857+ Distinct (x :*: x') ->
1858+ "DISTINCT" <+> renderSQL x <> ", " <> renderSQL x'
1859+
1860+instance Aggregate
1861+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1862+ (Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from))
1863+ (Expression outer ('Grouped bys) commons schemas params from) where
1864+ countStar = UnsafeExpression "count(*)"
1865+ count = unsafeAggregate1 "count"
1866+ sum_ = unsafeAggregate1 "sum"
1867+ arrayAgg = unsafeAggregate1 "array_agg"
1868+ jsonAgg = unsafeAggregate1 "json_agg"
1869+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1870+ bitAnd = unsafeAggregate1 "bit_and"
1871+ bitOr = unsafeAggregate1 "bit_or"
1872+ boolAnd = unsafeAggregate1 "bool_and"
1873+ boolOr = unsafeAggregate1 "bool_or"
1874+ every = unsafeAggregate1 "every"
1875+ max_ = unsafeAggregate1 "max"
1876+ min_ = unsafeAggregate1 "min"
1877+ avg = unsafeAggregate1 "avg"
1878+ corr = unsafeAggregate2 "corr"
1879+ covarPop = unsafeAggregate2 "covar_pop"
1880+ covarSamp = unsafeAggregate2 "covar_samp"
1881+ regrAvgX = unsafeAggregate2 "regr_avgx"
1882+ regrAvgY = unsafeAggregate2 "regr_avgy"
1883+ regrCount = unsafeAggregate2 "regr_count"
1884+ regrIntercept = unsafeAggregate2 "regr_intercept"
1885+ regrR2 = unsafeAggregate2 "regr_r2"
1886+ regrSlope = unsafeAggregate2 "regr_slope"
1887+ regrSxx = unsafeAggregate2 "regr_sxx"
1888+ regrSxy = unsafeAggregate2 "regr_sxy"
1889+ regrSyy = unsafeAggregate2 "regr_syy"
1890+ stddev = unsafeAggregate1 "stddev"
1891+ stddevPop = unsafeAggregate1 "stddev_pop"
1892+ stddevSamp = unsafeAggregate1 "stddev_samp"
1893+ variance = unsafeAggregate1 "variance"
1894+ varPop = unsafeAggregate1 "var_pop"
1895+ varSamp = unsafeAggregate1 "var_samp"
1896+instance Aggregate
1897+ (Expression outer grp commons schemas params from)
1898+ (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from)
1899+ (WindowFunction outer grp commons schemas params from) where
1900+ countStar = UnsafeWindowFunction "count(*)"
1901+ count = unsafeWindowFunction1 "count"
1902+ sum_ = unsafeWindowFunction1 "sum"
1903+ arrayAgg = unsafeWindowFunction1 "array_agg"
1904+ jsonAgg = unsafeWindowFunction1 "json_agg"
1905+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1906+ bitAnd = unsafeWindowFunction1 "bit_and"
1907+ bitOr = unsafeWindowFunction1 "bit_or"
1908+ boolAnd = unsafeWindowFunction1 "bool_and"
1909+ boolOr = unsafeWindowFunction1 "bool_or"
1910+ every = unsafeWindowFunction1 "every"
1911+ max_ = unsafeWindowFunction1 "max"
1912+ min_ = unsafeWindowFunction1 "min"
1913+ avg = unsafeWindowFunction1 "avg"
1914+ corr = unsafeWindowFunction2 "corr"
1915+ covarPop = unsafeWindowFunction2 "covar_pop"
1916+ covarSamp = unsafeWindowFunction2 "covar_samp"
1917+ regrAvgX = unsafeWindowFunction2 "regr_avgx"
1918+ regrAvgY = unsafeWindowFunction2 "regr_avgy"
1919+ regrCount = unsafeWindowFunction2 "regr_count"
1920+ regrIntercept = unsafeWindowFunction2 "regr_intercept"
1921+ regrR2 = unsafeWindowFunction2 "regr_r2"
1922+ regrSlope = unsafeWindowFunction2 "regr_slope"
1923+ regrSxx = unsafeWindowFunction2 "regr_sxx"
1924+ regrSxy = unsafeWindowFunction2 "regr_sxy"
1925+ regrSyy = unsafeWindowFunction2 "regr_syy"
1926+ stddev = unsafeWindowFunction1 "stddev"
1927+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1928+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1929+ variance = unsafeWindowFunction1 "variance"
1930+ varPop = unsafeWindowFunction1 "var_pop"
1931+ varSamp = unsafeWindowFunction1 "var_samp"
1932+
1933+-- | escape hatch to define aggregate functions
1934+unsafeAggregate1
1935+ :: ByteString -- ^ aggregate function
1936+ -> Distinction (Expression outer 'Ungrouped commons schemas params from) xty
1937+ -> Expression outer ('Grouped bys) commons schemas params from yty
1938+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1939+ [fun, "(", renderSQL x, ")"]
1940+
1941+-- | escape hatch to define aggregate binary functions
1942+unsafeAggregate2
1943+ :: ByteString -- ^ aggregate function
1944+ -> Distinction (Expression outer 'Ungrouped commons schemas params from :*: Expression outer 'Ungrouped commons schemas params from) xty
1945+ -> Expression outer ('Grouped bys) commons schemas params from yty
1946+unsafeAggregate2 fun xx = UnsafeExpression $ mconcat
1947+ [fun, "(", renderSQL xx, ")"]
1948+
1949+-- | A type family that calculates `PGAvg` type of a `PGType`.
1950+type family PGAvg ty where
1951+ PGAvg 'PGint2 = 'PGnumeric
1952+ PGAvg 'PGint4 = 'PGnumeric
1953+ PGAvg 'PGint8 = 'PGnumeric
1954+ PGAvg 'PGnumeric = 'PGnumeric
1955+ PGAvg 'PGfloat4 = 'PGfloat8
1956+ PGAvg 'PGfloat8 = 'PGfloat8
1957+ PGAvg 'PGinterval = 'PGinterval
1958+ PGAvg pg = TypeError
1959+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1960+
1961+{-----------------------------------------
1962+type expressions
1963+-----------------------------------------}
1964+
1965+-- | `TypeExpression`s are used in `cast`s and
1966+-- `Squeal.PostgreSQL.Definition.createTable` commands.
1967+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
1968+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
1969+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1970+instance RenderSQL (TypeExpression schemas ty) where
1971+ renderSQL = renderTypeExpression
1972+
1973+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
1974+typedef
1975+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
1976+ => QualifiedAlias sch td
1977+ -> TypeExpression schemas (null ty)
1978+typedef = UnsafeTypeExpression . renderSQL
1979+
1980+-- | The composite type corresponding to a `Table` definition can be expressed
1981+-- by its alias.
1982+typetable
1983+ :: (Has sch schemas schema, Has tab schema ('Table table))
1984+ => QualifiedAlias sch tab
1985+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
1986+typetable = UnsafeTypeExpression . renderSQL
1987+
1988+-- | The composite type corresponding to a `View` definition can be expressed
1989+-- by its alias.
1990+typeview
1991+ :: (Has sch schemas schema, Has vw schema ('View view))
1992+ => QualifiedAlias sch vw
1993+ -> TypeExpression schemas (null ('PGcomposite view))
1994+typeview = UnsafeTypeExpression . renderSQL
1995+
1996+-- | logical Boolean (true/false)
1997+bool :: TypeExpression schemas (null 'PGbool)
1998+bool = UnsafeTypeExpression "bool"
1999+-- | signed two-byte integer
2000+int2, smallint :: TypeExpression schemas (null 'PGint2)
2001+int2 = UnsafeTypeExpression "int2"
2002+smallint = UnsafeTypeExpression "smallint"
2003+-- | signed four-byte integer
2004+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2005+int4 = UnsafeTypeExpression "int4"
2006+int = UnsafeTypeExpression "int"
2007+integer = UnsafeTypeExpression "integer"
2008+-- | signed eight-byte integer
2009+int8, bigint :: TypeExpression schemas (null 'PGint8)
2010+int8 = UnsafeTypeExpression "int8"
2011+bigint = UnsafeTypeExpression "bigint"
2012+-- | arbitrary precision numeric type
2013+numeric :: TypeExpression schemas (null 'PGnumeric)
2014+numeric = UnsafeTypeExpression "numeric"
2015+-- | single precision floating-point number (4 bytes)
2016+float4, real :: TypeExpression schemas (null 'PGfloat4)
2017+float4 = UnsafeTypeExpression "float4"
2018+real = UnsafeTypeExpression "real"
2019+-- | double precision floating-point number (8 bytes)
2020+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2021+float8 = UnsafeTypeExpression "float8"
2022+doublePrecision = UnsafeTypeExpression "double precision"
2023+-- | currency amount
2024+money :: TypeExpression schema (null 'PGmoney)
2025+money = UnsafeTypeExpression "money"
2026+-- | variable-length character string
2027+text :: TypeExpression schemas (null 'PGtext)
2028+text = UnsafeTypeExpression "text"
2029+-- | fixed-length character string
2030+char, character
2031+ :: forall n schemas null. (KnownNat n, 1 <= n)
2032+ => TypeExpression schemas (null ('PGchar n))
2033+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2034+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2035+-- | variable-length character string
2036+varchar, characterVarying
2037+ :: forall n schemas null. (KnownNat n, 1 <= n)
2038+ => TypeExpression schemas (null ('PGvarchar n))
2039+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2040+characterVarying = UnsafeTypeExpression $
2041+ "character varying(" <> renderNat @n <> ")"
2042+-- | binary data ("byte array")
2043+bytea :: TypeExpression schemas (null 'PGbytea)
2044+bytea = UnsafeTypeExpression "bytea"
2045+-- | date and time (no time zone)
2046+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2047+timestamp = UnsafeTypeExpression "timestamp"
2048+-- | date and time, including time zone
2049+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2050+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2051+-- | calendar date (year, month, day)
2052+date :: TypeExpression schemas (null 'PGdate)
2053+date = UnsafeTypeExpression "date"
2054+-- | time of day (no time zone)
2055+time :: TypeExpression schemas (null 'PGtime)
2056+time = UnsafeTypeExpression "time"
2057+-- | time of day, including time zone
2058+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2059+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2060+-- | time span
2061+interval :: TypeExpression schemas (null 'PGinterval)
2062+interval = UnsafeTypeExpression "interval"
2063+-- | universally unique identifier
2064+uuid :: TypeExpression schemas (null 'PGuuid)
2065+uuid = UnsafeTypeExpression "uuid"
2066+-- | IPv4 or IPv6 host address
2067+inet :: TypeExpression schemas (null 'PGinet)
2068+inet = UnsafeTypeExpression "inet"
2069+-- | textual JSON data
2070+json :: TypeExpression schemas (null 'PGjson)
2071+json = UnsafeTypeExpression "json"
2072+-- | binary JSON data, decomposed
2073+jsonb :: TypeExpression schemas (null 'PGjsonb)
2074+jsonb = UnsafeTypeExpression "jsonb"
2075+-- | variable length array
2076+vararray
2077+ :: TypeExpression schemas pg
2078+ -> TypeExpression schemas (null ('PGvararray pg))
2079+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2080+-- | fixed length array
2081+--
2082+-- >>> renderSQL (fixarray @'[2] json)
2083+-- "json[2]"
2084+fixarray
2085+ :: forall dims schemas null pg. SOP.All KnownNat dims
2086+ => TypeExpression schemas pg
2087+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2088+fixarray ty = UnsafeTypeExpression $
2089+ renderSQL ty <> renderDims @dims
2090+ where
2091+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2092+ renderDims =
2093+ ("[" <>)
2094+ . (<> "]")
2095+ . ByteString.intercalate "]["
2096+ . hcollapse
2097+ $ hcmap (SOP.Proxy @KnownNat)
2098+ (K . fromString . show . natVal)
2099+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2100+tsvector :: TypeExpression schemas (null 'PGtsvector)
2101+tsvector = UnsafeTypeExpression "tsvector"
2102+tsquery :: TypeExpression schemas (null 'PGtsquery)
2103+tsquery = UnsafeTypeExpression "tsquery"
2104+
2105+-- | `pgtype` is a demoted version of a `PGType`
2106+class PGTyped schemas (ty :: NullityType) where
2107+ pgtype :: TypeExpression schemas ty
2108+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2109+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2110+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2111+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2112+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2113+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2114+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2115+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2116+instance PGTyped schemas (null 'PGtext) where pgtype = text
2117+instance (KnownNat n, 1 <= n)
2118+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2119+instance (KnownNat n, 1 <= n)
2120+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2121+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2122+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2123+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2124+instance PGTyped schemas (null 'PGdate) where pgtype = date
2125+instance PGTyped schemas (null 'PGtime) where pgtype = time
2126+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2127+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2128+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2129+instance PGTyped schemas (null 'PGjson) where pgtype = json
2130+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2131+instance PGTyped schemas ty
2132+ => PGTyped schemas (null ('PGvararray ty)) where
2133+ pgtype = vararray (pgtype @schemas @ty)
2134+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2135+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2136+ pgtype = fixarray @dims (pgtype @schemas @ty)
2137+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2138+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2139+
2140+{-----------------------------------------
2141+Sorting
2142+-----------------------------------------}
2143+
2144+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2145+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2146+-- set the sort direction of a `NotNull` result
2147+-- column to ascending or descending. Ascending order puts smaller values
2148+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2149+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2150+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2151+-- determine whether nulls appear before or after non-null values in the sort
2152+-- ordering of a `Null` result column.
2153+data SortExpression outer grp commons schemas params from where
2154+ Asc
2155+ :: Expression outer grp commons schemas params from ('NotNull ty)
2156+ -> SortExpression outer grp commons schemas params from
2157+ Desc
2158+ :: Expression outer grp commons schemas params from ('NotNull ty)
2159+ -> SortExpression outer grp commons schemas params from
2160+ AscNullsFirst
2161+ :: Expression outer grp commons schemas params from ('Null ty)
2162+ -> SortExpression outer grp commons schemas params from
2163+ AscNullsLast
2164+ :: Expression outer grp commons schemas params from ('Null ty)
2165+ -> SortExpression outer grp commons schemas params from
2166+ DescNullsFirst
2167+ :: Expression outer grp commons schemas params from ('Null ty)
2168+ -> SortExpression outer grp commons schemas params from
2169+ DescNullsLast
2170+ :: Expression outer grp commons schemas params from ('Null ty)
2171+ -> SortExpression outer grp commons schemas params from
2172+deriving instance Show (SortExpression outer grp commons schemas params from)
2173+
2174+{- |
2175+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2176+to be sorted according to the specified `SortExpression`(s).
2177+If two rows are equal according to the leftmost expression,
2178+they are compared according to the next expression and so on.
2179+If they are equal according to all specified expressions,
2180+they are returned in an implementation-dependent order.
2181+
2182+You can also control the order in which rows are processed by window functions
2183+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2184+-}
2185+class OrderBy expr where
2186+ orderBy
2187+ :: [SortExpression outer grp commons schemas params from]
2188+ -> expr outer grp commons schemas params from
2189+ -> expr outer grp commons schemas params from
2190+
2191+-- | Render a `SortExpression`.
2192+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2193+ renderSQL = \case
2194+ Asc expression -> renderSQL expression <+> "ASC"
2195+ Desc expression -> renderSQL expression <+> "DESC"
2196+ AscNullsFirst expression -> renderSQL expression
2197+ <+> "ASC NULLS FIRST"
2198+ DescNullsFirst expression -> renderSQL expression
2199+ <+> "DESC NULLS FIRST"
2200+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2201+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2202+
2203+-- | A `WindowDefinition` is a set of table rows that are somehow related
2204+-- to the current row
2205+data WindowDefinition outer grp commons schemas params from where
2206+ WindowDefinition
2207+ :: SListI bys
2208+ => NP (Expression outer grp commons schemas params from) bys
2209+ -> [SortExpression outer grp commons schemas params from]
2210+ -> WindowDefinition outer grp commons schemas params from
2211+
2212+instance OrderBy WindowDefinition where
2213+ orderBy sortsR (WindowDefinition parts sortsL)
2214+ = WindowDefinition parts (sortsL ++ sortsR)
2215+
2216+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2217+ renderSQL (WindowDefinition part ord) =
2218+ renderPartitionByClause part <> renderOrderByClause ord
2219+ where
2220+ renderPartitionByClause = \case
2221+ Nil -> ""
2222+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2223+ renderOrderByClause = \case
2224+ [] -> ""
2225+ srts -> " ORDER" <+> "BY"
2226+ <+> commaSeparated (renderSQL <$> srts)
2227+
2228+{- |
2229+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2230+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2231+For each row, the window function is computed across the rows that fall into
2232+the same partition as the current row.
2233+-}
2234+partitionBy
2235+ :: SListI bys
2236+ => NP (Expression outer grp commons schemas params from) bys
2237+ -> WindowDefinition outer grp commons schemas params from
2238+partitionBy bys = WindowDefinition bys []
2239+
2240+{- |
2241+A window function performs a calculation across a set of table rows
2242+that are somehow related to the current row. This is comparable to the type
2243+of calculation that can be done with an aggregate function.
2244+However, window functions do not cause rows to become grouped into a single
2245+output row like non-window aggregate calls would.
2246+Instead, the rows retain their separate identities.
2247+Behind the scenes, the window function is able to access more than
2248+just the current row of the query result.
2249+-}
2250+newtype WindowFunction
2251+ (outer :: FromType)
2252+ (grp :: Grouping)
2253+ (commons :: FromType)
2254+ (schemas :: SchemasType)
2255+ (params :: [NullityType])
2256+ (from :: FromType)
2257+ (ty :: NullityType)
2258+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2259+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2260+
2261+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2262+ renderSQL = renderWindowFunction
2263+
2264+unsafeWindowFunction1
2265+ :: ByteString
2266+ -> Expression outer grp commons schemas params from ty0
2267+ -> WindowFunction outer grp commons schemas params from ty1
2268+unsafeWindowFunction1 fun x
2269+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2270+
2271+unsafeWindowFunction2
2272+ :: ByteString
2273+ -> (Expression outer grp commons schemas params from :*: Expression outer grp commons schemas params from) ty0
2274+ -> WindowFunction outer grp commons schemas params from ty1
2275+unsafeWindowFunction2 fun (x :*: x')
2276+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x <> ", " <> renderSQL x')
2277+
2278+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2279+>>> printSQL rank
2280+rank()
2281+-}
2282+rank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2283+rank = UnsafeWindowFunction "rank()"
2284+
2285+{- | number of the current row within its partition, counting from 1
2286+>>> printSQL rowNumber
2287+row_number()
2288+-}
2289+rowNumber :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2290+rowNumber = UnsafeWindowFunction "row_number()"
2291+
2292+{- | rank of the current row without gaps; this function counts peer groups
2293+>>> printSQL denseRank
2294+dense_rank()
2295+-}
2296+denseRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGint8)
2297+denseRank = UnsafeWindowFunction "dense_rank()"
2298+
2299+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2300+>>> printSQL percentRank
2301+percent_rank()
2302+-}
2303+percentRank :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2304+percentRank = UnsafeWindowFunction "percent_rank()"
2305+
2306+{- | cumulative distribution: (number of partition rows
2307+preceding or peer with current row) / total partition rows
2308+>>> printSQL cumeDist
2309+cume_dist()
2310+-}
2311+cumeDist :: WindowFunction outer grp commons schemas params from ('NotNull 'PGfloat8)
2312+cumeDist = UnsafeWindowFunction "cume_dist()"
2313+
2314+{- | integer ranging from 1 to the argument value,
2315+dividing the partition as equally as possible
2316+-}
2317+ntile
2318+ :: Expression outer grp commons schemas params from ('NotNull 'PGint4)
2319+ -- ^ num buckets
2320+ -> WindowFunction outer grp commons schemas params from ('NotNull 'PGint4)
2321+ntile = unsafeWindowFunction1 "ntile"
2322+
2323+{- | returns value evaluated at the row that is offset rows before the current
2324+row within the partition; if there is no such row, instead return default
2325+(which must be of the same type as value). Both offset and default are
2326+evaluated with respect to the current row.
2327+-}
2328+lag
2329+ :: Expression outer grp commons schemas params from ty
2330+ -- ^ value
2331+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2332+ -- ^ offset
2333+ -> Expression outer grp commons schemas params from ty
2334+ -- ^ default
2335+ -> WindowFunction outer grp commons schemas params from ty
2336+lag value offset def = UnsafeWindowFunction $ "lag"
2337+ <> parenthesized
2338+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2339+
2340+{- | returns value evaluated at the row that is offset rows after the current
2341+row within the partition; if there is no such row, instead return default
2342+(which must be of the same type as value). Both offset and default are
2343+evaluated with respect to the current row.
2344+-}
2345+lead
2346+ :: Expression outer grp commons schemas params from ty
2347+ -- ^ value
2348+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2349+ -- ^ offset
2350+ -> Expression outer grp commons schemas params from ty
2351+ -- ^ default
2352+ -> WindowFunction outer grp commons schemas params from ty
2353+lead value offset def = UnsafeWindowFunction $ "lag"
2354+ <> parenthesized
2355+ (commaSeparated ([renderSQL value, renderSQL offset, renderSQL def]))
2356+
2357+{- | returns value evaluated at the row that is the
2358+first row of the window frame
2359+-}
2360+firstValue
2361+ :: Expression outer grp commons schemas params from ty
2362+ -- ^ value
2363+ -> WindowFunction outer grp commons schemas params from ty
2364+firstValue = unsafeWindowFunction1 "first_value"
2365+
2366+{- | returns value evaluated at the row that is the
2367+last row of the window frame
2368+-}
2369+lastValue
2370+ :: Expression outer grp commons schemas params from ty
2371+ -- ^ value
2372+ -> WindowFunction outer grp commons schemas params from ty
2373+lastValue = unsafeWindowFunction1 "last_value"
2374+
2375+{- | returns value evaluated at the row that is the nth
2376+row of the window frame (counting from 1); null if no such row
2377+-}
2378+nthValue
2379+ :: Expression outer grp commons schemas params from (null ty)
2380+ -- ^ value
2381+ -> Expression outer grp commons schemas params from ('NotNull 'PGint4)
2382+ -- ^ nth
2383+ -> WindowFunction outer grp commons schemas params from ('Null ty)
2384+nthValue value nth = UnsafeWindowFunction $ "nth_value"
2385+ <> parenthesized (commaSeparated [renderSQL value, renderSQL nth])
2386+
2387+{-|
2388+Create date from year, month and day fields
2389+
2390+>>> printSQL (makeDate (1984 :* 7 *: 3))
2391+make_date(1984, 7, 3)
2392+-}
2393+makeDate :: FunctionHet
2394+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2395+ ( null 'PGdate )
2396+makeDate = unsafeFunctionHet "make_date"
2397+
2398+{-|
2399+Create time from hour, minute and seconds fields
2400+
2401+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2402+make_time(8, 15, 23.5)
2403+-}
2404+makeTime :: FunctionHet
2405+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2406+ ( null 'PGtime )
2407+makeTime = unsafeFunctionHet "make_time"
2408+
2409+{-|
2410+Create timestamp from year, month, day, hour, minute and seconds fields
2411+
2412+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2413+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2414+-}
2415+makeTimestamp :: FunctionHet
2416+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2417+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2418+ ( null 'PGtimestamp )
2419+makeTimestamp = unsafeFunctionHet "make_timestamp"
2420+
2421+{-|
2422+Create timestamp with time zone from
2423+year, month, day, hour, minute and seconds fields;
2424+the current time zone is used
2425+
2426+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2427+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2428+-}
2429+makeTimestamptz :: FunctionHet
2430+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2431+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2432+ ( null 'PGtimestamptz )
2433+makeTimestamptz = unsafeFunctionHet "make_timestamptz"
2434+
2435+{-|
2436+Affine space operations on time types.
2437+-}
2438+class TimeOp time diff | time -> diff where
2439+ {-|
2440+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2441+ (make_date(1984, 7, 3) + 365)
2442+ -}
2443+ (!+) :: Operator (null time) (null diff) (null time)
2444+ (!+) = unsafeBinaryOp "+"
2445+ {-|
2446+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2447+ (365 + make_date(1984, 7, 3))
2448+ -}
2449+ (+!) :: Operator (null diff) (null time) (null time)
2450+ (+!) = unsafeBinaryOp "+"
2451+ {-|
2452+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2453+ (make_date(1984, 7, 3) - 365)
2454+ -}
2455+ (!-) :: Operator (null time) (null diff) (null time)
2456+ (!-) = unsafeBinaryOp "-"
2457+ {-|
2458+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2459+ (make_date(1984, 7, 3) - CURRENT_DATE)
2460+ -}
2461+ (!-!) :: Operator (null time) (null time) (null diff)
2462+ (!-!) = unsafeBinaryOp "-"
2463+instance TimeOp 'PGtimestamp 'PGinterval
2464+instance TimeOp 'PGtimestamptz 'PGinterval
2465+instance TimeOp 'PGtime 'PGinterval
2466+instance TimeOp 'PGtimetz 'PGinterval
2467+instance TimeOp 'PGinterval 'PGinterval
2468+instance TimeOp 'PGdate 'PGint4
2469+infixl 6 !+
2470+infixl 6 +!
2471+infixl 6 !-
2472+infixl 6 !-!