@@ -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,54 +35,253 @@ module Squeal.PostgreSQL.Expression
3435 ( -- * Expression
3536 Expression (..)
3637 , Expr
37− , type (-->)
38− , FunctionDB
38+ , (:-->)
3939 , unsafeFunction
40− , function
41− , unsafeLeftOp
42− , leftOp
43− , unsafeRightOp
44− , rightOp
40+ , unsafeUnaryOpL
41+ , unsafeUnaryOpR
4542 , Operator
46− , OperatorDB
4743 , unsafeBinaryOp
48− , binaryOp
4944 , FunctionVar
5045 , unsafeFunctionVar
51− , type (--->)
52− , FunctionNDB
46+ , FunctionN
5347 , unsafeFunctionN
54− , functionN
48+ , Literal (..)
49+ , HasParameter (parameter)
50+ , param
51+ -- * Null
52+ , null_
53+ , notNull
54+ , coalesce
55+ , fromNull
56+ , isNull
57+ , isNotNull
58+ , matchNull
59+ , nullIf
60+ -- * Collections
61+ , array
62+ , array1
63+ , array2
64+ , cardinality
65+ , index
66+ , row
67+ , field
5568 , PGSubset (..)
56− , PGIntersect (..)
69+ -- * Numerical
70+ , atan2_
71+ , quot_
72+ , rem_
73+ , trunc
74+ , round_
75+ , ceiling_
76+ -- * Logic
77+ , Condition
78+ , true
79+ , false
80+ , not_
81+ , (.&&)
82+ , (.||)
83+ , caseWhenThenElse
84+ , ifThenElse
85+ -- * Comparison
86+ , (.==)
87+ , (./=)
88+ , (.>=)
89+ , (.<)
90+ , (.<=)
91+ , (.>)
92+ , greatest
93+ , least
94+ , between
95+ , notBetween
96+ , betweenSymmetric
97+ , notBetweenSymmetric
98+ , isDistinctFrom
99+ , isNotDistinctFrom
100+ , isTrue
101+ , isNotTrue
102+ , isFalse
103+ , isNotFalse
104+ , isUnknown
105+ , isNotUnknown
106+ -- * Time
107+ , TimeOp (..)
108+ , currentDate
109+ , currentTime
110+ , currentTimestamp
111+ , localTime
112+ , localTimestamp
113+ , now
114+ , makeDate
115+ , makeTime
116+ , makeTimestamp
117+ , makeTimestamptz
118+ , interval_
119+ , TimeUnit (..)
120+ -- * Text
121+ , lower
122+ , upper
123+ , charLength
124+ , like
125+ , ilike
126+ -- * Json
127+ -- ** Json and Jsonb operators
128+ , (.->)
129+ , (.->>)
130+ , (.#>)
131+ , (.#>>)
132+ -- ** Jsonb operators
133+ , (.?)
134+ , (.?|)
135+ , (.?&)
136+ , (.-.)
137+ , (#-.)
138+ -- ** Functions
139+ , toJson
140+ , toJsonb
141+ , arrayToJson
142+ , rowToJson
143+ , jsonBuildArray
144+ , jsonbBuildArray
145+ , PGBuildObject
146+ , jsonBuildObject
147+ , jsonbBuildObject
148+ , jsonObject
149+ , jsonbObject
150+ , jsonZipObject
151+ , jsonbZipObject
152+ , jsonArrayLength
153+ , jsonbArrayLength
154+ , jsonExtractPath
155+ , jsonbExtractPath
156+ , jsonExtractPathAsText
157+ , jsonbExtractPathAsText
158+ , jsonTypeof
159+ , jsonbTypeof
160+ , jsonStripNulls
161+ , jsonbStripNulls
162+ , jsonbSet
163+ , jsonbInsert
164+ , jsonbPretty
165+ -- * Text Search
166+ , (@@)
167+ , (.&)
168+ , (.|)
169+ , (.!)
170+ , (<->)
171+ , arrayToTSvector
172+ , tsvectorLength
173+ , numnode
174+ , plainToTSquery
175+ , phraseToTSquery
176+ , websearchToTSquery
177+ , queryTree
178+ , toTSquery
179+ , toTSvector
180+ , setWeight
181+ , strip
182+ , jsonToTSvector
183+ , jsonbToTSvector
184+ , tsDelete
185+ , tsFilter
186+ , tsHeadline
187+ -- * Aggregation
188+ , Aggregate (..)
189+ , Distinction (..)
190+ , PGAvg
191+ -- * Window Functions
192+ , WindowDefinition (..)
193+ , partitionBy
194+ , WindowFunction (..)
195+ , rank
196+ , rowNumber
197+ , denseRank
198+ , percentRank
199+ , cumeDist
200+ , ntile
201+ , lag
202+ , lead
203+ , firstValue
204+ , lastValue
205+ , nthValue
206+ -- * Sorting
207+ , SortExpression (..)
208+ , OrderBy (..)
209+ -- * Types
210+ , TypeExpression (..)
211+ , cast
212+ , PGTyped (..)
213+ , typedef
214+ , typetable
215+ , typeview
216+ , bool
217+ , int2
218+ , smallint
219+ , int4
220+ , int
221+ , integer
222+ , int8
223+ , bigint
224+ , numeric
225+ , float4
226+ , real
227+ , float8
228+ , doublePrecision
229+ , money
230+ , text
231+ , char
232+ , character
233+ , varchar
234+ , characterVarying
235+ , bytea
236+ , timestamp
237+ , timestampWithTimeZone
238+ , date
239+ , time
240+ , timeWithTimeZone
241+ , interval
242+ , uuid
243+ , inet
244+ , json
245+ , jsonb
246+ , vararray
247+ , fixarray
248+ , tsvector
249+ , tsquery
57250 -- * Re-export
58251 , (&)
252+ , NP (..)
59253 , K (..)
60− , unK
61254 ) where
62255
63256import Control.Category
64257import Control.DeepSeq
65258import Data.ByteString (ByteString)
259+import Data.ByteString.Lazy (toStrict)
66260import Data.Function ((&))
261+import Data.Kind
67262import Data.Semigroup hiding (All)
263+import qualified Data.Aeson as JSON
264+import Data.Int
68265import Data.String
266+import Data.Text (Text)
267+import Data.Word
69268import Generics.SOP hiding (All, from)
70269import GHC.OverloadedLabels
71270import GHC.TypeLits
72271import Numeric
73272import Prelude hiding (id, (.))
74273
274+import qualified Data.ByteString as ByteString
275+import qualified Data.Text as Text
276+import qualified Data.Text.Lazy as Lazy (Text)
277+import qualified Data.Text.Lazy as Lazy.Text
75278import qualified GHC.Generics as GHC
279+import qualified Generics.SOP as SOP
76280
77−import Squeal.PostgreSQL.Alias
78−import Squeal.PostgreSQL.List
281+import Squeal.PostgreSQL.Binary
79282import Squeal.PostgreSQL.Render
80283import Squeal.PostgreSQL.Schema
81284
82−-- $setup
83−-- >>> import Squeal.PostgreSQL
84−
85285{-----------------------------------------
86286column expressions
87287-----------------------------------------}
@@ -91,22 +291,21 @@ such as in the target `Squeal.PostgreSQL.Query.List` of the
91291`Squeal.PostgreSQL.Query.select` command,
92292as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or
93293`Squeal.PostgreSQL.Manipulation.update`,
94−or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.
294+or in search `Condition`s in a number of commands.
95295
96296The expression syntax allows the calculation of
97297values from primitive expression using arithmetic, logical,
98298and other operations.
99299
100−The type parameters of `Expression` are
300+The type paremeters of `Expression` are
101301
102302* @outer :: @ `FromType`, the @from@ clauses of any outer queries in which
103303 the `Expression` is a correlated subquery expression;
104−* @commons :: @ `FromType`, the `Squeal.PostgreSQL.Query.CommonTableExpression`s
105− that are in scope for the `Expression`;
304+* @commons :: @ `FromType`, `Squeal.PostgreSQL.Query.CommonTableExpression`s that are in
305+ scope for the `Expression`;
106306* @grp :: @ `Grouping`, the `Grouping` of the @from@ clause which may limit
107307 which columns may be referenced by alias;
108−* @schemas :: @ `SchemasType`, the schemas of your database that are in
109− scope for the `Expression`;
308+* @schemas :: @ `SchemasType`, the schemas of your database;
110309* @from :: @ `FromType`, the @from@ clause which the `Expression` may use
111310 to reference columns by alias;
112311* @ty :: @ `NullityType`, the type of the `Expression`.
@@ -125,7 +324,7 @@ instance RenderSQL (Expression outer commons grp schemas params from ty) where
125324 renderSQL = renderExpression
126325
127326-- | An `Expr` is a closed `Expression`.
128−-- It is a F@RankNType@ but don't be scared.
327+-- It is a F`RankNType` but don't be scared.
129328-- Think of it as an expression which sees no
130329-- namespaces, so you can't use parameters
131330-- or alias references. It can be used as
@@ -135,7 +334,7 @@ type Expr x
135334 . Expression outer commons grp schemas params from x
136335 -- ^ cannot reference aliases
137336
138−-- | A @RankNType@ for binary operators.
337+-- | A `RankNType` for binary operators.
139338type Operator x1 x2 y
140339 = forall outer commons grp schemas params from
141340 . Expression outer commons grp schemas params from x1
@@ -145,55 +344,32 @@ type Operator x1 x2 y
145344 -> Expression outer commons grp schemas params from y
146345 -- ^ output
147346
148−type OperatorDB schemas x1 x2 y
149− = forall outer commons grp params from
150− . Expression outer commons grp schemas params from x1
151− -- ^ left input
152− -> Expression outer commons grp schemas params from x2
153− -- ^ right input
154− -> Expression outer commons grp schemas params from y
155− -- ^ output
156−
157−-- | A @RankNType@ for functions with a single argument.
347+-- | A `RankNType` for functions with a single argument.
158348-- These could be either function calls or unary operators.
159349-- This is a subtype of the usual Haskell function type `Prelude.->`,
160350-- indeed a subcategory as it is closed under the usual
161351-- `Prelude..` and `Prelude.id`.
162−type (-->) x y
352+type (:-->) x y
163353 = forall outer commons grp schemas params from
164354 . Expression outer commons grp schemas params from x
165355 -- ^ input
166356 -> Expression outer commons grp schemas params from y
167357 -- ^ output
168358
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.
359+{- | A `RankNType` for functions with a fixed-length list of heterogeneous arguments.
177360Use the `*:` operator to end your argument lists, like so.
178361
179362>>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true))
180363fun(TRUE, FALSE, LOCALTIME, TRUE)
181364-}
182−type (--->) xs y
365+type FunctionN xs y
183366 = forall outer commons grp schemas params from
184367 . NP (Expression outer commons grp schemas params from) xs
185368 -- ^ inputs
186369 -> Expression outer commons grp schemas params from y
187370 -- ^ output
188371
189−type FunctionNDB schemas xs y
190− = forall outer commons grp params from
191− . NP (Expression outer commons grp schemas params from) xs
192− -- ^ inputs
193− -> Expression outer commons grp schemas params from y
194− -- ^ output
195−
196−{- | A @RankNType@ for functions with a variable-length list of
372+{- | A `RankNType` for functions with a variable-length list of
197373homogeneous arguments and at least 1 more argument.
198374-}
199375type FunctionVar x0 x1 y
@@ -212,6 +388,46 @@ unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
212388unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
213389 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
214390
391+{- | A `HasParameter` constraint is used to indicate a value that is
392+supplied externally to a SQL statement.
393+`Squeal.PostgreSQL.PQ.manipulateParams`,
394+`Squeal.PostgreSQL.PQ.queryParams` and
395+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
396+separately from the SQL command string, in which case `param`s are used to
397+refer to the out-of-line data values.
398+-}
399+class KnownNat n => HasParameter
400+ (n :: Nat)
401+ (params :: [NullityType])
402+ (ty :: NullityType)
403+ | n params -> ty where
404+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
405+ --
406+ -- >>> let expr = parameter @1 int4 :: Expression outer '[] grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
407+ -- >>> printSQL expr
408+ -- ($1 :: int4)
409+ parameter
410+ :: TypeExpression schemas ty
411+ -> Expression outer commons grp schemas params from ty
412+ parameter ty = UnsafeExpression $ parenthesized $
413+ "$" <> renderNat @n <+> "::"
414+ <+> renderSQL ty
415+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
416+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
417+ => HasParameter n (ty' : params) ty
418+
419+-- | `param` takes a `Nat` using type application and for basic types,
420+-- infers a `TypeExpression`.
421+--
422+-- >>> let expr = param @1 :: Expression outer commons grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
423+-- >>> printSQL expr
424+-- ($1 :: int4)
425+param
426+ :: forall n outer commons schemas params from grp ty
427+ . (PGTyped schemas ty, HasParameter n params ty)
428+ => Expression outer commons grp schemas params from ty -- ^ param
429+param = parameter @n (pgtype @schemas)
430+
215431instance (HasUnique tab (Join outer from) row, Has col row ty)
216432 => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
217433 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
@@ -308,73 +524,245 @@ instance
308524 (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where
309525 tab ! col = tab ! col :* Nil
310526
527+-- | analagous to `Nothing`
528+--
529+-- >>> printSQL null_
530+-- NULL
531+null_ :: Expr ('Null ty)
532+null_ = UnsafeExpression "NULL"
533+
534+-- | analagous to `Just`
535+--
536+-- >>> printSQL $ notNull true
537+-- TRUE
538+notNull :: 'NotNull ty :--> 'Null ty
539+notNull = UnsafeExpression . renderSQL
540+
541+-- | return the leftmost value which is not NULL
542+--
543+-- >>> printSQL $ coalesce [null_, true] false
544+-- COALESCE(NULL, TRUE, FALSE)
545+coalesce :: FunctionVar ('Null ty) ('NotNull ty) ('NotNull ty)
546+coalesce nullxs notNullx = UnsafeExpression $
547+ "COALESCE" <> parenthesized (commaSeparated
548+ ((renderSQL <$> nullxs) <> [renderSQL notNullx]))
549+
550+-- | analagous to `Data.Maybe.fromMaybe` using @COALESCE@
551+--
552+-- >>> printSQL $ fromNull true null_
553+-- COALESCE(NULL, TRUE)
554+fromNull
555+ :: Expression outer commons grp schemas params from ('NotNull ty)
556+ -- ^ what to convert @NULL@ to
557+ -> Expression outer commons grp schemas params from ('Null ty)
558+ -> Expression outer commons grp schemas params from ('NotNull ty)
559+fromNull notNullx nullx = coalesce [nullx] notNullx
560+
561+-- | >>> printSQL $ null_ & isNull
562+-- NULL IS NULL
563+isNull :: 'Null ty :--> null 'PGbool
564+isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL"
565+
566+-- | >>> printSQL $ null_ & isNotNull
567+-- NULL IS NOT NULL
568+isNotNull :: 'Null ty :--> null 'PGbool
569+isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL"
570+
571+-- | analagous to `maybe` using @IS NULL@
572+--
573+-- >>> printSQL $ matchNull true not_ null_
574+-- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END
575+matchNull
576+ :: Expression outer commons grp schemas params from (nullty)
577+ -- ^ what to convert @NULL@ to
578+ -> ( Expression outer commons grp schemas params from ('NotNull ty)
579+ -> Expression outer commons grp schemas params from (nullty) )
580+ -- ^ function to perform when @NULL@ is absent
581+ -> Expression outer commons grp schemas params from ('Null ty)
582+ -> Expression outer commons grp schemas params from (nullty)
583+matchNull y f x = ifThenElse (isNull x) y
584+ (f (UnsafeExpression (renderSQL x)))
585+
586+{-| right inverse to `fromNull`, if its arguments are equal then
587+`nullIf` gives @NULL@.
588+
589+>>> :set -XTypeApplications -XDataKinds
590+>>> let expr = nullIf (false *: param @1) :: Expression outer commons grp schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
591+>>> printSQL expr
592+NULLIF(FALSE, ($1 :: bool))
593+-}
594+nullIf :: FunctionN '[ 'NotNull ty, 'NotNull ty] ('Null ty)
595+nullIf = unsafeFunctionN "NULLIF"
596+
597+-- | >>> printSQL $ array [null_, false, true]
598+-- ARRAY[NULL, FALSE, TRUE]
599+array
600+ :: [Expression outer commons grp schemas params from ty]
601+ -- ^ array elements
602+ -> Expression outer commons grp schemas params from (null ('PGvararray ty))
603+array xs = UnsafeExpression $ "ARRAY" <>
604+ bracketed (commaSeparated (renderSQL <$> xs))
605+
606+{- | construct a 1-dimensional fixed length array
607+
608+>>> printSQL $ array1 (null_ :* false *: true)
609+ARRAY[NULL, FALSE, TRUE]
610+
611+>>> :type array1 (null_ :* false *: true)
612+array1 (null_ :* false *: true)
613+ :: Expression
614+ outer
615+ commons
616+ grp
617+ schemas
618+ params
619+ from
620+ (null ('PGfixarray '[3] ('Null 'PGbool)))
621+-}
622+array1
623+ :: (n ~ Length tys, SOP.All ((~) ty) tys)
624+ => NP (Expression outer commons grp schemas params from) tys
625+ -> Expression outer commons grp schemas params from (null ('PGfixarray '[n] ty))
626+array1 xs = UnsafeExpression $ "ARRAY" <>
627+ bracketed (renderCommaSeparated renderSQL xs)
628+
629+{- | construct a 2-dimensional fixed length array
630+
631+>>> printSQL $ array2 ((null_ :* false *: true) *: (false :* null_ *: true))
632+ARRAY[[NULL, FALSE, TRUE], [FALSE, NULL, TRUE]]
633+
634+>>> :type array2 ((null_ :* false *: true) *: (false :* null_ *: true))
635+array2 ((null_ :* false *: true) *: (false :* null_ *: true))
636+ :: Expression
637+ outer
638+ commons
639+ grp
640+ schemas
641+ params
642+ from
643+ (null ('PGfixarray '[2, 3] ('Null 'PGbool)))
644+-}
645+array2
646+ :: ( SOP.All ((~) tys) tyss
647+ , SOP.All SOP.SListI tyss
648+ , Length tyss ~ n1
649+ , SOP.All ((~) ty) tys
650+ , Length tys ~ n2 )
651+ => NP (NP (Expression outer commons grp schemas params from)) tyss
652+ -> Expression outer commons grp schemas params from (null ('PGfixarray '[n1,n2] ty))
653+array2 xss = UnsafeExpression $ "ARRAY" <>
654+ bracketed (renderCommaSeparatedConstraint @SOP.SListI (bracketed . renderCommaSeparated renderSQL) xss)
655+
656+-- | >>> printSQL $ cardinality (array [null_, false, true])
657+-- cardinality(ARRAY[NULL, FALSE, TRUE])
658+cardinality :: null ('PGvararray ty) :--> null 'PGint8
659+cardinality = unsafeFunction "cardinality"
660+
661+-- | >>> printSQL $ array [null_, false, true] & index 2
662+-- (ARRAY[NULL, FALSE, TRUE])[2]
663+index
664+ :: Word64 -- ^ index
665+ -> null ('PGvararray ty) :--> NullifyType ty
666+index n expr = UnsafeExpression $
667+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
668+
311669instance (KnownSymbol label, label `In` labels) => IsPGlabel label
312670 (Expression outer commons grp schemas params from (null ('PGenum labels))) where
313671 label = UnsafeExpression $ renderSQL (PGlabel @label)
314672
673+-- | A row constructor is an expression that builds a row value
674+-- (also called a composite value) using values for its member fields.
675+--
676+-- >>> :{
677+-- type Complex = 'PGcomposite
678+-- '[ "real" ::: 'NotNull 'PGfloat8
679+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
680+-- :}
681+--
682+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer commons grp schemas params from ('NotNull Complex)
683+-- >>> printSQL i
684+-- ROW(0, 1)
685+row
686+ :: SListI row
687+ => NP (Aliased (Expression outer commons grp schemas params from)) row
688+ -- ^ zero or more expressions for the row field values
689+ -> Expression outer commons grp schemas params from (null ('PGcomposite row))
690+row exprs = UnsafeExpression $ "ROW" <> parenthesized
691+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)
692+
693+-- | >>> :{
694+-- type Complex = 'PGcomposite
695+-- '[ "real" ::: 'NotNull 'PGfloat8
696+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
697+-- type Schema = '["complex" ::: 'Typedef Complex]
698+-- :}
699+--
700+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer '[] grp (Public Schema) from params ('NotNull Complex)
701+-- >>> printSQL $ i & field #complex #imaginary
702+-- (ROW(0, 1)::"complex")."imaginary"
703+field
704+ :: ( Has sch schemas schema
705+ , Has tydef schema ('Typedef ('PGcomposite row))
706+ , Has field row ty)
707+ => QualifiedAlias sch tydef -- ^ row type
708+ -> Alias field -- ^ field name
709+ -> Expression outer commons grp schemas params from ('NotNull ('PGcomposite row))
710+ -> Expression outer commons grp schemas params from ty
711+field td fld expr = UnsafeExpression $
712+ parenthesized (renderSQL expr <> "::" <> renderSQL td)
713+ <> "." <> renderSQL fld
714+
715+instance Semigroup
716+ (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
717+ (<>) = unsafeBinaryOp "||"
718+
719+instance Monoid
720+ (Expression outer commons grp schemas params from (null ('PGvararray ty))) where
721+ mempty = array []
722+ mappend = (<>)
723+
724+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer commons grp schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
725+-- >>> printSQL expr
726+-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
727+greatest :: FunctionVar ty ty ty
728+greatest = unsafeFunctionVar "GREATEST"
729+
730+-- | >>> printSQL $ least [null_] currentTimestamp
731+-- LEAST(NULL, CURRENT_TIMESTAMP)
732+least :: FunctionVar ty ty ty
733+least = unsafeFunctionVar "LEAST"
734+
315735-- | >>> printSQL $ unsafeBinaryOp "OR" true false
316736-- (TRUE OR FALSE)
317−unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2
737+unsafeBinaryOp :: ByteString {- ^ operator -} -> Operator ty0 ty1 ty2
318738unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $
319739 renderSQL x <+> op <+> renderSQL y
320740
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
741+-- | >>> printSQL $ unsafeUnaryOpL "NOT" true
329742-- (NOT TRUE)
330−unsafeLeftOp :: ByteString -> x --> y
331−unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
332−
333−leftOp
334− :: forall op sch schemas schema x y.
335− ( Has sch schemas schema
336− , Has op schema ('Operator ('LeftOp x y)) )
337− => FunctionDB schemas x y
338−leftOp = unsafeLeftOp $ renderSymbol @op
743+unsafeUnaryOpL :: ByteString {- ^ operator -} -> x :--> y
744+unsafeUnaryOpL op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x
339745
340−-- | >>> printSQL $ true & unsafeRightOp "IS NOT TRUE"
746+-- | >>> printSQL $ true & unsafeUnaryOpR "IS NOT TRUE"
341747-- (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
748+unsafeUnaryOpR :: ByteString {- ^ operator -} -> x :--> y
749+unsafeUnaryOpR op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op
351750
352751-- | >>> printSQL $ unsafeFunction "f" true
353752-- f(TRUE)
354−unsafeFunction :: ByteString -> x --> y
753+unsafeFunction :: ByteString {- ^ function -} -> x :--> y
355754unsafeFunction fun x = UnsafeExpression $
356755 fun <> parenthesized (renderSQL x)
357756
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−
364757-- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a')
365758-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')
366−unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
759+unsafeFunctionN
760+ :: SListI xs
761+ => ByteString {- ^ function -}
762+ -> FunctionN xs y
367763unsafeFunctionN fun xs = UnsafeExpression $
368764 fun <> parenthesized (renderCommaSeparated renderSQL xs)
369765
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−
378766instance ty `In` PGNum
379767 => Num (Expression outer commons grp schemas params from (null ty)) where
380768 (+) = unsafeBinaryOp "+"
@@ -419,22 +807,364 @@ instance (ty `In` PGNum, ty `In` PGFloating) => Floating
419807 acosh x = log (x + sqrt (x*x - 1))
420808 atanh x = log ((1 + x) / (1 - x)) / 2
421809
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)
810+-- | >>> :{
811+-- let
812+-- expression :: Expr (null 'PGfloat4)
813+-- expression = atan2_ (pi *: 2)
814+-- in printSQL expression
815+-- :}
816+-- atan2(pi(), 2)
817+atan2_
818+ :: float `In` PGFloating
819+ => FunctionN '[ null float, null float] (null float)
820+atan2_ = unsafeFunctionN "atan2"
821+
822+-- When a `cast` is applied to an `Expression` of a known type, it
823+-- represents a run-time type conversion. The cast will succeed only if a
824+-- suitable type conversion operation has been defined.
825+--
826+-- | >>> printSQL $ true & cast int4
827+-- (TRUE :: int4)
828+cast
829+ :: TypeExpression schemas ty1
830+ -- ^ type to cast as
831+ -> Expression outer commons grp schemas params from ty0
832+ -- ^ value to convert
833+ -> Expression outer commons grp schemas params from ty1
834+cast ty x = UnsafeExpression $ parenthesized $
835+ renderSQL x <+> "::" <+> renderSQL ty
836+
837+-- | integer division, truncates the result
838+--
839+-- >>> :{
840+-- let
841+-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
842+-- expression = 5 `quot_` 2
843+-- in printSQL expression
844+-- :}
845+-- (5 / 2)
846+quot_
847+ :: int `In` PGIntegral
848+ => Operator (null int) (null int) (null int)
849+quot_ = unsafeBinaryOp "/"
850+
851+-- | remainder upon integer division
852+--
853+-- >>> :{
854+-- let
855+-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
856+-- expression = 5 `rem_` 2
857+-- in printSQL expression
858+-- :}
859+-- (5 % 2)
860+rem_
861+ :: int `In` PGIntegral
862+ => Operator (null int) (null int) (null int)
863+rem_ = unsafeBinaryOp "%"
864+
865+-- | >>> :{
866+-- let
867+-- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)
868+-- expression = trunc pi
869+-- in printSQL expression
870+-- :}
871+-- trunc(pi())
872+trunc :: frac `In` PGFloating => null frac :--> null frac
873+trunc = unsafeFunction "trunc"
874+
875+-- | >>> :{
876+-- let
877+-- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)
878+-- expression = round_ pi
879+-- in printSQL expression
880+-- :}
881+-- round(pi())
882+round_ :: frac `In` PGFloating => null frac :--> null frac
883+round_ = unsafeFunction "round"
884+
885+-- | >>> :{
886+-- let
887+-- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)
888+-- expression = ceiling_ pi
889+-- in printSQL expression
890+-- :}
891+-- ceiling(pi())
892+ceiling_ :: frac `In` PGFloating => null frac :--> null frac
893+ceiling_ = unsafeFunction "ceiling"
894+
895+-- | A `Condition` is an `Expression`, which can evaluate
896+-- to `true`, `false` or `null_`. This is because SQL uses
897+-- a three valued logic.
898+type Condition outer commons grp schemas params from =
899+ Expression outer commons grp schemas params from ('Null 'PGbool)
900+
901+-- | >>> printSQL true
902+-- TRUE
903+true :: Expr (null 'PGbool)
904+true = UnsafeExpression "TRUE"
905+
906+-- | >>> printSQL false
907+-- FALSE
908+false :: Expr (null 'PGbool)
909+false = UnsafeExpression "FALSE"
910+
911+-- | >>> printSQL $ not_ true
912+-- (NOT TRUE)
913+not_ :: null 'PGbool :--> null 'PGbool
914+not_ = unsafeUnaryOpL "NOT"
915+
916+-- | >>> printSQL $ true .&& false
917+-- (TRUE AND FALSE)
918+(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
919+infixr 3 .&&
920+(.&&) = unsafeBinaryOp "AND"
921+
922+-- | >>> printSQL $ true .|| false
923+-- (TRUE OR FALSE)
924+(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool)
925+infixr 2 .||
926+(.||) = unsafeBinaryOp "OR"
927+
928+-- | >>> :{
929+-- let
930+-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
931+-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
932+-- in printSQL expression
933+-- :}
934+-- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END
935+caseWhenThenElse
936+ :: [ ( Condition outer commons grp schemas params from
937+ , Expression outer commons grp schemas params from ty
938+ ) ]
939+ -- ^ whens and thens
940+ -> Expression outer commons grp schemas params from ty
941+ -- ^ else
942+ -> Expression outer commons grp schemas params from ty
943+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
944+ [ "CASE"
945+ , mconcat
946+ [ mconcat
947+ [ " WHEN ", renderSQL when_
948+ , " THEN ", renderSQL then_
949+ ]
950+ | (when_,then_) <- whenThens
951+ ]
952+ , " ELSE ", renderSQL else_
953+ , " END"
954+ ]
955+
956+-- | >>> :{
957+-- let
958+-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
959+-- expression = ifThenElse true 1 0
960+-- in printSQL expression
961+-- :}
962+-- CASE WHEN TRUE THEN 1 ELSE 0 END
963+ifThenElse
964+ :: Condition outer commons grp schemas params from
965+ -> Expression outer commons grp schemas params from ty -- ^ then
966+ -> Expression outer commons grp schemas params from ty -- ^ else
967+ -> Expression outer commons grp schemas params from ty
968+ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
969+
970+-- | Comparison operations like `.==`, `./=`, `.>`, `.>=`, `.<` and `.<=`
971+-- will produce @NULL@s if one of their arguments is @NULL@.
972+--
973+-- >>> printSQL $ true .== null_
974+-- (TRUE = NULL)
975+(.==) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
976+(.==) = unsafeBinaryOp "="
977+infix 4 .==
978+
979+-- | >>> printSQL $ true ./= null_
980+-- (TRUE <> NULL)
981+(./=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
982+(./=) = unsafeBinaryOp "<>"
983+infix 4 ./=
984+
985+-- | >>> printSQL $ true .>= null_
986+-- (TRUE >= NULL)
987+(.>=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
988+(.>=) = unsafeBinaryOp ">="
989+infix 4 .>=
990+
991+-- | >>> printSQL $ true .< null_
992+-- (TRUE < NULL)
993+(.<) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
994+(.<) = unsafeBinaryOp "<"
995+infix 4 .<
996+
997+-- | >>> printSQL $ true .<= null_
998+-- (TRUE <= NULL)
999+(.<=) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
1000+(.<=) = unsafeBinaryOp "<="
1001+infix 4 .<=
4321002
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)
1003+-- | >>> printSQL $ true .> null_
1004+-- (TRUE > NULL)
1005+(.>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
1006+(.>) = unsafeBinaryOp ">"
1007+infix 4 .>
1008+
1009+{- | >>> printSQL $ true `between` (null_, false)
1010+TRUE BETWEEN NULL AND FALSE
1011+-}
1012+between
1013+ :: Expression outer commons grp schemas params from (null ty)
1014+ -> ( Expression outer commons grp schemas params from (null ty)
1015+ , Expression outer commons grp schemas params from (null ty) ) -- ^ bounds
1016+ -> Condition outer commons grp schemas params from
1017+between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
1018+ <+> renderSQL x <+> "AND" <+> renderSQL y
1019+
1020+{- | >>> printSQL $ true `notBetween` (null_, false)
1021+TRUE NOT BETWEEN NULL AND FALSE
1022+-}
1023+notBetween
1024+ :: Expression outer commons grp schemas params from (null ty)
1025+ -> ( Expression outer commons grp schemas params from (null ty)
1026+ , Expression outer commons grp schemas params from (null ty) ) -- ^ bounds
1027+ -> Condition outer commons grp schemas params from
1028+notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
1029+ <+> renderSQL x <+> "AND" <+> renderSQL y
1030+
1031+{- | between, after sorting the comparison values
1032+
1033+>>> printSQL $ true `betweenSymmetric` (null_, false)
1034+TRUE BETWEEN SYMMETRIC NULL AND FALSE
1035+-}
1036+betweenSymmetric
1037+ :: Expression outer commons grp schemas params from (null ty)
1038+ -> ( Expression outer commons grp schemas params from (null ty)
1039+ , Expression outer commons grp schemas params from (null ty) ) -- ^ bounds
1040+ -> Condition outer commons grp schemas params from
1041+betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
1042+ <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
1043+
1044+{- | not between, after sorting the comparison values
1045+
1046+>>> printSQL $ true `notBetweenSymmetric` (null_, false)
1047+TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
1048+-}
1049+notBetweenSymmetric
1050+ :: Expression outer commons grp schemas params from (null ty)
1051+ -> ( Expression outer commons grp schemas params from (null ty)
1052+ , Expression outer commons grp schemas params from (null ty) ) -- ^ bounds
1053+ -> Condition outer commons grp schemas params from
1054+notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
1055+ <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
1056+
1057+{- | not equal, treating null like an ordinary value
1058+
1059+>>> printSQL $ true `isDistinctFrom` null_
1060+(TRUE IS DISTINCT FROM NULL)
1061+-}
1062+isDistinctFrom :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)
1063+isDistinctFrom = unsafeBinaryOp "IS DISTINCT FROM"
1064+
1065+{- | equal, treating null like an ordinary value
1066+
1067+>>> printSQL $ true `isNotDistinctFrom` null_
1068+(TRUE IS NOT DISTINCT FROM NULL)
1069+-}
1070+isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ('NotNull 'PGbool)
1071+isNotDistinctFrom = unsafeBinaryOp "IS NOT DISTINCT FROM"
1072+
1073+{- | is true
1074+
1075+>>> printSQL $ true & isTrue
1076+(TRUE IS TRUE)
1077+-}
1078+isTrue :: null0 'PGbool :--> null1 'PGbool
1079+isTrue = unsafeUnaryOpR "IS TRUE"
1080+
1081+{- | is false or unknown
1082+
1083+>>> printSQL $ true & isNotTrue
1084+(TRUE IS NOT TRUE)
1085+-}
1086+isNotTrue :: null0 'PGbool :--> null1 'PGbool
1087+isNotTrue = unsafeUnaryOpR "IS NOT TRUE"
1088+
1089+{- | is false
1090+
1091+>>> printSQL $ true & isFalse
1092+(TRUE IS FALSE)
1093+-}
1094+isFalse :: null0 'PGbool :--> null1 'PGbool
1095+isFalse = unsafeUnaryOpR "IS FALSE"
1096+
1097+{- | is true or unknown
1098+
1099+>>> printSQL $ true & isNotFalse
1100+(TRUE IS NOT FALSE)
1101+-}
1102+isNotFalse :: null0 'PGbool :--> null1 'PGbool
1103+isNotFalse = unsafeUnaryOpR "IS NOT FALSE"
1104+
1105+{- | is unknown
1106+
1107+>>> printSQL $ true & isUnknown
1108+(TRUE IS UNKNOWN)
1109+-}
1110+isUnknown :: null0 'PGbool :--> null1 'PGbool
1111+isUnknown = unsafeUnaryOpR "IS UNKNOWN"
1112+
1113+{- | is true or false
1114+
1115+>>> printSQL $ true & isNotUnknown
1116+(TRUE IS NOT UNKNOWN)
1117+-}
1118+isNotUnknown :: null0 'PGbool :--> null1 'PGbool
1119+isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"
1120+
1121+-- | >>> printSQL currentDate
1122+-- CURRENT_DATE
1123+currentDate :: Expr (null 'PGdate)
1124+currentDate = UnsafeExpression "CURRENT_DATE"
1125+
1126+-- | >>> printSQL currentTime
1127+-- CURRENT_TIME
1128+currentTime :: Expr (null 'PGtimetz)
1129+currentTime = UnsafeExpression "CURRENT_TIME"
1130+
1131+-- | >>> printSQL currentTimestamp
1132+-- CURRENT_TIMESTAMP
1133+currentTimestamp :: Expr (null 'PGtimestamptz)
1134+currentTimestamp = UnsafeExpression "CURRENT_TIMESTAMP"
1135+
1136+-- | >>> printSQL localTime
1137+-- LOCALTIME
1138+localTime :: Expr (null 'PGtime)
1139+localTime = UnsafeExpression "LOCALTIME"
1140+
1141+-- | >>> printSQL localTimestamp
1142+-- LOCALTIMESTAMP
1143+localTimestamp :: Expr (null 'PGtimestamp)
1144+localTimestamp = UnsafeExpression "LOCALTIMESTAMP"
1145+
1146+-- | Current date and time (equivalent to `currentTimestamp`)
1147+--
1148+-- >>> printSQL now
1149+-- now()
1150+now :: Expr (null 'PGtimestamptz)
1151+now = UnsafeExpression "now()"
1152+
1153+{-----------------------------------------
1154+text
1155+-----------------------------------------}
1156+
1157+escape :: Char -> String
1158+escape = \case
1159+ '\NUL' -> "\\0"
1160+ '\'' -> "''"
1161+ '"' -> "\\\""
1162+ '\b' -> "\\b"
1163+ '\n' -> "\\n"
1164+ '\r' -> "\\r"
1165+ '\t' -> "\\t"
1166+ '\\' -> "\\\\"
1167+ c -> [c]
4381168
4391169instance IsString
4401170 (Expression outer commons grp schemas params from (null 'PGtext)) where
@@ -442,19 +1172,13 @@ instance IsString
4421172 "E\'" <> fromString (escape =<< str) <> "\'"
4431173instance IsString
4441174 (Expression outer commons grp schemas params from (null 'PGtsvector)) where
445− fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
1175+ fromString str = cast tsvector . UnsafeExpression $
4461176 "E\'" <> fromString (escape =<< str) <> "\'"
4471177instance IsString
4481178 (Expression outer commons grp schemas params from (null 'PGtsquery)) where
449− fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
1179+ fromString str = cast tsquery . UnsafeExpression $
4501180 "E\'" <> fromString (escape =<< str) <> "\'"
4511181
452−instance 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 "||"
4581182instance Semigroup
4591183 (Expression outer commons grp schemas params from (null 'PGtext)) where
4601184 (<>) = unsafeBinaryOp "||"
@@ -470,3 +1194,1391 @@ instance Monoid
4701194 (Expression outer commons grp schemas params from (null 'PGtsvector)) where
4711195 mempty = fromString ""
4721196 mappend = (<>)
1197+
1198+-- | >>> printSQL $ lower "ARRRGGG"
1199+-- lower(E'ARRRGGG')
1200+lower :: null 'PGtext :--> null 'PGtext
1201+lower = unsafeFunction "lower"
1202+
1203+-- | >>> printSQL $ upper "eeee"
1204+-- upper(E'eeee')
1205+upper :: null 'PGtext :--> null 'PGtext
1206+upper = unsafeFunction "upper"
1207+
1208+-- | >>> printSQL $ charLength "four"
1209+-- char_length(E'four')
1210+charLength :: null 'PGtext :--> null 'PGint4
1211+charLength = unsafeFunction "char_length"
1212+
1213+-- | The `like` expression returns true if the @string@ matches
1214+-- the supplied @pattern@. If @pattern@ does not contain percent signs
1215+-- or underscores, then the pattern only represents the string itself;
1216+-- in that case `like` acts like the equals operator. An underscore (_)
1217+-- in pattern stands for (matches) any single character; a percent sign (%)
1218+-- matches any sequence of zero or more characters.
1219+--
1220+-- >>> printSQL $ "abc" `like` "a%"
1221+-- (E'abc' LIKE E'a%')
1222+like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1223+like = unsafeBinaryOp "LIKE"
1224+
1225+-- | The key word ILIKE can be used instead of LIKE to make the
1226+-- match case-insensitive according to the active locale.
1227+--
1228+-- >>> printSQL $ "abc" `ilike` "a%"
1229+-- (E'abc' ILIKE E'a%')
1230+ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool)
1231+ilike = unsafeBinaryOp "ILIKE"
1232+
1233+{-----------------------------------------
1234+ -- json and jsonb support
1235+
1236+See https://www.postgresql.org/docs/10/static/functions-json.html -- most
1237+comments lifted directly from this page.
1238+
1239+Table 9.44: json and jsonb operators
1240+-----------------------------------------}
1241+
1242+-- | Get JSON value (object field or array element) at a key.
1243+(.->)
1244+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1245+ => Operator (null json) (null key) ('Null json)
1246+infixl 8 .->
1247+(.->) = unsafeBinaryOp "->"
1248+
1249+-- | Get JSON value (object field or array element) at a key, as text.
1250+(.->>)
1251+ :: (json `In` PGJsonType, key `In` PGJsonKey)
1252+ => Operator (null json) (null key) ('Null 'PGtext)
1253+infixl 8 .->>
1254+(.->>) = unsafeBinaryOp "->>"
1255+
1256+-- | Get JSON value at a specified path.
1257+(.#>)
1258+ :: json `In` PGJsonType
1259+ => Operator (null json) (null ('PGvararray ('NotNull 'PGtext))) ('Null json)
1260+infixl 8 .#>
1261+(.#>) = unsafeBinaryOp "#>"
1262+
1263+-- | Get JSON value at a specified path as text.
1264+(.#>>)
1265+ :: json `In` PGJsonType
1266+ => Operator (null json) (null ('PGvararray ('NotNull 'PGtext))) ('Null 'PGtext)
1267+infixl 8 .#>>
1268+(.#>>) = unsafeBinaryOp "#>>"
1269+
1270+-- Additional jsonb operators
1271+
1272+class PGSubset container where
1273+ (@>) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1274+ (@>) = unsafeBinaryOp "@>"
1275+ (<@) :: Operator (null0 container) (null1 container) ('Null 'PGbool)
1276+ (<@) = unsafeBinaryOp "<@"
1277+instance PGSubset 'PGjsonb
1278+instance PGSubset 'PGtsquery
1279+instance PGSubset ('PGvararray ty)
1280+
1281+-- | Does the string exist as a top-level key within the JSON value?
1282+(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ('Null 'PGbool)
1283+infixl 9 .?
1284+(.?) = unsafeBinaryOp "?"
1285+
1286+-- | Do any of these array strings exist as top-level keys?
1287+(.?|) :: Operator
1288+ (null 'PGjsonb)
1289+ (null ('PGvararray ('NotNull 'PGtext)))
1290+ ('Null 'PGbool)
1291+infixl 9 .?|
1292+(.?|) = unsafeBinaryOp "?|"
1293+
1294+-- | Do all of these array strings exist as top-level keys?
1295+(.?&) :: Operator
1296+ (null 'PGjsonb)
1297+ (null ('PGvararray ('NotNull 'PGtext)))
1298+ ('Null 'PGbool)
1299+infixl 9 .?&
1300+(.?&) = unsafeBinaryOp "?&"
1301+
1302+instance Semigroup
1303+ (Expression outer commons grp schemas params from (null 'PGjsonb)) where
1304+ (<>) = unsafeBinaryOp "||"
1305+
1306+-- | Delete a key or keys from a JSON object, or remove an array element.
1307+--
1308+-- If the right operand is..
1309+--
1310+-- @ text @: Delete key/value pair or string element from left operand. Key/value pairs
1311+-- are matched based on their key value.
1312+--
1313+-- @ text[] @: Delete multiple key/value pairs or string elements
1314+-- from left operand. Key/value pairs are matched based on their key value.
1315+--
1316+-- @ integer @: Delete the array element with specified index (Negative integers
1317+-- count from the end). Throws an error if top level container is not an array.
1318+(.-.)
1319+ :: (key `In` '[ 'PGtext, 'PGvararray ('NotNull 'PGtext), 'PGint4, 'PGint2 ]) -- hlint error without parens here
1320+ => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
1321+infixl 6 .-.
1322+(.-.) = unsafeBinaryOp "-"
1323+
1324+-- | Delete the field or element with specified path (for JSON arrays, negative
1325+-- integers count from the end)
1326+(#-.) :: Operator (null 'PGjsonb) (null ('PGvararray ('NotNull 'PGtext))) (null 'PGjsonb)
1327+infixl 6 #-.
1328+(#-.) = unsafeBinaryOp "#-"
1329+
1330+{-----------------------------------------
1331+Table 9.45: JSON creation functions
1332+-----------------------------------------}
1333+
1334+-- | Returns the value as json. Arrays and composites are converted
1335+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1336+-- type to json, the cast function will be used to perform the conversion;
1337+-- otherwise, a scalar value is produced. For any scalar type other than a
1338+-- number, a Boolean, or a null value, the text representation will be used, in
1339+-- such a fashion that it is a valid json value.
1340+toJson :: null ty :--> null 'PGjson
1341+toJson = unsafeFunction "to_json"
1342+
1343+-- | Returns the value as jsonb. Arrays and composites are converted
1344+-- (recursively) to arrays and objects; otherwise, if there is a cast from the
1345+-- type to json, the cast function will be used to perform the conversion;
1346+-- otherwise, a scalar value is produced. For any scalar type other than a
1347+-- number, a Boolean, or a null value, the text representation will be used, in
1348+-- such a fashion that it is a valid jsonb value.
1349+toJsonb :: null ty :--> null 'PGjsonb
1350+toJsonb = unsafeFunction "to_jsonb"
1351+
1352+-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
1353+-- becomes a JSON array of arrays.
1354+arrayToJson :: null ('PGvararray ty) :--> null 'PGjson
1355+arrayToJson = unsafeFunction "array_to_json"
1356+
1357+-- | Returns the row as a JSON object.
1358+rowToJson :: null ('PGcomposite ty) :--> null 'PGjson
1359+rowToJson = unsafeFunction "row_to_json"
1360+
1361+-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
1362+-- argument list.
1363+jsonBuildArray :: SListI tuple => FunctionN tuple (null 'PGjson)
1364+jsonBuildArray = unsafeFunctionN "json_build_array"
1365+
1366+-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
1367+-- variadic argument list.
1368+jsonbBuildArray :: SListI tuple => FunctionN tuple (null 'PGjsonb)
1369+jsonbBuildArray = unsafeFunctionN "jsonb_build_array"
1370+
1371+class PGBuildObject tys where
1372+instance PGBuildObject '[]
1373+instance (PGBuildObject tys, key `In` PGJsonKey)
1374+ => PGBuildObject ('NotNull key ': value ': tys)
1375+
1376+-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
1377+-- argument list. The elements of the argument list must alternate between text
1378+-- and values.
1379+jsonBuildObject
1380+ :: (SListI elems, PGBuildObject elems)
1381+ => FunctionN elems (null 'PGjson)
1382+jsonBuildObject = unsafeFunctionN "json_build_object"
1383+
1384+-- | Builds a possibly-heterogeneously-typed (binary) JSON object out of a
1385+-- variadic argument list. The elements of the argument list must alternate
1386+-- between keys and values.
1387+jsonbBuildObject
1388+ :: (SListI elems, PGBuildObject elems)
1389+ => FunctionN elems (null 'PGjsonb)
1390+jsonbBuildObject = unsafeFunctionN "jsonb_build_object"
1391+
1392+-- | Builds a JSON object out of a text array.
1393+-- The array must have two dimensions
1394+-- such that each inner array has exactly two elements,
1395+-- which are taken as a key/value pair.
1396+jsonObject
1397+ :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))
1398+ :--> null 'PGjson
1399+jsonObject = unsafeFunction "json_object"
1400+
1401+-- | Builds a binary JSON object out of a text array.
1402+-- The array must have two dimensions
1403+-- such that each inner array has exactly two elements,
1404+-- which are taken as a key/value pair.
1405+jsonbObject
1406+ :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))
1407+ :--> null 'PGjsonb
1408+jsonbObject = unsafeFunction "jsonb_object"
1409+
1410+-- | This is an alternate form of 'jsonObject' that takes two arrays; one for
1411+-- keys and one for values, that are zipped pairwise to create a JSON object.
1412+jsonZipObject :: FunctionN
1413+ '[ null ('PGvararray ('NotNull 'PGtext))
1414+ , null ('PGvararray ('NotNull 'PGtext)) ]
1415+ ( null 'PGjson )
1416+jsonZipObject = unsafeFunctionN "json_object"
1417+
1418+-- | This is an alternate form of 'jsonbObject' that takes two arrays; one for
1419+-- keys and one for values, that are zipped pairwise to create a binary JSON
1420+-- object.
1421+jsonbZipObject :: FunctionN
1422+ '[ null ('PGvararray ('NotNull 'PGtext))
1423+ , null ('PGvararray ('NotNull 'PGtext)) ]
1424+ ( null 'PGjsonb )
1425+jsonbZipObject = unsafeFunctionN "jsonb_object"
1426+
1427+{-----------------------------------------
1428+Table 9.46: JSON processing functions
1429+-----------------------------------------}
1430+
1431+-- | Returns the number of elements in the outermost JSON array.
1432+jsonArrayLength :: null 'PGjson :--> null 'PGint4
1433+jsonArrayLength = unsafeFunction "json_array_length"
1434+
1435+-- | Returns the number of elements in the outermost binary JSON array.
1436+jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
1437+jsonbArrayLength = unsafeFunction "jsonb_array_length"
1438+
1439+-- | Returns JSON value pointed to by the given path (equivalent to #>
1440+-- operator).
1441+jsonExtractPath
1442+ :: SListI elems
1443+ => Expression outer commons grp schemas params from (null 'PGjson)
1444+ -> NP (Expression outer commons grp schemas params from) elems
1445+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1446+jsonExtractPath x xs =
1447+ unsafeFunctionN "json_extract_path" (x :* xs)
1448+
1449+-- | Returns JSON value pointed to by the given path (equivalent to #>
1450+-- operator).
1451+jsonbExtractPath
1452+ :: SListI elems
1453+ => Expression outer commons grp schemas params from (null 'PGjsonb)
1454+ -> NP (Expression outer commons grp schemas params from) elems
1455+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1456+jsonbExtractPath x xs =
1457+ unsafeFunctionN "jsonb_extract_path" (x :* xs)
1458+
1459+-- | Returns JSON value pointed to by the given path (equivalent to #>
1460+-- operator), as text.
1461+jsonExtractPathAsText
1462+ :: SListI elems
1463+ => Expression outer commons grp schemas params from (null 'PGjson)
1464+ -> NP (Expression outer commons grp schemas params from) elems
1465+ -> Expression outer commons grp schemas params from (null 'PGjson)
1466+jsonExtractPathAsText x xs =
1467+ unsafeFunctionN "json_extract_path_text" (x :* xs)
1468+
1469+-- | Returns JSON value pointed to by the given path (equivalent to #>
1470+-- operator), as text.
1471+jsonbExtractPathAsText
1472+ :: SListI elems
1473+ => Expression outer commons grp schemas params from (null 'PGjsonb)
1474+ -> NP (Expression outer commons grp schemas params from) elems
1475+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1476+jsonbExtractPathAsText x xs =
1477+ unsafeFunctionN "jsonb_extract_path_text" (x :* xs)
1478+
1479+-- | Returns the type of the outermost JSON value as a text string. Possible
1480+-- types are object, array, string, number, boolean, and null.
1481+jsonTypeof :: null 'PGjson :--> null 'PGtext
1482+jsonTypeof = unsafeFunction "json_typeof"
1483+
1484+-- | Returns the type of the outermost binary JSON value as a text string.
1485+-- Possible types are object, array, string, number, boolean, and null.
1486+jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
1487+jsonbTypeof = unsafeFunction "jsonb_typeof"
1488+
1489+-- | Returns its argument with all object fields that have null values omitted.
1490+-- Other null values are untouched.
1491+jsonStripNulls :: null 'PGjson :--> null 'PGjson
1492+jsonStripNulls = unsafeFunction "json_strip_nulls"
1493+
1494+-- | Returns its argument with all object fields that have null values omitted.
1495+-- Other null values are untouched.
1496+jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
1497+jsonbStripNulls = unsafeFunction "jsonb_strip_nulls"
1498+
1499+-- | @ jsonbSet target path new_value create_missing @
1500+--
1501+-- Returns target with the section designated by path replaced by new_value,
1502+-- or with new_value added if create_missing is true ( default is true) and the
1503+-- item designated by path does not exist. As with the path orientated
1504+-- operators, negative integers that appear in path count from the end of JSON
1505+-- arrays.
1506+jsonbSet
1507+ :: Expression outer commons grp schemas params from (null 'PGjsonb)
1508+ -> Expression outer commons grp schemas params from (null ('PGvararray ('NotNull 'PGtext)))
1509+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1510+ -> Maybe (Expression outer commons grp schemas params from (null 'PGbool))
1511+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1512+jsonbSet tgt path val createMissing = case createMissing of
1513+ Just m -> unsafeFunctionN "jsonb_set" (tgt :* path :* val :* m :* Nil)
1514+ Nothing -> unsafeFunctionN "jsonb_set" (tgt :* path :* val :* Nil)
1515+
1516+-- | @ jsonbInsert target path new_value insert_after @
1517+--
1518+-- Returns target with new_value inserted. If target section designated by
1519+-- path is in a JSONB array, new_value will be inserted before target or after
1520+-- if insert_after is true (default is false). If target section designated by
1521+-- path is in JSONB object, new_value will be inserted only if target does not
1522+-- exist. As with the path orientated operators, negative integers that appear
1523+-- in path count from the end of JSON arrays.
1524+jsonbInsert
1525+ :: Expression outer commons grp schemas params from (null 'PGjsonb)
1526+ -> Expression outer commons grp schemas params from (null ('PGvararray ('NotNull 'PGtext)))
1527+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1528+ -> Maybe (Expression outer commons grp schemas params from (null 'PGbool))
1529+ -> Expression outer commons grp schemas params from (null 'PGjsonb)
1530+jsonbInsert tgt path val insertAfter = case insertAfter of
1531+ Just i -> unsafeFunctionN "jsonb_insert" (tgt :* path :* val :* i :* Nil)
1532+ Nothing -> unsafeFunctionN "jsonb_insert" (tgt :* path :* val :* Nil)
1533+
1534+-- | Returns its argument as indented JSON text.
1535+jsonbPretty :: null 'PGjsonb :--> null 'PGtext
1536+jsonbPretty = unsafeFunction "jsonb_pretty"
1537+
1538+(@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)
1539+(@@) = unsafeBinaryOp "@@"
1540+
1541+(.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1542+(.&) = unsafeBinaryOp "&&"
1543+
1544+(.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1545+(.|) = unsafeBinaryOp "||"
1546+
1547+(.!) :: null 'PGtsquery :--> null 'PGtsquery
1548+(.!) = unsafeUnaryOpL "!!"
1549+
1550+(<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery)
1551+(<->) = unsafeBinaryOp "<->"
1552+
1553+arrayToTSvector
1554+ :: null ('PGvararray ('NotNull 'PGtext))
1555+ :--> null 'PGtsvector
1556+arrayToTSvector = unsafeFunction "array_to_tsvector"
1557+
1558+tsvectorLength :: null 'PGtsvector :--> null 'PGint4
1559+tsvectorLength = unsafeFunction "length"
1560+
1561+numnode :: null 'PGtsquery :--> null 'PGint4
1562+numnode = unsafeFunction "numnode"
1563+
1564+plainToTSquery :: null 'PGtext :--> null 'PGtsquery
1565+plainToTSquery = unsafeFunction "plainto_tsquery"
1566+
1567+phraseToTSquery :: null 'PGtext :--> null 'PGtsquery
1568+phraseToTSquery = unsafeFunction "phraseto_tsquery"
1569+
1570+websearchToTSquery :: null 'PGtext :--> null 'PGtsquery
1571+websearchToTSquery = unsafeFunction "websearch_to_tsquery"
1572+
1573+queryTree :: null 'PGtsquery :--> null 'PGtext
1574+queryTree = unsafeFunction "query_tree"
1575+
1576+toTSquery :: null 'PGtext :--> null 'PGtsquery
1577+toTSquery = unsafeFunction "to_tsquery"
1578+
1579+toTSvector
1580+ :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1581+ => null ty :--> null 'PGtsvector
1582+toTSvector = unsafeFunction "to_tsvector"
1583+
1584+setWeight
1585+ :: FunctionN '[null 'PGtsvector, null ('PGchar 1)] (null 'PGtsvector)
1586+setWeight = unsafeFunctionN "set_weight"
1587+
1588+strip :: null 'PGtsvector :--> null 'PGtsvector
1589+strip = unsafeFunction "strip"
1590+
1591+jsonToTSvector :: FunctionN '[null 'PGjson, null 'PGjson] (null 'PGtsvector)
1592+jsonToTSvector = unsafeFunctionN "json_to_tsvector"
1593+
1594+jsonbToTSvector :: FunctionN '[null 'PGjsonb, null 'PGjsonb] (null 'PGtsvector)
1595+jsonbToTSvector = unsafeFunctionN "jsonb_to_tsvector"
1596+
1597+tsDelete :: FunctionN
1598+ '[null 'PGtsvector, null ('PGvararray ('NotNull 'PGtext))]
1599+ (null 'PGtsvector)
1600+tsDelete = unsafeFunctionN "ts_delete"
1601+
1602+tsFilter :: FunctionN
1603+ '[null 'PGtsvector, null ('PGvararray ('NotNull ('PGchar 1)))]
1604+ (null 'PGtsvector)
1605+tsFilter = unsafeFunctionN "ts_filter"
1606+
1607+tsHeadline
1608+ :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb]
1609+ => FunctionN '[null document, null 'PGtsquery] (null 'PGtext)
1610+tsHeadline = unsafeFunctionN "ts_headline"
1611+{-----------------------------------------
1612+aggregation
1613+-----------------------------------------}
1614+
1615+unsafeAggregateHet
1616+ :: SOP.SListI xs
1617+ => ByteString -- ^ function
1618+ -> Distinction (NP (Expression outer commons 'Ungrouped schemas params from)) xs
1619+ -> Expression outer commons ('Grouped bys) schemas params from y
1620+unsafeAggregateHet fun xs = UnsafeExpression $ fun <> parenthesized (renderSQL xs)
1621+
1622+{- |
1623+`Aggregate` functions compute a single result from a set of input values.
1624+`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
1625+as `WindowFunction`s.
1626+-}
1627+class Aggregate expr1 exprHet aggr
1628+ | aggr -> expr1, aggr -> exprHet where
1629+
1630+ -- | A special aggregation that does not require an input
1631+ --
1632+ -- >>> :{
1633+ -- let
1634+ -- expression :: Expression '[] commons ('Grouped bys) schemas params from ('NotNull 'PGint8)
1635+ -- expression = countStar
1636+ -- in printSQL expression
1637+ -- :}
1638+ -- count(*)
1639+ countStar :: aggr ('NotNull 'PGint8)
1640+
1641+ -- | >>> :{
1642+ -- let
1643+ -- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
1644+ -- expression = count (All #col)
1645+ -- in printSQL expression
1646+ -- :}
1647+ -- count(ALL "col")
1648+ count
1649+ :: expr1 ty
1650+ -- ^ what to count
1651+ -> aggr ('NotNull 'PGint8)
1652+
1653+ -- | >>> :{
1654+ -- let
1655+ -- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('NotNull 'PGnumeric)
1656+ -- expression = sum_ (Distinct #col)
1657+ -- in printSQL expression
1658+ -- :}
1659+ -- sum(DISTINCT "col")
1660+ sum_
1661+ :: ty `In` PGNum
1662+ => expr1 (null ty)
1663+ -> aggr ('NotNull ty)
1664+
1665+ -- | input values, including nulls, concatenated into an array
1666+ arrayAgg
1667+ :: expr1 ty
1668+ -> aggr ('Null ('PGvararray ty))
1669+
1670+ -- | aggregates values as a JSON array
1671+ jsonAgg
1672+ :: expr1 ty
1673+ -> aggr ('Null 'PGjson)
1674+
1675+ -- | aggregates values as a JSON array
1676+ jsonbAgg
1677+ :: expr1 ty
1678+ -> aggr ('Null 'PGjsonb)
1679+
1680+ {- |
1681+ the bitwise AND of all non-null input values, or null if none
1682+ >>> :{
1683+ let
1684+ expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1685+ expression = bitAnd (Distinct #col)
1686+ in printSQL expression
1687+ :}
1688+ bit_and(DISTINCT "col")
1689+ -}
1690+ bitAnd
1691+ :: int `In` PGIntegral
1692+ => expr1 (null int)
1693+ -- ^ what to aggregate
1694+ -> aggr ('Null int)
1695+
1696+ {- |
1697+ the bitwise OR of all non-null input values, or null if none
1698+
1699+ >>> :{
1700+ let
1701+ expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
1702+ expression = bitOr (All #col)
1703+ in printSQL expression
1704+ :}
1705+ bit_or(ALL "col")
1706+ -}
1707+ bitOr
1708+ :: int `In` PGIntegral
1709+ => expr1 (null int)
1710+ -- ^ what to aggregate
1711+ -> aggr ('Null int)
1712+
1713+ {- |
1714+ true if all input values are true, otherwise false
1715+
1716+ >>> :{
1717+ let
1718+ winFun :: WindowFunction '[] commons 'Ungrouped schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1719+ winFun = boolAnd #col
1720+ in printSQL winFun
1721+ :}
1722+ bool_and("col")
1723+ -}
1724+ boolAnd
1725+ :: expr1 (null 'PGbool)
1726+ -- ^ what to aggregate
1727+ -> aggr ('Null 'PGbool)
1728+
1729+ {- |
1730+ true if at least one input value is true, otherwise false
1731+
1732+ >>> :{
1733+ let
1734+ expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1735+ expression = boolOr (All #col)
1736+ in printSQL expression
1737+ :}
1738+ bool_or(ALL "col")
1739+ -}
1740+ boolOr
1741+ :: expr1 (null 'PGbool)
1742+ -- ^ what to aggregate
1743+ -> aggr ('Null 'PGbool)
1744+
1745+ {- |
1746+ equivalent to `boolAnd`
1747+
1748+ >>> :{
1749+ let
1750+ expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
1751+ expression = every (Distinct #col)
1752+ in printSQL expression
1753+ :}
1754+ every(DISTINCT "col")
1755+ -}
1756+ every
1757+ :: expr1 (null 'PGbool)
1758+ -- ^ what to aggregate
1759+ -> aggr ('Null 'PGbool)
1760+
1761+ {- |maximum value of expression across all input values-}
1762+ max_
1763+ :: expr1 (null ty)
1764+ -- ^ what to maximize
1765+ -> aggr ('Null ty)
1766+
1767+ -- | minimum value of expression across all input values
1768+ min_
1769+ :: expr1 (null ty)
1770+ -- ^ what to minimize
1771+ -> aggr ('Null ty)
1772+
1773+ -- | the average (arithmetic mean) of all input values
1774+ avg
1775+ :: expr1 (null ty)
1776+ -- ^ what to average
1777+ -> aggr ('Null (PGAvg ty))
1778+
1779+ {- | correlation coefficient
1780+ >>> :{
1781+ let
1782+ expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1783+ expression = corr (All (#y *: #x))
1784+ in printSQL expression
1785+ :}
1786+ corr(ALL "y", "x")
1787+ -}
1788+ corr
1789+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1790+ -> aggr ('Null 'PGfloat8)
1791+
1792+ {- | population covariance
1793+ >>> :{
1794+ let
1795+ expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1796+ expression = covarPop (All (#y *: #x))
1797+ in printSQL expression
1798+ :}
1799+ covar_pop(ALL "y", "x")
1800+ -}
1801+ covarPop
1802+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1803+ -> aggr ('Null 'PGfloat8)
1804+
1805+ {- | sample covariance
1806+ >>> :{
1807+ let
1808+ winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1809+ winFun = covarSamp (#y *: #x)
1810+ in printSQL winFun
1811+ :}
1812+ covar_samp("y", "x")
1813+ -}
1814+ covarSamp
1815+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1816+ -> aggr ('Null 'PGfloat8)
1817+
1818+ {- | average of the independent variable (sum(X)/N)
1819+ >>> :{
1820+ let
1821+ expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1822+ expression = regrAvgX (All (#y *: #x))
1823+ in printSQL expression
1824+ :}
1825+ regr_avgx(ALL "y", "x")
1826+ -}
1827+ regrAvgX
1828+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1829+ -> aggr ('Null 'PGfloat8)
1830+
1831+ {- | average of the dependent variable (sum(Y)/N)
1832+ >>> :{
1833+ let
1834+ winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1835+ winFun = regrAvgY (#y *: #x)
1836+ in printSQL winFun
1837+ :}
1838+ regr_avgy("y", "x")
1839+ -}
1840+ regrAvgY
1841+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1842+ -> aggr ('Null 'PGfloat8)
1843+
1844+ {- | number of input rows in which both expressions are nonnull
1845+ >>> :{
1846+ let
1847+ winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
1848+ winFun = regrCount (#y *: #x)
1849+ in printSQL winFun
1850+ :}
1851+ regr_count("y", "x")
1852+ -}
1853+ regrCount
1854+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1855+ -> aggr ('Null 'PGint8)
1856+
1857+ {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs
1858+ >>> :{
1859+ let
1860+ expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
1861+ expression = regrIntercept (All (#y *: #x))
1862+ in printSQL expression
1863+ :}
1864+ regr_intercept(ALL "y", "x")
1865+ -}
1866+ regrIntercept
1867+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1868+ -> aggr ('Null 'PGfloat8)
1869+
1870+ -- | @regr_r2(Y, X)@, square of the correlation coefficient
1871+ regrR2
1872+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1873+ -> aggr ('Null 'PGfloat8)
1874+
1875+ -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation
1876+ -- determined by the (X, Y) pairs
1877+ regrSlope
1878+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1879+ -> aggr ('Null 'PGfloat8)
1880+
1881+ -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N
1882+ -- (“sum of squares” of the independent variable)
1883+ regrSxx
1884+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1885+ -> aggr ('Null 'PGfloat8)
1886+
1887+ -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N
1888+ -- (“sum of products” of independent times dependent variable)
1889+ regrSxy
1890+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1891+ -> aggr ('Null 'PGfloat8)
1892+
1893+ -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N
1894+ -- (“sum of squares” of the dependent variable)
1895+ regrSyy
1896+ :: exprHet '[null 'PGfloat8, null 'PGfloat8]
1897+ -> aggr ('Null 'PGfloat8)
1898+
1899+ -- | historical alias for `stddevSamp`
1900+ stddev
1901+ :: expr1 (null ty)
1902+ -> aggr ('Null (PGAvg ty))
1903+
1904+ -- | population standard deviation of the input values
1905+ stddevPop
1906+ :: expr1 (null ty)
1907+ -> aggr ('Null (PGAvg ty))
1908+
1909+ -- | sample standard deviation of the input values
1910+ stddevSamp
1911+ :: expr1 (null ty)
1912+ -> aggr ('Null (PGAvg ty))
1913+
1914+ -- | historical alias for `varSamp`
1915+ variance
1916+ :: expr1 (null ty)
1917+ -> aggr ('Null (PGAvg ty))
1918+
1919+ -- | population variance of the input values
1920+ -- (square of the population standard deviation)
1921+ varPop
1922+ :: expr1 (null ty)
1923+ -> aggr ('Null (PGAvg ty))
1924+
1925+ -- | sample variance of the input values
1926+ -- (square of the sample standard deviation)
1927+ varSamp
1928+ :: expr1 (null ty)
1929+ -> aggr ('Null (PGAvg ty))
1930+
1931+{- |
1932+`Distinction`s are used for the input of `Aggregate` `Expression`s.
1933+`All` invokes the aggregate once for each input row.
1934+`Distinct` invokes the aggregate once for each distinct value of the expression
1935+(or distinct set of values, for multiple expressions) found in the input
1936+-}
1937+data Distinction (expr :: kind -> Type) (ty :: kind)
1938+ = All (expr ty)
1939+ | Distinct (expr ty)
1940+ deriving (GHC.Generic,Show,Eq,Ord)
1941+instance NFData (Distinction (Expression outer commons grp schemas params from) ty)
1942+instance RenderSQL (Distinction (Expression outer commons grp schemas params from) ty) where
1943+ renderSQL = \case
1944+ All x -> "ALL" <+> renderSQL x
1945+ Distinct x -> "DISTINCT" <+> renderSQL x
1946+instance SOP.SListI tys => RenderSQL
1947+ (Distinction (NP (Expression outer commons grp schemas params from)) tys) where
1948+ renderSQL = \case
1949+ All xs -> "ALL" <+> renderCommaSeparated renderSQL xs
1950+ Distinct xs -> "DISTINCT" <+> renderCommaSeparated renderSQL xs
1951+
1952+instance Aggregate
1953+ (Distinction (Expression outer commons 'Ungrouped schemas params from))
1954+ (Distinction (NP (Expression outer commons 'Ungrouped schemas params from)))
1955+ (Expression outer commons ('Grouped bys) schemas params from) where
1956+ countStar = UnsafeExpression "count(*)"
1957+ count = unsafeAggregate1 "count"
1958+ sum_ = unsafeAggregate1 "sum"
1959+ arrayAgg = unsafeAggregate1 "array_agg"
1960+ jsonAgg = unsafeAggregate1 "json_agg"
1961+ jsonbAgg = unsafeAggregate1 "jsonb_agg"
1962+ bitAnd = unsafeAggregate1 "bit_and"
1963+ bitOr = unsafeAggregate1 "bit_or"
1964+ boolAnd = unsafeAggregate1 "bool_and"
1965+ boolOr = unsafeAggregate1 "bool_or"
1966+ every = unsafeAggregate1 "every"
1967+ max_ = unsafeAggregate1 "max"
1968+ min_ = unsafeAggregate1 "min"
1969+ avg = unsafeAggregate1 "avg"
1970+ corr = unsafeAggregateHet "corr"
1971+ covarPop = unsafeAggregateHet "covar_pop"
1972+ covarSamp = unsafeAggregateHet "covar_samp"
1973+ regrAvgX = unsafeAggregateHet "regr_avgx"
1974+ regrAvgY = unsafeAggregateHet "regr_avgy"
1975+ regrCount = unsafeAggregateHet "regr_count"
1976+ regrIntercept = unsafeAggregateHet "regr_intercept"
1977+ regrR2 = unsafeAggregateHet "regr_r2"
1978+ regrSlope = unsafeAggregateHet "regr_slope"
1979+ regrSxx = unsafeAggregateHet "regr_sxx"
1980+ regrSxy = unsafeAggregateHet "regr_sxy"
1981+ regrSyy = unsafeAggregateHet "regr_syy"
1982+ stddev = unsafeAggregate1 "stddev"
1983+ stddevPop = unsafeAggregate1 "stddev_pop"
1984+ stddevSamp = unsafeAggregate1 "stddev_samp"
1985+ variance = unsafeAggregate1 "variance"
1986+ varPop = unsafeAggregate1 "var_pop"
1987+ varSamp = unsafeAggregate1 "var_samp"
1988+instance Aggregate
1989+ (Expression outer commons grp schemas params from)
1990+ (NP (Expression outer commons grp schemas params from))
1991+ (WindowFunction outer commons grp schemas params from) where
1992+ countStar = UnsafeWindowFunction "count(*)"
1993+ count = unsafeWindowFunction1 "count"
1994+ sum_ = unsafeWindowFunction1 "sum"
1995+ arrayAgg = unsafeWindowFunction1 "array_agg"
1996+ jsonAgg = unsafeWindowFunction1 "json_agg"
1997+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"
1998+ bitAnd = unsafeWindowFunction1 "bit_and"
1999+ bitOr = unsafeWindowFunction1 "bit_or"
2000+ boolAnd = unsafeWindowFunction1 "bool_and"
2001+ boolOr = unsafeWindowFunction1 "bool_or"
2002+ every = unsafeWindowFunction1 "every"
2003+ max_ = unsafeWindowFunction1 "max"
2004+ min_ = unsafeWindowFunction1 "min"
2005+ avg = unsafeWindowFunction1 "avg"
2006+ corr = unsafeWindowFunctionN "corr"
2007+ covarPop = unsafeWindowFunctionN "covar_pop"
2008+ covarSamp = unsafeWindowFunctionN "covar_samp"
2009+ regrAvgX = unsafeWindowFunctionN "regr_avgx"
2010+ regrAvgY = unsafeWindowFunctionN "regr_avgy"
2011+ regrCount = unsafeWindowFunctionN "regr_count"
2012+ regrIntercept = unsafeWindowFunctionN "regr_intercept"
2013+ regrR2 = unsafeWindowFunctionN "regr_r2"
2014+ regrSlope = unsafeWindowFunctionN "regr_slope"
2015+ regrSxx = unsafeWindowFunctionN "regr_sxx"
2016+ regrSxy = unsafeWindowFunctionN "regr_sxy"
2017+ regrSyy = unsafeWindowFunctionN "regr_syy"
2018+ stddev = unsafeWindowFunction1 "stddev"
2019+ stddevPop = unsafeWindowFunction1 "stddev_pop"
2020+ stddevSamp = unsafeWindowFunction1 "stddev_samp"
2021+ variance = unsafeWindowFunction1 "variance"
2022+ varPop = unsafeWindowFunction1 "var_pop"
2023+ varSamp = unsafeWindowFunction1 "var_samp"
2024+
2025+-- | escape hatch to define aggregate functions
2026+unsafeAggregate1
2027+ :: ByteString -- ^ aggregate function
2028+ -> Distinction (Expression outer commons 'Ungrouped schemas params from) x
2029+ -> Expression outer commons ('Grouped bys) schemas params from y
2030+unsafeAggregate1 fun x = UnsafeExpression $ fun <> parenthesized (renderSQL x)
2031+
2032+-- | A type family that calculates `PGAvg` type of a `PGType`.
2033+type family PGAvg ty where
2034+ PGAvg 'PGint2 = 'PGnumeric
2035+ PGAvg 'PGint4 = 'PGnumeric
2036+ PGAvg 'PGint8 = 'PGnumeric
2037+ PGAvg 'PGnumeric = 'PGnumeric
2038+ PGAvg 'PGfloat4 = 'PGfloat8
2039+ PGAvg 'PGfloat8 = 'PGfloat8
2040+ PGAvg 'PGinterval = 'PGinterval
2041+ PGAvg pg = TypeError
2042+ ('Text "Squeal type error: No average for " ':<>: 'ShowType pg)
2043+
2044+{-----------------------------------------
2045+type expressions
2046+-----------------------------------------}
2047+
2048+-- | `TypeExpression`s are used in `cast`s and
2049+-- `Squeal.PostgreSQL.Definition.createTable` commands.
2050+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
2051+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
2052+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2053+instance RenderSQL (TypeExpression schemas ty) where
2054+ renderSQL = renderTypeExpression
2055+
2056+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
2057+typedef
2058+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
2059+ => QualifiedAlias sch td
2060+ -> TypeExpression schemas (null ty)
2061+typedef = UnsafeTypeExpression . renderSQL
2062+
2063+-- | The composite type corresponding to a `Table` definition can be expressed
2064+-- by its alias.
2065+typetable
2066+ :: (Has sch schemas schema, Has tab schema ('Table table))
2067+ => QualifiedAlias sch tab
2068+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
2069+typetable = UnsafeTypeExpression . renderSQL
2070+
2071+-- | The composite type corresponding to a `View` definition can be expressed
2072+-- by its alias.
2073+typeview
2074+ :: (Has sch schemas schema, Has vw schema ('View view))
2075+ => QualifiedAlias sch vw
2076+ -> TypeExpression schemas (null ('PGcomposite view))
2077+typeview = UnsafeTypeExpression . renderSQL
2078+
2079+-- | logical Boolean (true/false)
2080+bool :: TypeExpression schemas (null 'PGbool)
2081+bool = UnsafeTypeExpression "bool"
2082+-- | signed two-byte integer
2083+int2, smallint :: TypeExpression schemas (null 'PGint2)
2084+int2 = UnsafeTypeExpression "int2"
2085+smallint = UnsafeTypeExpression "smallint"
2086+-- | signed four-byte integer
2087+int4, int, integer :: TypeExpression schemas (null 'PGint4)
2088+int4 = UnsafeTypeExpression "int4"
2089+int = UnsafeTypeExpression "int"
2090+integer = UnsafeTypeExpression "integer"
2091+-- | signed eight-byte integer
2092+int8, bigint :: TypeExpression schemas (null 'PGint8)
2093+int8 = UnsafeTypeExpression "int8"
2094+bigint = UnsafeTypeExpression "bigint"
2095+-- | arbitrary precision numeric type
2096+numeric :: TypeExpression schemas (null 'PGnumeric)
2097+numeric = UnsafeTypeExpression "numeric"
2098+-- | single precision floating-point number (4 bytes)
2099+float4, real :: TypeExpression schemas (null 'PGfloat4)
2100+float4 = UnsafeTypeExpression "float4"
2101+real = UnsafeTypeExpression "real"
2102+-- | double precision floating-point number (8 bytes)
2103+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
2104+float8 = UnsafeTypeExpression "float8"
2105+doublePrecision = UnsafeTypeExpression "double precision"
2106+-- | currency amount
2107+money :: TypeExpression schema (null 'PGmoney)
2108+money = UnsafeTypeExpression "money"
2109+-- | variable-length character string
2110+text :: TypeExpression schemas (null 'PGtext)
2111+text = UnsafeTypeExpression "text"
2112+-- | fixed-length character string
2113+char, character
2114+ :: forall n schemas null. (KnownNat n, 1 <= n)
2115+ => TypeExpression schemas (null ('PGchar n))
2116+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
2117+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
2118+-- | variable-length character string
2119+varchar, characterVarying
2120+ :: forall n schemas null. (KnownNat n, 1 <= n)
2121+ => TypeExpression schemas (null ('PGvarchar n))
2122+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
2123+characterVarying = UnsafeTypeExpression $
2124+ "character varying(" <> renderNat @n <> ")"
2125+-- | binary data ("byte array")
2126+bytea :: TypeExpression schemas (null 'PGbytea)
2127+bytea = UnsafeTypeExpression "bytea"
2128+-- | date and time (no time zone)
2129+timestamp :: TypeExpression schemas (null 'PGtimestamp)
2130+timestamp = UnsafeTypeExpression "timestamp"
2131+-- | date and time, including time zone
2132+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
2133+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
2134+-- | calendar date (year, month, day)
2135+date :: TypeExpression schemas (null 'PGdate)
2136+date = UnsafeTypeExpression "date"
2137+-- | time of day (no time zone)
2138+time :: TypeExpression schemas (null 'PGtime)
2139+time = UnsafeTypeExpression "time"
2140+-- | time of day, including time zone
2141+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
2142+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
2143+-- | time span
2144+interval :: TypeExpression schemas (null 'PGinterval)
2145+interval = UnsafeTypeExpression "interval"
2146+-- | universally unique identifier
2147+uuid :: TypeExpression schemas (null 'PGuuid)
2148+uuid = UnsafeTypeExpression "uuid"
2149+-- | IPv4 or IPv6 host address
2150+inet :: TypeExpression schemas (null 'PGinet)
2151+inet = UnsafeTypeExpression "inet"
2152+-- | textual JSON data
2153+json :: TypeExpression schemas (null 'PGjson)
2154+json = UnsafeTypeExpression "json"
2155+-- | binary JSON data, decomposed
2156+jsonb :: TypeExpression schemas (null 'PGjsonb)
2157+jsonb = UnsafeTypeExpression "jsonb"
2158+-- | variable length array
2159+vararray
2160+ :: TypeExpression schemas pg
2161+ -> TypeExpression schemas (null ('PGvararray pg))
2162+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
2163+-- | fixed length array
2164+--
2165+-- >>> renderSQL (fixarray @'[2] json)
2166+-- "json[2]"
2167+fixarray
2168+ :: forall dims schemas null pg. SOP.All KnownNat dims
2169+ => TypeExpression schemas pg
2170+ -> TypeExpression schemas (null ('PGfixarray dims pg))
2171+fixarray ty = UnsafeTypeExpression $
2172+ renderSQL ty <> renderDims @dims
2173+ where
2174+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
2175+ renderDims =
2176+ ("[" <>)
2177+ . (<> "]")
2178+ . ByteString.intercalate "]["
2179+ . hcollapse
2180+ $ hcmap (SOP.Proxy @KnownNat)
2181+ (K . fromString . show . natVal)
2182+ (hpure SOP.Proxy :: NP SOP.Proxy ns)
2183+tsvector :: TypeExpression schemas (null 'PGtsvector)
2184+tsvector = UnsafeTypeExpression "tsvector"
2185+tsquery :: TypeExpression schemas (null 'PGtsquery)
2186+tsquery = UnsafeTypeExpression "tsquery"
2187+
2188+-- | `pgtype` is a demoted version of a `PGType`
2189+class PGTyped schemas (ty :: NullityType) where
2190+ pgtype :: TypeExpression schemas ty
2191+instance PGTyped schemas (null 'PGbool) where pgtype = bool
2192+instance PGTyped schemas (null 'PGint2) where pgtype = int2
2193+instance PGTyped schemas (null 'PGint4) where pgtype = int4
2194+instance PGTyped schemas (null 'PGint8) where pgtype = int8
2195+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
2196+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
2197+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
2198+instance PGTyped schemas (null 'PGmoney) where pgtype = money
2199+instance PGTyped schemas (null 'PGtext) where pgtype = text
2200+instance (KnownNat n, 1 <= n)
2201+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
2202+instance (KnownNat n, 1 <= n)
2203+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
2204+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
2205+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
2206+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
2207+instance PGTyped schemas (null 'PGdate) where pgtype = date
2208+instance PGTyped schemas (null 'PGtime) where pgtype = time
2209+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
2210+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
2211+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
2212+instance PGTyped schemas (null 'PGjson) where pgtype = json
2213+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
2214+instance PGTyped schemas ty
2215+ => PGTyped schemas (null ('PGvararray ty)) where
2216+ pgtype = vararray (pgtype @schemas @ty)
2217+instance (SOP.All KnownNat dims, PGTyped schemas ty)
2218+ => PGTyped schemas (null ('PGfixarray dims ty)) where
2219+ pgtype = fixarray @dims (pgtype @schemas @ty)
2220+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
2221+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
2222+
2223+{-----------------------------------------
2224+Sorting
2225+-----------------------------------------}
2226+
2227+-- | `SortExpression`s are used by `orderBy` to optionally sort the results
2228+-- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`
2229+-- set the sort direction of a `NotNull` result
2230+-- column to ascending or descending. Ascending order puts smaller values
2231+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
2232+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
2233+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
2234+-- determine whether nulls appear before or after non-null values in the sort
2235+-- ordering of a `Null` result column.
2236+data SortExpression outer commons grp schemas params from where
2237+ Asc
2238+ :: Expression outer commons grp schemas params from ('NotNull ty)
2239+ -> SortExpression outer commons grp schemas params from
2240+ Desc
2241+ :: Expression outer commons grp schemas params from ('NotNull ty)
2242+ -> SortExpression outer commons grp schemas params from
2243+ AscNullsFirst
2244+ :: Expression outer commons grp schemas params from ('Null ty)
2245+ -> SortExpression outer commons grp schemas params from
2246+ AscNullsLast
2247+ :: Expression outer commons grp schemas params from ('Null ty)
2248+ -> SortExpression outer commons grp schemas params from
2249+ DescNullsFirst
2250+ :: Expression outer commons grp schemas params from ('Null ty)
2251+ -> SortExpression outer commons grp schemas params from
2252+ DescNullsLast
2253+ :: Expression outer commons grp schemas params from ('Null ty)
2254+ -> SortExpression outer commons grp schemas params from
2255+deriving instance Show (SortExpression outer commons grp schemas params from)
2256+
2257+{- |
2258+The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`
2259+to be sorted according to the specified `SortExpression`(s).
2260+If two rows are equal according to the leftmost expression,
2261+they are compared according to the next expression and so on.
2262+If they are equal according to all specified expressions,
2263+they are returned in an implementation-dependent order.
2264+
2265+You can also control the order in which rows are processed by window functions
2266+using `orderBy` within `Squeal.PostgreSQL.Query.Over`.
2267+-}
2268+class OrderBy expr where
2269+ orderBy
2270+ :: [SortExpression outer commons grp schemas params from]
2271+ -> expr outer commons grp schemas params from
2272+ -> expr outer commons grp schemas params from
2273+
2274+-- | Render a `SortExpression`.
2275+instance RenderSQL (SortExpression outer commons grp schemas params from) where
2276+ renderSQL = \case
2277+ Asc expression -> renderSQL expression <+> "ASC"
2278+ Desc expression -> renderSQL expression <+> "DESC"
2279+ AscNullsFirst expression -> renderSQL expression
2280+ <+> "ASC NULLS FIRST"
2281+ DescNullsFirst expression -> renderSQL expression
2282+ <+> "DESC NULLS FIRST"
2283+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
2284+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
2285+
2286+-- | A `WindowDefinition` is a set of table rows that are somehow related
2287+-- to the current row
2288+data WindowDefinition outer commons grp schemas params from where
2289+ WindowDefinition
2290+ :: SListI bys
2291+ => NP (Expression outer commons grp schemas params from) bys
2292+ -> [SortExpression outer commons grp schemas params from]
2293+ -> WindowDefinition outer commons grp schemas params from
2294+
2295+instance OrderBy WindowDefinition where
2296+ orderBy sortsR (WindowDefinition parts sortsL)
2297+ = WindowDefinition parts (sortsL ++ sortsR)
2298+
2299+instance RenderSQL (WindowDefinition outer commons schemas from grp params) where
2300+ renderSQL (WindowDefinition part ord) =
2301+ renderPartitionByClause part <> renderOrderByClause ord
2302+ where
2303+ renderPartitionByClause = \case
2304+ Nil -> ""
2305+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
2306+ renderOrderByClause = \case
2307+ [] -> ""
2308+ srts -> " ORDER" <+> "BY"
2309+ <+> commaSeparated (renderSQL <$> srts)
2310+
2311+{- |
2312+The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,
2313+or partitions, that share the same values of the `partitionBy` `Expression`(s).
2314+For each row, the window function is computed across the rows that fall into
2315+the same partition as the current row.
2316+-}
2317+partitionBy
2318+ :: SListI bys
2319+ => NP (Expression outer commons grp schemas params from) bys
2320+ -> WindowDefinition outer commons grp schemas params from
2321+partitionBy bys = WindowDefinition bys []
2322+
2323+{- |
2324+A window function performs a calculation across a set of table rows
2325+that are somehow related to the current row. This is comparable to the type
2326+of calculation that can be done with an aggregate function.
2327+However, window functions do not cause rows to become grouped into a single
2328+output row like non-window aggregate calls would.
2329+Instead, the rows retain their separate identities.
2330+Behind the scenes, the window function is able to access more than
2331+just the current row of the query result.
2332+-}
2333+newtype WindowFunction
2334+ (outer :: FromType)
2335+ (commons :: FromType)
2336+ (grp :: Grouping)
2337+ (schemas :: SchemasType)
2338+ (params :: [NullityType])
2339+ (from :: FromType)
2340+ (ty :: NullityType)
2341+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
2342+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
2343+
2344+instance RenderSQL (WindowFunction outer commons grp schemas params from ty) where
2345+ renderSQL = renderWindowFunction
2346+
2347+type WinFun0 x
2348+ = forall outer commons grp schemas params from
2349+ . WindowFunction outer commons grp schemas params from x
2350+ -- ^ cannot reference aliases
2351+
2352+type WinFun1 x y
2353+ = forall outer commons grp schemas params from
2354+ . Expression outer commons grp schemas params from x
2355+ -- ^ input
2356+ -> WindowFunction outer commons grp schemas params from y
2357+ -- ^ output
2358+
2359+type WinFunHet xs y
2360+ = forall outer commons grp schemas params from
2361+ . NP (Expression outer commons grp schemas params from) xs
2362+ -- ^ inputs
2363+ -> WindowFunction outer commons grp schemas params from y
2364+ -- ^ output
2365+
2366+unsafeWindowFunction1 :: ByteString -> WinFun1 x y
2367+unsafeWindowFunction1 fun x
2368+ = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)
2369+
2370+unsafeWindowFunctionN :: SOP.SListI xs => ByteString -> WinFunHet xs y
2371+unsafeWindowFunctionN fun xs = UnsafeWindowFunction $ fun <>
2372+ parenthesized (renderCommaSeparated renderSQL xs)
2373+
2374+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
2375+>>> printSQL rank
2376+rank()
2377+-}
2378+rank :: WinFun0 ('NotNull 'PGint8)
2379+rank = UnsafeWindowFunction "rank()"
2380+
2381+{- | number of the current row within its partition, counting from 1
2382+>>> printSQL rowNumber
2383+row_number()
2384+-}
2385+rowNumber :: WinFun0 ('NotNull 'PGint8)
2386+rowNumber = UnsafeWindowFunction "row_number()"
2387+
2388+{- | rank of the current row without gaps; this function counts peer groups
2389+>>> printSQL denseRank
2390+dense_rank()
2391+-}
2392+denseRank :: WinFun0 ('NotNull 'PGint8)
2393+denseRank = UnsafeWindowFunction "dense_rank()"
2394+
2395+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
2396+>>> printSQL percentRank
2397+percent_rank()
2398+-}
2399+percentRank :: WinFun0 ('NotNull 'PGfloat8)
2400+percentRank = UnsafeWindowFunction "percent_rank()"
2401+
2402+{- | cumulative distribution: (number of partition rows
2403+preceding or peer with current row) / total partition rows
2404+>>> printSQL cumeDist
2405+cume_dist()
2406+-}
2407+cumeDist :: WinFun0 ('NotNull 'PGfloat8)
2408+cumeDist = UnsafeWindowFunction "cume_dist()"
2409+
2410+{- | integer ranging from 1 to the argument value,
2411+dividing the partition as equally as possible
2412+-}
2413+ntile :: WinFun1 ('NotNull 'PGint4) ('NotNull 'PGint4)
2414+ntile = unsafeWindowFunction1 "ntile"
2415+
2416+{- | returns value evaluated at the row that is offset rows before the current
2417+row within the partition; if there is no such row, instead return default
2418+(which must be of the same type as value). Both offset and default are
2419+evaluated with respect to the current row.
2420+-}
2421+lag :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2422+lag = unsafeWindowFunctionN "lag"
2423+
2424+{- | returns value evaluated at the row that is offset rows after the current
2425+row within the partition; if there is no such row, instead return default
2426+(which must be of the same type as value). Both offset and default are
2427+evaluated with respect to the current row.
2428+-}
2429+lead :: WinFunHet '[ty, 'NotNull 'PGint4, ty] ty
2430+lead = unsafeWindowFunctionN "lag"
2431+
2432+{- | returns value evaluated at the row that is the
2433+first row of the window frame
2434+-}
2435+firstValue :: WinFun1 ty ty
2436+firstValue = unsafeWindowFunction1 "first_value"
2437+
2438+{- | returns value evaluated at the row that is the
2439+last row of the window frame
2440+-}
2441+lastValue :: WinFun1 ty ty
2442+lastValue = unsafeWindowFunction1 "last_value"
2443+
2444+{- | returns value evaluated at the row that is the nth
2445+row of the window frame (counting from 1); null if no such row
2446+-}
2447+nthValue :: WinFunHet '[null ty, 'NotNull 'PGint4] ('Null ty)
2448+nthValue = unsafeWindowFunctionN "nth_value"
2449+
2450+{-|
2451+Create date from year, month and day fields
2452+
2453+>>> printSQL (makeDate (1984 :* 7 *: 3))
2454+make_date(1984, 7, 3)
2455+-}
2456+makeDate :: FunctionN
2457+ '[ null 'PGint4, null 'PGint4, null 'PGint4 ]
2458+ ( null 'PGdate )
2459+makeDate = unsafeFunctionN "make_date"
2460+
2461+{-|
2462+Create time from hour, minute and seconds fields
2463+
2464+>>> printSQL (makeTime (8 :* 15 *: 23.5))
2465+make_time(8, 15, 23.5)
2466+-}
2467+makeTime :: FunctionN
2468+ '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2469+ ( null 'PGtime )
2470+makeTime = unsafeFunctionN "make_time"
2471+
2472+{-|
2473+Create timestamp from year, month, day, hour, minute and seconds fields
2474+
2475+>>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2476+make_timestamp(2013, 7, 15, 8, 15, 23.5)
2477+-}
2478+makeTimestamp :: FunctionN
2479+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2480+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2481+ ( null 'PGtimestamp )
2482+makeTimestamp = unsafeFunctionN "make_timestamp"
2483+
2484+{-|
2485+Create timestamp with time zone from
2486+year, month, day, hour, minute and seconds fields;
2487+the current time zone is used
2488+
2489+>>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))
2490+make_timestamptz(2013, 7, 15, 8, 15, 23.5)
2491+-}
2492+makeTimestamptz :: FunctionN
2493+ '[ null 'PGint4, null 'PGint4, null 'PGint4
2494+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ]
2495+ ( null 'PGtimestamptz )
2496+makeTimestamptz = unsafeFunctionN "make_timestamptz"
2497+
2498+{-|
2499+Affine space operations on time types.
2500+-}
2501+class TimeOp time diff | time -> diff where
2502+ {-|
2503+ >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)
2504+ (make_date(1984, 7, 3) + 365)
2505+ -}
2506+ (!+) :: Operator (null time) (null diff) (null time)
2507+ (!+) = unsafeBinaryOp "+"
2508+ {-|
2509+ >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))
2510+ (365 + make_date(1984, 7, 3))
2511+ -}
2512+ (+!) :: Operator (null diff) (null time) (null time)
2513+ (+!) = unsafeBinaryOp "+"
2514+ {-|
2515+ >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)
2516+ (make_date(1984, 7, 3) - 365)
2517+ -}
2518+ (!-) :: Operator (null time) (null diff) (null time)
2519+ (!-) = unsafeBinaryOp "-"
2520+ {-|
2521+ >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)
2522+ (make_date(1984, 7, 3) - CURRENT_DATE)
2523+ -}
2524+ (!-!) :: Operator (null time) (null time) (null diff)
2525+ (!-!) = unsafeBinaryOp "-"
2526+instance TimeOp 'PGtimestamp 'PGinterval
2527+instance TimeOp 'PGtimestamptz 'PGinterval
2528+instance TimeOp 'PGtime 'PGinterval
2529+instance TimeOp 'PGtimetz 'PGinterval
2530+instance TimeOp 'PGinterval 'PGinterval
2531+instance TimeOp 'PGdate 'PGint4
2532+infixl 6 !+
2533+infixl 6 +!
2534+infixl 6 !-
2535+infixl 6 !-!
2536+
2537+data TimeUnit
2538+ = Years | Months | Weeks | Days
2539+ | Hours | Minutes | Seconds
2540+ | Microseconds | Milliseconds
2541+ | Decades | Centuries | Millennia
2542+ deriving (Eq, Ord, Show, Read, Enum, GHC.Generic)
2543+instance SOP.Generic TimeUnit
2544+instance SOP.HasDatatypeInfo TimeUnit
2545+instance RenderSQL TimeUnit where
2546+ renderSQL = \case
2547+ Years -> "years"
2548+ Months -> "months"
2549+ Weeks -> "weeks"
2550+ Days -> "days"
2551+ Hours -> "hours"
2552+ Minutes -> "minutes"
2553+ Seconds -> "seconds"
2554+ Microseconds -> "microseconds"
2555+ Milliseconds -> "milliseconds"
2556+ Decades -> "decades"
2557+ Centuries -> "centuries"
2558+ Millennia -> "millennia"
2559+
2560+-- | >>> printSQL $ interval_ 7 Days
2561+-- (INTERVAL '7.0 days')
2562+interval_ :: Double -> TimeUnit -> Expr (null 'PGinterval)
2563+interval_ num unit = UnsafeExpression . parenthesized $ "INTERVAL" <+>
2564+ "'" <> fromString (show num) <+> renderSQL unit <> "'"
2565+
2566+class Literal hask where
2567+ literal :: hask -> Expr (null (PG hask))
2568+instance JSON.ToJSON hask => Literal (Json hask) where
2569+ literal = cast json . UnsafeExpression
2570+ . singleQuotedUtf8 . toStrict . JSON.encode . getJson
2571+instance JSON.ToJSON hask => Literal (Jsonb hask) where
2572+ literal = cast jsonb . UnsafeExpression
2573+ . singleQuotedUtf8 . toStrict . JSON.encode . getJsonb
2574+instance Literal Char where
2575+ literal chr = UnsafeExpression $
2576+ "E\'" <> fromString (escape chr) <> "\'"
2577+instance Literal String where literal = fromString
2578+instance Literal Int16 where literal = fromIntegral
2579+instance Literal Int32 where literal = fromIntegral
2580+instance Literal Int64 where literal = fromIntegral
2581+instance Literal Float where literal = fromRational . toRational
2582+instance Literal Double where literal = fromRational . toRational
2583+instance Literal Text where literal = fromString . Text.unpack
2584+instance Literal Lazy.Text where literal = fromString . Lazy.Text.unpack