{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module DataFrame.Operators where

import Data.Function ((&))
import qualified Data.Text as T
import DataFrame.Internal.Column (Columnable)
import DataFrame.Internal.Expression (
    BinUDF (MkBinaryOp),
    BinaryOp (
        binaryCommutative,
        binaryFn,
        binaryName,
        binaryPrecedence,
        binarySymbol
    ),
    Expr (Binary, Col, If, Lit, Unary),
    NamedExpr,
    UExpr (UExpr),
    UnUDF (MkUnaryOp),
 )
import DataFrame.Internal.Nullable (
    BaseType,
    DivWidenOp,
    NullCmpResult,
    NullLift2Op (applyNull2),
    NullableCmpOp (nullCmpOp),
    NumericWidenOp,
    WidenResult,
    WidenResultDiv,
    divArithOp,
    widenArithOp,
    widenCmpOp,
 )
import DataFrame.Internal.Types (Promote, PromoteDiv)

infixr 8 .^^, .^^., .^, .^.
infixl 7 .*, ./, .*., ./.
infixl 6 .+, .-, .+., .-.
infix 4 .==, .==., .<, .<., .<=, .<=., .>=, .>=., .>, .>., ./=, ./=.
infixr 3 .&&, .&&.
infixr 2 .||, .||.
infixr 0 .=

(|>) :: a -> (a -> b) -> b
|> :: forall a b. a -> (a -> b) -> b
(|>) = a -> (a -> b) -> b
forall a b. a -> (a -> b) -> b
(&)

as :: (Columnable a) => Expr a -> T.Text -> NamedExpr
as :: forall a. Columnable a => Expr a -> Text -> NamedExpr
as Expr a
expr Text
colName = (Text
colName, Expr a -> UExpr
forall a. Columnable a => Expr a -> UExpr
UExpr Expr a
expr)

name :: (Show a) => Expr a -> T.Text
name :: forall a. Show a => Expr a -> Text
name (Col Text
n) = Text
n
name Expr a
other =
    [Char] -> Text
forall a. HasCallStack => [Char] -> a
error ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$
        [Char]
"You must call `name` on a column reference. Not the expression: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Expr a -> [Char]
forall a. Show a => a -> [Char]
show Expr a
other

col :: (Columnable a) => T.Text -> Expr a
col :: forall a. Columnable a => Text -> Expr a
col = Text -> Expr a
forall a. Columnable a => Text -> Expr a
Col

ifThenElse :: (Columnable a) => Expr Bool -> Expr a -> Expr a -> Expr a
ifThenElse :: forall a. Columnable a => Expr Bool -> Expr a -> Expr a -> Expr a
ifThenElse = Expr Bool -> Expr a -> Expr a -> Expr a
forall a. Columnable a => Expr Bool -> Expr a -> Expr a -> Expr a
If

lit :: (Columnable a) => a -> Expr a
lit :: forall a. Columnable a => a -> Expr a
lit = a -> Expr a
forall a. Columnable a => a -> Expr a
Lit

(.=) :: (Columnable a) => T.Text -> Expr a -> NamedExpr
.= :: forall a. Columnable a => Text -> Expr a -> NamedExpr
(.=) = (Expr a -> Text -> NamedExpr) -> Text -> Expr a -> NamedExpr
forall a b c. (a -> b -> c) -> b -> a -> c
flip Expr a -> Text -> NamedExpr
forall a. Columnable a => Expr a -> Text -> NamedExpr
as

liftDecorated ::
    (Columnable a, Columnable b) =>
    (a -> b) -> T.Text -> Maybe T.Text -> Expr a -> Expr b
liftDecorated :: forall a b.
(Columnable a, Columnable b) =>
(a -> b) -> Text -> Maybe Text -> Expr a -> Expr b
liftDecorated a -> b
f Text
opName Maybe Text
rep = UnUDF a b -> Expr a -> Expr b
forall (op :: * -> * -> *) a b.
(UnaryOp op, Columnable a, Columnable b) =>
op b a -> Expr b -> Expr a
Unary ((a -> b) -> Text -> Maybe Text -> UnUDF a b
forall a b. (a -> b) -> Text -> Maybe Text -> UnUDF a b
MkUnaryOp a -> b
f Text
opName Maybe Text
rep)

lift2Decorated ::
    (Columnable c, Columnable b, Columnable a) =>
    (c -> b -> a) ->
    T.Text ->
    Maybe T.Text ->
    Bool ->
    Int ->
    Expr c ->
    Expr b ->
    Expr a
lift2Decorated :: forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated c -> b -> a
f Text
opName Maybe Text
rep Bool
comm Int
prec =
    BinUDF c b a -> Expr c -> Expr b -> Expr a
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary ((c -> b -> a) -> Text -> Maybe Text -> Bool -> Int -> BinUDF c b a
forall a b c.
(a -> b -> c) -> Text -> Maybe Text -> Bool -> Int -> BinUDF a b c
MkBinaryOp c -> b -> a
f Text
opName Maybe Text
rep Bool
comm Int
prec)

data NullEq a b c where
    NullEq ::
        ( NumericWidenOp (BaseType a) (BaseType b)
        , NullLift2Op a b Bool (NullCmpResult a b)
        , Eq (Promote (BaseType a) (BaseType b))
        ) =>
        NullEq a b (NullCmpResult a b)

data NullNeq a b c where
    NullNeq ::
        ( NumericWidenOp (BaseType a) (BaseType b)
        , NullLift2Op a b Bool (NullCmpResult a b)
        , Eq (Promote (BaseType a) (BaseType b))
        ) =>
        NullNeq a b (NullCmpResult a b)

data NullLt a b c where
    NullLt ::
        ( NumericWidenOp (BaseType a) (BaseType b)
        , NullLift2Op a b Bool (NullCmpResult a b)
        , Ord (Promote (BaseType a) (BaseType b))
        ) =>
        NullLt a b (NullCmpResult a b)

data NullGt a b c where
    NullGt ::
        ( NumericWidenOp (BaseType a) (BaseType b)
        , NullLift2Op a b Bool (NullCmpResult a b)
        , Ord (Promote (BaseType a) (BaseType b))
        ) =>
        NullGt a b (NullCmpResult a b)

data NullLeq a b c where
    NullLeq ::
        ( NumericWidenOp (BaseType a) (BaseType b)
        , NullLift2Op a b Bool (NullCmpResult a b)
        , Ord (Promote (BaseType a) (BaseType b))
        ) =>
        NullLeq a b (NullCmpResult a b)

data NullGeq a b c where
    NullGeq ::
        ( NumericWidenOp (BaseType a) (BaseType b)
        , NullLift2Op a b Bool (NullCmpResult a b)
        , Ord (Promote (BaseType a) (BaseType b))
        ) =>
        NullGeq a b (NullCmpResult a b)

data NullAnd a b c where
    NullAnd ::
        (NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
        NullAnd a b (NullCmpResult a b)

data NullOr a b c where
    NullOr ::
        (NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
        NullOr a b (NullCmpResult a b)

instance BinaryOp NullEq where
    binaryFn :: forall a b c. NullEq a b c -> a -> b -> c
binaryFn NullEq a b c
NullEq = (BaseType a -> BaseType b -> Bool) -> a -> b -> c
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b) -> Bool)
-> BaseType a -> BaseType b -> Bool
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Bool) -> a -> b -> Bool
widenCmpOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b) -> Bool
forall a. Eq a => a -> a -> Bool
(==))
    binaryName :: forall a b c. NullEq a b c -> Text
