{-# LANGUAGE GeneralizedNewtypeDeriving #-}

{- |
Copyright : Flipstone Technology Partners 2023
License   : MIT
Stability : Stable

@since 1.0.0.0
-}
module Orville.PostgreSQL.Expr.Time
  ( now
  , makeInterval
  , IntervalArgument
  , years
  , months
  , weeks
  , days
  , hours
  , minutes
  , seconds
  )
where

import Orville.PostgreSQL.Expr.Name (functionName)
import Orville.PostgreSQL.Expr.ValueExpression (ParameterName, ValueExpression, functionCall, functionCallNamedParams)
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql

{- |
  The value of the current time as returned by the PostgreSQL function @now()@.

  @since 1.0.0.0
-}
now :: ValueExpression
now :: ValueExpression
now = FunctionName -> [ValueExpression] -> ValueExpression
functionCall (String -> FunctionName
functionName String
"now") []

{- |
  Constructs a 'ValueExpression' whose value in PostgreSQL is the result of
  calling @make_interval@ with the specified time intervals passed as named
  arguments.

  @since 1.0.0.0
-}
makeInterval :: [(IntervalArgument, ValueExpression)] -> ValueExpression
makeInterval :: [(IntervalArgument, ValueExpression)] -> ValueExpression
makeInterval [(IntervalArgument, ValueExpression)]
args =
  FunctionName
-> [(ParameterName, ValueExpression)] -> ValueExpression
functionCallNamedParams
    (String -> FunctionName
functionName String
"make_interval")
    (((IntervalArgument, ValueExpression)
 -> (ParameterName, ValueExpression))
-> [(IntervalArgument, ValueExpression)]
-> [(ParameterName, ValueExpression)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(IntervalArgument ParameterName
paramName, ValueExpression
value) -> (ParameterName
paramName, ValueExpression
value)) [(IntervalArgument, ValueExpression)]
args)

{- |
Type to represent the name of a time interval argument to the PostgreSQL
@make_interval@ function. E.G.

> years

'IntervalArgument' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype IntervalArgument
  = IntervalArgument ParameterName
  deriving (RawSql -> IntervalArgument
IntervalArgument -> RawSql
(IntervalArgument -> RawSql)
-> (RawSql -> IntervalArgument) -> SqlExpression IntervalArgument
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: IntervalArgument -> RawSql
toRawSql :: IntervalArgument -> RawSql
$cunsafeFromRawSql :: RawSql -> IntervalArgument
unsafeFromRawSql :: RawSql -> IntervalArgument
RawSql.SqlExpression)

{- |
  Constructs an arbitrary 'IntervalArgument' with whatever name you specify. It
  is up to you to ensure that name a valid argument name for @make_interval@.

  @since 1.0.0.0
-}
unsafeIntervalArg :: String -> IntervalArgument
unsafeIntervalArg :: String -> IntervalArgument
unsafeIntervalArg =
  ParameterName -> IntervalArgument
IntervalArgument (ParameterName -> IntervalArgument)
-> (String -> ParameterName) -> String -> IntervalArgument
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ParameterName
forall a. SqlExpression a => String -> a
RawSql.unsafeSqlExpression

{- |
  The @years@ argument to @make_interval@.

  @since 1.0.0.0
-}
years :: IntervalArgument
years :: IntervalArgument
years = String -> IntervalArgument
unsafeIntervalArg String
"years"

{- |
  The @months@ argument to @make_interval@.

  @since 1.0.0.0
-}
months :: IntervalArgument
months :: IntervalArgument
months = String -> IntervalArgument
unsafeIntervalArg String
"months"

{- |
  The @weeks@ argument to @make_interval@.

  @since 1.0.0.0
-}
weeks :: IntervalArgument
weeks :: IntervalArgument
weeks = String -> IntervalArgument
unsafeIntervalArg String
"weeks"

{- |
  The @days@ argument to @make_interval@.

  @since 1.0.0.0
-}
days :: IntervalArgument
days :: IntervalArgument
days = String -> IntervalArgument
unsafeIntervalArg String
"days"

{- |
  The @hours@ argument to @make_interval@.

  @since 1.0.0.0
-}
hours :: IntervalArgument
hours :: IntervalArgument
hours = String -> IntervalArgument
unsafeIntervalArg String
"hours"

{- |
  The @mins@ argument to @make_interval@.

  @since 1.0.0.0
-}
minutes :: IntervalArgument
minutes :: IntervalArgument
minutes = String -> IntervalArgument
unsafeIntervalArg String
"mins"

{- |
  The @secs@ argument to @make_interval@.

  @since 1.0.0.0
-}
seconds :: IntervalArgument
seconds :: IntervalArgument
seconds = String -> IntervalArgument
unsafeIntervalArg String
"secs"