packages feed

orville-postgresql-1.1.0.0: test/Test/Expr/ConditionalExpr.hs

module Test.Expr.ConditionalExpr
  ( conditionalTests
  )
where

import qualified Data.ByteString.Char8 as B8
import qualified Data.List.NonEmpty as NE
import GHC.Stack (HasCallStack, withFrozenCallStack)
import qualified Hedgehog as HH

import qualified Orville.PostgreSQL.Expr as Expr
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import qualified Orville.PostgreSQL.Raw.SqlValue as SqlValue

import qualified Test.Property as Property

conditionalTests :: Property.Group
conditionalTests =
  Property.group
    "Expr - Conditional"
    [ prop_caseWithNoElse
    , prop_caseWithElse
    , prop_caseMultipleWhenWithElse
    ]

prop_caseWithNoElse :: Property.NamedProperty
prop_caseWithNoElse =
  let
    whenTrueThen1 =
      Expr.whenExpr (Expr.literalBooleanExpr True) (Expr.valueExpression $ SqlValue.fromInt32 1)
    caseExpr = Expr.caseExpr (pure whenTrueThen1) Nothing
  in
    Property.singletonNamedProperty "caseExpr with a trivial WHEN and no ELSE generates expected sql." $
      assertConditionalEquals
        "CASE WHEN TRUE THEN $1 END"
        caseExpr

prop_caseWithElse :: Property.NamedProperty
prop_caseWithElse =
  let
    firstEqualsSecond =
      Expr.equals (Expr.valueExpression $ SqlValue.fromInt32 1) (Expr.valueExpression $ SqlValue.fromInt32 1)
    whenExpr =
      Expr.whenExpr firstEqualsSecond (Expr.valueExpression $ SqlValue.fromInt32 1)
    caseExpr = Expr.caseExpr (pure whenExpr) (Just . Expr.valueExpression $ SqlValue.fromInt32 1)
  in
    Property.singletonNamedProperty "caseExpr with a simple WHEN and simple ELSE generates expected sql." $
      assertConditionalEquals
        "CASE WHEN ($1) = ($2) THEN $3 ELSE $4 END"
        caseExpr

prop_caseMultipleWhenWithElse :: Property.NamedProperty
prop_caseMultipleWhenWithElse =
  let
    firstVal = Expr.valueExpression $ SqlValue.fromInt32 1
    secondVal = Expr.valueExpression $ SqlValue.fromInt32 1
    firstGreaterSecond =
      Expr.greaterThan firstVal secondVal
    firstLessSecond =
      Expr.lessThan firstVal secondVal
    whenGreaterExpr =
      Expr.whenExpr firstGreaterSecond (Expr.valueExpression $ SqlValue.fromInt32 1)
    whenLessExpr =
      Expr.whenExpr firstLessSecond (Expr.valueExpression $ SqlValue.fromInt32 1)
    caseExpr = Expr.caseExpr (whenGreaterExpr NE.:| [whenLessExpr]) (Just . Expr.valueExpression $ SqlValue.fromInt32 1)
  in
    Property.singletonNamedProperty "caseExpr with a simple WHEN and simple ELSE generates expected sql." $
      assertConditionalEquals
        "CASE WHEN ($1) > ($2) THEN $3 WHEN ($4) < ($5) THEN $6 ELSE $7 END"
        caseExpr

assertConditionalEquals :: (HH.MonadTest m, HasCallStack) => String -> Expr.ValueExpression -> m ()
assertConditionalEquals valueExpressionStr valueExpr =
  withFrozenCallStack $
    RawSql.toExampleBytes valueExpr HH.=== B8.pack valueExpressionStr