@@ -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+ , unsafeUnaryOpR
62+ , unsafeFunction
63+ , unsafeVariadicFunction
64+ , atan2_
65+ , cast
66+ , quot_
67+ , rem_
68+ , trunc
69+ , round_
70+ , ceiling_
71+ , greatest
72+ , least
73+ , litChar
74+ -- ** Conditions
75+ , true
76+ , false
77+ , not_
78+ , (.&&)
79+ , (.||)
80+ , Condition
81+ , caseWhenThenElse
82+ , ifThenElse
83+ , (.==)
84+ , (./=)
85+ , (.>=)
86+ , (.<)
87+ , (.<=)
88+ , (.>)
89+ , between
90+ , notBetween
91+ , betweenSymmetric
92+ , notBetweenSymmetric
93+ , isDistinctFrom
94+ , isNotDistinctFrom
95+ , isTrue
96+ , isNotTrue
97+ , isFalse
98+ , isNotFalse
99+ , isUnknown
100+ , isNotUnknown
101+ -- ** Time
102+ , currentDate
103+ , currentTime
104+ , currentTimestamp
105+ , localTime
106+ , localTimestamp
107+ , TimeOp (..)
108+ , makeDate
109+ , makeTime
110+ , makeTimestamp
111+ , makeTimestamptz
112+ -- ** Text
113+ , lower
114+ , upper
115+ , charLength
116+ , like
117+ , ilike
118+ -- ** Json
119+ -- *** Json and Jsonb operators
120+ , (.->)
121+ , (.->>)
122+ , (.#>)
123+ , (.#>>)
124+ -- *** Jsonb operators
125+ , (.?)
126+ , (.?|)
127+ , (.?&)
128+ , (.-.)
129+ , (#-.)
130+ -- *** Functions
131+ , jsonLit
132+ , jsonbLit
133+ , toJson
134+ , toJsonb
135+ , arrayToJson
136+ , rowToJson
137+ , jsonBuildArray
138+ , jsonbBuildArray
139+ , jsonBuildObject
140+ , jsonbBuildObject
141+ , jsonObject
142+ , jsonbObject
143+ , jsonZipObject
144+ , jsonbZipObject
145+ , jsonArrayLength
146+ , jsonbArrayLength
147+ , jsonExtractPath
148+ , jsonbExtractPath
149+ , jsonExtractPathAsText
150+ , jsonbExtractPathAsText
151+ , jsonTypeof
152+ , jsonbTypeof
153+ , jsonStripNulls
154+ , jsonbStripNulls
155+ , jsonbSet
156+ , jsonbInsert
157+ , jsonbPretty
158+ -- ** Text Search
159+ , (@@)
160+ , (.&)
161+ , (.|)
162+ , (.!)
163+ , (<->)
164+ , arrayToTSvector
165+ , tsvectorLength
166+ , numnode
167+ , plainToTSquery
168+ , phraseToTSquery
169+ , websearchToTSquery
170+ , queryTree
171+ , toTSquery
172+ , toTSvector
173+ , setWeight
174+ , strip
175+ , jsonToTSvector
176+ , jsonbToTSvector
177+ , tsDelete
178+ , tsFilter
179+ , tsHeadline
180+ -- ** Aggregation
181+ , Aggregate (..)
182+ , Distinction (..)
183+ , PGAvg
184+ -- * Window Functions
185+ , WindowDefinition (..)
186+ , partitionBy
187+ , WindowFunction (..)
188+ , rank
189+ , rowNumber
190+ , denseRank
191+ , percentRank
192+ , cumeDist
193+ , ntile
194+ , lag
195+ , lead
196+ , firstValue
197+ , lastValue
198+ , nthValue
199+ -- * Sorting
200+ , SortExpression (..)
201+ , OrderBy (..)
202+ -- * Types
203+ , TypeExpression (..)
204+ , PGTyped (..)
205+ , typedef
206+ , typetable
207+ , typeview
208+ , bool
209+ , int2
210+ , smallint
211+ , int4
212+ , int
213+ , integer
214+ , int8
215+ , bigint
216+ , numeric
217+ , float4
218+ , real
219+ , float8
220+ , doublePrecision
221+ , money
222+ , text
223+ , char
224+ , character
225+ , varchar
226+ , characterVarying
227+ , bytea
228+ , timestamp
229+ , timestampWithTimeZone
230+ , date
231+ , time
232+ , timeWithTimeZone
233+ , interval
234+ , uuid
235+ , inet
236+ , json
237+ , jsonb
238+ , vararray
239+ , fixarray
240+ , tsvector
241+ , tsquery
57242 -- * Re-export
58243 , (&)
244+ , NP (..)
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 ((&))
253+import Data.Kind
67254import Data.Semigroup hiding (All)
255+import qualified Data.Aeson as JSON
68256import Data.String
257+import Data.Word
69258import Generics.SOP hiding (All, from)
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
142− -- ^ left input
143− -> Expression outer commons grp schemas params from x2
144− -- ^ right input
145− -> Expression outer commons grp schemas params from y
146− -- ^ output
147−
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
150− . Expression outer commons grp schemas params from x1
305+ = forall outer grp commons schemas params from
306+ . Expression outer grp commons schemas params from x1
151307 -- ^ left input
152− -> Expression outer commons grp schemas params from x2
308+ -> Expression outer grp commons schemas params from x2
153309 -- ^ 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
310+ -> Expression outer grp commons schemas params from y
167311 -- ^ output
168312
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
192− -- ^ inputs
193− -> Expression outer commons grp schemas params from y
194− -- ^ output
195−
196−{- | A @RankNType@ for functions with a variable-length list of
197−homogeneous arguments and at least 1 more argument.
198−-}
199−type FunctionVar x0 x1 y
200− = forall outer commons grp schemas params from
201− . [Expression outer commons grp schemas params from x0]
327+type FunctionHom x0 x1 y
328+ = forall outer grp commons schemas params from
329+ . [Expression outer grp commons schemas params from x0]
202330 -- ^ 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,1775 @@ 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 .<=
907+
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
432925
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)
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 :: null0 'PGbool :--> null1 'PGbool
981+isTrue = unsafeUnaryOpR "IS TRUE"
982+
983+{- | is false or unknown
984+>>> printSQL $ true & isNotTrue
985+(TRUE IS NOT TRUE)
986+-}
987+isNotTrue :: null0 'PGbool :--> null1 'PGbool
988+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
989+
990+{- | is false
991+>>> printSQL $ true & isFalse
992+(TRUE IS FALSE)
993+-}
994+isFalse :: null0 'PGbool :--> null1 'PGbool
995+isFalse = unsafeUnaryOpR "IS FALSE"
996+
997+{- | is true or unknown
998+>>> printSQL $ true & isNotFalse
999+(TRUE IS NOT FALSE)
1000+-}
1001+isNotFalse :: null0 'PGbool :--> null1 'PGbool
1002+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1003+
1004+{- | is unknown
1005+>>> printSQL $ true & isUnknown
1006+(TRUE IS UNKNOWN)
1007+-}
1008+isUnknown :: null0 'PGbool :--> null1 'PGbool
1009+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1010+
1011+{- | is true or false
1012+>>> printSQL $ true & isNotUnknown
1013+(TRUE IS NOT UNKNOWN)
1014+-}
1015+isNotUnknown :: null0 'PGbool :--> null1 '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
1073+ (Expression outer grp commons schemas params from (null 'PGtext)) where
4541074 (<>) = unsafeBinaryOp "||"
4551075instance Semigroup
456− (Expression outer commons grp schemas params from (null 'PGjsonb)) where
457− (<>) = unsafeBinaryOp "||"
458−instance Semigroup
459− (Expression outer commons grp schemas params from (null 'PGtext)) where
460− (<>) = unsafeBinaryOp "||"
461−instance Semigroup
462− (Expression outer commons grp schemas params from (null 'PGtsvector)) where
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+type AggrFun x y
1556+ = forall outer bys commons schemas params from
1557+ . Distinction (Expression outer 'Ungrouped commons schemas params from) x
1558+ -- ^ input
1559+ -> Expression outer ('Grouped bys) commons schemas params from y
1560+ -- ^ output
1561+
1562+type AggrHet xs y
1563+ = forall outer bys commons schemas params from
1564+ . Distinction (NP (Expression outer 'Ungrouped commons schemas params from)) xs
1565+ -- ^ inputs
1566+ -> Expression outer ('Grouped bys) commons schemas params from y
1567+ -- ^ output
1568+
1569+unsafeAggregateHet :: SOP.SListI xs => ByteString -> AggrHet xs y
1570+unsafeAggregateHet fun xs = UnsafeExpression $ mconcat
1571+ [fun, "(", renderSQL xs, ")"]
1572+
1573+{- |
1574+`Aggregate` functions compute a single result from a set of input values.
1575+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1576+as `WindowFunction`s.
1577+-}
1578+class Aggregate expr1 exprHet aggr
1579+ | aggr -> expr1, aggr -> exprHet where
1580+
1581+ -- | A special aggregation that does not require an input
1582+ --
1583+ -- >>> :{
1584+ -- let
1585+ -- expression :: Expression '[] ('Grouped bys) commons schemas params from ('NotNull 'PGint8)
1586+ -- expression = countStar
1587+ -- in printSQL expression
1588+ -- :}
1589+ -- count(*)
1590+ countStar :: aggr ('NotNull 'PGint8)
1591+
1592+ -- | >>> :{
1593+ -- let
1594+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1595+ -- expression = count (All #col)
1596+ -- in printSQL expression
1597+ -- :}
1598+ -- count(ALL "col")
1599+ count
1600+ :: expr1 ty
1601+ -- ^ what to count
1602+ -> aggr ('NotNull 'PGint8)
1603+
1604+ -- | >>> :{
1605+ -- let
1606+ -- expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1607+ -- expression = sum_ (Distinct #col)
1608+ -- in printSQL expression
1609+ -- :}
1610+ -- sum(DISTINCT "col")
1611+ sum_
1612+ :: ty `In` PGNum
1613+ => expr1 (null ty)
1614+ -> aggr ('NotNull ty)
1615+
1616+ -- | input values, including nulls, concatenated into an array
1617+ arrayAgg
1618+ :: expr1 ty
1619+ -> aggr ('Null ('PGvararray ty))
1620+
1621+ -- | aggregates values as a JSON array
1622+ jsonAgg
1623+ :: expr1 ty
1624+ -> aggr ('Null 'PGjson)
1625+
1626+ -- | aggregates values as a JSON array
1627+ jsonbAgg
1628+ :: expr1 ty
1629+ -> aggr ('Null 'PGjsonb)
1630+
1631+ {- |
1632+ the bitwise AND of all non-null input values, or null if none
1633+ >>> :{
1634+ let
1635+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1636+ expression = bitAnd (Distinct #col)
1637+ in printSQL expression
1638+ :}
1639+ bit_and(DISTINCT "col")
1640+ -}
1641+ bitAnd
1642+ :: int `In` PGIntegral
1643+ => expr1 (null int)
1644+ -- ^ what to aggregate
1645+ -> aggr ('Null int)
1646+
1647+ {- |
1648+ the bitwise OR of all non-null input values, or null if none
1649+
1650+ >>> :{
1651+ let
1652+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1653+ expression = bitOr (All #col)
1654+ in printSQL expression
1655+ :}
1656+ bit_or(ALL "col")
1657+ -}
1658+ bitOr
1659+ :: int `In` PGIntegral
1660+ => expr1 (null int)
1661+ -- ^ what to aggregate
1662+ -> aggr ('Null int)
1663+
1664+ {- |
1665+ true if all input values are true, otherwise false
1666+
1667+ >>> :{
1668+ let
1669+ winFun :: WindowFunction '[] 'Ungrouped commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1670+ winFun = boolAnd #col
1671+ in printSQL winFun
1672+ :}
1673+ bool_and("col")
1674+ -}
1675+ boolAnd
1676+ :: expr1 (null 'PGbool)
1677+ -- ^ what to aggregate
1678+ -> aggr ('Null 'PGbool)
1679+
1680+ {- |
1681+ true if at least one input value is true, otherwise false
1682+
1683+ >>> :{
1684+ let
1685+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1686+ expression = boolOr (All #col)
1687+ in printSQL expression
1688+ :}
1689+ bool_or(ALL "col")
1690+ -}
1691+ boolOr
1692+ :: expr1 (null 'PGbool)
1693+ -- ^ what to aggregate
1694+ -> aggr ('Null 'PGbool)
1695+
1696+ {- |
1697+ equivalent to `boolAnd`
1698+
1699+ >>> :{
1700+ let
1701+ expression :: Expression '[] ('Grouped bys) commons schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1702+ expression = every (Distinct #col)
1703+ in printSQL expression
1704+ :}
1705+ every(DISTINCT "col")
1706+ -}
1707+ every
1708+ :: expr1 (null 'PGbool)
1709+ -- ^ what to aggregate
1710+ -> aggr ('Null 'PGbool)
1711+
1712+ {- |maximum value of expression across all input values-}
1713+ max_
1714+ :: expr1 (null ty)
1715+ -- ^ what to maximize
1716+ -> aggr ('Null ty)
1717+
1718+ -- | minimum value of expression across all input values
1719+ min_
1720+ :: expr1 (null ty)
1721+ -- ^ what to minimize
1722+ -> aggr ('Null ty)
1723+
1724+ -- | the average (arithmetic mean) of all input values
1725+ avg
1726+ :: expr1 (null ty)
1727+ -- ^ what to average
1728+ -> aggr ('Null (PGAvg ty))
1729+
1730+ {- | correlation coefficient
1731+ >>> :{
1732+ let
1733+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1734+ expression = corr (All (#y *: #x))
1735+ in printSQL expression
1736+ :}
1737+ corr(ALL "y", "x")
1738+ -}
1739+ corr
1740+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1741+ -> aggr ('Null 'PGfloat8)
1742+
1743+ {- | population covariance
1744+ >>> :{
1745+ let
1746+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1747+ expression = covarPop (All (#y *: #x))
1748+ in printSQL expression
1749+ :}
1750+ covar_pop(ALL "y", "x")
1751+ -}
1752+ covarPop
1753+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1754+ -> aggr ('Null 'PGfloat8)
1755+
1756+ {- | sample covariance
1757+ >>> :{
1758+ let
1759+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1760+ winFun = covarSamp (#y *: #x)
1761+ in printSQL winFun
1762+ :}
1763+ covar_samp("y", "x")
1764+ -}
1765+ covarSamp
1766+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1767+ -> aggr ('Null 'PGfloat8)
1768+
1769+ {- | average of the independent variable (sum(X)/N)
1770+ >>> :{
1771+ let
1772+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1773+ expression = regrAvgX (All (#y *: #x))
1774+ in printSQL expression
1775+ :}
1776+ regr_avgx(ALL "y", "x")
1777+ -}
1778+ regrAvgX
1779+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1780+ -> aggr ('Null 'PGfloat8)
1781+
1782+ {- | average of the dependent variable (sum(Y)/N)
1783+ >>> :{
1784+ let
1785+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1786+ winFun = regrAvgY (#y *: #x)
1787+ in printSQL winFun
1788+ :}
1789+ regr_avgy("y", "x")
1790+ -}
1791+ regrAvgY
1792+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1793+ -> aggr ('Null 'PGfloat8)
1794+
1795+ {- | number of input rows in which both expressions are nonnull
1796+ >>> :{
1797+ let
1798+ winFun :: WindowFunction '[] 'Ungrouped c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1799+ winFun = regrCount (#y *: #x)
1800+ in printSQL winFun
1801+ :}
1802+ regr_count("y", "x")
1803+ -}
1804+ regrCount
1805+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1806+ -> aggr ('Null 'PGint8)
1807+
1808+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1809+ >>> :{
1810+ let
1811+ expression :: Expression '[] ('Grouped g) c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1812+ expression = regrIntercept (All (#y *: #x))
1813+ in printSQL expression
1814+ :}
1815+ regr_intercept(ALL "y", "x")
1816+ -}
1817+ regrIntercept
1818+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1819+ -> aggr ('Null 'PGfloat8)
1820+
1821+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1822+ regrR2
1823+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1824+ -> aggr ('Null 'PGfloat8)
1825+
1826+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1827+ -- determined by the (X, Y) pairs
1828+ regrSlope
1829+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1830+ -> aggr ('Null 'PGfloat8)
1831+
1832+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1833+ -- (“sum of squares” of the independent variable)
1834+ regrSxx
1835+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1836+ -> aggr ('Null 'PGfloat8)
1837+
1838+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1839+ -- (“sum of products” of independent times dependent variable)
1840+ regrSxy
1841+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1842+ -> aggr ('Null 'PGfloat8)
1843+
1844+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1845+ -- (“sum of squares” of the dependent variable)
1846+ regrSyy
1847+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1848+ -> aggr ('Null 'PGfloat8)
1849+
1850+ -- | historical alias for `stddevSamp`
1851+ stddev
1852+ :: expr1 (null ty)
1853+ -> aggr ('Null (PGAvg ty))
1854+
1855+ -- | population standard deviation of the input values
1856+ stddevPop
1857+ :: expr1 (null ty)
1858+ -> aggr ('Null (PGAvg ty))
1859+
1860+ -- | sample standard deviation of the input values
1861+ stddevSamp
1862+ :: expr1 (null ty)
1863+ -> aggr ('Null (PGAvg ty))
1864+
1865+ -- | historical alias for `varSamp`
1866+ variance
1867+ :: expr1 (null ty)
1868+ -> aggr ('Null (PGAvg ty))
1869+
1870+ -- | population variance of the input values
1871+ -- (square of the population standard deviation)
1872+ varPop
1873+ :: expr1 (null ty)
1874+ -> aggr ('Null (PGAvg ty))
1875+
1876+ -- | sample variance of the input values
1877+ -- (square of the sample standard deviation)
1878+ varSamp
1879+ :: expr1 (null ty)
1880+ -> aggr ('Null (PGAvg ty))
1881+
1882+{- |
1883+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1884+`All` invokes the aggregate once for each input row.
1885+`Distinct` invokes the aggregate once for each distinct value of the expression
1886+(or distinct set of values, for multiple expressions) found in the input
1887+-}
1888+data Distinction (expr :: kind -> Type) (ty :: kind)
1889+ = All (expr ty)
1890+ | Distinct (expr ty)
1891+ deriving (GHC.Generic,Show,Eq,Ord)
1892+instance NFData (Distinction (Expression outer grp commons schemas params from) ty)
1893+instance RenderSQL (Distinction (Expression outer grp commons schemas params from) ty) where
1894+ renderSQL = \case
1895+ All x -> "ALL" <+> renderSQL x
1896+ Distinct x -> "DISTINCT" <+> renderSQL x
1897+instance SOP.SListI tys => RenderSQL
1898+ (Distinction (NP (Expression outer grp commons schemas params from)) tys) where
1899+ renderSQL = \case
1900+ All xs -> "ALL" <+> renderCommaSeparated renderSQL xs
1901+ Distinct xs -> "DISTINCT" <+> renderCommaSeparated renderSQL xs
1902+
1903+instance Aggregate
1904+ (Distinction (Expression outer 'Ungrouped commons schemas params from))
1905+ (Distinction (NP (Expression outer 'Ungrouped commons schemas params from)))
1906+ (Expression outer ('Grouped bys) commons schemas params from) where
1907+ countStar = UnsafeExpression "count(*)"
1908+ count = unsafeAggregate1 "count"
1909+ sum_ = unsafeAggregate1 "sum"
1910+ arrayAgg = unsafeAggregate1 "array_agg"
1911+ jsonAgg = unsafeAggregate1 "json_agg"
1912+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1913+ bitAnd = unsafeAggregate1 "bit_and"
1914+ bitOr = unsafeAggregate1 "bit_or"
1915+ boolAnd = unsafeAggregate1 "bool_and"
1916+ boolOr = unsafeAggregate1 "bool_or"
1917+ every = unsafeAggregate1 "every"
1918+ max_ = unsafeAggregate1 "max"
1919+ min_ = unsafeAggregate1 "min"
1920+ avg = unsafeAggregate1 "avg"
1921+ corr = unsafeAggregateHet "corr"
1922+ covarPop = unsafeAggregateHet "covar_pop"
1923+ covarSamp = unsafeAggregateHet "covar_samp"
1924+ regrAvgX = unsafeAggregateHet "regr_avgx"
1925+ regrAvgY = unsafeAggregateHet "regr_avgy"
1926+ regrCount = unsafeAggregateHet "regr_count"
1927+ regrIntercept = unsafeAggregateHet "regr_intercept"
1928+ regrR2 = unsafeAggregateHet "regr_r2"
1929+ regrSlope = unsafeAggregateHet "regr_slope"
1930+ regrSxx = unsafeAggregateHet "regr_sxx"
1931+ regrSxy = unsafeAggregateHet "regr_sxy"
1932+ regrSyy = unsafeAggregateHet "regr_syy"
1933+ stddev = unsafeAggregate1 "stddev"
1934+ stddevPop = unsafeAggregate1 "stddev_pop"
1935+ stddevSamp = unsafeAggregate1 "stddev_samp"
1936+ variance = unsafeAggregate1 "variance"
1937+ varPop = unsafeAggregate1 "var_pop"
1938+ varSamp = unsafeAggregate1 "var_samp"
1939+instance Aggregate
1940+ (Expression outer grp commons schemas params from)
1941+ (NP (Expression outer grp commons schemas params from))
1942+ (WindowFunction outer grp commons schemas params from) where
1943+ countStar = UnsafeWindowFunction "count(*)"
1944+ count = unsafeWindowFunction1 "count"
1945+ sum_ = unsafeWindowFunction1 "sum"
1946+ arrayAgg = unsafeWindowFunction1 "array_agg"
1947+ jsonAgg = unsafeWindowFunction1 "json_agg"
1948+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1949+ bitAnd = unsafeWindowFunction1 "bit_and"
1950+ bitOr = unsafeWindowFunction1 "bit_or"
1951+ boolAnd = unsafeWindowFunction1 "bool_and"
1952+ boolOr = unsafeWindowFunction1 "bool_or"
1953+ every = unsafeWindowFunction1 "every"
1954+ max_ = unsafeWindowFunction1 "max"
1955+ min_ = unsafeWindowFunction1 "min"
1956+ avg = unsafeWindowFunction1 "avg"
1957+ corr = unsafeWindowFunctionHet "corr"
1958+ covarPop = unsafeWindowFunctionHet "covar_pop"
1959+ covarSamp = unsafeWindowFunctionHet "covar_samp"
1960+ regrAvgX = unsafeWindowFunctionHet "regr_avgx"
1961+ regrAvgY = unsafeWindowFunctionHet "regr_avgy"
1962+ regrCount = unsafeWindowFunctionHet "regr_count"
1963+ regrIntercept = unsafeWindowFunctionHet "regr_intercept"
1964+ regrR2 = unsafeWindowFunctionHet "regr_r2"
1965+ regrSlope = unsafeWindowFunctionHet "regr_slope"
1966+ regrSxx = unsafeWindowFunctionHet "regr_sxx"
1967+ regrSxy = unsafeWindowFunctionHet "regr_sxy"
1968+ regrSyy = unsafeWindowFunctionHet "regr_syy"
1969+ stddev = unsafeWindowFunction1 "stddev"
1970+ stddevPop = unsafeWindowFunction1 "stddev_pop"
1971+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
1972+ variance = unsafeWindowFunction1 "variance"
1973+ varPop = unsafeWindowFunction1 "var_pop"
1974+ varSamp = unsafeWindowFunction1 "var_samp"
1975+
1976+-- | escape hatch to define aggregate functions
1977+unsafeAggregate1
1978+ :: ByteString -- ^ aggregate function
1979+ -> AggrFun xty yty
1980+unsafeAggregate1 fun x = UnsafeExpression $ mconcat
1981+ [fun, "(", renderSQL x, ")"]
1982+
1983+-- | A type family that calculates `PGAvg` type of a `PGType`.
1984+type family PGAvg ty where
1985+ PGAvg 'PGint2 = 'PGnumeric
1986+ PGAvg 'PGint4 = 'PGnumeric
1987+ PGAvg 'PGint8 = 'PGnumeric
1988+ PGAvg 'PGnumeric = 'PGnumeric
1989+ PGAvg 'PGfloat4 = 'PGfloat8
1990+ PGAvg 'PGfloat8 = 'PGfloat8
1991+ PGAvg 'PGinterval = 'PGinterval
1992+ PGAvg pg = TypeError
1993+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
1994+
1995+{-----------------------------------------
1996+type expressions
1997+-----------------------------------------}
1998+
1999+-- | `TypeExpression`s are used in `cast`s and
2000+-- `Squeal.PostgreSQL.Definition.createTable` commands.
2001+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
2002+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
2003+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2004+instance RenderSQL (TypeExpression schemas ty) where
2005+ renderSQL = renderTypeExpression
2006+
2007+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
2008+typedef
2009+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
2010+ => QualifiedAlias sch td
2011+ -> TypeExpression schemas (null ty)
2012+typedef = UnsafeTypeExpression . renderSQL
2013+
2014+-- | The composite type corresponding to a `Table` definition can be expressed
2015+-- by its alias.
2016+typetable
2017+ :: (Has sch schemas schema, Has tab schema ('Table table))
2018+ => QualifiedAlias sch tab
2019+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
2020+typetable = UnsafeTypeExpression . renderSQL
2021+
2022+-- | The composite type corresponding to a `View` definition can be expressed
2023+-- by its alias.
2024+typeview
2025+ :: (Has sch schemas schema, Has vw schema ('View view))
2026+ => QualifiedAlias sch vw
2027+ -> TypeExpression schemas (null ('PGcomposite view))
2028+typeview = UnsafeTypeExpression . renderSQL
2029+
2030+-- | logical Boolean (true/false)
2031+bool :: TypeExpression schemas (null 'PGbool)
2032+bool = UnsafeTypeExpression "bool"
2033+-- | signed two-byte integer
2034+int2, smallint :: TypeExpression schemas (null 'PGint2)
2035+int2 = UnsafeTypeExpression "int2"
2036+smallint = UnsafeTypeExpression "smallint"
2037+-- | signed four-byte integer
2038+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2039+int4 = UnsafeTypeExpression "int4"
2040+int = UnsafeTypeExpression "int"
2041+integer = UnsafeTypeExpression "integer"
2042+-- | signed eight-byte integer
2043+int8, bigint :: TypeExpression schemas (null 'PGint8)
2044+int8 = UnsafeTypeExpression "int8"
2045+bigint = UnsafeTypeExpression "bigint"
2046+-- | arbitrary precision numeric type
2047+numeric :: TypeExpression schemas (null 'PGnumeric)
2048+numeric = UnsafeTypeExpression "numeric"
2049+-- | single precision floating-point number (4 bytes)
2050+float4, real :: TypeExpression schemas (null 'PGfloat4)
2051+float4 = UnsafeTypeExpression "float4"
2052+real = UnsafeTypeExpression "real"
2053+-- | double precision floating-point number (8 bytes)
2054+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2055+float8 = UnsafeTypeExpression "float8"
2056+doublePrecision = UnsafeTypeExpression "double precision"
2057+-- | currency amount
2058+money :: TypeExpression schema (null 'PGmoney)
2059+money = UnsafeTypeExpression "money"
2060+-- | variable-length character string
2061+text :: TypeExpression schemas (null 'PGtext)
2062+text = UnsafeTypeExpression "text"
2063+-- | fixed-length character string
2064+char, character
2065+ :: forall n schemas null. (KnownNat n, 1 <= n)
2066+ => TypeExpression schemas (null ('PGchar n))
2067+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2068+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2069+-- | variable-length character string
2070+varchar, characterVarying
2071+ :: forall n schemas null. (KnownNat n, 1 <= n)
2072+ => TypeExpression schemas (null ('PGvarchar n))
2073+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2074+characterVarying = UnsafeTypeExpression $
2075+ "character varying(" <> renderNat @n <> ")"
2076+-- | binary data ("byte array")
2077+bytea :: TypeExpression schemas (null 'PGbytea)
2078+bytea = UnsafeTypeExpression "bytea"
2079+-- | date and time (no time zone)
2080+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2081+timestamp = UnsafeTypeExpression "timestamp"
2082+-- | date and time, including time zone
2083+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2084+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2085+-- | calendar date (year, month, day)
2086+date :: TypeExpression schemas (null 'PGdate)
2087+date = UnsafeTypeExpression "date"
2088+-- | time of day (no time zone)
2089+time :: TypeExpression schemas (null 'PGtime)
2090+time = UnsafeTypeExpression "time"
2091+-- | time of day, including time zone
2092+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2093+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2094+-- | time span
2095+interval :: TypeExpression schemas (null 'PGinterval)
2096+interval = UnsafeTypeExpression "interval"
2097+-- | universally unique identifier
2098+uuid :: TypeExpression schemas (null 'PGuuid)
2099+uuid = UnsafeTypeExpression "uuid"
2100+-- | IPv4 or IPv6 host address
2101+inet :: TypeExpression schemas (null 'PGinet)
2102+inet = UnsafeTypeExpression "inet"
2103+-- | textual JSON data
2104+json :: TypeExpression schemas (null 'PGjson)
2105+json = UnsafeTypeExpression "json"
2106+-- | binary JSON data, decomposed
2107+jsonb :: TypeExpression schemas (null 'PGjsonb)
2108+jsonb = UnsafeTypeExpression "jsonb"
2109+-- | variable length array
2110+vararray
2111+ :: TypeExpression schemas pg
2112+ -> TypeExpression schemas (null ('PGvararray pg))
2113+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2114+-- | fixed length array
2115+--
2116+-- >>> renderSQL (fixarray @'[2] json)
2117+-- "json[2]"
2118+fixarray
2119+ :: forall dims schemas null pg. SOP.All KnownNat dims
2120+ => TypeExpression schemas pg
2121+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2122+fixarray ty = UnsafeTypeExpression $
2123+ renderSQL ty <> renderDims @dims
2124+ where
2125+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2126+ renderDims =
2127+ ("[" <>)
2128+ . (<> "]")
2129+ . ByteString.intercalate "]["
2130+ . hcollapse
2131+ $ hcmap (SOP.Proxy @KnownNat)
2132+ (K . fromString . show . natVal)
2133+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2134+tsvector :: TypeExpression schemas (null 'PGtsvector)
2135+tsvector = UnsafeTypeExpression "tsvector"
2136+tsquery :: TypeExpression schemas (null 'PGtsquery)
2137+tsquery = UnsafeTypeExpression "tsquery"
2138+
2139+-- | `pgtype` is a demoted version of a `PGType`
2140+class PGTyped schemas (ty :: NullityType) where
2141+ pgtype :: TypeExpression schemas ty
2142+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2143+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2144+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2145+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2146+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2147+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2148+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2149+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2150+instance PGTyped schemas (null 'PGtext) where pgtype = text
2151+instance (KnownNat n, 1 <= n)
2152+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2153+instance (KnownNat n, 1 <= n)
2154+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2155+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2156+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2157+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2158+instance PGTyped schemas (null 'PGdate) where pgtype = date
2159+instance PGTyped schemas (null 'PGtime) where pgtype = time
2160+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2161+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2162+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2163+instance PGTyped schemas (null 'PGjson) where pgtype = json
2164+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2165+instance PGTyped schemas ty
2166+ => PGTyped schemas (null ('PGvararray ty)) where
2167+ pgtype = vararray (pgtype @schemas @ty)
2168+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2169+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2170+ pgtype = fixarray @dims (pgtype @schemas @ty)
2171+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2172+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2173+
2174+{-----------------------------------------
2175+Sorting
2176+-----------------------------------------}
2177+
2178+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2179+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2180+-- set the sort direction of a `NotNull` result
2181+-- column to ascending or descending. Ascending order puts smaller values
2182+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2183+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2184+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2185+-- determine whether nulls appear before or after non-null values in the sort
2186+-- ordering of a `Null` result column.
2187+data SortExpression outer grp commons schemas params from where
2188+ Asc
2189+ :: Expression outer grp commons schemas params from ('NotNull ty)
2190+ -> SortExpression outer grp commons schemas params from
2191+ Desc
2192+ :: Expression outer grp commons schemas params from ('NotNull ty)
2193+ -> SortExpression outer grp commons schemas params from
2194+ AscNullsFirst
2195+ :: Expression outer grp commons schemas params from ('Null ty)
2196+ -> SortExpression outer grp commons schemas params from
2197+ AscNullsLast
2198+ :: Expression outer grp commons schemas params from ('Null ty)
2199+ -> SortExpression outer grp commons schemas params from
2200+ DescNullsFirst
2201+ :: Expression outer grp commons schemas params from ('Null ty)
2202+ -> SortExpression outer grp commons schemas params from
2203+ DescNullsLast
2204+ :: Expression outer grp commons schemas params from ('Null ty)
2205+ -> SortExpression outer grp commons schemas params from
2206+deriving instance Show (SortExpression outer grp commons schemas params from)
2207+
2208+{- |
2209+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2210+to be sorted according to the specified `SortExpression`(s).
2211+If two rows are equal according to the leftmost expression,
2212+they are compared according to the next expression and so on.
2213+If they are equal according to all specified expressions,
2214+they are returned in an implementation-dependent order.
2215+
2216+You can also control the order in which rows are processed by window functions
2217+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2218+-}
2219+class OrderBy expr where
2220+ orderBy
2221+ :: [SortExpression outer grp commons schemas params from]
2222+ -> expr outer grp commons schemas params from
2223+ -> expr outer grp commons schemas params from
2224+
2225+-- | Render a `SortExpression`.
2226+instance RenderSQL (SortExpression outer grp commons schemas params from) where
2227+ renderSQL = \case
2228+ Asc expression -> renderSQL expression <+> "ASC"
2229+ Desc expression -> renderSQL expression <+> "DESC"
2230+ AscNullsFirst expression -> renderSQL expression
2231+ <+> "ASC NULLS FIRST"
2232+ DescNullsFirst expression -> renderSQL expression
2233+ <+> "DESC NULLS FIRST"
2234+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2235+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2236+
2237+-- | A `WindowDefinition` is a set of table rows that are somehow related
2238+-- to the current row
2239+data WindowDefinition outer grp commons schemas params from where
2240+ WindowDefinition
2241+ :: SListI bys
2242+ => NP (Expression outer grp commons schemas params from) bys
2243+ -> [SortExpression outer grp commons schemas params from]
2244+ -> WindowDefinition outer grp commons schemas params from
2245+
2246+instance OrderBy WindowDefinition where
2247+ orderBy sortsR (WindowDefinition parts sortsL)
2248+ = WindowDefinition parts (sortsL ++ sortsR)
2249+
2250+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2251+ renderSQL (WindowDefinition part ord) =
2252+ renderPartitionByClause part <> renderOrderByClause ord
2253+ where
2254+ renderPartitionByClause = \case
2255+ Nil -> ""
2256+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2257+ renderOrderByClause = \case
2258+ [] -> ""
2259+ srts -> " ORDER" <+> "BY"
2260+ <+> commaSeparated (renderSQL <$> srts)
2261+
2262+{- |
2263+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2264+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2265+For each row, the window function is computed across the rows that fall into
2266+the same partition as the current row.
2267+-}
2268+partitionBy
2269+ :: SListI bys
2270+ => NP (Expression outer grp commons schemas params from) bys
2271+ -> WindowDefinition outer grp commons schemas params from
2272+partitionBy bys = WindowDefinition bys []
2273+
2274+{- |
2275+A window function performs a calculation across a set of table rows
2276+that are somehow related to the current row. This is comparable to the type
2277+of calculation that can be done with an aggregate function.
2278+However, window functions do not cause rows to become grouped into a single
2279+output row like non-window aggregate calls would.
2280+Instead, the rows retain their separate identities.
2281+Behind the scenes, the window function is able to access more than
2282+just the current row of the query result.
2283+-}
2284+newtype WindowFunction
2285+ (outer :: FromType)
2286+ (grp :: Grouping)
2287+ (commons :: FromType)
2288+ (schemas :: SchemasType)
2289+ (params :: [NullityType])
2290+ (from :: FromType)
2291+ (ty :: NullityType)
2292+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2293+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2294+
2295+instance RenderSQL (WindowFunction outer grp commons schemas params from ty) where
2296+ renderSQL = renderWindowFunction
2297+
2298+type WinFun0 x
2299+ = forall outer grp commons schemas params from
2300+ . WindowFunction outer grp commons schemas params from x
2301+ -- ^ cannot reference aliases
2302+
2303+type WinFun1 x y
2304+ = forall outer grp commons schemas params from
2305+ . Expression outer grp commons schemas params from x
2306+ -- ^ input
2307+ -> WindowFunction outer grp commons schemas params from y
2308+ -- ^ output
2309+
2310+type WinFunHet xs y
2311+ = forall outer grp commons schemas params from
2312+ . NP (Expression outer grp commons schemas params from) xs
2313+ -- ^ inputs
2314+ -> WindowFunction outer grp commons schemas params from y
2315+ -- ^ output
2316+
2317+unsafeWindowFunction1 :: ByteString -> WinFun1 x y
2318+unsafeWindowFunction1 fun x
2319+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2320+
2321+unsafeWindowFunctionHet :: SOP.SListI xs => ByteString -> WinFunHet xs y
2322+unsafeWindowFunctionHet fun xs = UnsafeWindowFunction $ fun <>
2323+ parenthesized (renderCommaSeparated renderSQL xs)
2324+
2325+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2326+>>> printSQL rank
2327+rank()
2328+-}
2329+rank :: WinFun0 ('NotNull 'PGint8)
2330+rank = UnsafeWindowFunction "rank()"
2331+
2332+{- | number of the current row within its partition, counting from 1
2333+>>> printSQL rowNumber
2334+row_number()
2335+-}
2336+rowNumber :: WinFun0 ('NotNull 'PGint8)
2337+rowNumber = UnsafeWindowFunction "row_number()"
2338+
2339+{- | rank of the current row without gaps; this function counts peer groups
2340+>>> printSQL denseRank
2341+dense_rank()
2342+-}
2343+denseRank :: WinFun0 ('NotNull 'PGint8)
2344+denseRank = UnsafeWindowFunction "dense_rank()"
2345+
2346+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2347+>>> printSQL percentRank
2348+percent_rank()
2349+-}
2350+percentRank :: WinFun0 ('NotNull 'PGfloat8)
2351+percentRank = UnsafeWindowFunction "percent_rank()"
2352+
2353+{- | cumulative distribution: (number of partition rows
2354+preceding or peer with current row) / total partition rows
2355+>>> printSQL cumeDist
2356+cume_dist()
2357+-}
2358+cumeDist :: WinFun0 ('NotNull 'PGfloat8)
2359+cumeDist = UnsafeWindowFunction "cume_dist()"
2360+
2361+{- | integer ranging from 1 to the argument value,
2362+dividing the partition as equally as possible
2363+-}
2364+ntile :: WinFun1 ('NotNull 'PGint4) ('NotNull 'PGint4)
2365+ntile = unsafeWindowFunction1 "ntile"
2366+
2367+{- | returns value evaluated at the row that is offset rows before the current
2368+row within the partition; if there is no such row, instead return default
2369+(which must be of the same type as value). Both offset and default are
2370+evaluated with respect to the current row.
2371+-}
2372+lag :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2373+lag = unsafeWindowFunctionHet "lag"
2374+
2375+{- | returns value evaluated at the row that is offset rows after the current
2376+row within the partition; if there is no such row, instead return default
2377+(which must be of the same type as value). Both offset and default are
2378+evaluated with respect to the current row.
2379+-}
2380+lead :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2381+lead = unsafeWindowFunctionHet "lag"
2382+
2383+{- | returns value evaluated at the row that is the
2384+first row of the window frame
2385+-}
2386+firstValue :: WinFun1 ty ty
2387+firstValue = unsafeWindowFunction1 "first_value"
2388+
2389+{- | returns value evaluated at the row that is the
2390+last row of the window frame
2391+-}
2392+lastValue :: WinFun1 ty ty
2393+lastValue = unsafeWindowFunction1 "last_value"
2394+
2395+{- | returns value evaluated at the row that is the nth
2396+row of the window frame (counting from 1); null if no such row
2397+-}
2398+nthValue :: WinFunHet '[null ty, 'NotNull 'PGint4] ('Null ty)
2399+nthValue = unsafeWindowFunctionHet "nth_value"
2400+
2401+{-|
2402+Create date from year, month and day fields
2403+
2404+>>> printSQL (makeDate (1984 :* 7 *: 3))
2405+make_date(1984, 7, 3)
2406+-}
2407+makeDate :: FunctionHet
2408+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2409+ ( null 'PGdate )
2410+makeDate = unsafeFunctionHet "make_date"
2411+
2412+{-|
2413+Create time from hour, minute and seconds fields
2414+
2415+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2416+make_time(8, 15, 23.5)
2417+-}
2418+makeTime :: FunctionHet
2419+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2420+ ( null 'PGtime )
2421+makeTime = unsafeFunctionHet "make_time"
2422+
2423+{-|
2424+Create timestamp from year, month, day, hour, minute and seconds fields
2425+
2426+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2427+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2428+-}
2429+makeTimestamp :: FunctionHet
2430+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2431+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2432+ ( null 'PGtimestamp )
2433+makeTimestamp = unsafeFunctionHet "make_timestamp"
2434+
2435+{-|
2436+Create timestamp with time zone from
2437+year, month, day, hour, minute and seconds fields;
2438+the current time zone is used
2439+
2440+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2441+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2442+-}
2443+makeTimestamptz :: FunctionHet
2444+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2445+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2446+ ( null 'PGtimestamptz )
2447+makeTimestamptz = unsafeFunctionHet "make_timestamptz"
2448+
2449+{-|
2450+Affine space operations on time types.
2451+-}
2452+class TimeOp time diff | time -> diff where
2453+ {-|
2454+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2455+ (make_date(1984, 7, 3) + 365)
2456+ -}
2457+ (!+) :: Operator (null time) (null diff) (null time)
2458+ (!+) = unsafeBinaryOp "+"
2459+ {-|
2460+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2461+ (365 + make_date(1984, 7, 3))
2462+ -}
2463+ (+!) :: Operator (null diff) (null time) (null time)
2464+ (+!) = unsafeBinaryOp "+"
2465+ {-|
2466+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2467+ (make_date(1984, 7, 3) - 365)
2468+ -}
2469+ (!-) :: Operator (null time) (null diff) (null time)
2470+ (!-) = unsafeBinaryOp "-"
2471+ {-|
2472+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2473+ (make_date(1984, 7, 3) - CURRENT_DATE)
2474+ -}
2475+ (!-!) :: Operator (null time) (null time) (null diff)
2476+ (!-!) = unsafeBinaryOp "-"
2477+instance TimeOp 'PGtimestamp 'PGinterval
2478+instance TimeOp 'PGtimestamptz 'PGinterval
2479+instance TimeOp 'PGtime 'PGinterval
2480+instance TimeOp 'PGtimetz 'PGinterval
2481+instance TimeOp 'PGinterval 'PGinterval
2482+instance TimeOp 'PGdate 'PGint4
2483+infixl 6 !+
2484+infixl 6 +!
2485+infixl 6 !-
2486+infixl 6 !-!