{-# LANGUAGE Arrows #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}

-- We can probably disable ConstraintKinds and TypeSynonymInstances
-- when we move to Sql... instead of PG..

module Opaleye.Operators
  (
  -- * Restriction operators
    where_
  , restrict
  , restrictExists
  , restrictNotExists
  -- * Numerical operators
  -- | Numeric 'Column' / 'F.Field' types are instances of 'Num'
  -- and 'Fractional', so you can use the standard Haskell numerical
  -- operators (e.g.. '*', '/', '+', '-') on them and you can create
  -- them with numerical literals such as @3.14 :: 'F.Field' 'T.SqlFloat8'@.
  , (+)
  , (-)
  , (*)
  , (/)
  , fromInteger
  , abs
  , negate
  , signum
  -- * Equality operators
  , (.==)
  , (./=)
  , (.===)
  , (./==)
  -- * Comparison operators
  , (.>)
  , (.<)
  , (.<=)
  , (.>=)
  -- * Numerical operators
  , quot_
  , rem_
  -- * Conditional operators
  , case_
  , ifThenElse
  , ifThenElseMany
  -- * Logical operators
  , (.||)
  , (.&&)
  , not
  , ors
  -- * Text operators
  , (.++)
  , lower
  , upper
  , like
  , ilike
  , charLength
  , sqlLength
  -- * Containment operators
  , in_
  , inSelect
  -- * JSON operators
  , SqlIsJson
  , PGIsJson
  , SqlJsonIndex
  , PGJsonIndex
  , (.->)
  , (.->>)
  , (.#>)
  , (.#>>)
  , (.@>)
  , (.<@)
  , (.?)
  , (.?|)
  , (.?&)
  , JBOF.jsonBuildObject
  , JBOF.jsonBuildObjectField
  , JBOF.JSONBuildObjectFields
  -- * SqlArray operators
  , emptyArray
  , arrayAppend
  , arrayPrepend
  , arrayRemove
  , arrayRemoveNulls
  , singletonArray
  , index
  , arrayPosition
  , sqlElem
  -- * Range operators
  , overlap
  , liesWithin
  , upperBound
  , lowerBound
  , (.<<)
  , (.>>)
  , (.&<)
  , (.&>)
  , (.-|-)
  -- * Other operators
  , timestamptzAtTimeZone
  , dateOfTimestamp
  , now
  -- * Deprecated
  , exists
  , notExists
  , inQuery
  , keepWhen
  )

  where

import qualified Control.Arrow as A
import qualified Data.Foldable as F
import qualified Data.List.NonEmpty as NEL
import           Prelude hiding (not)
import qualified Opaleye.Exists as E
import qualified Opaleye.Field as F
import           Opaleye.Internal.Column (Column(Column), unsafeCase_,
                                          unsafeIfThenElse, unsafeGt)
import qualified Opaleye.Internal.Column as C
import qualified Opaleye.Internal.JSONBuildObjectFields as JBOF
import           Opaleye.Internal.QueryArr (SelectArr(QueryArr),
                                            Query, QueryArr, runSimpleQueryArr)
import qualified Opaleye.Internal.PrimQuery as PQ
import qualified Opaleye.Internal.Operators as O
import           Opaleye.Internal.Helpers   ((.:))
import qualified Opaleye.Lateral as L
import qualified Opaleye.Order as Ord
import qualified Opaleye.Select   as S
import qualified Opaleye.SqlTypes as T

import qualified Opaleye.Column   as Column

import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ

import qualified Data.Profunctor.Product.Default as D

{-| Keep only the rows of a query satisfying a given condition, using an
SQL @WHERE@ clause.  It is equivalent to the Haskell function

@
where_ :: Bool -> [()]
where_ True  = [()]
where_ False = []
@
-}
where_ :: F.Field T.SqlBool -> S.Select ()
where_ :: Field SqlBool -> Select ()
where_ = SelectArr (Column SqlBool) () -> Column SqlBool -> Select ()
forall i a. SelectArr i a -> i -> Select a
L.viaLateral SelectArr (Column SqlBool) ()
SelectArr (Field SqlBool) ()
restrict

{-| You would typically use 'restrict' if you want to write your query
using 'A.Arrow' notation.  If you want to use monadic style
then 'where_' will suit you better. -}
restrict :: S.SelectArr (F.Field T.SqlBool) ()
restrict :: SelectArr (Field SqlBool) ()
restrict = SelectArr (Field SqlBool) ()
O.restrict

{-| Add a @WHERE EXISTS@ clause to the current query. -}
restrictExists :: S.SelectArr a b -> S.SelectArr a ()
restrictExists :: SelectArr a b -> SelectArr a ()
restrictExists SelectArr a b
criteria = ((a, Tag) -> ((), Lateral -> PrimQuery -> PrimQuery, Tag))
-> SelectArr a ()
forall a b.
((a, Tag) -> (b, Lateral -> PrimQuery -> PrimQuery, Tag))
-> SelectArr a b
QueryArr (a, Tag) -> ((), Lateral -> PrimQuery -> PrimQuery, Tag)
forall p. (a, Tag) -> ((), p -> PrimQuery -> PrimQuery, Tag)
f where
  -- A where exists clause can always refer to columns defined by the
  -- query it references so needs no special treatment on LATERAL.
  f :: (a, Tag) -> ((), p -> PrimQuery -> PrimQuery, Tag)
f (a
a, Tag
t0) = ((), \p
_ PrimQuery
primQ -> SemijoinType -> PrimQuery -> PrimQuery -> PrimQuery
forall a.
SemijoinType -> PrimQuery' a -> PrimQuery' a -> PrimQuery' a
PQ.Semijoin SemijoinType
PQ.Semi PrimQuery
primQ PrimQuery
existsQ, Tag
t1) where
    (b
_, PrimQuery
existsQ, Tag
t1) = SelectArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
forall a b. QueryArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
runSimpleQueryArr SelectArr a b
criteria (a
a, Tag
t0)

{-| Add a @WHERE NOT EXISTS@ clause to the current query. -}
restrictNotExists :: S.SelectArr a b -> S.SelectArr a ()
restrictNotExists :: SelectArr a b -> SelectArr a ()
restrictNotExists SelectArr a b
criteria = ((a, Tag) -> ((), Lateral -> PrimQuery -> PrimQuery, Tag))
-> SelectArr a ()
forall a b.
((a, Tag) -> (b, Lateral -> PrimQuery -> PrimQuery, Tag))
-> SelectArr a b
QueryArr (a, Tag) -> ((), Lateral -> PrimQuery -> PrimQuery, Tag)
forall p. (a, Tag) -> ((), p -> PrimQuery -> PrimQuery, Tag)
f where
  -- A where exists clause can always refer to columns defined by the
  -- query it references so needs no special treatment on LATERAL.
  f :: (a, Tag) -> ((), p -> PrimQuery -> PrimQuery, Tag)
f (a
a, Tag
t0) = ((), \p
_ PrimQuery
primQ -> SemijoinType -> PrimQuery -> PrimQuery -> PrimQuery
forall a.
SemijoinType -> PrimQuery' a -> PrimQuery' a -> PrimQuery' a
PQ.Semijoin SemijoinType
PQ.Anti PrimQuery
primQ PrimQuery
existsQ, Tag
t1) where
    (b
_, PrimQuery
existsQ, Tag
t1) = SelectArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
forall a b. QueryArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
runSimpleQueryArr SelectArr a b
criteria (a
a, Tag
t0)

infix 4 .==
(.==) :: Column a -> Column a -> F.Field T.SqlBool
.== :: Column a -> Column a -> Field SqlBool
(.==) = BinOp -> Column a -> Column a -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:==)

infix 4 ./=
(./=) :: Column a -> Column a -> F.Field T.SqlBool
./= :: Column a -> Column a -> Field SqlBool
(./=) = BinOp -> Column a -> Column a -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:<>)

infix 4 .===
-- | A polymorphic equality operator that works for all types that you
-- have run `makeAdaptorAndInstance` on.  This may be unified with
-- `.==` in a future version.
(.===) :: D.Default O.EqPP fields fields => fields -> fields -> F.Field T.SqlBool
.=== :: fields -> fields -> Field SqlBool
(.===) = fields -> fields -> Field SqlBool
forall columns.
Default EqPP columns columns =>
columns -> columns -> Column SqlBool
(O..==)

infix 4 ./==
-- | A polymorphic inequality operator that works for all types that
-- you have run `makeAdaptorAndInstance` on.  This may be unified with
-- `./=` in a future version.
(./==) :: D.Default O.EqPP fields fields => fields -> fields -> F.Field T.SqlBool
./== :: fields -> fields -> Field SqlBool
(./==) = Column SqlBool -> Column SqlBool
Field SqlBool -> Field SqlBool
Opaleye.Operators.not (Column SqlBool -> Column SqlBool)
-> (fields -> fields -> Column SqlBool)
-> fields
-> fields
-> Column SqlBool
forall r z a b. (r -> z) -> (a -> b -> r) -> a -> b -> z
.: fields -> fields -> Column SqlBool
forall columns.
Default EqPP columns columns =>
columns -> columns -> Column SqlBool
(O..==)

infix 4 .>
(.>) :: Ord.SqlOrd a => Column a -> Column a -> F.Field T.SqlBool
.> :: Column a -> Column a -> Field SqlBool
(.>) = Column a -> Column a -> Field SqlBool
forall a pgBool. Column a -> Column a -> Column pgBool
unsafeGt

infix 4 .<
(.<) :: Ord.SqlOrd a => Column a -> Column a -> F.Field T.SqlBool
.< :: Column a -> Column a -> Field SqlBool
(.<) = BinOp -> Column a -> Column a -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:<)

