///|
/// Fluent cron expression builder API.
/// Provides a readable, programmatic way to construct cron expressions.
///|
/// A builder for constructing cron expressions step by step.
pub struct CronBuilder {
mut seconds : String
mut minutes : String
mut hours : String
mut dom : String
mut month : String
mut dow : String
mut include_seconds : Bool
}
///|
/// Create a new CronBuilder with default values (all wildcards).
pub fn CronBuilder::new() -> CronBuilder {
{
seconds: "0",
minutes: "*",
hours: "*",
dom: "*",
month: "*",
dow: "*",
include_seconds: false,
}
}
///|
/// Start building the seconds field.
pub fn CronBuilder::every(self : CronBuilder, n : Int) -> CronFieldBuilder {
CronFieldBuilder::new(self, n.to_string())
}
///|
/// Start building the seconds field with a specific value.
pub fn CronBuilder::at_second(self : CronBuilder, n : Int) -> CronBuilder {
self.seconds = n.to_string()
self.include_seconds = true
self
}
///|
/// Set the seconds field directly.
pub fn CronBuilder::seconds(self : CronBuilder, expr : String) -> CronBuilder {
self.seconds = expr
self.include_seconds = true
self
}
///|
/// Set the minutes field directly.
pub fn CronBuilder::minutes(self : CronBuilder, expr : String) -> CronBuilder {
self.minutes = expr
self
}
///|
/// Set the hours field directly.
pub fn CronBuilder::hours(self : CronBuilder, expr : String) -> CronBuilder {
self.hours = expr
self
}
///|
/// Set the day-of-month field directly.
pub fn CronBuilder::dom(self : CronBuilder, expr : String) -> CronBuilder {
self.dom = expr
self
}
///|
/// Set the month field directly.
pub fn CronBuilder::month(self : CronBuilder, expr : String) -> CronBuilder {
self.month = expr
self
}
///|
/// Set the day-of-week field directly.
pub fn CronBuilder::dow(self : CronBuilder, expr : String) -> CronBuilder {
self.dow = expr
self
}
///|
/// Set every minute.
pub fn CronBuilder::every_minute(self : CronBuilder) -> CronBuilder {
self.minutes = "*"
self
}
///|
/// Set specific minutes (e.g., 0,15,30,45).
pub fn CronBuilder::at_minutes(
self : CronBuilder,
mins : Array[Int],
) -> CronBuilder {
self.minutes = join_ints(mins, ",")
self
}
///|
/// Set minutes to run every N minutes.
pub fn CronBuilder::every_n_minutes(self : CronBuilder, n : Int) -> CronBuilder {
self.minutes = "*/" + n.to_string()
self
}
///|
/// Set specific hours.
pub fn CronBuilder::at_hours(
self : CronBuilder,
hrs : Array[Int],
) -> CronBuilder {
self.hours = join_ints(hrs, ",")
self
}
///|
/// Set a range of hours.
pub fn CronBuilder::between_hours(
self : CronBuilder,
start : Int,
end : Int,
) -> CronBuilder {
self.hours = start.to_string() + "-" + end.to_string()
self
}
///|
/// Set the expression to run on weekdays only (Mon-Fri).
pub fn CronBuilder::on_weekdays(self : CronBuilder) -> CronBuilder {
self.dow = "1-5"
self
}
///|
/// Set the expression to run on weekends only.
pub fn CronBuilder::on_weekends(self : CronBuilder) -> CronBuilder {
self.dow = "0,6"
self
}
///|
/// Set specific days of week.
pub fn CronBuilder::on_days_of_week(
self : CronBuilder,
days : Array[Int],
) -> CronBuilder {
self.dow = join_ints(days, ",")
self
}
///|
/// Set specific days of month.
pub fn CronBuilder::on_days_of_month(
self : CronBuilder,
days : Array[Int],
) -> CronBuilder {
self.dom = join_ints(days, ",")
self
}
///|
/// Set specific months.
pub fn CronBuilder::in_months(
self : CronBuilder,
months : Array[Int],
) -> CronBuilder {
self.month = join_ints(months, ",")
self
}
///|
/// Build the cron expression string.
pub fn CronBuilder::build(self : CronBuilder) -> String {
if self.include_seconds {
self.seconds +
" " +
self.minutes +
" " +
self.hours +
" " +
self.dom +
" " +
self.month +
" " +
self.dow
} else {
self.minutes +
" " +
self.hours +
" " +
self.dom +
" " +
self.month +
" " +
self.dow
}
}
///|
/// Build and parse into a CronExpr.
pub fn CronBuilder::build_expr(
self : CronBuilder,
) -> Result[CronExpr, CronError] {
CronExpr::parse(self.build())
}
///|
/// A field-level builder returned by `every(n)` to chain `.minutes()`, `.hours()`, etc.
pub struct CronFieldBuilder {
builder : CronBuilder
value : String
}
///|
/// Create a field builder.
fn CronFieldBuilder::new(
builder : CronBuilder,
value : String,
) -> CronFieldBuilder {
{ builder, value }
}
///|
/// Apply to the seconds field.
pub fn CronFieldBuilder::seconds(self : CronFieldBuilder) -> CronBuilder {
let b = self.builder
b.seconds = "*/" + self.value
b.include_seconds = true
b
}
///|
/// Apply to the minutes field.
pub fn CronFieldBuilder::minutes(self : CronFieldBuilder) -> CronBuilder {
let b = self.builder
b.minutes = "*/" + self.value
b
}
///|
/// Apply to the hours field.
pub fn CronFieldBuilder::hours(self : CronFieldBuilder) -> CronBuilder {
let b = self.builder
b.hours = "*/" + self.value
b
}
///|
/// Apply to the day-of-month field.
pub fn CronFieldBuilder::days_of_month(self : CronFieldBuilder) -> CronBuilder {
let b = self.builder
b.dom = "*/" + self.value
b
}
///|
/// Apply to the month field.
pub fn CronFieldBuilder::months(self : CronFieldBuilder) -> CronBuilder {
let b = self.builder
b.month = "*/" + self.value
b
}
///|
/// Set range for hours between start and end.
pub fn CronFieldBuilder::between(
self : CronFieldBuilder,
start : Int,
end : Int,
) -> CronRangeBuilder {
CronRangeBuilder::new(self.builder, self.value, start, end)
}
///|
/// A range builder for constructing "between X and Y" clauses.
pub struct CronRangeBuilder {
builder : CronBuilder
step : String
start : Int
end : Int
}
///|
/// Create a range builder.
fn CronRangeBuilder::new(
builder : CronBuilder,
step : String,
start : Int,
end : Int,
) -> CronRangeBuilder {
{ builder, step, start, end }
}
///|
/// Apply range to hours with the step.
pub fn CronRangeBuilder::hours(self : CronRangeBuilder) -> CronBuilder {
let b = self.builder
b.minutes = "*/" + self.step
b.hours = self.start.to_string() + "-" + self.end.to_string()
b
}
///|
/// Join integers into a comma-separated string.
fn join_ints(values : Array[Int], sep : String) -> String {
let mut result = ""
for i = 0; i < values.length(); i = i + 1 {
if i > 0 {
result = result + sep
}
result = result + values[i].to_string()
}
result
}
///|
/// Quick constructors for common patterns.
///|
/// Every N minutes.
pub fn every_n_minutes(n : Int) -> String {
"*/" + n.to_string() + " * * * *"
}
///|
/// Every N hours at minute 0.
pub fn every_n_hours(n : Int) -> String {
"0 */" + n.to_string() + " * * *"
}
///|
/// Daily at a specific time.
pub fn daily_at(hour : Int, minute : Int) -> String {
minute.to_string() + " " + hour.to_string() + " * * *"
}
///|
/// Weekdays at a specific time.
pub fn weekdays_at(hour : Int, minute : Int) -> String {
minute.to_string() + " " + hour.to_string() + " * * 1-5"
}
///|
/// Weekly on a specific day at a specific time.
pub fn weekly_at(day_of_week : Int, hour : Int, minute : Int) -> String {
minute.to_string() +
" " +
hour.to_string() +
" * * " +
day_of_week.to_string()
}
///|
/// Monthly on a specific day at a specific time.
pub fn monthly_at(day : Int, hour : Int, minute : Int) -> String {
minute.to_string() + " " + hour.to_string() + " " + day.to_string() + " * *"
}
///|
/// Yearly on a specific date and time.
pub fn yearly_at(month : Int, day : Int, hour : Int, minute : Int) -> String {
minute.to_string() +
" " +
hour.to_string() +
" " +
day.to_string() +
" " +
month.to_string() +
" *"
}