use super::expression::{CronExpression, DayOfWeek};
use super::task::{BoxedFuture, BoxedTask, ClosureTask, Task, TaskEntry, TaskResult};
use std::sync::Arc;
pub struct TaskBuilder {
pub(crate) task: BoxedTask,
pub(crate) expression: CronExpression,
pub(crate) name: Option<String>,
pub(crate) description: Option<String>,
pub(crate) without_overlapping: bool,
pub(crate) run_in_background: bool,
}
impl TaskBuilder {
pub fn new<F>(f: F) -> Self
where
F: Fn() -> BoxedFuture<'static> + Send + Sync + 'static,
{
Self {
task: Arc::new(ClosureTask { handler: f }),
expression: CronExpression::every_minute(),
name: None,
description: None,
without_overlapping: false,
run_in_background: false,
}
}
pub fn from_async<F, Fut>(f: F) -> Self
where
F: Fn() -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = TaskResult> + Send + 'static,
{
Self::new(move || Box::pin(f()))
}
pub fn from_task<T: Task + 'static>(task: T) -> Self {
Self {
task: Arc::new(task),
expression: CronExpression::every_minute(),
name: None,
description: None,
without_overlapping: false,
run_in_background: false,
}
}
pub fn cron(mut self, expression: &str) -> Self {
self.expression = CronExpression::parse(expression).expect("Invalid cron expression");
self
}
pub fn try_cron(mut self, expression: &str) -> Result<Self, String> {
self.expression = CronExpression::parse(expression)?;
Ok(self)
}
pub fn every_minute(mut self) -> Self {
self.expression = CronExpression::every_minute();
self
}
pub fn every_two_minutes(mut self) -> Self {
self.expression = CronExpression::every_n_minutes(2);
self
}
pub fn every_five_minutes(mut self) -> Self {
self.expression = CronExpression::every_n_minutes(5);
self
}
pub fn every_ten_minutes(mut self) -> Self {
self.expression = CronExpression::every_n_minutes(10);
self
}
pub fn every_fifteen_minutes(mut self) -> Self {
self.expression = CronExpression::every_n_minutes(15);
self
}
pub fn every_thirty_minutes(mut self) -> Self {
self.expression = CronExpression::every_n_minutes(30);
self
}
pub fn hourly(mut self) -> Self {
self.expression = CronExpression::hourly();
self
}
pub fn hourly_at(mut self, minute: u32) -> Self {
self.expression = CronExpression::hourly_at(minute);
self
}
pub fn every_two_hours(mut self) -> Self {
self.expression = CronExpression::parse("0 */2 * * *").unwrap();
self
}
pub fn every_three_hours(mut self) -> Self {
self.expression = CronExpression::parse("0 */3 * * *").unwrap();
self
}
pub fn every_four_hours(mut self) -> Self {
self.expression = CronExpression::parse("0 */4 * * *").unwrap();
self
}
pub fn every_six_hours(mut self) -> Self {
self.expression = CronExpression::parse("0 */6 * * *").unwrap();
self
}
pub fn daily(mut self) -> Self {
self.expression = CronExpression::daily();
self
}
pub fn daily_at(mut self, time: &str) -> Self {
self.expression = CronExpression::daily_at(time);
self
}
pub fn twice_daily(mut self, first_hour: u32, second_hour: u32) -> Self {
self.expression =
CronExpression::parse(&format!("0 {first_hour},{second_hour} * * *")).unwrap();
self
}
pub fn at(mut self, time: &str) -> Self {
self.expression = self.expression.at(time);
self
}
pub fn weekly(mut self) -> Self {
self.expression = CronExpression::weekly();
self
}
pub fn weekly_on(mut self, day: DayOfWeek) -> Self {
self.expression = CronExpression::weekly_on(day);
self
}
pub fn days(mut self, days: &[DayOfWeek]) -> Self {
self.expression = CronExpression::on_days(days);
self
}
pub fn weekdays(mut self) -> Self {
self.expression = CronExpression::weekdays();
self
}
pub fn weekends(mut self) -> Self {
self.expression = CronExpression::weekends();
self
}
pub fn sundays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Sunday);
self
}
pub fn mondays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Monday);
self
}
pub fn tuesdays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Tuesday);
self
}
pub fn wednesdays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Wednesday);
self
}
pub fn thursdays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Thursday);
self
}
pub fn fridays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Friday);
self
}
pub fn saturdays(mut self) -> Self {
self.expression = CronExpression::weekly_on(DayOfWeek::Saturday);
self
}
pub fn monthly(mut self) -> Self {
self.expression = CronExpression::monthly();
self
}
pub fn monthly_on(mut self, day: u32) -> Self {
self.expression = CronExpression::monthly_on(day);
self
}
pub fn quarterly(mut self) -> Self {
self.expression = CronExpression::quarterly();
self
}
pub fn yearly(mut self) -> Self {
self.expression = CronExpression::yearly();
self
}
pub fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_string());
self
}
pub fn description(mut self, desc: &str) -> Self {
self.description = Some(desc.to_string());
self
}
pub fn without_overlapping(mut self) -> Self {
self.without_overlapping = true;
self
}
pub fn run_in_background(mut self) -> Self {
self.run_in_background = true;
self
}
pub(crate) fn build(self, task_index: usize) -> TaskEntry {
let name = self
.name
.unwrap_or_else(|| format!("closure-task-{task_index}"));
TaskEntry {
name,
expression: self.expression,
task: self.task,
description: self.description,
without_overlapping: self.without_overlapping,
run_in_background: self.run_in_background,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_builder() -> TaskBuilder {
TaskBuilder::from_async(|| async { Ok(()) })
}
#[test]
fn test_builder_schedule_methods() {
let builder = create_test_builder().every_minute();
assert_eq!(builder.expression.expression(), "* * * * *");
let builder = create_test_builder().hourly();
assert_eq!(builder.expression.expression(), "0 * * * *");
let builder = create_test_builder().daily();
assert_eq!(builder.expression.expression(), "0 0 * * *");
let builder = create_test_builder().weekly();
assert_eq!(builder.expression.expression(), "0 0 * * 0");
}
#[test]
fn test_builder_daily_at() {
let builder = create_test_builder().daily_at("14:30");
assert_eq!(builder.expression.expression(), "30 14 * * *");
}
#[test]
fn test_builder_at_modifier() {
let builder = create_test_builder().daily().at("09:15");
assert_eq!(builder.expression.expression(), "15 9 * * *");
}
#[test]
fn test_builder_configuration() {
let builder = create_test_builder()
.name("test-task")
.description("A test task")
.without_overlapping()
.run_in_background();
assert_eq!(builder.name, Some("test-task".to_string()));
assert_eq!(builder.description, Some("A test task".to_string()));
assert!(builder.without_overlapping);
assert!(builder.run_in_background);
}
#[test]
fn test_builder_build() {
let builder = create_test_builder()
.daily()
.name("my-task")
.description("My task description");
let entry = builder.build(0);
assert_eq!(entry.name, "my-task");
assert_eq!(entry.description, Some("My task description".to_string()));
}
#[test]
fn test_builder_default_name() {
let builder = create_test_builder().daily();
let entry = builder.build(5);
assert_eq!(entry.name, "closure-task-5");
}
}