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