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