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