major features update
This commit is contained in:
parent
519fb49901
commit
4e2fab67c5
48 changed files with 3925 additions and 208 deletions
93
src/models/birthday.rs
Normal file
93
src/models/birthday.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use chrono::Local;
|
||||
use sqlx::sqlite::SqliteRow;
|
||||
use sqlx::{FromRow, Row};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::models::YearOptionalDate;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Text {
|
||||
// language: Option<String>,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Birthday {
|
||||
Date(YearOptionalDate),
|
||||
Text(Text),
|
||||
}
|
||||
|
||||
impl Display for Birthday {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let str = match self {
|
||||
Birthday::Date(date) => date.to_string(),
|
||||
Birthday::Text(t) => t.value.clone(),
|
||||
};
|
||||
write!(f, "{}", str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Birthday {
|
||||
pub fn next_occurrence(&self) -> Option<chrono::NaiveDate> {
|
||||
match &self {
|
||||
Birthday::Text(_) => None,
|
||||
Birthday::Date(date) => Some(date.next_month_day_occurrence()?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn until_next(&self) -> Option<chrono::TimeDelta> {
|
||||
self.next_occurrence()
|
||||
.map(|when| when.signed_duration_since(Local::now().date_naive()))
|
||||
}
|
||||
|
||||
/// None if this is a text birthday or doesn't have a year
|
||||
pub fn age(&self) -> Option<u32> {
|
||||
match &self {
|
||||
Birthday::Text(_) => None,
|
||||
Birthday::Date(date) => date
|
||||
.to_date_naive()
|
||||
.map(|birthdate| Local::now().date_naive().years_since(birthdate))?,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> String {
|
||||
match &self {
|
||||
Birthday::Text(text) => text.value.clone(),
|
||||
Birthday::Date(date) => date.serialize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Birthday {
|
||||
type Err = ();
|
||||
fn from_str(str: &str) -> Result<Self, Self::Err> {
|
||||
if let Some(date) = YearOptionalDate::from_str(str).ok() {
|
||||
Ok(Birthday::Date(date))
|
||||
} else {
|
||||
Ok(Birthday::Text(super::birthday::Text {
|
||||
value: str.to_string(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FromRow<'_, SqliteRow> for Birthday {
|
||||
fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {
|
||||
let birthday_str = row.try_get("birthday")?;
|
||||
Ok(Birthday::from_str(birthday_str).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
use sqlx::{Database, Decode, Sqlite};
|
||||
impl<'r> Decode<'r, Sqlite> for Birthday
|
||||
where
|
||||
&'r str: Decode<'r, Sqlite>,
|
||||
{
|
||||
fn decode(
|
||||
value: <Sqlite as Database>::ValueRef<'r>,
|
||||
) -> Result<Birthday, Box<dyn std::error::Error + 'static + Send + Sync>> {
|
||||
let value = <&str as Decode<Sqlite>>::decode(value)?;
|
||||
|
||||
Ok(Birthday::from_str(value).unwrap())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue