feat: add event database entities
							parent
							
								
									1bc9ae01d8
								
							
						
					
					
						commit
						d7c5c85460
					
				| 
						 | 
					@ -253,6 +253,7 @@ dependencies = [
 | 
				
			||||||
 "chrono",
 | 
					 "chrono",
 | 
				
			||||||
 "r2d2",
 | 
					 "r2d2",
 | 
				
			||||||
 "r2d2_sqlite",
 | 
					 "r2d2_sqlite",
 | 
				
			||||||
 | 
					 "rusqlite",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "tera",
 | 
					 "tera",
 | 
				
			||||||
 "tokio",
 | 
					 "tokio",
 | 
				
			||||||
| 
						 | 
					@ -286,6 +287,7 @@ dependencies = [
 | 
				
			||||||
 "iana-time-zone",
 | 
					 "iana-time-zone",
 | 
				
			||||||
 "js-sys",
 | 
					 "js-sys",
 | 
				
			||||||
 "num-traits",
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 "wasm-bindgen",
 | 
					 "wasm-bindgen",
 | 
				
			||||||
 "windows-targets",
 | 
					 "windows-targets",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -1062,6 +1064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
 | 
					checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "bitflags",
 | 
					 "bitflags",
 | 
				
			||||||
 | 
					 "chrono",
 | 
				
			||||||
 "fallible-iterator",
 | 
					 "fallible-iterator",
 | 
				
			||||||
 "fallible-streaming-iterator",
 | 
					 "fallible-streaming-iterator",
 | 
				
			||||||
 "hashlink",
 | 
					 "hashlink",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,12 @@ edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
axum = { version = "0.7.9", features = ["macros"] }
 | 
					axum = { version = "0.7.9", features = ["macros"] }
 | 
				
			||||||
chrono = "0.4.39"
 | 
					chrono = { version = "0.4.39", features = ["serde"] }
 | 
				
			||||||
r2d2 = "0.8.10"
 | 
					r2d2 = "0.8.10"
 | 
				
			||||||
r2d2_sqlite = "0.25.0"
 | 
					r2d2_sqlite = "0.25.0"
 | 
				
			||||||
 | 
					# this dependency is needed soly because the r2d2_sqlite crate doesn't export
 | 
				
			||||||
 | 
					# the 'chrono' feature flag
 | 
				
			||||||
 | 
					rusqlite = { version = "0.32.1", features = ["chrono"] }
 | 
				
			||||||
serde = { version = "1.0.217", features = ["derive"] }
 | 
					serde = { version = "1.0.217", features = ["derive"] }
 | 
				
			||||||
tera = "1.20.0"
 | 
					tera = "1.20.0"
 | 
				
			||||||
tokio = { version = "1.42.0", features = ["full"] }
 | 
					tokio = { version = "1.42.0", features = ["full"] }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					use std::{fmt::Display, str::FromStr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use chrono::Utc;
 | 
				
			||||||
 | 
					use r2d2_sqlite::rusqlite::{
 | 
				
			||||||
 | 
					    self,
 | 
				
			||||||
 | 
					    types::{FromSql, FromSqlError},
 | 
				
			||||||
 | 
					    Row, ToSql,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub enum EventType {
 | 
				
			||||||
 | 
					    Watering,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToString for EventType {
 | 
				
			||||||
 | 
					    fn to_string(&self) -> String {
 | 
				
			||||||
 | 
					        String::from(match self {
 | 
				
			||||||
 | 
					            Self::Watering => "watering",
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct ParseEventTypeErr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for ParseEventTypeErr {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "invalid name")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl std::error::Error for ParseEventTypeErr {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl FromStr for EventType {
 | 
				
			||||||
 | 
					    type Err = ParseEventTypeErr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn from_str(s: &str) -> Result<Self, Self::Err> {
 | 
				
			||||||
 | 
					        match s {
 | 
				
			||||||
 | 
					            "watering" => Ok(Self::Watering),
 | 
				
			||||||
 | 
					            _ => Err(ParseEventTypeErr),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToSql for EventType {
 | 
				
			||||||
 | 
					    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
 | 
				
			||||||
 | 
					        Ok(self.to_string().into())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl FromSql for EventType {
 | 
				
			||||||
 | 
					    fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
 | 
				
			||||||
 | 
					        value
 | 
				
			||||||
 | 
					            .as_str()?
 | 
				
			||||||
 | 
					            .parse()
 | 
				
			||||||
 | 
					            .map_err(|e| FromSqlError::Other(Box::new(e)))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize)]
 | 
				
			||||||
 | 
					pub struct Event {
 | 
				
			||||||
 | 
					    id: i32,
 | 
				
			||||||
 | 
					    plant_id: i32,
 | 
				
			||||||
 | 
					    event_type: EventType,
 | 
				
			||||||
 | 
					    time: chrono::DateTime<Utc>,
 | 
				
			||||||
 | 
					    description: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Event {
 | 
				
			||||||
 | 
					    pub fn from_row(row: Row<'_>) -> rusqlite::Result<Self> {
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            id: row.get("id")?,
 | 
				
			||||||
 | 
					            plant_id: row.get("plant_id")?,
 | 
				
			||||||
 | 
					            event_type: row.get("event_type")?,
 | 
				
			||||||
 | 
					            time: row.get("time")?,
 | 
				
			||||||
 | 
					            description: row.get("description")?,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Deserialize)]
 | 
				
			||||||
 | 
					pub struct NewEvent {
 | 
				
			||||||
 | 
					    plant_id: i32,
 | 
				
			||||||
 | 
					    event_type: EventType,
 | 
				
			||||||
 | 
					    time: chrono::DateTime<Utc>,
 | 
				
			||||||
 | 
					    description: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
mod comment;
 | 
					mod comment;
 | 
				
			||||||
 | 
					mod event;
 | 
				
			||||||
mod plant;
 | 
					mod plant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use r2d2_sqlite::{rusqlite, SqliteConnectionManager};
 | 
					use r2d2_sqlite::{rusqlite, SqliteConnectionManager};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +7,11 @@ use r2d2_sqlite::SqliteConnectionManager;
 | 
				
			||||||
use tera::Tera;
 | 
					use tera::Tera;
 | 
				
			||||||
use tower_http::compression::CompressionLayer;
 | 
					use tower_http::compression::CompressionLayer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MIGRATIONS: [&str; 3] = [
 | 
					const MIGRATIONS: [&str; 4] = [
 | 
				
			||||||
    include_str!("migrations/000_initial.sql"),
 | 
					    include_str!("migrations/000_initial.sql"),
 | 
				
			||||||
    include_str!("migrations/001_plants.sql"),
 | 
					    include_str!("migrations/001_plants.sql"),
 | 
				
			||||||
    include_str!("migrations/002_comments.sql"),
 | 
					    include_str!("migrations/002_comments.sql"),
 | 
				
			||||||
 | 
					    include_str!("migrations/003_events.sql"),
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
const STATIC_FILES: [(&str, &'static str); 1] = [(
 | 
					const STATIC_FILES: [(&str, &'static str); 1] = [(
 | 
				
			||||||
    "htmx_2.0.4.min.js",
 | 
					    "htmx_2.0.4.min.js",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					create table events (
 | 
				
			||||||
 | 
					    id integer primary key,
 | 
				
			||||||
 | 
					    plant_id integer not null
 | 
				
			||||||
 | 
					        references plants (id)
 | 
				
			||||||
 | 
					        on delete cascade,
 | 
				
			||||||
 | 
					    event_type text not null,
 | 
				
			||||||
 | 
					    time text not null,
 | 
				
			||||||
 | 
					    description text not null
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
		Loading…
	
		Reference in New Issue