1mod birthday;
2mod birthday_store;
3use anyhow::{bail, Result};
4pub use birthday::Birthday;
5use chrono::{Datelike, NaiveDate};
6
7pub fn add(name: String, day: u32, month: u32, year: i32) -> Result<()> {
8 let birthdate = NaiveDate::from_ymd_opt(year, month, day).expect("Invalid date");
9 birthday_store::add(name, birthdate)
10}
11
12pub fn get_all() -> Result<Vec<Birthday>> {
13 birthday_store::get_all()
14}
15
16pub fn get_next(today: NaiveDate) -> Result<Option<Birthday>> {
17 let mut birthdays = birthday_store::get_all()?;
18 birthdays.sort_by_key(|birthday| birthday.next(today));
19 Ok(birthdays.into_iter().next())
20}
21
22pub fn search(
23 name: Option<String>,
24 year: Option<i32>,
25 month: Option<u32>,
26 day: Option<u32>,
27) -> Result<Vec<Birthday>> {
28 let mut birthdays = birthday_store::get_all()?;
29
30 if let Some(name) = name {
31 birthdays.retain(|birthday| birthday.name.contains(&name));
32 }
33
34 if let Some(year) = year {
35 birthdays.retain(|birthday| birthday.date.year() == year);
36 }
37
38 if let Some(month) = month {
39 if !(1..=12).contains(&month) {
40 bail!("Month must be between 1 and 12");
41 }
42 birthdays.retain(|birthday| birthday.date.month() == month);
43 }
44
45 if let Some(day) = day {
46 if !(1..=31).contains(&day) {
47 bail!("Month must be between 1 and 31");
48 }
49 birthdays.retain(|birthday| birthday.date.day() == day);
50 }
51
52 Ok(birthdays)
53}
54
55pub fn forget(id: i32) -> Result<Option<Birthday>> {
56 birthday_store::remove(id)
57}