infix 4 .<=
(.<=) :: Ord.SqlOrd a => Column a -> Column a -> F.Field T.SqlBool
.<= :: Column a -> Column a -> Field SqlBool
(.<=) = BinOp -> Column a -> Column a -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:<=)

infix 4 .>=
(.>=) :: Ord.SqlOrd a => Column a -> Column a -> F.Field T.SqlBool
.>= :: Column a -> Column a -> Field SqlBool
(.>=) = BinOp -> Column a -> Column a -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:>=)

-- | Integral division, named after 'Prelude.quot'.  It maps to the
-- @/@ operator in Postgres.
quot_ :: C.SqlIntegral a => Column a -> Column a -> Column a
quot_ :: Column a -> Column a -> Column a
quot_ = BinOp -> Column a -> Column a -> Column a
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:/)

-- | The remainder of integral division, named after 'Prelude.rem'.
-- It maps to 'MOD' ('%') in Postgres, confusingly described as
-- "modulo (remainder)".
rem_ :: C.SqlIntegral a => Column a -> Column a -> Column a
rem_ :: Column a -> Column a -> Column a
rem_ = BinOp -> Column a -> Column a -> Column a
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
HPQ.OpMod

-- | Select the first case for which the condition is true.
case_ :: [(F.Field T.SqlBool, Column a)] -> Column a -> Column a
case_ :: [(Field SqlBool, Column a)] -> Column a -> Column a
case_ = [(Field SqlBool, Column a)] -> Column a -> Column a
forall pgBool a.
[(Column pgBool, Column a)] -> Column a -> Column a
unsafeCase_

