use std::ops::DerefMut; use serde_derive::{Deserialize, Serialize}; use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::{DbController, DbMacroAction, DbRelay, DbSchedule}; use crate::errors::DatabaseError; use crate::types::{EmgauwaUid, RequestMacroAction}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DbMacro { #[serde(skip)] pub id: i64, #[serde(rename = "id")] pub uid: EmgauwaUid, pub name: String, } impl DbMacro { pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbMacro>, DatabaseError> { sqlx::query_as!(DbMacro, "SELECT * FROM macros") .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get( conn: &mut PoolConnection<Sqlite>, id: i64, ) -> Result<Option<DbMacro>, DatabaseError> { sqlx::query_as!(DbMacro, "SELECT * FROM macros 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<DbMacro>, DatabaseError> { sqlx::query_as!(DbMacro, "SELECT * FROM macros WHERE uid = ?", filter_uid) .fetch_optional(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn create( conn: &mut PoolConnection<Sqlite>, new_uid: EmgauwaUid, new_name: &str, ) -> Result<DbMacro, DatabaseError> { sqlx::query_as!( DbMacro, "INSERT INTO macros (uid, name) VALUES (?, ?) RETURNING *", new_uid, new_name ) .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 macros WHERE id = ?", self.id) .execute(conn.deref_mut()) .await .map(|res| match res.rows_affected() { 0 => Err(DatabaseError::DeleteError), _ => Ok(()), })? } pub async fn delete_by_uid( conn: &mut PoolConnection<Sqlite>, filter_uid: EmgauwaUid, ) -> Result<(), DatabaseError> { if sqlx::query_scalar!("SELECT 1 FROM macros WHERE uid = ?", filter_uid) .fetch_optional(conn.deref_mut()) .await? .is_none() { return Err(DatabaseError::NotFound); } sqlx::query!("DELETE FROM macros WHERE uid = ?", filter_uid) .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, ) -> Result<DbMacro, DatabaseError> { sqlx::query!("UPDATE macros SET name = ? WHERE id = ?", new_name, self.id,) .execute(conn.deref_mut()) .await?; DbMacro::get(conn, self.id) .await? .ok_or(DatabaseError::UpdateGetError) } pub async fn set_actions( &self, conn: &mut PoolConnection<Sqlite>, new_actions: &[RequestMacroAction], ) -> Result<(), DatabaseError> { sqlx::query!("DELETE FROM macro_actions WHERE macro_id = ?", self.id) .execute(conn.deref_mut()) .await?; for new_action in new_actions { let controller = DbController::get_by_uid(conn, &new_action.relay.controller_id) .await? .ok_or(DatabaseError::NotFound)?; let relay = DbRelay::get_by_controller_and_num(conn, &controller, new_action.relay.number) .await? .ok_or(DatabaseError::NotFound)?; let schedule = DbSchedule::get_by_uid(conn, &new_action.schedule.id) .await? .ok_or(DatabaseError::NotFound)?; DbMacroAction::create(conn, self, &relay, &schedule, new_action.weekday).await?; } Ok(()) } pub async fn get_actions( &self, conn: &mut PoolConnection<Sqlite>, ) -> Result<Vec<DbMacroAction>, DatabaseError> { sqlx::query_as!( DbMacroAction, "SELECT * FROM macro_actions WHERE macro_id = ?", self.id ) .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } pub async fn get_actions_weekday( &self, conn: &mut PoolConnection<Sqlite>, weekday: i64, ) -> Result<Vec<DbMacroAction>, DatabaseError> { sqlx::query_as!( DbMacroAction, "SELECT * FROM macro_actions WHERE macro_id = ? AND weekday = ?", self.id, weekday ) .fetch_all(conn.deref_mut()) .await .map_err(DatabaseError::from) } }