{-# language FlexibleContexts #-}
{-# language TypeFamilies #-}

{-# options_ghc -fno-warn-redundant-constraints #-}

module Rel8.Expr.Num
  ( fromIntegral, realToFrac, div, mod, ceiling, floor, round, truncate
  )
where

-- base
import Prelude ()

-- rel
import Rel8.Expr ( Expr( Expr ) )
import Rel8.Expr.Function ( function )
import Rel8.Expr.Opaleye ( castExpr )
import Rel8.Schema.Null ( Homonullable, Sql )
import Rel8.Type.Num ( DBFractional, DBIntegral, DBNum )


-- | Cast 'DBIntegral' types to 'DBNum' types. For example, this can be useful
-- if you need to turn an @Expr Int32@ into an @Expr Double@.
fromIntegral :: (Sql DBIntegral a, Sql DBNum b, Homonullable a b)
  => Expr a -> Expr b
fromIntegral :: Expr a -> Expr b
fromIntegral (Expr PrimExpr
a) = Expr b -> Expr b
forall a. Sql DBType a => Expr a -> Expr a
castExpr (PrimExpr -> Expr b
forall k (a :: k). (k ~ *) => PrimExpr -> Expr a
Expr PrimExpr
a)


-- | Cast 'DBNum' types to 'DBFractional' types. For example, his can be useful
-- to convert @Expr Float@ to @Expr Double@.
realToFrac :: (Sql DBNum a, Sql DBFractional b, Homonullable a b)
  => Expr a -> Expr b
realToFrac :: Expr a -> Expr b
realToFrac (Expr PrimExpr
a) = Expr b -> Expr b
forall a. Sql DBType a => Expr a -> Expr a
castExpr (PrimExpr -> Expr b
forall k (a :: k). (k ~ *) => PrimExpr -> Expr a
Expr PrimExpr
a)


-- | Round a 'DBFractional' to a 'DBIntegral' by rounding to the nearest larger
-- integer.
--
-- Corresponds to the @ceiling()@ function.
ceiling :: (Sql DBFractional a, Sql DBIntegral b, Homonullable a b)
  => Expr a -> Expr b
ceiling :: Expr a -> Expr b
ceiling = String -> Expr a -> Expr b
forall args result.
Function args result =>
String -> args -> result
function String
"ceiling"


-- | Perform integral division. Corresponds to the @div()@ function.
div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
div :: Expr a -> Expr a -> Expr a
div = String -> Expr a -> Expr a -> Expr a
forall args result.
Function args result =>
String -> args -> result
function String
"div"


-- | Corresponds to the @mod()@ function.
mod :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
mod :: Expr a -> Expr a -> Expr a
mod = String -> Expr a -> Expr a -> Expr a
forall args result.
Function args result =>
String -> args -> result
function String
"mod"


-- | Round a 'DFractional' to a 'DBIntegral' by rounding to the nearest smaller
-- integer. 
--
-- Corresponds to the @floor()@ function.
floor :: (Sql DBFractional a, Sql DBIntegral b, Homonullable a b)
  => Expr a -> Expr b
floor :: Expr a -> Expr b
floor = String -> Expr a -> Expr b
forall args result.
Function args result =>
String -> args -> result
function String
"floor"


-- | Round a 'DBFractional' to a 'DBIntegral' by rounding to the nearest
-- integer.
--
-- Corresponds to the @round()@ function.
round :: (Sql DBFractional a, Sql DBIntegral b, Homonullable a b)
  => Expr a -> Expr b
round :: Expr a -> Expr b
round = String -> Expr a -> Expr b
forall args result.
Function args result =>
String -> args -> result
function String
"round"


-- | Round a 'DBFractional' to a 'DBIntegral' by rounding to the nearest
-- integer towards zero.
truncate :: (Sql DBFractional a, Sql DBIntegral b, Homonullable a b)
  => Expr a -> Expr b
truncate :: Expr a -> Expr b
truncate = String -> Expr a -> Expr b
forall args result.
Function args result =>
String -> args -> result
function String
"trunc"