-- | Monomorphic if\/then\/else.
--
-- This may be replaced by 'ifThenElseMany' in a future version.
ifThenElse :: F.Field T.SqlBool -> Column a -> Column a -> Column a
ifThenElse :: Field SqlBool -> Column a -> Column a -> Column a
ifThenElse = Field SqlBool -> Column a -> Column a -> Column a
forall pgBool a. Column pgBool -> Column a -> Column a -> Column a
unsafeIfThenElse

-- | Polymorphic if\/then\/else.
ifThenElseMany :: D.Default O.IfPP fields fields
               => F.Field T.SqlBool
               -> fields
               -> fields
               -> fields
ifThenElseMany :: Field SqlBool -> fields -> fields -> fields
ifThenElseMany = IfPP fields fields -> Column SqlBool -> fields -> fields -> fields
forall columns columns'.
IfPP columns columns'
-> Column SqlBool -> columns -> columns -> columns'
O.ifExplict IfPP fields fields
forall (p :: * -> * -> *) a b. Default p a b => p a b
D.def

infixr 2 .||

-- | Boolean or
(.||) :: F.Field T.SqlBool -> F.Field T.SqlBool -> F.Field T.SqlBool
.|| :: Field SqlBool -> Field SqlBool -> Field SqlBool
(.||) = Field SqlBool -> Field SqlBool -> Field SqlBool
(O..||)

infixr 3 .&&

-- | Boolean and
(.&&) :: F.Field T.SqlBool -> F.Field T.SqlBool -> F.Field T.SqlBool
.&& :: Field SqlBool -> Field SqlBool -> Field SqlBool
(.&&) = Column SqlBool -> Column SqlBool -> Column SqlBool
Field SqlBool -> Field SqlBool -> Field SqlBool
(O..&&)