binaryName NullEq a b c
NullEq = Text
"eq"
    binarySymbol :: forall a b c. NullEq a b c -> Maybe Text
binarySymbol NullEq a b c
NullEq = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".=="
    binaryCommutative :: forall a b c. NullEq a b c -> Bool
binaryCommutative NullEq a b c
NullEq = Bool
True
    binaryPrecedence :: forall a b c. NullEq a b c -> Int
binaryPrecedence NullEq a b c
NullEq = Int
4
instance BinaryOp NullNeq where
    binaryFn :: forall a b c. NullNeq a b c -> a -> b -> c
binaryFn NullNeq a b c
NullNeq = (BaseType a -> BaseType b -> Bool) -> a -> b -> c
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b) -> Bool)
-> BaseType a -> BaseType b -> Bool
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Bool) -> a -> b -> Bool
widenCmpOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b) -> Bool
forall a. Eq a => a -> a -> Bool
(/=))
    binaryName :: forall a b c. NullNeq a b c -> Text
binaryName NullNeq a b c
NullNeq = Text
"neq"
    binarySymbol :: forall a b c. NullNeq a b c -> Maybe Text
binarySymbol NullNeq a b c
NullNeq = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"./="
    binaryCommutative :: forall a b c. NullNeq a b c -> Bool
