Add junction between relays and schedules

This commit is contained in:
Tobias Reisinger 2023-11-30 00:57:03 +01:00
parent a90ea25b87
commit 2f51ebf91e
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
10 changed files with 209 additions and 53 deletions

View file

@ -2,10 +2,12 @@
build: build:
cargo build cargo build
sqlx: sqlx-prepare:
rm ./emgauwa-dev.sqlite || true rm ./emgauwa-dev.sqlite || true
cargo sqlx database create cargo sqlx database create
cargo sqlx migrate run cargo sqlx migrate run
sqlx: sqlx-prepare
cargo sqlx prepare --workspace cargo sqlx prepare --workspace
build-rpi: build-rpi:
@ -15,7 +17,7 @@ clean-db:
rm ./emgauwa-dev.sqlite || true rm ./emgauwa-dev.sqlite || true
rm ./emgauwa-core.sqlite || true rm ./emgauwa-core.sqlite || true
rm ./emgauwa-controller.sqlite || true rm ./emgauwa-controller.sqlite || true
$(MAKE) sqlx $(MAKE) sqlx-prepare
fmt: fmt:
cargo +nightly fmt cargo +nightly fmt

View file

@ -1,5 +1,6 @@
use emgauwa_lib::constants::WEBSOCKET_RETRY_TIMEOUT; 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::models::{Controller, FromDbModel};
use emgauwa_lib::types::{ControllerUid, ControllerWsAction}; use emgauwa_lib::types::{ControllerUid, ControllerWsAction};
use emgauwa_lib::{db, utils}; use emgauwa_lib::{db, utils};
@ -37,15 +38,21 @@ async fn create_this_relay(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
this_controller: &DbController, this_controller: &DbController,
settings_relay: &settings::Relay, settings_relay: &settings::Relay,
) -> DbRelay { ) -> Result<DbRelay, DatabaseError> {
DbRelay::create( let relay = DbRelay::create(
conn, conn,
&settings_relay.name, &settings_relay.name,
settings_relay.number.unwrap(), settings_relay.number.unwrap(),
this_controller, this_controller,
) )
.await .await?;
.expect("Failed to create relay")
let off = DbSchedule::get_off(conn).await?;
for weekday in 0..7 {
DbJunctionRelaySchedule::set_schedule(conn, &relay, &off, weekday).await?;
}
Ok(relay)
} }
#[tokio::main] #[tokio::main]
@ -71,7 +78,9 @@ async fn main() {
.expect("Failed to get relay from database") .expect("Failed to get relay from database")
.is_none() .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.");
} }
} }

View file

@ -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<Sqlite>,
id: i64,
) -> Result<Option<DbJunctionRelaySchedule>, 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<Sqlite>,
relay: &DbRelay,
schedule: &DbSchedule,
weekday: Weekday,
) -> Result<Option<DbJunctionRelaySchedule>, 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<Sqlite>,
relay: &DbRelay,
weekday: Weekday,
) -> Result<Option<DbSchedule>, 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<Sqlite>,
relay: &DbRelay,
) -> Result<Vec<DbSchedule>, 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<Sqlite>,
relay: &DbRelay,
schedule: &DbSchedule,
weekday: Weekday,
) -> Result<DbJunctionRelaySchedule, DatabaseError> {
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<Sqlite>,
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(())
}
}

View file

@ -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<i64>,
pub schedule_id: Option<i64>,
}
impl DbJunctionTag {
pub async fn link_relay(
conn: &mut PoolConnection<Sqlite>,
tag: &DbTag,
relay: &DbRelay,
) -> Result<DbJunctionTag, DatabaseError> {
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<Sqlite>,
tag: &DbTag,
schedule: &DbSchedule,
) -> Result<DbJunctionTag, DatabaseError> {
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)
}
}

View file