-- | Boolean not
not :: F.Field T.SqlBool -> F.Field T.SqlBool
not :: Field SqlBool -> Field SqlBool
not = Field SqlBool -> Field SqlBool
O.not

-- | True when any element of the container is true
ors :: F.Foldable f => f (F.Field T.SqlBool) -> F.Field T.SqlBool
ors :: f (Field SqlBool) -> Field SqlBool
ors = (Column SqlBool -> Column SqlBool -> Column SqlBool)
-> Column SqlBool -> f (Column SqlBool) -> Column SqlBool
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' Column SqlBool -> Column SqlBool -> Column SqlBool
Field SqlBool -> Field SqlBool -> Field SqlBool
(.||) (Bool -> Field SqlBool
T.sqlBool Bool
False)

-- | Concatenate 'F.Field' 'T.SqlText'
(.++) :: F.Field T.SqlText -> F.Field T.SqlText -> F.Field T.SqlText
.++ :: Field SqlText -> Field SqlText -> Field SqlText
(.++) = BinOp -> Column SqlText -> Column SqlText -> Column SqlText
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:||)

-- | To lowercase
lower :: F.Field T.SqlText -> F.Field T.SqlText
lower :: Field SqlText -> Field SqlText
lower = UnOp -> Column SqlText -> Column SqlText
forall a b. UnOp -> Column a -> Column b
C.unOp UnOp
HPQ.OpLower

-- | To uppercase
upper :: F.Field T.SqlText -> F.Field T.SqlText
upper :: Field SqlText -> Field SqlText
upper = UnOp -> Column SqlText -> Column SqlText
forall a b. UnOp -> Column a -> Column b
C.unOp UnOp
HPQ.OpUpper

-- | Postgres @LIKE@ operator
like :: F.Field T.SqlText -> F.Field T.SqlText -> F.Field T.SqlBool
like :: Field SqlText -> Field SqlText -> Field SqlBool
like = BinOp -> Column SqlText -> Column SqlText -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
HPQ.OpLike

-- | Postgres @ILIKE@ operator
ilike :: F.Field T.SqlText -> F.Field T.SqlText -> F.Field T.SqlBool
ilike :: Field SqlText -> Field SqlText -> Field SqlBool
ilike = BinOp -> Column SqlText -> Column SqlText -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
HPQ.OpILike

-- {-# DEPRECATED charLength "You probably want to use 'sqlLength' instead" #-}
-- | Do not use.  Will be deprecated in 0.8.  You probably want to use
-- 'sqlLength' instead.
charLength :: C.PGString a => Column a -> Column Int
charLength :: Column a -> Column Int
charLength (Column PrimExpr
e) = PrimExpr -> Column Int
forall pgType. PrimExpr -> Column pgType
Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"char_length" [PrimExpr
e])

sqlLength :: C.PGString a => F.Field a -> F.Field T.SqlInt4
sqlLength :: Field a -> Field SqlInt4
sqlLength  (Column e) = PrimExpr -> Column SqlInt4
forall pgType. PrimExpr -> Column pgType
Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"length" [PrimExpr
e])

