use std::sync::Arc; use crate::ResultDbErrorExt; use async_trait::async_trait; use dao::{ booking::{BookingDao, BookingEntity}, DaoError, }; use sqlx::{query, query_as}; use time::{format_description::well_known::Iso8601, PrimitiveDateTime}; use uuid::Uuid; #[derive(Debug)] struct BookingDb { id: Vec, sales_person_id: Vec, slot_id: Vec, calendar_week: i64, year: i64, created: String, deleted: Option, update_version: Vec, } impl TryFrom<&BookingDb> for BookingEntity { type Error = DaoError; fn try_from(booking: &BookingDb) -> Result { Ok(Self { id: Uuid::from_slice(booking.id.as_ref()).unwrap(), sales_person_id: Uuid::from_slice(booking.sales_person_id.as_ref()).unwrap(), slot_id: Uuid::from_slice(booking.slot_id.as_ref()).unwrap(), calendar_week: booking.calendar_week as i32, year: booking.year as u32, created: PrimitiveDateTime::parse(&booking.created, &Iso8601::DATE_TIME)?, deleted: booking .deleted .as_ref() .map(|deleted| PrimitiveDateTime::parse(deleted, &Iso8601::DATE_TIME)) .transpose()?, version: Uuid::from_slice(&booking.update_version).unwrap(), }) } } pub struct BookingDaoImpl { pub pool: Arc, } impl BookingDaoImpl { pub fn new(pool: Arc) -> Self { Self { pool } } } #[async_trait] impl BookingDao for BookingDaoImpl { async fn all(&self) -> Result, DaoError> { Ok(query_as!( BookingDb, "SELECT id, sales_person_id, slot_id, calendar_week, year, created, deleted, update_version FROM booking WHERE deleted IS NULL" ) .fetch_all(self.pool.as_ref()) .await .map_db_error()? .iter() .map(BookingEntity::try_from) .collect::, DaoError>>()? ) } async fn find_by_id(&self, id: Uuid) -> Result, DaoError> { let id_vec = id.as_bytes().to_vec(); Ok(query_as!( BookingDb, "SELECT id, sales_person_id, slot_id, calendar_week, year, created, deleted, update_version FROM booking WHERE id = ?", id_vec, ) .fetch_optional(self.pool.as_ref()) .await .map_db_error()? .as_ref() .map(BookingEntity::try_from) .transpose()?) } async fn find_by_booking_data( &self, sales_person_id: Uuid, slot_id: Uuid, calendar_week: i32, year: u32, ) -> Result, DaoError> { let sales_person_id_vec = sales_person_id.as_bytes().to_vec(); let slot_id_vec = slot_id.as_bytes().to_vec(); Ok(query_as!( BookingDb, "SELECT id, sales_person_id, slot_id, calendar_week, year, created, deleted, update_version FROM booking WHERE sales_person_id = ? AND slot_id = ? AND calendar_week = ? AND year = ? AND deleted IS NULL", sales_person_id_vec, slot_id_vec, calendar_week, year, ) .fetch_optional(self.pool.as_ref()) .await .map_db_error()? .as_ref() .map(BookingEntity::try_from) .transpose()?) } async fn find_by_week( &self, calendar_week: u8, year: u32, ) -> Result, DaoError> { Ok(query_as!( BookingDb, "SELECT id, sales_person_id, slot_id, calendar_week, year, created, deleted, update_version FROM booking WHERE calendar_week = ? AND year = ? AND deleted IS NULL", calendar_week, year, ) .fetch_all(self.pool.as_ref()) .await .map_db_error()? .iter() .map(BookingEntity::try_from) .collect::, DaoError>>()? ) } async fn create(&self, entity: &BookingEntity, process: &str) -> Result<(), DaoError> { let id_vec = entity.id.as_bytes().to_vec(); let sales_person_id_vec = entity.sales_person_id.as_bytes().to_vec(); let slot_id_vec = entity.slot_id.as_bytes().to_vec(); let created = entity.created.format(&Iso8601::DATE_TIME).map_db_error()?; let deleted = entity .deleted .as_ref() .map(|deleted| deleted.format(&Iso8601::DATE_TIME)) .transpose() .map_db_error()?; let version_vec = entity.version.as_bytes().to_vec(); query!("INSERT INTO booking (id, sales_person_id, slot_id, calendar_week, year, created, deleted, update_version, update_process) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", id_vec, sales_person_id_vec, slot_id_vec, entity.calendar_week, entity.year, created, deleted, version_vec, process ).execute(self.pool.as_ref()).await.map_db_error()?; Ok(()) } async fn update(&self, entity: &BookingEntity, process: &str) -> Result<(), DaoError> { let id_vec = entity.id.as_bytes().to_vec(); let version_vec = entity.version.as_bytes().to_vec(); let deleted = entity .deleted .as_ref() .map(|deleted| deleted.format(&Iso8601::DATE_TIME)) .transpose() .map_db_error()?; query!( "UPDATE booking SET deleted = ?, update_version = ?, update_process = ? WHERE id = ?", deleted, version_vec, process, id_vec ) .execute(self.pool.as_ref()) .await .map_db_error()?; Ok(()) } }