diff --git a/Cargo.lock b/Cargo.lock index 35b3f37..a582dcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -577,6 +577,7 @@ version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12" dependencies = [ + "chrono", "diesel_derives", "libsqlite3-sys", "r2d2", diff --git a/Cargo.toml b/Cargo.toml index da3b0c2..3308327 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ axum = { version = "0.8.0", features = ["macros"] } axum-extra = { version = "0.10.0", features = ["cookie"] } chrono = { version = "0.4.39", features = ["serde"] } clap = { version = "4.5.26", features = ["derive", "env"] } -diesel = { version = "2.2.6", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "r2d2"] } +diesel = { version = "2.2.6", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "r2d2", "chrono"] } r2d2 = "0.8.10" r2d2_sqlite = "0.25.0" rand = "0.8.5" diff --git a/diesel.toml b/diesel.toml index 66f122f..bb1d1f7 100644 --- a/diesel.toml +++ b/diesel.toml @@ -6,4 +6,4 @@ file = "src/db/schema.rs" custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] [migrations_directory] -dir = "/home/jef/dev/calathea/migrations" +dir = "migrations" diff --git a/migrations/2025-01-13-115505_create_events/up.sql b/migrations/2025-01-13-115505_create_events/up.sql index b4db1e3..cc9c0c5 100644 --- a/migrations/2025-01-13-115505_create_events/up.sql +++ b/migrations/2025-01-13-115505_create_events/up.sql @@ -4,6 +4,6 @@ create table events ( references plants (id) on delete cascade, event_type text not null, - date text not null, + date date not null, description text not null ); diff --git a/src/db/models/event.rs b/src/db/models/event.rs new file mode 100644 index 0000000..b6084f9 --- /dev/null +++ b/src/db/models/event.rs @@ -0,0 +1,101 @@ +use chrono::NaiveDate; +use diesel::{ + deserialize::FromSql, + prelude::*, + serialize::ToSql, + sql_types::Text, + sqlite::{Sqlite, SqliteValue}, + AsExpression, FromSqlRow, +}; +use serde::{Deserialize, Serialize}; + +use std::{fmt, str::FromStr}; + +use crate::db::schema::*; + +#[derive(FromSqlRow, Debug, AsExpression, Serialize, Deserialize)] +#[diesel(sql_type = Text)] +pub enum EventType { + Watering, +} + +impl fmt::Display for EventType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::Watering => "Watering", + }; + + write!(f, "{}", s) + } +} + +#[derive(Debug)] +pub struct ParseEventTypeErr(String); + +impl fmt::Display for ParseEventTypeErr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "invalid event type '{}'", self.0) + } +} + +impl std::error::Error for ParseEventTypeErr {} + +impl FromStr for EventType { + type Err = ParseEventTypeErr; + + fn from_str(s: &str) -> Result { + match s { + "Watering" => Ok(Self::Watering), + _ => Err(ParseEventTypeErr(s.to_string())), + } + } +} + +impl FromSql for EventType { + fn from_sql(bytes: SqliteValue) -> diesel::deserialize::Result { + let s = >::from_sql(bytes)?; + + Ok(s.as_str().parse()?) + } +} + +impl ToSql for EventType { + fn to_sql<'b>( + &'b self, + out: &mut diesel::serialize::Output<'b, '_, Sqlite>, + ) -> diesel::serialize::Result { + out.set_value(self.to_string()); + + Ok(diesel::serialize::IsNull::No) + } +} + +#[derive(Serialize, Queryable, Selectable)] +#[diesel(table_name = events)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] +pub struct Event { + id: i64, + plant_id: i64, + event_type: EventType, + date: NaiveDate, + description: String, +} + +#[derive(Deserialize, Insertable)] +#[diesel(table_name = events)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] +pub struct NewEvent { + plant_id: i64, + event_type: EventType, + date: NaiveDate, + description: String, +} + +impl NewEvent { + pub fn insert(self, conn: &mut SqliteConnection) -> QueryResult { + diesel::insert_into(events::table) + .values(self) + .returning(Event::as_returning()) + .get_result(conn) + } +} diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index fa539ed..443bd6a 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -1,3 +1,4 @@ +mod event; mod plant; mod session; mod user; diff --git a/src/db/schema.rs b/src/db/schema.rs index 7bd1846..664720e 100644 --- a/src/db/schema.rs +++ b/src/db/schema.rs @@ -13,7 +13,7 @@ diesel::table! { id -> BigInt, plant_id -> BigInt, event_type -> Text, - date -> Text, + date -> Date, description -> Text, } } @@ -47,10 +47,4 @@ diesel::joinable!(comments -> plants (plant_id)); diesel::joinable!(events -> plants (plant_id)); diesel::joinable!(sessions -> users (user_id)); -diesel::allow_tables_to_appear_in_same_query!( - comments, - events, - plants, - sessions, - users, -); +diesel::allow_tables_to_appear_in_same_query!(comments, events, plants, sessions, users,);