-- | 'in_' is designed to be used in prefix form.
--
-- 'in_' @validProducts@ @product@ checks whether @product@ is a valid
-- product.  'in_' @validProducts@ is a function which checks whether
-- a product is a valid product.
in_ :: (Functor f, F.Foldable f) => f (Column a) -> Column a -> F.Field T.SqlBool
in_ :: f (Column a) -> Column a -> Field SqlBool
in_ f (Column a)
fcas (Column PrimExpr
a) = PrimExpr -> Column SqlBool
forall pgType. PrimExpr -> Column pgType
Column (PrimExpr -> Column SqlBool) -> PrimExpr -> Column SqlBool
forall a b. (a -> b) -> a -> b
$ case [Column a] -> Maybe (NonEmpty (Column a))
forall a. [a] -> Maybe (NonEmpty a)
NEL.nonEmpty (f (Column a) -> [Column a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList f (Column a)
fcas) of
   Maybe (NonEmpty (Column a))
Nothing -> Literal -> PrimExpr
HPQ.ConstExpr (Bool -> Literal
HPQ.BoolLit Bool
False)
   Just NonEmpty (Column a)
xs -> BinOp -> PrimExpr -> PrimExpr -> PrimExpr
HPQ.BinExpr BinOp
HPQ.OpIn PrimExpr
a (NonEmpty PrimExpr -> PrimExpr
HPQ.ListExpr ((Column a -> PrimExpr) -> NonEmpty (Column a) -> NonEmpty PrimExpr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Column a -> PrimExpr
forall a. Column a -> PrimExpr
C.unColumn NonEmpty (Column a)
xs))

-- | True if the first argument occurs amongst the rows of the second,
-- false otherwise.
--
-- This operation is equivalent to Postgres's @IN@ operator.
inSelect :: D.Default O.EqPP fields fields
         => fields -> S.Select fields -> S.Select (F.Field T.SqlBool)
inSelect :: fields -> Select fields -> Select (Field SqlBool)
inSelect fields
c Select fields
q = Select fields -> Select (Field SqlBool)
forall a. Select a -> Select (Field SqlBool)
E.exists ((fields -> Field SqlBool) -> SelectArr fields fields
forall a. (a -> Field SqlBool) -> SelectArr a a
keepWhen (fields
c fields -> fields -> Field SqlBool
forall fields.
Default EqPP fields fields =>
fields -> fields -> Field SqlBool
.===) SelectArr fields fields -> Select fields -> Select fields
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
A.<<< Select fields
q)

-- | Class of Postgres types that represent json values.
-- Used to overload functions and operators that work on both 'T.SqlJson' and 'T.SqlJsonb'.
--
-- Warning: making additional instances of this class can lead to broken code!
class SqlIsJson a

{-# DEPRECATED PGIsJson "Use SqlIsJson instead" #-}
type PGIsJson = SqlIsJson

instance SqlIsJson T.SqlJson
instance SqlIsJson T.SqlJsonb

-- | Class of Postgres types that can be used to index json values.
--
-- Warning: making additional instances of this class can lead to broken code!
class SqlJsonIndex a

type PGJsonIndex = SqlJsonIndex

instance SqlJsonIndex T.SqlInt4
instance SqlJsonIndex T.SqlInt8
instance SqlJsonIndex T.SqlText

-- | Get JSON object field by key.
infixl 8 .->
(.->) :: (SqlIsJson a, SqlJsonIndex k)
      => F.FieldNullable a -- ^
      -> F.Field k -- ^ key or index
      -> F.FieldNullable a
.-> :: FieldNullable a -> Field k -> FieldNullable a
(.->) = BinOp -> Column (Nullable a) -> Column k -> Column (Nullable a)
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:->)

-- | Get JSON object field as text.
infixl 8 .->>
(.->>) :: (SqlIsJson a, SqlJsonIndex k)
       => F.FieldNullable a -- ^
       -> F.Field k -- ^ key or index
       -> F.FieldNullable T.SqlText
.->> :: FieldNullable a -> Field k -> FieldNullable SqlText
(.->>) = BinOp
-> Column (Nullable a) -> Column k -> Column (Nullable SqlText)
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:->>)

-- | Get JSON object at specified path.
infixl 8 .#>
(.#>) :: (SqlIsJson a)
      => F.FieldNullable a -- ^
      -> Column (T.SqlArray T.SqlText) -- ^ path
      -> F.FieldNullable a
.#> :: FieldNullable a -> Column (SqlArray SqlText) -> FieldNullable a
(.#>) = BinOp
-> Column (Nullable a)
-> Column (SqlArray SqlText)
-> Column (Nullable a)
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:#>)

-- | Get JSON object at specified path as text.
infixl 8 .#>>
(.#>>) :: (SqlIsJson a)
       => F.FieldNullable a -- ^
       -> Column (T.SqlArray T.SqlText) -- ^ path
       -> F.FieldNullable T.SqlText
.#>> :: FieldNullable a
-> Column (SqlArray SqlText) -> FieldNullable SqlText
(.#>>) = BinOp
-> Column (Nullable a)
-> Column (SqlArray SqlText)
-> Column (Nullable SqlText)
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:#>>)

-- | Does the left JSON value contain within it the right value?
infix 4 .@>
(.@>) :: F.Field T.SqlJsonb -> F.Field T.SqlJsonb -> F.Field T.SqlBool
.@> :: Field SqlJsonb -> Field SqlJsonb -> Field SqlBool
(.@>) = BinOp -> Column SqlJsonb -> Column SqlJsonb -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:@>)

-- | Is the left JSON value contained within the right value?
infix 4 .<@
(.<@) :: F.Field T.SqlJsonb -> F.Field T.SqlJsonb -> F.Field T.SqlBool
.<@ :: Field SqlJsonb -> Field SqlJsonb -> Field SqlBool
(.<@) = BinOp -> Column SqlJsonb -> Column SqlJsonb -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:<@)

-- | Does the key/element string exist within the JSON value?
infix 4 .?
(.?) :: F.Field T.SqlJsonb -> F.Field T.SqlText -> F.Field T.SqlBool
.? :: Field SqlJsonb -> Field SqlText -> Field SqlBool
(.?) = BinOp -> Column SqlJsonb -> Column SqlText -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:?)

-- | Do any of these key/element strings exist?
infix 4 .?|
(.?|) :: F.Field T.SqlJsonb
      -> Column (T.SqlArray T.SqlText)
      -> F.Field T.SqlBool
.?| :: Field SqlJsonb -> Column (SqlArray SqlText) -> Field SqlBool
(.?|) = BinOp
-> Column SqlJsonb -> Column (SqlArray SqlText) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:?|)

