packages feed

aws-eventbridge-cron 0.1.0.0 → 0.1.0.1

raw patch · 5 files changed

+93/−6 lines, 5 filesPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

API changes (from Hackage documentation)

+ AWS.EventBridge.Cron: CronSchedule :: ScheduleKind
+ AWS.EventBridge.Cron: OneTimeSchedule :: ScheduleKind
+ AWS.EventBridge.Cron: RateSchedule :: ScheduleKind
+ AWS.EventBridge.Cron: data ScheduleKind
+ AWS.EventBridge.Cron: instance GHC.Classes.Eq AWS.EventBridge.Cron.ScheduleKind
+ AWS.EventBridge.Cron: instance GHC.Classes.Ord AWS.EventBridge.Cron.ScheduleKind
+ AWS.EventBridge.Cron: instance GHC.Show.Show AWS.EventBridge.Cron.ScheduleKind
+ AWS.EventBridge.Cron: isRecurring :: CronExprT -> Bool
+ AWS.EventBridge.Cron: scheduleKind :: CronExprT -> ScheduleKind

Files

CHANGELOG.md view
@@ -5,10 +5,14 @@ The format is based on Keep a Changelog and this project adheres to Semantic Versioning. +## [0.1.0.1] - 2025-11-17+### Added+- `ScheduleKind`, `scheduleKind`, and `isRecurring` helpers for classifying parsed schedules without re-parsing downstream.+- QuickCheck properties covering the new helpers to ensure they align with parsed expression variants.+- README documentation demonstrating schedule introspection and clarifying the helper API.+ ## [0.1.0.0] - 2025-11-16 ### Added - Initial `AWS.EventBridge.Cron` module for parsing and scheduling AWS Scheduler cron expressions. - Support for `rate(...)` and `at(...)` expressions with validation, evaluation, and round-trip tests. - Property-based and unit tests across all cron fields plus helper utilities.-- Project metadata, README, LICENSE, and Haddock documentation suitable for Hackage distribution.-- GitHub Actions workflows for CI and release automation, including Hackage candidate/publish steps.
README.md view
@@ -13,6 +13,9 @@   weekday ranges, and nth-weekday modifiers (`2#1`). - `rate(...)` and `at(...)` expressions share the same API, so callers do not   need to branch on expression variants.+- Schedule introspection helpers: `scheduleKind` returns a `ScheduleKind`, and+  `isRecurring` distinguishes recurring (`cron`/`rate`) expressions from+  `at(...)` one-time schedules. - Extensive property-based test suite that mirrors the behaviour documented by   AWS. @@ -58,6 +61,15 @@ atExample = do   expr <- parseCronText "at(2025-11-16T09:30:00)"   nextRunTimes expr base 5++-- Introspect the parsed expression without re-parsing downstream.+kindExample :: Either String ScheduleKind+kindExample = scheduleKind <$> parseCronText "rate(5 minutes)"+-- Right RateSchedule++isRecurringExample :: Either String Bool+isRecurringExample = isRecurring <$> parseCronText "at(2025-11-16T09:30:00)"+-- Right False ```  ### Error Reporting
aws-eventbridge-cron.cabal view
@@ -1,7 +1,7 @@ cabal-version:      3.0  name:               aws-eventbridge-cron-version:            0.1.0.0+version:            0.1.0.1 synopsis:           AWS EventBridge cron, rate, and one-time parser with scheduler description:   Parse AWS EventBridge cron, rate, and one-time expressions and compute
src/AWS/EventBridge/Cron.hs view
@@ -6,6 +6,9 @@ -- support for cron, rate, and one-time ("at") expressions. module AWS.EventBridge.Cron   ( CronExprT+  , ScheduleKind(..)+  , scheduleKind+  , isRecurring   , parseCronText   , nextRunTimes   ) where@@ -29,9 +32,8 @@  -- | EventBridge scheduling expression. ----- Constructors mirror the three families of EventBridge schedules. The structure is--- exposed to allow pattern matching by advanced users, but most callers should rely on--- the parser and evaluator helpers provided by this module.+-- The concrete representation is intentionally opaque; use 'scheduleKind' to detect the+-- backing schedule family and 'nextRunTimes' to evaluate upcoming occurrences. data CronExprT   = CronExpr       { minutes    :: MinutesExprT@@ -44,6 +46,26 @@   | RateExpr RateExprT   | OneTimeExpr OneTimeExprT   deriving (Eq, Show)++-- | Classification of an EventBridge scheduling expression.+data ScheduleKind+  = CronSchedule+  | RateSchedule+  | OneTimeSchedule+  deriving (Eq, Ord, Show)++-- | Determine which family of expression a parsed value belongs to.+scheduleKind :: CronExprT -> ScheduleKind+scheduleKind CronExpr{}    = CronSchedule+scheduleKind RateExpr{}    = RateSchedule+scheduleKind OneTimeExpr{} = OneTimeSchedule++-- | True when the schedule produces multiple occurrences (cron or rate).+isRecurring :: CronExprT -> Bool+isRecurring expr =+  case scheduleKind expr of+    OneTimeSchedule -> False+    _               -> True  type Parser = Parsec Void Text 
test/AWS/EventBridge/CronSpec.hs view
@@ -90,11 +90,60 @@ propertyTests :: TestTree propertyTests = testGroup "properties"   [ QC.testProperty "rate schedule monotonic" propRateMonotonic+  , QC.testProperty "schedule kind round-trips for cron" propScheduleKindCron+  , QC.testProperty "schedule kind round-trips for rate" propScheduleKindRate+  , QC.testProperty "schedule kind identifies one-time" propScheduleKindOneTime+  , QC.testProperty "isRecurring agrees with schedule kind" propIsRecurring   , QC.testProperty "cron returns at most requested" propCronLimit   , QC.testProperty "cron schedule monotonic and >= base" propCronMonotonic   , QC.testProperty "cron with '?' dom relies on day-of-week" propCronDomQuestionUsesDow   , QC.testProperty "cron with '?' dow relies on day-of-month" propCronDowQuestionUsesDom   ]++propScheduleKindCron :: QC.Property+propScheduleKindCron =+  let exprText = "cron(0 0 ? NOV MON 2025)"+  in case parseCronText exprText of+      Left err -> QC.counterexample ("cron parse failed: " <> err) False+      Right expr ->+        QC.counterexample (show (scheduleKind expr)) (scheduleKind expr QC.=== CronSchedule)++propScheduleKindRate :: QC.Property+propScheduleKindRate =+  let exprText = "rate(15 minutes)"+  in case parseCronText exprText of+      Left err -> QC.counterexample ("rate parse failed: " <> err) False+      Right expr ->+        QC.counterexample (show (scheduleKind expr)) (scheduleKind expr QC.=== RateSchedule)++propScheduleKindOneTime :: QC.Property+propScheduleKindOneTime =+  let exprText = "at(2025-11-16T09:30:00)"+  in case parseCronText exprText of+      Left err -> QC.counterexample ("at parse failed: " <> err) False+      Right expr ->+        QC.counterexample (show (scheduleKind expr)) (scheduleKind expr QC.=== OneTimeSchedule)++propIsRecurring :: QC.Property+propIsRecurring =+  QC.conjoin+    [ QC.counterexample "cron should be recurring" cronRecurring+    , QC.counterexample "rate should be recurring" rateRecurring+    , QC.counterexample "one-time should not be recurring" oneTimeNonRecurring+    ]+  where+    cronRecurring =+      case parseCronText "cron(0 12 ? JAN MON 2025)" of+        Right expr -> isRecurring expr+        Left _ -> False+    rateRecurring =+      case parseCronText "rate(1 hour)" of+        Right expr -> isRecurring expr+        Left _ -> False+    oneTimeNonRecurring =+      case parseCronText "at(2025-11-16T09:30:00)" of+        Right expr -> not (isRecurring expr)+        Left _ -> False  propRateMonotonic :: QC.Property propRateMonotonic =