birthday/
lib.rs

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}