binaryCommutative NullNeq a b c
NullNeq = Bool
True
    binaryPrecedence :: forall a b c. NullNeq a b c -> Int
binaryPrecedence NullNeq a b c
NullNeq = Int
4
instance BinaryOp NullLt where
    binaryFn :: forall a b c. NullLt a b c -> a -> b -> c
binaryFn NullLt a b c
NullLt = (BaseType a -> BaseType b -> Bool) -> a -> b -> c
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b) -> Bool)
-> BaseType a -> BaseType b -> Bool
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Bool) -> a -> b -> Bool
widenCmpOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b) -> Bool
forall a. Ord a => a -> a -> Bool
(<))
    binaryName :: forall a b c. NullLt a b c -> Text
binaryName NullLt a b c
NullLt = Text
"lt"
    binarySymbol :: forall a b c. NullLt a b c -> Maybe Text
binarySymbol NullLt a b c
NullLt = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".<"
    binaryPrecedence :: forall a b c. NullLt a b c -> Int
binaryPrecedence NullLt a b c
NullLt = Int
4
instance BinaryOp NullGt where
    binaryFn :: forall a b c. NullGt a b c -> a -> b -> c
binaryFn NullGt a b c
NullGt = (BaseType a -> BaseType b -> Bool) -> a -> b -> c
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b) -> Bool)
-> BaseType a -> BaseType b -> Bool
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Bool) -> a -> b -> Bool
widenCmpOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b) -> Bool
forall a. Ord a => a -> a -> Bool
(>))
    binaryName :: forall a b c. NullGt a b c -> Text
binaryName NullGt a b c
NullGt = Text
"gt"
    binarySymbol :: forall a b c. NullGt a b c -> Maybe Text
binarySymbol NullGt a b c
NullGt = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".>"
    binaryPrecedence :: forall a b c. NullGt a b c -> Int
binaryPrecedence NullGt a b c
NullGt = Int
4
instance BinaryOp NullLeq where
    binaryFn :: forall a b c. NullLeq a b c -> a -> b -> c
binaryFn NullLeq a b c
NullLeq = (BaseType a -> BaseType b -> Bool) -> a -> b -> c
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b) -> Bool)
-> BaseType a -> BaseType b -> Bool
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Bool) -> a -> b -> Bool
widenCmpOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b) -> Bool
forall a. Ord a => a -> a -> Bool
(<=))
    binaryName :: forall a b c. NullLeq a b c -> Text
binaryName NullLeq a b c
NullLeq = Text
"leq"
    binarySymbol :: forall a b c. NullLeq a b c -> Maybe Text
binarySymbol NullLeq a b c
NullLeq = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".<="
    binaryPrecedence :: forall a b c. NullLeq a b c -> Int
binaryPrecedence NullLeq a b c
NullLeq = Int
4
instance BinaryOp NullGeq where
    binaryFn :: forall a b c. NullGeq a b c -> a -> b -> c
binaryFn NullGeq a b c
NullGeq = (BaseType a -> BaseType b -> Bool) -> a -> b -> c
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b) -> Bool)
-> BaseType a -> BaseType b -> Bool
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Bool) -> a -> b -> Bool
widenCmpOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b) -> Bool
forall a. Ord a => a -> a -> Bool
(>=))
    binaryName :: forall a b c. NullGeq a b c -> Text
binaryName NullGeq a b c
NullGeq = Text
"geq"
    binarySymbol :: forall a b c. NullGeq a b c -> Maybe Text
binarySymbol NullGeq a b c
NullGeq = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".>="
    binaryPrecedence :: forall a b c. NullGeq a b c -> Int
binaryPrecedence NullGeq a b c
NullGeq = Int
4
instance BinaryOp NullAnd where
    binaryFn :: forall a b c. NullAnd a b c -> a -> b -> c