-- | Do all of these key/element strings exist?
infix 4 .?&
(.?&) :: F.Field T.SqlJsonb
      -> Column (T.SqlArray T.SqlText)
      -> F.Field T.SqlBool
.?& :: Field SqlJsonb -> Column (SqlArray SqlText) -> Field SqlBool
(.?&) = BinOp
-> Column SqlJsonb -> Column (SqlArray SqlText) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:?&)

emptyArray :: T.IsSqlType a => Column (T.SqlArray a)
emptyArray :: Column (SqlArray a)
emptyArray = (Column a -> Field a) -> [Column a] -> Field (SqlArray a)
forall b a.
IsSqlType b =>
(a -> Field b) -> [a] -> Field (SqlArray b)
T.sqlArray Column a -> Field a
forall a. a -> a
id []

-- | Append two 'T.SqlArray's
arrayAppend :: F.Field (T.SqlArray a) -> F.Field (T.SqlArray a) -> F.Field (T.SqlArray a)
arrayAppend :: Field (SqlArray a) -> Field (SqlArray a) -> Field (SqlArray a)
arrayAppend = BinOp
-> Column (SqlArray a)
-> Column (SqlArray a)
-> Column (SqlArray a)
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:||)

-- | Prepend an element to a 'T.SqlArray'
arrayPrepend :: Column a -> Column (T.SqlArray a) -> Column (T.SqlArray a)
arrayPrepend :: Column a -> Column (SqlArray a) -> Column (SqlArray a)
arrayPrepend (Column PrimExpr
e) (Column PrimExpr
es) = PrimExpr -> Column (SqlArray a)
forall pgType. PrimExpr -> Column pgType
Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"array_prepend" [PrimExpr
e, PrimExpr
es])

-- | Remove all instances of an element from a 'T.SqlArray'
arrayRemove :: Column a -> Column (T.SqlArray a) -> Column (T.SqlArray a)
arrayRemove :: Column a -> Column (SqlArray a) -> Column (SqlArray a)
arrayRemove (Column PrimExpr
e) (Column PrimExpr
es) = PrimExpr -> Column (SqlArray a)
forall pgType. PrimExpr -> Column pgType
Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"array_remove" [PrimExpr
es, PrimExpr
e])

-- | Remove all 'NULL' values from a 'T.SqlArray'
arrayRemoveNulls :: Column (T.SqlArray (C.Nullable a)) -> Column (T.SqlArray a)
arrayRemoveNulls :: Column (SqlArray (Nullable a)) -> Column (SqlArray a)
arrayRemoveNulls = Column (SqlArray (Nullable a)) -> Column (SqlArray a)
forall a b. Column a -> Column b
Column.unsafeCoerceColumn (Column (SqlArray (Nullable a)) -> Column (SqlArray a))
-> (Column (SqlArray (Nullable a))
    -> Column (SqlArray (Nullable a)))
