orville-postgresql-1.0.0.0: src/Orville/PostgreSQL/Expr/ValueExpression.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{- |
Copyright : Flipstone Technology Partners 2023
License : MIT
Stability : Stable
@since 1.0.0.0
-}
module Orville.PostgreSQL.Expr.ValueExpression
( ValueExpression
, cast
, ParameterName
, columnReference
, valueExpression
, rowValueConstructor
, functionCall
, functionCallNamedParams
)
where
import qualified Data.List.NonEmpty as NE
import Orville.PostgreSQL.Expr.DataType (DataType)
import Orville.PostgreSQL.Expr.Name (ColumnName, FunctionName)
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import Orville.PostgreSQL.Raw.SqlValue (SqlValue)
{- |
Type to represent an arbitrary value in a SQL expression. This could be a
constant value, a column reference or any arbitrary calculated expression.
E.G.
> (foo + bar) > 20
'ValueExpression' 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 ValueExpression = ValueExpression RawSql.RawSql
deriving (RawSql.SqlExpression)
{- |
Performs a SQL type cast to the specified type on the given 'ValueExpression'.
E.G.
> foo :: integer
@since 1.0.0.0
-}
cast :: ValueExpression -> DataType -> ValueExpression
cast value dataType =
ValueExpression $
RawSql.toRawSql value
<> RawSql.fromString "::"
<> RawSql.toRawSql dataType
{- |
Uses a 'ColumnName' to reference a column as a 'ValueExpression'. This
is the equivalent of simply writing the column name as the expression. E.G.
> foo
@since 1.0.0.0
-}
columnReference :: ColumnName -> ValueExpression
columnReference = ValueExpression . RawSql.toRawSql
{- |
Uses the given 'SqlValue' as a constant expression. The value will be passed
as a statement parameter, not as a literal expression, so there is not need
to worry about escaping. However, there are a few places (usually in DDL)
where PostgreSQL does not support values passed as parameters where this
cannot be used.
@since 1.0.0.0
-}
valueExpression :: SqlValue -> ValueExpression
valueExpression = ValueExpression . RawSql.parameter
{- |
Constructs a PostgreSQL row value expression from the given list of
expressions. E.G.
> (foo, bar, now())
@since 1.0.0.0
-}
rowValueConstructor :: NE.NonEmpty ValueExpression -> ValueExpression
rowValueConstructor elements =
ValueExpression $
RawSql.leftParen
<> RawSql.intercalate RawSql.comma elements
<> RawSql.rightParen
{- |
Constructs a 'ValueExpression' that will call the specified PostgreSQL
function with the given arguments passed as position parameters. E.G.
> nextval(sequence_name)
@since 1.0.0.0
-}
functionCall :: FunctionName -> [ValueExpression] -> ValueExpression
functionCall functionName parameters =
ValueExpression $
RawSql.toRawSql functionName
<> RawSql.leftParen
<> RawSql.intercalate RawSql.comma parameters
<> RawSql.rightParen
{- |
Type to represent the name of a name parameter in a PostgreSQL function call.
E.G.
> foo
in
> some_func(foo => 1)
'ParameterName' 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 ParameterName = ParameterName RawSql.RawSql
deriving (RawSql.SqlExpression)
{- |
Constructs a 'ValueExpression' that will call the specified PostgreSQL
function with the given arguments passed as named parameters. E.G.
> make_interval(years => 1)
@since 1.0.0.0
-}
functionCallNamedParams :: FunctionName -> [(ParameterName, ValueExpression)] -> ValueExpression
functionCallNamedParams functionName parameters =
ValueExpression $
RawSql.toRawSql functionName
<> RawSql.leftParen
<> RawSql.intercalate RawSql.comma (fmap (uncurry namedParameterArgument) parameters)
<> RawSql.rightParen
{- |
Constructs a sql fragment that will pass the given named argument with the
specified value.
@since 1.0.0.0
-}
namedParameterArgument :: ParameterName -> ValueExpression -> RawSql.RawSql
namedParameterArgument name value =
RawSql.toRawSql name
<> RawSql.space
<> RawSql.fromString "=>"
<> RawSql.space
<> RawSql.toRawSql value