binaryFn NullAnd a b c
NullAnd = (BaseType a -> BaseType a -> Bool) -> a -> b -> c
forall a b e.
NullableCmpOp a b e =>
(BaseType a -> BaseType a -> Bool) -> a -> b -> e
nullCmpOp Bool -> Bool -> Bool
BaseType a -> BaseType a -> Bool
(&&)
    binaryName :: forall a b c. NullAnd a b c -> Text
binaryName NullAnd a b c
NullAnd = Text
"nulland"
    binarySymbol :: forall a b c. NullAnd a b c -> Maybe Text
binarySymbol NullAnd a b c
NullAnd = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".&&"
    binaryCommutative :: forall a b c. NullAnd a b c -> Bool
binaryCommutative NullAnd a b c
NullAnd = Bool
True
    binaryPrecedence :: forall a b c. NullAnd a b c -> Int
binaryPrecedence NullAnd a b c
NullAnd = Int
3
instance BinaryOp NullOr where
    binaryFn :: forall a b c. NullOr a b c -> a -> b -> c
binaryFn NullOr a b c
NullOr = (BaseType a -> BaseType a -> Bool) -> a -> b -> c
forall a b e.
NullableCmpOp a b e =>
(BaseType a -> BaseType a -> Bool) -> a -> b -> e
nullCmpOp Bool -> Bool -> Bool
BaseType a -> BaseType a -> Bool
(||)
    binaryName :: forall a b c. NullOr a b c -> Text
binaryName NullOr a b c
NullOr = Text
"nullor"
    binarySymbol :: forall a b c. NullOr a b c -> Maybe Text
binarySymbol NullOr a b c
NullOr = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".||"
    binaryCommutative :: forall a b c. NullOr a b c -> Bool
binaryCommutative NullOr a b c
NullOr = Bool
True
    binaryPrecedence :: forall a b c. NullOr a b c -> Int
binaryPrecedence NullOr a b c
NullOr = Int
2

(.==.) ::
    (Columnable a, Eq a) =>
    Expr a ->
    Expr a ->
    Expr Bool
.==. :: forall a. (Columnable a, Eq a) => Expr a -> Expr a -> Expr Bool
(.==.) = (a -> a -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr a
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==) Text
"eq" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".==.") Bool
True Int
4

(./=.) ::
    (Columnable a, Eq a) =>
    Expr a ->
    Expr a ->
    Expr Bool
./=. :: forall a. (Columnable a, Eq a) => Expr a -> Expr a -> Expr Bool
(./=.) = (a -> a -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr a
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(/=) Text
"neq" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"./=.") Bool
True Int
4

(.<.) ::
    (Columnable a, Ord a) =>
    Expr a ->
    Expr a ->
    Expr Bool
.<. :: forall a. (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool
(.<.) = (a -> a -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr a
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<) Text
"lt" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".<.") Bool
False Int
4

(.>.) ::
    (Columnable a, Ord a) =>
    Expr a ->
    Expr a ->
    Expr Bool
