use std::ops::DerefMut; use serde_derive::{Deserialize, Serialize}; use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::{DbRelay, DbTag}; use crate::errors::DatabaseError; use crate::types::EmgauwaUid; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DbController { #[serde(skip)] pub id: i64, #[serde(rename = "id")] pub uid: EmgauwaUid, pub name: String, pub relay_count: i64, pub active: bool, } impl DbController { pub async fn get_all( conn: &mut PoolConnection<Sqlite>, ) -> Result<Vec<DbController>, DatabaseError> { sqlx::query_as!(DbController, "SELECT * FROM controllers") .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get( conn: &mut PoolConnection<Sqlite>, id: i64, ) -> Result<Option<DbController>, DatabaseError> { sqlx::query_as!(DbController, "SELECT * FROM controllers WHERE id = ?", id) .fetch_optional(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get_by_uid( conn: &mut PoolConnection<Sqlite>, filter_uid: &EmgauwaUid, ) -> Result<Option<DbController>, DatabaseError> { sqlx::query_as!( DbController, "SELECT * FROM controllers WHERE uid = ?", filter_uid ) .fetch_optional(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get_by_uid_or_create( conn: &mut PoolConnection<Sqlite>, uid: &EmgauwaUid, new_name: &str, new_relay_count: i64, ) -> Result<DbController, DatabaseError> { match DbController::get_by_uid(conn, uid).await? { Some(tag) => Ok(tag), None => DbController::create(conn, uid, new_name, new_relay_count).await, } } pub async fn get_by_tag( conn: &mut PoolConnection<Sqlite>, tag: &DbTag, ) -> Result<Vec<DbController>, DatabaseError> { sqlx::query_as!(DbController, "SELECT schedule.* FROM controllers 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 delete_by_uid( conn: &mut PoolConnection<Sqlite>, filter_uid: EmgauwaUid, ) -> Result<(), DatabaseError> { if sqlx::query_scalar!("SELECT 1 FROM controllers WHERE uid = ?", filter_uid) .fetch_optional(conn.deref_mut()) .await? .is_none() { return Err(DatabaseError::NotFound); } sqlx::query!("DELETE FROM controllers WHERE uid = ?", filter_uid) .execute(conn.deref_mut()) .await .map(|res| match res.rows_affected() { 0 => Err(DatabaseError::DeleteError), _ => Ok(()), })? } pub async fn create( conn: &mut PoolConnection<Sqlite>, new_uid: &EmgauwaUid, new_name: &str, new_relay_count: i64, ) -> Result<DbController, DatabaseError> { sqlx::query_as!( DbController, "INSERT INTO controllers (uid, name, relay_count) VALUES (?, ?, ?) RETURNING *", new_uid, new_name, new_relay_count, ) .fetch_optional(conn.deref_mut()) .await? .ok_or(DatabaseError::InsertGetError) } pub async fn update( &self, conn: &mut PoolConnection<Sqlite>, new_name: &str, new_relay_count: i64, ) -> Result<DbController, DatabaseError> { sqlx::query!( "UPDATE controllers SET name = ?, relay_count = ? WHERE id = ?", new_name, new_relay_count, self.id, ) .execute(conn.deref_mut()) .await?; Self::get(conn, self.id) .await? .ok_or(DatabaseError::UpdateGetError) } pub async fn update_active( &self, conn: &mut PoolConnection<Sqlite>, new_active: bool, ) -> Result<DbController, DatabaseError> { sqlx::query!( "UPDATE controllers SET active = ? WHERE id = ?", new_active, self.id, ) .execute(conn.deref_mut()) .await?; Self::get(conn, self.id) .await? .ok_or(DatabaseError::UpdateGetError) } pub async fn get_relays( &self, conn: &mut PoolConnection<Sqlite>, ) -> Result<Vec<DbRelay>, DatabaseError> { sqlx::query_as!( DbRelay, "SELECT * FROM relays WHERE controller_id = ?", self.id ) .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn all_inactive(conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> { sqlx::query!("UPDATE controllers SET active = 0") .execute(conn.deref_mut()) .await?; Ok(()) } pub async fn reload( &self, conn: &mut PoolConnection<Sqlite>, ) -> Result<DbController, DatabaseError> { Self::get(conn, self.id) .await? .ok_or(DatabaseError::NotFound) } }