-> Column (SqlArray (Nullable a))
-> Column (SqlArray a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Column (Nullable a)
-> Column (SqlArray (Nullable a)) -> Column (SqlArray (Nullable a))
forall a. Column a -> Column (SqlArray a) -> Column (SqlArray a)
arrayRemove Column (Nullable a)
forall a. Column (Nullable a)
Column.null

singletonArray :: T.IsSqlType a => Column a -> Column (T.SqlArray a)
singletonArray :: Column a -> Column (SqlArray a)
singletonArray Column a
x = Column a -> Column (SqlArray a) -> Column (SqlArray a)
forall a. Column a -> Column (SqlArray a) -> Column (SqlArray a)
arrayPrepend Column a
x Column (SqlArray a)
forall a. IsSqlType a => Column (SqlArray a)
emptyArray

index :: (C.SqlIntegral n) => Column (T.SqlArray a) -> Column n -> Column (C.Nullable a)
index :: Column (SqlArray a) -> Column n -> Column (Nullable a)
index (Column PrimExpr
a) (Column PrimExpr
b) = PrimExpr -> Column (Nullable a)
forall pgType. PrimExpr -> Column pgType
Column (PrimExpr -> PrimExpr -> PrimExpr
HPQ.ArrayIndex PrimExpr
a PrimExpr
b)

-- | Postgres's @array_position@
arrayPosition :: F.Field (T.SqlArray a) -- ^ Haystack
              -> F.Field a -- ^ Needle
              -> F.Field (Column.Nullable T.SqlInt4)
arrayPosition :: Field (SqlArray a) -> Field a -> Field (Nullable SqlInt4)
arrayPosition (Column fs) (Column f') =
  PrimExpr -> Column (Nullable SqlInt4)
forall pgType. PrimExpr -> Column pgType
C.Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"array_position" [PrimExpr
fs , PrimExpr
f'])

-- | Whether the element (needle) exists in the array (haystack).
-- N.B. this is implemented hackily using @array_position@.  If you
-- need it to be implemented using @= any@ then please open an issue.
sqlElem :: F.Field a -- ^ Needle
        -> F.Field (T.SqlArray a) -- ^ Haystack
        -> F.Field T.SqlBool
sqlElem :: Field a -> Field (SqlArray a) -> Field SqlBool
sqlElem Field a
f Field (SqlArray a)
fs = (Column SqlBool -> Column SqlBool
Field SqlBool -> Field SqlBool
O.not (Column SqlBool -> Column SqlBool)
-> (Column a -> Column SqlBool) -> Column a -> Column SqlBool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Column (Nullable SqlInt4) -> Column SqlBool
forall a. FieldNullable a -> Field SqlBool
F.isNull (Column (Nullable SqlInt4) -> Column SqlBool)
-> (Column a -> Column (Nullable SqlInt4))
-> Column a
-> Column SqlBool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field (SqlArray a) -> Field a -> Field (Nullable SqlInt4)
forall a. Field (SqlArray a) -> Field a -> Field (Nullable SqlInt4)
arrayPosition Field (SqlArray a)
fs) Column a
Field a
f

overlap :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool
overlap :: Column (SqlRange a) -> Column (SqlRange a) -> Field SqlBool
overlap = BinOp
-> Column (SqlRange a) -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:&&)

liesWithin :: T.IsRangeType a => Column a -> Column (T.SqlRange a) -> F.Field T.SqlBool
liesWithin :: Column a -> Column (SqlRange a) -> Field SqlBool
liesWithin = BinOp -> Column a -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:<@)

-- | Access the upper bound of a range. For discrete range types it is the exclusive bound.
upperBound :: T.IsRangeType a => Column (T.SqlRange a) -> Column (C.Nullable a)
upperBound :: Column (SqlRange a) -> Column (Nullable a)
upperBound (Column PrimExpr
range) = PrimExpr -> Column (Nullable a)
forall pgType. PrimExpr -> Column pgType
Column (PrimExpr -> Column (Nullable a))
-> PrimExpr -> Column (Nullable a)
forall a b. (a -> b) -> a -> b
$ Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"upper" [PrimExpr
range]

-- | Access the lower bound of a range. For discrete range types it is the inclusive bound.
lowerBound :: T.IsRangeType a => Column (T.SqlRange a) -> Column (C.Nullable a)
lowerBound :: Column (SqlRange a) -> Column (Nullable a)
lowerBound (Column PrimExpr
range) = PrimExpr -> Column (Nullable a)
forall pgType. PrimExpr -> Column pgType
Column (PrimExpr -> Column (Nullable a))
-> PrimExpr -> Column (Nullable a)
forall a b. (a -> b) -> a -> b
$ Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"lower" [PrimExpr
range]

infix 4 .<<
(.<<) :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool
.<< :: Column (SqlRange a) -> Column (SqlRange a) -> Field SqlBool
(.<<) = BinOp
-> Column (SqlRange a) -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:<<)