.>. :: forall a. (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool
(.>.) = (a -> a -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr a
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(>) Text
"gt" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".>.") Bool
False Int
4

(.<=.) ::
    (Columnable a, Ord a) =>
    Expr a ->
    Expr a ->
    Expr Bool
.<=. :: forall a. (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool
(.<=.) = (a -> a -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr a
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<=) Text
"leq" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".<=.") Bool
False Int
4

(.>=.) ::
    (Columnable a, Ord a) =>
    Expr a ->
    Expr a ->
    Expr Bool
.>=. :: forall a. (Columnable a, Ord a) => Expr a -> Expr a -> Expr Bool
(.>=.) = (a -> a -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr a
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(>=) Text
"geq" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".>=.") Bool
False Int
4

(.+.) :: (Columnable a, Num a) => Expr a -> Expr a -> Expr a
.+. :: forall a. (Columnable a, Num a) => Expr a -> Expr a -> Expr a
(.+.) = Expr a -> Expr a -> Expr a
forall a. Num a => a -> a -> a
(+)

(.-.) :: (Columnable a, Num a) => Expr a -> Expr a -> Expr a
.-. :: forall a. (Columnable a, Num a) => Expr a -> Expr a -> Expr a
(.-.) = (-)

(.*.) :: (Columnable a, Num a) => Expr a -> Expr a -> Expr a
.*. :: forall a. (Columnable a, Num a) => Expr a -> Expr a -> Expr a
(.*.) = Expr a -> Expr a -> Expr a
forall a. Num a => a -> a -> a
(*)

(./.) :: (Columnable a, Fractional a) => Expr a -> Expr a -> Expr a
./. :: forall a.
(Columnable a, Fractional a) =>
Expr a -> Expr a -> Expr a
(./.) = Expr a -> Expr a -> Expr a
forall a. Fractional a => a -> a -> a
(/)

-- Nullable-aware arithmetic operators

{- | Nullable-aware addition. Works for all combinations of nullable\/non-nullable operands.
@col \@Int "x" .+ col \@(Maybe Int) "y"  -- :: Expr (Maybe Int)@
-}
(.+) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b (Promote (BaseType a) (BaseType b)) (WidenResult a b)
    , Num (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (WidenResult a b)
.+ :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op
   a b (Promote (BaseType a) (BaseType b)) (WidenResult a b),
 Num (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (WidenResult a b)
(.+) = (a -> b -> WidenResult a b)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr b
-> Expr (WidenResult a b)
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated ((BaseType a -> BaseType b -> Promote (BaseType a) (BaseType b))
-> a -> b -> WidenResult a b
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b))
-> BaseType a -> BaseType b -> Promote (BaseType a) (BaseType b)
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Promote a b)
-> a -> b -> Promote a b
widenArithOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b)
forall a. Num a => a -> a -> a
(+))) Text
"nulladd" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".+") Bool
True Int
6

-- | Nullable-aware subtraction.
(.-) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b (Promote (BaseType a) (BaseType b)) (WidenResult a b)
    , Num (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (WidenResult a b)
.- :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op
   a b (Promote (BaseType a) (BaseType b)) (WidenResult a b),
 Num (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (WidenResult a b)
(.-) = (a -> b -> WidenResult a b)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr b
-> Expr (WidenResult a b)
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated ((BaseType a -> BaseType b -> Promote (BaseType a) (BaseType b))
-> a -> b -> WidenResult a b
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b))
-> BaseType a -> BaseType b -> Promote (BaseType a) (BaseType b)
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Promote a b)
-> a -> b -> Promote a b
widenArithOp (-))) Text
"nullsub" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".-") Bool
False Int
6

-- | Nullable-aware multiplication.
(.*) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b (Promote (BaseType a) (BaseType b)) (WidenResult a b)
    , Num (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (WidenResult a b)
.* :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op
   a b (Promote (BaseType a) (BaseType b)) (WidenResult a b),
 Num (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (WidenResult a b)
(.*) = (a -> b -> WidenResult a b)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr b
-> Expr (WidenResult a b)
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated ((BaseType a -> BaseType b -> Promote (BaseType a) (BaseType b))
-> a -> b -> WidenResult a b
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b)
 -> Promote (BaseType a) (BaseType b))
-> BaseType a -> BaseType b -> Promote (BaseType a) (BaseType b)
forall a b.
NumericWidenOp a b =>
(Promote a b -> Promote a b -> Promote a b)
-> a -> b -> Promote a b
widenArithOp Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b)
-> Promote (BaseType a) (BaseType b)
forall a. Num a => a -> a -> a
(*))) Text
"nullmul" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".*") Bool
True Int
7

