diff --git a/Makefile b/Makefile index d847842..80d21ba 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,12 @@ build: cargo build -sqlx: +sqlx-prepare: rm ./emgauwa-dev.sqlite || true cargo sqlx database create cargo sqlx migrate run + +sqlx: sqlx-prepare cargo sqlx prepare --workspace build-rpi: @@ -15,7 +17,7 @@ clean-db: rm ./emgauwa-dev.sqlite || true rm ./emgauwa-core.sqlite || true rm ./emgauwa-controller.sqlite || true - $(MAKE) sqlx + $(MAKE) sqlx-prepare fmt: cargo +nightly fmt diff --git a/emgauwa-controller/src/main.rs b/emgauwa-controller/src/main.rs index b3022e1..59db1ac 100644 --- a/emgauwa-controller/src/main.rs +++ b/emgauwa-controller/src/main.rs @@ -1,5 +1,6 @@ use emgauwa_lib::constants::WEBSOCKET_RETRY_TIMEOUT; -use emgauwa_lib::db::{DbController, DbRelay}; +use emgauwa_lib::db::errors::DatabaseError; +use emgauwa_lib::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule}; use emgauwa_lib::models::{Controller, FromDbModel}; use emgauwa_lib::types::{ControllerUid, ControllerWsAction}; use emgauwa_lib::{db, utils}; @@ -37,15 +38,21 @@ async fn create_this_relay( conn: &mut PoolConnection, this_controller: &DbController, settings_relay: &settings::Relay, -) -> DbRelay { - DbRelay::create( +) -> Result { + let relay = DbRelay::create( conn, &settings_relay.name, settings_relay.number.unwrap(), this_controller, ) - .await - .expect("Failed to create relay") + .await?; + + let off = DbSchedule::get_off(conn).await?; + for weekday in 0..7 { + DbJunctionRelaySchedule::set_schedule(conn, &relay, &off, weekday).await?; + } + + Ok(relay) } #[tokio::main] @@ -71,7 +78,9 @@ async fn main() { .expect("Failed to get relay from database") .is_none() { - create_this_relay(&mut conn, &db_controller, relay).await; + create_this_relay(&mut conn, &db_controller, relay) + .await + .expect("Failed to create schedule."); } } diff --git a/emgauwa-lib/src/db/junction_relay_schedule.rs b/emgauwa-lib/src/db/junction_relay_schedule.rs new file mode 100644 index 0000000..b331610 --- /dev/null +++ b/emgauwa-lib/src/db/junction_relay_schedule.rs @@ -0,0 +1,131 @@ +use std::ops::DerefMut; + +use sqlx::pool::PoolConnection; +use sqlx::Sqlite; + +use crate::db::errors::DatabaseError; +use crate::db::{DbRelay, DbSchedule}; +use crate::types::Weekday; + +pub struct DbJunctionRelaySchedule { + pub id: i64, + pub weekday: Weekday, + pub relay_id: i64, + pub schedule_id: i64, +} + +impl DbJunctionRelaySchedule { + pub async fn get( + conn: &mut PoolConnection, + id: i64, + ) -> Result, DatabaseError> { + sqlx::query_as!( + DbJunctionRelaySchedule, + "SELECT * FROM junction_relay_schedule WHERE id = ?", + id + ) + .fetch_optional(conn.deref_mut()) + .await + .map_err(DatabaseError::from) + } + + pub async fn get_junction( + conn: &mut PoolConnection, + relay: &DbRelay, + schedule: &DbSchedule, + weekday: Weekday, + ) -> Result, DatabaseError> { + sqlx::query_as!( + DbJunctionRelaySchedule, + "SELECT * FROM junction_relay_schedule WHERE relay_id = ? AND schedule_id = ? AND weekday = ?", + relay.id, + schedule.id, + weekday + ) + .fetch_optional(conn.deref_mut()) + .await + .map_err(DatabaseError::from) + } + + pub async fn get_schedule( + conn: &mut PoolConnection, + relay: &DbRelay, + weekday: Weekday, + ) -> Result, DatabaseError> { + sqlx::query_as!( + DbSchedule, + r#"SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule + ON junction_relay_schedule.schedule_id = schedules.id + WHERE junction_relay_schedule.relay_id = ? AND junction_relay_schedule.weekday = ?"#, + relay.id, + weekday + ) + .fetch_optional(conn.deref_mut()) + .await + .map_err(DatabaseError::from) + } + + pub async fn get_schedules( + conn: &mut PoolConnection, + relay: &DbRelay, + ) -> Result, DatabaseError> { + sqlx::query_as!( + DbSchedule, + r#"SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule + ON junction_relay_schedule.schedule_id = schedules.id + WHERE junction_relay_schedule.relay_id = ? + ORDER BY junction_relay_schedule.weekday"#, + relay.id + ) + .fetch_all(conn.deref_mut()) + .await + .map_err(DatabaseError::from) + } + + pub async fn set_schedule( + conn: &mut PoolConnection, + relay: &DbRelay, + schedule: &DbSchedule, + weekday: Weekday, + ) -> Result { + match Self::get_junction(conn, relay, schedule, weekday).await? { + None => sqlx::query_as!( + DbJunctionRelaySchedule, + "INSERT INTO junction_relay_schedule (weekday, relay_id, schedule_id) VALUES (?, ?, ?) RETURNING *", + weekday, + relay.id, + schedule.id + ) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError), + + Some(junction) => { + sqlx::query!( + "UPDATE junction_relay_schedule SET weekday = ?, relay_id = ?, schedule_id= ? WHERE id = ?", + weekday, + relay.id, + schedule.id, + junction.id + ) + .execute(conn.deref_mut()) + .await?; + + Self::get(conn, junction.id) + .await? + .ok_or(DatabaseError::UpdateGetError) + } + } + } + + pub async fn set_schedules( + conn: &mut PoolConnection, + relay: &DbRelay, + schedules: Vec<&DbSchedule>, + ) -> Result<(), DatabaseError> { + for (weekday, schedule) in schedules.iter().enumerate() { + Self::set_schedule(conn, relay, schedule, weekday as Weekday).await?; + } + Ok(()) + } +} diff --git a/emgauwa-lib/src/db/junction_tag.rs b/emgauwa-lib/src/db/junction_tag.rs new file mode 100644 index 0000000..8229636 --- /dev/null +++ b/emgauwa-lib/src/db/junction_tag.rs @@ -0,0 +1,48 @@ +use std::ops::DerefMut; + +use sqlx::pool::PoolConnection; +use sqlx::Sqlite; + +use crate::db::errors::DatabaseError; +use crate::db::{DbRelay, DbSchedule, DbTag}; + +pub struct DbJunctionTag { + pub id: i64, + pub tag_id: i64, + pub relay_id: Option, + pub schedule_id: Option, +} + +impl DbJunctionTag { + pub async fn link_relay( + conn: &mut PoolConnection, + tag: &DbTag, + relay: &DbRelay, + ) -> Result { + sqlx::query_as!( + DbJunctionTag, + "INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *", + tag.id, + relay.id + ) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError) + } + + pub async fn link_schedule( + conn: &mut PoolConnection, + tag: &DbTag, + schedule: &DbSchedule, + ) -> Result { + sqlx::query_as!( + DbJunctionTag, + "INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *", + tag.id, + schedule.id + ) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError) + } +} diff --git a/emgauwa-lib/src/db/mod.rs b/emgauwa-lib/src/db/mod.rs index c21e96f..e0ccaeb 100644 --- a/emgauwa-lib/src/db/mod.rs +++ b/emgauwa-lib/src/db/mod.rs @@ -6,12 +6,16 @@ use sqlx::{Pool, Sqlite}; mod controllers; pub mod errors; +mod junction_relay_schedule; +mod junction_tag; mod model_utils; mod relays; mod schedules; mod tag; pub use controllers::DbController; +pub use junction_relay_schedule::DbJunctionRelaySchedule; +pub use junction_tag::DbJunctionTag; pub use relays::DbRelay; pub use schedules::{DbPeriods, DbSchedule}; pub use tag::DbTag; diff --git a/emgauwa-lib/src/db/relays.rs b/emgauwa-lib/src/db/relays.rs index 65a5f4b..ec6fe60 100644 --- a/emgauwa-lib/src/db/relays.rs +++ b/emgauwa-lib/src/db/relays.rs @@ -5,7 +5,7 @@ use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::errors::DatabaseError; -use crate::db::{DbController, DbTag}; +use crate::db::{DbController, DbJunctionTag, DbTag}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DbRelay { @@ -153,7 +153,7 @@ impl DbRelay { for new_tag in new_tags { let tag: DbTag = DbTag::get_by_tag_or_create(conn, new_tag).await?; - tag.link_relay(conn, self).await?; + DbJunctionTag::link_relay(conn, &tag, self).await?; } Ok(()) } diff --git a/emgauwa-lib/src/db/schedules.rs b/emgauwa-lib/src/db/schedules.rs index d2596a6..caf74d6 100644 --- a/emgauwa-lib/src/db/schedules.rs +++ b/emgauwa-lib/src/db/schedules.rs @@ -7,7 +7,7 @@ use sqlx::Sqlite; use crate::db::errors::DatabaseError; use crate::db::model_utils::Period; -use crate::db::DbTag; +use crate::db::{DbJunctionTag, DbTag}; use crate::types::ScheduleUid; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -166,7 +166,7 @@ impl DbSchedule { for new_tag in new_tags { let tag: DbTag = DbTag::get_by_tag_or_create(conn, new_tag).await?; - tag.link_schedule(conn, self).await?; + DbJunctionTag::link_schedule(conn, &tag, self).await?; } Ok(()) } diff --git a/emgauwa-lib/src/db/tag.rs b/emgauwa-lib/src/db/tag.rs index 2cb9551..3694e96 100644 --- a/emgauwa-lib/src/db/tag.rs +++ b/emgauwa-lib/src/db/tag.rs @@ -5,7 +5,6 @@ use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::errors::DatabaseError; -use crate::db::{DbRelay, DbSchedule}; #[derive(Debug, Serialize, Clone)] pub struct DbTag { @@ -13,13 +12,6 @@ pub struct DbTag { pub tag: String, } -pub struct DbJunctionTag { - pub id: i64, - pub tag_id: i64, - pub relay_id: Option, - pub schedule_id: Option, -} - impl DbTag { pub async fn create( conn: &mut PoolConnection, @@ -64,36 +56,4 @@ impl DbTag { .await .map_err(DatabaseError::from) } - - pub async fn link_relay( - &self, - conn: &mut PoolConnection, - target_relay: &DbRelay, - ) -> Result { - sqlx::query_as!( - DbJunctionTag, - "INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *", - self.id, - target_relay.id - ) - .fetch_optional(conn.deref_mut()) - .await? - .ok_or(DatabaseError::InsertGetError) - } - - pub async fn link_schedule( - &self, - conn: &mut PoolConnection, - target_schedule: &DbSchedule, - ) -> Result { - sqlx::query_as!( - DbJunctionTag, - "INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *", - self.id, - target_schedule.id - ) - .fetch_optional(conn.deref_mut()) - .await? - .ok_or(DatabaseError::InsertGetError) - } } diff --git a/emgauwa-lib/src/types/mod.rs b/emgauwa-lib/src/types/mod.rs index 4c0cc95..838ddec 100644 --- a/emgauwa-lib/src/types/mod.rs +++ b/emgauwa-lib/src/types/mod.rs @@ -11,6 +11,7 @@ use serde_derive::{Deserialize, Serialize}; use crate::models::Controller; pub type ConnectedControllersType = Arc>>; +pub type Weekday = i64; #[derive(Debug, Serialize, Deserialize)] pub enum ControllerWsAction { diff --git a/migrations/20231120000000_init.up.sql b/migrations/20231120000000_init.up.sql index e370f41..1e5f205 100644 --- a/migrations/20231120000000_init.up.sql +++ b/migrations/20231120000000_init.up.sql @@ -107,11 +107,12 @@ CREATE TABLE junction_relay_schedule NOT NULL, relay_id INTEGER + NOT NULL REFERENCES relays (id) ON DELETE CASCADE, schedule_id INTEGER - DEFAULT 1 + NOT NULL REFERENCES schedules (id) ON DELETE SET DEFAULT );