infix 4 .>>
(.>>) :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool
.>> :: Column (SqlRange a) -> Column (SqlRange a) -> Field SqlBool
(.>>) = BinOp
-> Column (SqlRange a) -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:>>)

infix 4 .&<
(.&<) :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool
.&< :: Column (SqlRange a) -> Column (SqlRange a) -> Field SqlBool
(.&<) = BinOp
-> Column (SqlRange a) -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:&<)

infix 4 .&>
(.&>) :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool
.&> :: Column (SqlRange a) -> Column (SqlRange a) -> Field SqlBool
(.&>) = BinOp
-> Column (SqlRange a) -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:&>)

infix 4 .-|-
(.-|-) :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool
.-|- :: Column (SqlRange a) -> Column (SqlRange a) -> Field SqlBool
(.-|-) = BinOp
-> Column (SqlRange a) -> Column (SqlRange a) -> Column SqlBool
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
(HPQ.:-|-)

timestamptzAtTimeZone :: F.Field T.SqlTimestamptz
                      -> F.Field T.SqlText
                      -> F.Field T.SqlTimestamp
timestamptzAtTimeZone :: Field SqlTimestamptz -> Field SqlText -> Field SqlTimestamp
timestamptzAtTimeZone = BinOp
-> Column SqlTimestamptz -> Column SqlText -> Column SqlTimestamp
forall a b c. BinOp -> Column a -> Column b -> Column c
C.binOp BinOp
HPQ.OpAtTimeZone

dateOfTimestamp :: F.Field T.SqlTimestamp -> F.Field T.SqlDate
dateOfTimestamp :: Field SqlTimestamp -> Field SqlDate
dateOfTimestamp (Column e) = PrimExpr -> Column SqlDate
forall pgType. PrimExpr -> Column pgType
Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"date" [PrimExpr
e])

{-# DEPRECATED exists "Identical to 'restrictExists'.  Will be removed in version 0.8." #-}
exists :: QueryArr a b -> QueryArr a ()
exists :: QueryArr a b -> QueryArr a ()
exists = QueryArr a b -> QueryArr a ()
forall a b. SelectArr a b -> SelectArr a ()
restrictExists

{-# DEPRECATED notExists "Identical to 'restrictNotExists'.  Will be removed in version 0.8." #-}
notExists :: QueryArr a b -> QueryArr a ()
notExists :: QueryArr a b -> QueryArr a ()
notExists = QueryArr a b -> QueryArr a ()
forall a b. SelectArr a b -> SelectArr a ()
restrictNotExists

{-# DEPRECATED inQuery "Identical to 'inSelect'.  Will be removed in version 0.8." #-}
inQuery :: D.Default O.EqPP fields fields
        => fields -> Query fields -> S.Select (F.Field T.SqlBool)
inQuery :: fields -> Query fields -> Select (Field SqlBool)
inQuery = fields -> Query fields -> Select (Field SqlBool)
forall fields.
Default EqPP fields fields =>
fields -> Select fields -> Select (Field SqlBool)
inSelect

{-| This function is probably not useful and is likely to be deprecated
  in the future.

Keep only the rows of a query satisfying a given condition, using
an SQL @WHERE@ clause.

You would typically use 'keepWhen' if you want to write
your query using a "point free" style.  If you want to use 'A.Arrow'
notation then 'restrict' will suit you better.

This is the 'S.SelectArr' equivalent of 'Prelude.filter' from the
'Prelude'.
-}
keepWhen :: (a -> F.Field T.SqlBool) -> S.SelectArr a a
keepWhen :: (a -> Field SqlBool) -> SelectArr a a
keepWhen a -> Field SqlBool
p = proc a
a -> do
  SelectArr (Column SqlBool) ()
SelectArr (Field SqlBool) ()
restrict  -< a -> Field SqlBool
p a
a
  SelectArr a a
forall (a :: * -> * -> *) b. Arrow a => a b b
A.returnA -< a
a

-- | Current date and time (start of current transaction)
now :: F.Field T.SqlTimestamptz
now :: Field SqlTimestamptz
now = PrimExpr -> Column SqlTimestamptz
forall pgType. PrimExpr -> Column pgType
Column (PrimExpr -> Column SqlTimestamptz)
-> PrimExpr -> Column SqlTimestamptz
forall a b. (a -> b) -> a -> b
$ Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"now" []