-- | Nullable-aware division. Integral operands are promoted to Double.
(./) ::
    ( DivWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b (PromoteDiv (BaseType a) (BaseType b)) (WidenResultDiv a b)
    , Fractional (PromoteDiv (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (WidenResultDiv a b)
./ :: forall a b.
(DivWidenOp (BaseType a) (BaseType b),
 NullLift2Op
   a b (PromoteDiv (BaseType a) (BaseType b)) (WidenResultDiv a b),
 Fractional (PromoteDiv (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (WidenResultDiv a b)
(./) = (a -> b -> WidenResultDiv a b)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr a
-> Expr b
-> Expr (WidenResultDiv a b)
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated ((BaseType a -> BaseType b -> PromoteDiv (BaseType a) (BaseType b))
-> a -> b -> WidenResultDiv a b
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 ((PromoteDiv (BaseType a) (BaseType b)
 -> PromoteDiv (BaseType a) (BaseType b)
 -> PromoteDiv (BaseType a) (BaseType b))
-> BaseType a -> BaseType b -> PromoteDiv (BaseType a) (BaseType b)
forall a b.
DivWidenOp a b =>
(PromoteDiv a b -> PromoteDiv a b -> PromoteDiv a b)
-> a -> b -> PromoteDiv a b
divArithOp PromoteDiv (BaseType a) (BaseType b)
-> PromoteDiv (BaseType a) (BaseType b)
-> PromoteDiv (BaseType a) (BaseType b)
forall a. Fractional a => a -> a -> a
(/))) Text
"nulldiv" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"./") Bool
False Int
7

-- Nullable-aware comparison operators (three-valued logic: Nothing if either operand is Nothing)

{- | Nullable-aware equality. Widens numeric operands to their common type,
so @Expr Double .== Expr Int@ typechecks. Returns @Maybe Bool@ when either
operand is nullable.
-}
(.==) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b Bool (NullCmpResult a b)
    , Eq (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.== :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Eq (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.==) = NullEq a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullEq a b (NullCmpResult a b)
forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Eq (Promote (BaseType a) (BaseType b))) =>
NullEq a b (NullCmpResult a b)
NullEq

-- | Nullable-aware inequality. Widens numeric operands to their common type.
(./=) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b Bool (NullCmpResult a b)
    , Eq (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
./= :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Eq (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(./=) = NullNeq a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullNeq a b (NullCmpResult a b)
forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Eq (Promote (BaseType a) (BaseType b))) =>
NullNeq a b (NullCmpResult a b)
NullNeq

-- | Nullable-aware less-than. Widens numeric operands to their common type.
(.<) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b Bool (NullCmpResult a b)
    , Ord (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.< :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.<) = NullLt a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullLt a b (NullCmpResult a b)
forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
NullLt a b (NullCmpResult a b)
NullLt

-- | Nullable-aware greater-than. Widens numeric operands to their common type.
(.>) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b Bool (NullCmpResult a b)
    , Ord (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.> :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.>) = NullGt a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullGt a b (NullCmpResult a b)
forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
NullGt a b (NullCmpResult a b)
NullGt

{- | Nullable-aware less-than-or-equal. Widens numeric operands to their
common type, so @Expr Double .<= Expr Int@ typechecks.
-}
(.<=) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b Bool (NullCmpResult a b)
    , Ord (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.<= :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.<=) = NullLeq a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullLeq a b (NullCmpResult a b)
forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
NullLeq a b (NullCmpResult a b)
NullLeq

-- | Nullable-aware greater-than-or-equal. Widens numeric operands to their common type.
(.>=) ::
    ( NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b Bool (NullCmpResult a b)
    , Ord (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.>= :: forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.>=) = NullGeq a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullGeq a b (NullCmpResult a b)
forall a b.
(NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b Bool (NullCmpResult a b),
 Ord (Promote (BaseType a) (BaseType b))) =>
NullGeq a b (NullCmpResult a b)
NullGeq

(.&&.) :: Expr Bool -> Expr Bool -> Expr Bool
.&&. :: Expr Bool -> Expr Bool -> Expr Bool
(.&&.) = (Bool -> Bool -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr Bool
-> Expr Bool
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated Bool -> Bool -> Bool
(&&) Text
"and" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".&&.") Bool
True Int
3

(.||.) :: Expr Bool -> Expr Bool -> Expr Bool
.||. :: Expr Bool -> Expr Bool -> Expr Bool
(.||.) = (Bool -> Bool -> Bool)
-> Text
-> Maybe Text
-> Bool
-> Int
-> Expr Bool
-> Expr Bool
-> Expr Bool
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated Bool -> Bool -> Bool
(||) Text
"or" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".||.") Bool
True Int
2

-- | Nullable-aware logical AND. Returns @Maybe Bool@ when either operand is nullable.
(.&&) ::
    (NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.&& :: forall a b.
(NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.&&) = NullAnd a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullAnd a b (NullCmpResult a b)
forall a b.
(NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
NullAnd a b (NullCmpResult a b)
NullAnd

-- | Nullable-aware logical OR. Returns @Maybe Bool@ when either operand is nullable.
(.||) ::
    (NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
    Expr a ->
    Expr b ->
    Expr (NullCmpResult a b)
.|| :: forall a b.
(NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
Expr a -> Expr b -> Expr (NullCmpResult a b)
(.||) = NullOr a b (NullCmpResult a b)
-> Expr a -> Expr b -> Expr (NullCmpResult a b)
forall (op :: * -> * -> * -> *) c b a.
(BinaryOp op, Columnable c, Columnable b, Columnable a) =>
op c b a -> Expr c -> Expr b -> Expr a
Binary NullOr a b (NullCmpResult a b)
forall a b.
(NullableCmpOp a b (NullCmpResult a b), BaseType a ~ Bool) =>
NullOr a b (NullCmpResult a b)
NullOr

(.^^) ::
    ( Columnable (BaseType a)
    , Columnable (BaseType b)
    , Fractional (BaseType a)
    , Integral (BaseType b)
    , NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b (BaseType a) a
    , Num (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a -> Expr b -> Expr a
.^^ :: forall a b.
(Columnable (BaseType a), Columnable (BaseType b),
 Fractional (BaseType a), Integral (BaseType b),
 NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b (BaseType a) a,
 Num (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr a
(.^^) = (a -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr a -> Expr b -> Expr a
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated ((BaseType a -> BaseType b -> BaseType a) -> a -> b -> a
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 BaseType a -> BaseType b -> BaseType a
forall a b. (Fractional a, Integral b) => a -> b -> a
(^^)) Text
"pow" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".^^") Bool
False Int
8

(.^) ::
    ( Columnable (BaseType a)
    , Columnable (BaseType b)
    , Num (BaseType a)
    , Integral (BaseType b)
    , NumericWidenOp (BaseType a) (BaseType b)
    , NullLift2Op a b (BaseType a) a
    , Num (Promote (BaseType a) (BaseType b))
    ) =>
    Expr a -> Expr b -> Expr a
.^ :: forall a b.
(Columnable (BaseType a), Columnable (BaseType b),
 Num (BaseType a), Integral (BaseType b),
 NumericWidenOp (BaseType a) (BaseType b),
 NullLift2Op a b (BaseType a) a,
 Num (Promote (BaseType a) (BaseType b))) =>
Expr a -> Expr b -> Expr a
(.^) = (a -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr a -> Expr b -> Expr a
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated ((BaseType a -> BaseType b -> BaseType a) -> a -> b -> a
forall a b r c.
NullLift2Op a b r c =>
(BaseType a -> BaseType b -> r) -> a -> b -> c
applyNull2 BaseType a -> BaseType b -> BaseType a
forall a b. (Num a, Integral b) => a -> b -> a
(^)) Text
"pow" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".^") Bool
False Int
8

-- Same-type (non-nullable) exponentiation operators

(.^^.) ::
    (Columnable a, Columnable b, Fractional a, Integral b) =>
    Expr a -> Expr b -> Expr a
.^^. :: forall a b.
(Columnable a, Columnable b, Fractional a, Integral b) =>
Expr a -> Expr b -> Expr a
(.^^.) = (a -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr a -> Expr b -> Expr a
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> b -> a
forall a b. (Fractional a, Integral b) => a -> b -> a
(^^) Text
"pow" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".^^.") Bool
False Int
8

(.^.) ::
    (Columnable a, Columnable b, Num a, Integral b) =>
    Expr a -> Expr b -> Expr a
.^. :: forall a b.
(Columnable a, Columnable b, Num a, Integral b) =>
Expr a -> Expr b -> Expr a
(.^.) = (a -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr a -> Expr b -> Expr a
forall c b a.
(Columnable c, Columnable b, Columnable a) =>
(c -> b -> a)
-> Text -> Maybe Text -> Bool -> Int -> Expr c -> Expr b -> Expr a
lift2Decorated a -> b -> a
forall a b. (Num a, Integral b) => a -> b -> a
(^) Text
"pow" (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
".^.") Bool
False Int
8