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