use serde_derive::{Deserialize, Serialize}; use std::ops::DerefMut; use crate::db::DbController; use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::errors::DatabaseError; use crate::db::DbTag; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DbRelay { #[serde(skip)] pub id: i64, pub name: String, pub number: i64, #[serde(skip)] pub controller_id: i64, } impl DbRelay { pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbRelay>, DatabaseError> { sqlx::query_as!(DbRelay, "SELECT * FROM relays") .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get( conn: &mut PoolConnection<Sqlite>, id: i64, ) -> Result<Option<DbRelay>, DatabaseError> { sqlx::query_as!(DbRelay, "SELECT * FROM relays WHERE id = ?", id) .fetch_optional(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get_by_controller_and_num( conn: &mut PoolConnection<Sqlite>, controller: &DbController, number: i64, ) -> Result<Option<DbRelay>, DatabaseError> { sqlx::query_as!( DbRelay, "SELECT * FROM relays WHERE controller_id = ? AND number = ?", controller.id, number ) .fetch_optional(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get_by_controller_and_num_or_create( conn: &mut PoolConnection<Sqlite>, controller: &DbController, number: i64, new_name: &str, ) -> Result<DbRelay, DatabaseError> { match DbRelay::get_by_controller_and_num(conn, controller, number).await? { Some(relay) => Ok(relay), None => DbRelay::create(conn, new_name, number, controller).await, } } pub async fn get_by_tag( conn: &mut PoolConnection<Sqlite>, tag: &DbTag, ) -> Result<Vec<DbRelay>, DatabaseError> { sqlx::query_as!(DbRelay, "SELECT schedule.* FROM relays AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn create( conn: &mut PoolConnection<Sqlite>, new_name: &str, new_number: i64, new_controller: &DbController, ) -> Result<DbRelay, DatabaseError> { sqlx::query_as!( DbRelay, "INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?) RETURNING *", new_name, new_number, new_controller.id, ) .fetch_optional(conn.deref_mut()) .await? .ok_or(DatabaseError::InsertGetError) } pub async fn delete(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> { sqlx::query!("DELETE FROM relays WHERE id = ?", self.id) .execute(conn.deref_mut()) .await .map(|res| match res.rows_affected() { 0 => Err(DatabaseError::DeleteError), _ => Ok(()), })? } pub async fn update( &self, conn: &mut PoolConnection<Sqlite>, new_name: &str, new_number: i64, new_controller: &DbController, ) -> Result<DbRelay, DatabaseError> { sqlx::query!( "UPDATE relays SET name = ?, number = ?, controller_id = ? WHERE id = ?", new_name, new_number, new_controller.id, self.id, ) .execute(conn.deref_mut()) .await?; DbRelay::get(conn, self.id) .await? .ok_or(DatabaseError::UpdateGetError) } pub async fn get_controller( &self, conn: &mut PoolConnection<Sqlite>, ) -> Result<DbController, DatabaseError> { DbController::get(conn, self.controller_id) .await? .ok_or(DatabaseError::NotFound) } pub async fn get_tags( &self, conn: &mut PoolConnection<Sqlite>, ) -> Result<Vec<String>, DatabaseError> { sqlx::query_scalar!("SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.relay_id = ?", self.id) .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn set_tags( &self, conn: &mut PoolConnection<Sqlite>, new_tags: &[String], ) -> Result<(), DatabaseError> { sqlx::query!("DELETE FROM junction_tag WHERE relay_id = ?", self.id) .execute(conn.deref_mut()) .await?; 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?; } Ok(()) } }