use chrono::{NaiveDate, NaiveTime}; use sqlx::{query, PgPool}; use super::{function::Function, role::Role, user::User, Area}; #[derive(Clone)] pub struct Availabillity { pub id: i32, pub user_id: i32, pub user: Option, pub date: NaiveDate, pub start_time: Option, pub end_time: Option, pub comment: Option, } impl Availabillity { pub async fn create( pool: &PgPool, user_id: i32, date: NaiveDate, start_time: Option, end_time: Option, comment: Option, ) -> anyhow::Result { let result = match (start_time, end_time, comment) { (Some(start_time), Some(end_time), Some(comment)) => query!("INSERT INTO availabillity (userId, date, startTime, endTime, comment) VALUES ($1, $2, $3, $4, $5) RETURNING id;", user_id, date, start_time, end_time, comment).fetch_one(pool).await?.id, (Some(start_time), Some(end_time), None) => query!("INSERT INTO availabillity (userId, date, startTime, endTime) VALUES ($1, $2, $3, $4) RETURNING id;", user_id, date, start_time, end_time).fetch_one(pool).await?.id, (None, None, Some(comment)) => query!("INSERT INTO availabillity (userId, date, comment) VALUES ($1, $2, $3) RETURNING id;", user_id, date, comment).fetch_one(pool).await?.id, (_, _, _) => query!("INSERT INTO availabillity (userId, date) VALUES ($1, $2) RETURNING id;", user_id, date).fetch_one(pool).await?.id }; Ok(result) } pub async fn read_by_date_and_area_including_user( pool: &PgPool, date: NaiveDate, area_id: i32 ) -> anyhow::Result> { let records = query!( r##" SELECT availabillity.id, availabillity.userId, availabillity.date, availabillity.startTime, availabillity.endTime, availabillity.comment, user_.name, user_.email, user_.password, user_.salt, user_.role AS "role: Role", user_.function AS "function: Function", user_.areaId, user_.locked, user_.lastLogin, user_.receiveNotifications FROM availabillity JOIN user_ ON availabillity.userId = user_.id WHERE availabillity.date = $1 AND user_.areaId = $2; "##, date, area_id ) .fetch_all(pool) .await?; let availabillities = records .iter() .map(|r| Availabillity { id: r.id, user_id: r.userid, user: Some(User { id: r.userid, name: r.name.clone(), email: r.email.clone(), password: r.password.clone(), salt: r.salt.clone(), role: r.role.clone(), function: r.function.clone(), area_id: r.areaid, area: None, locked: r.locked, last_login: r.lastlogin, receive_notifications: r.receivenotifications, }), date: r.date, start_time: r.starttime, end_time: r.endtime, comment: r.comment.clone(), }) .collect(); Ok(availabillities) } pub async fn read_not_assigned_by_date_including_user( pool: &PgPool, date: NaiveDate, ) -> anyhow::Result> { let records = query!( r##" SELECT availabillity.id, availabillity.userId, availabillity.date, availabillity.startTime, availabillity.endTime, availabillity.comment, user_.name, user_.email, user_.password, user_.salt, user_.role AS "role: Role", user_.function AS "function: Function", user_.areaId, user_.locked, user_.lastLogin, user_.receiveNotifications FROM availabillity LEFT JOIN assignment ON availabillity.Id = assignment.availabillityId JOIN user_ ON availabillity.userId = user_.id WHERE availabillity.date = $1; "##, date ) .fetch_all(pool) .await?; let availabillities = records .iter() .map(|r| Availabillity { id: r.id, user_id: r.userid, user: Some(User { id: r.userid, name: r.name.clone(), email: r.email.clone(), password: r.password.clone(), salt: r.salt.clone(), role: r.role.clone(), function: r.function.clone(), area_id: r.areaid, area: None, locked: r.locked, last_login: r.lastlogin, receive_notifications: r.receivenotifications, }), date: r.date, start_time: r.starttime, end_time: r.endtime, comment: r.comment.clone(), }) .collect(); Ok(availabillities) } pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result { let record = query!("SELECT * FROM availabillity WHERE id = $1", id) .fetch_one(pool) .await?; let availabillity = Availabillity { id: record.id, user_id: record.userid, user: None, date: record.date, start_time: record.starttime, end_time: record.endtime, comment: record.comment.clone(), }; Ok(availabillity) } pub async fn read_for_export( pool: &PgPool, date_range: (NaiveDate, NaiveDate), area_id: i32, ) -> anyhow::Result> { let records = query!( r##" SELECT availabillity.id, availabillity.userId, availabillity.date, availabillity.startTime, availabillity.endTime, availabillity.comment, user_.name, user_.email, user_.password, user_.salt, user_.role AS "role: Role", user_.function AS "function: Function", user_.areaId, user_.locked, user_.lastLogin, user_.receiveNotifications, area.name AS areaName FROM availabillity JOIN user_ ON availabillity.userId = user_.id JOIN area ON user_.areaId = area.id WHERE user_.areaId = $1 AND availabillity.date >= $2 AND availabillity.date <= $3; "##, area_id, date_range.0, date_range.1 ) .fetch_all(pool) .await?; let availabillities = records .iter() .map(|r| Availabillity { id: r.id, user_id: r.userid, user: Some(User { id: r.userid, name: r.name.clone(), email: r.email.clone(), password: r.password.clone(), salt: r.salt.clone(), role: r.role.clone(), function: r.function.clone(), area_id: r.areaid, area: Some(Area { id: r.areaid, name: r.areaname.clone(), }), locked: r.locked, last_login: r.lastlogin, receive_notifications: r.receivenotifications, }), date: r.date, start_time: r.starttime, end_time: r.endtime, comment: r.comment.clone(), }) .collect(); Ok(availabillities) } pub async fn update( pool: &PgPool, id: i32, updated_availabillity: &Availabillity, ) -> anyhow::Result<()> { query!( "UPDATE availabillity SET startTime = $1, endTime = $2, comment = $3 WHERE id = $4", updated_availabillity.start_time, updated_availabillity.end_time, updated_availabillity.comment, id ) .execute(pool) .await?; Ok(()) } pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<()> { query!("DELETE FROM availabillity WHERE id = $1", id) .execute(pool) .await?; Ok(()) } }