use core::fmt; use std::str::FromStr; use anyhow::{Result, bail}; use diesel::{backend::Backend, deserialize::{self, FromSql, FromSqlRow}, expression::AsExpression, serialize::{self, ToSql}, sql_types::Text, sqlite::Sqlite}; use serde::{Deserialize, Serialize}; #[derive( Eq, PartialEq, Serialize, Deserialize, Clone, Debug, AsExpression, FromSqlRow, )] #[diesel(sql_type=Text)] pub enum BudgetPeriodUnit { Day, Month, Year, } impl fmt::Display for BudgetPeriodUnit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { BudgetPeriodUnit::Day => "DAY".fmt(f), BudgetPeriodUnit::Month => "MONTH".fmt(f), BudgetPeriodUnit::Year => "YEAR".fmt(f), } } } impl FromStr for BudgetPeriodUnit { type Err = anyhow::Error; fn from_str(s: &str) -> Result { match s { "DAY" => Ok(BudgetPeriodUnit::Day), "MONTH" => Ok(BudgetPeriodUnit::Month), "YEAR" => Ok(BudgetPeriodUnit::Year), _ => bail!("\"{}\" is not a valid budget period unit. Valid values are: DAY, MONTH, YEAR", s), } } } impl ToSql for BudgetPeriodUnit { fn to_sql<'b>( &'b self, out: &mut diesel::serialize::Output<'b, '_, Sqlite>, ) -> serialize::Result { out.set_value(self.to_string()); Ok(serialize::IsNull::No) } } impl FromSql for BudgetPeriodUnit { fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { let str = >::from_sql(bytes)?; Ok(str.parse()?) } } #[cfg(test)] mod test { use anyhow::Result; use super::BudgetPeriodUnit; #[test] fn display_when_day_then_day() { assert_eq!("DAY", format!("{}", BudgetPeriodUnit::Day)); } #[test] fn display_when_month_then_month() { assert_eq!("MONTH", format!("{}", BudgetPeriodUnit::Month)); } #[test] fn display_when_year_then_year() { assert_eq!("YEAR", format!("{}", BudgetPeriodUnit::Year)); } #[test] fn from_str_when_day_then_day() { let result: Result = "DAY".parse(); assert!(result.is_ok()); assert_eq!(BudgetPeriodUnit::Day, result.unwrap()); } #[test] fn from_str_when_month_then_month() { let result: Result = "MONTH".parse(); assert!(result.is_ok()); assert_eq!(BudgetPeriodUnit::Month, result.unwrap()); } #[test] fn from_str_when_year_then_year() { let result: Result = "YEAR".parse(); assert!(result.is_ok()); assert_eq!(BudgetPeriodUnit::Year, result.unwrap()); } #[test] fn from_str_when_sentence_case_day_then_err() { let result: Result = "Day".parse(); assert!(result.is_err()); } }