@ -6,12 +6,16 @@ use sqlx::{Pool, Sqlite};
mod controllers; mod controllers;
pub mod errors; pub mod errors;
mod junction_relay_schedule;
mod junction_tag;
mod model_utils; mod model_utils;
mod relays; mod relays;
mod schedules; mod schedules;
mod tag; mod tag;
pub use controllers::DbController; pub use controllers::DbController;
pub use junction_relay_schedule::DbJunctionRelaySchedule;
pub use junction_tag::DbJunctionTag;
pub use relays::DbRelay; pub use relays::DbRelay;
pub use schedules::{DbPeriods, DbSchedule}; pub use schedules::{DbPeriods, DbSchedule};
pub use tag::DbTag; pub use tag::DbTag;

View file

@ -5,7 +5,7 @@ use sqlx::pool::PoolConnection;
use sqlx::Sqlite; use sqlx::Sqlite;
use crate::db::errors::DatabaseError; use crate::db::errors::DatabaseError;
use crate::db::{DbController, DbTag}; use crate::db::{DbController, DbJunctionTag, DbTag};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbRelay { pub struct DbRelay {
@ -153,7 +153,7 @@ impl DbRelay {
for new_tag in new_tags { for new_tag in new_tags {
let tag: DbTag = DbTag::get_by_tag_or_create(conn, new_tag).await?; 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(()) Ok(())
} }

View file

@ -7,7 +7,7 @@ use sqlx::Sqlite;
use crate::db::errors::DatabaseError; use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period; use crate::db::model_utils::Period;
use crate::db::DbTag; use crate::db::{DbJunctionTag, DbTag};
use crate::types::ScheduleUid; use crate::types::ScheduleUid;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -166,7 +166,7 @@ impl DbSchedule {
for new_tag in new_tags { for new_tag in new_tags {
let tag: DbTag = DbTag::get_by_tag_or_create(conn, new_tag).await?; 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(()) Ok(())
} }

View file

@ -5,7 +5,6 @@ use sqlx::pool::PoolConnection;
use sqlx::Sqlite; use sqlx::Sqlite;
use crate::db::errors::DatabaseError; use crate::db::errors::DatabaseError;
use crate::db::{DbRelay, DbSchedule};
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
pub struct DbTag { pub struct DbTag {
@ -13,13 +12,6 @@ pub struct DbTag {
pub tag: String, pub tag: String,
} }
pub struct DbJunctionTag {
pub id: i64,
pub tag_id: i64,
pub relay_id: Option<i64>,
pub schedule_id: Option<i64>,
}
impl DbTag { impl DbTag {
pub async fn create( pub async fn create(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
@ -64,36 +56,4 @@ impl DbTag {
.await .await
.map_err(DatabaseError::from) .map_err(DatabaseError::from)
} }
pub async fn link_relay(
&self,
conn: &mut PoolConnection<Sqlite>,
target_relay: &DbRelay,
) -> Result<DbJunctionTag, DatabaseError> {
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<Sqlite>,
target_schedule: &DbSchedule,
) -> Result<DbJunctionTag, DatabaseError> {
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)
}
} }

View file

@ -11,6 +11,7 @@ use serde_derive::{Deserialize, Serialize};
use crate::models::Controller; use crate::models::Controller;
pub type ConnectedControllersType = Arc<Mutex<HashMap<ControllerUid, Controller>>>; pub type ConnectedControllersType = Arc<Mutex<HashMap<ControllerUid, Controller>>>;
pub type Weekday = i64;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum ControllerWsAction { pub enum ControllerWsAction {

View file

@ -107,11 +107,12 @@ CREATE TABLE junction_relay_schedule
NOT NULL, NOT NULL,
relay_id relay_id
INTEGER INTEGER
NOT NULL
REFERENCES relays (id) REFERENCES relays (id)
ON DELETE CASCADE, ON DELETE CASCADE,
schedule_id schedule_id
INTEGER INTEGER
DEFAULT 1 NOT NULL
REFERENCES schedules (id) REFERENCES schedules (id)
ON DELETE SET DEFAULT ON DELETE SET DEFAULT
); );