packages feed

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

module Test.Expr.Window
  ( windowTests
  )
where

import qualified Data.ByteString.Char8 as B8
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 Test.Expr.TestSchema (barColumn)
import qualified Test.Property as Property

windowTests :: Property.Group
windowTests =
  Property.group
    "Expr - Window"
    [ prop_windowClauseSingleDef
    , prop_windowClauseMultiDef
    ]

prop_windowClauseSingleDef :: Property.NamedProperty
prop_windowClauseSingleDef =
  let
    windowDef = Expr.windowDefinition Nothing (Just partitionBy) (Just orderBy) (Just frameClause)
    windowDefName = Expr.fromIdentifier $ Expr.identifier "a"
    partitionBy = Expr.partitionBy (pure . Expr.valueExpression $ SqlValue.fromInt32 1)
    orderBy = Expr.orderByClause $ Expr.orderByColumnName barColumn Expr.ascendingOrder
    frameClause = Expr.frameClause (Just Expr.rowsFrameMode) Expr.unboundedPrecedingFrameStart (Just Expr.unboundedFollowingFrameEnd) (Just Expr.tiesFrameExclusion)
  in
    Property.singletonNamedProperty "window clause with single window definition containing a partition by, an order by, and a frame clause generates expected sql."
      . assertWindowEquals
        "WINDOW \"a\" AS (PARTITION BY $1 ORDER BY \"bar\" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES)"
      . Expr.windowClause
      $ Expr.namedWindowDefinition windowDefName windowDef

prop_windowClauseMultiDef :: Property.NamedProperty
prop_windowClauseMultiDef =
  let
    windowDef1 = Expr.windowDefinition Nothing (Just partitionBy) Nothing Nothing
    windowDef1Name = Expr.fromIdentifier $ Expr.identifier "a"
    windowDef2 = Expr.windowDefinition (Just windowDef1Name) Nothing (Just orderBy) (Just frameClause)
    windowDef2Name = Expr.fromIdentifier $ Expr.identifier "b"
    partitionBy = Expr.partitionBy (pure . Expr.valueExpression $ SqlValue.fromInt32 1)
    orderBy = Expr.orderByClause $ Expr.orderByColumnName barColumn Expr.ascendingOrder
    frameClause = Expr.frameClause (Just Expr.rowsFrameMode) Expr.unboundedPrecedingFrameStart (Just Expr.unboundedFollowingFrameEnd) (Just Expr.tiesFrameExclusion)
  in
    Property.singletonNamedProperty "window clause with two window definitions, where the second \"copies\" the first,  generates expected sql."
      . assertWindowEquals
        "WINDOW \"a\" AS (PARTITION BY $1), \"b\" AS (\"a\" ORDER BY \"bar\" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES)"
      . Expr.windowClause
      $ Expr.namedWindowDefinition windowDef1Name windowDef1 <> Expr.namedWindowDefinition windowDef2Name windowDef2

assertWindowEquals :: (HH.MonadTest m, HasCallStack) => String -> Expr.WindowClause -> m ()
assertWindowEquals windowClauseStr windowClause =
  withFrozenCallStack $
    RawSql.toExampleBytes windowClause HH.=== B8.pack windowClauseStr