use diesel_async::AsyncPgConnection;
use reqwest::StatusCode;
use uuid::Uuid;
use crate::model::dto::actions::{ActionType, RestoreDrawingLayerActionPayload};
use crate::model::dto::drawings::DrawingDto;
use crate::model::dto::layers::UpdateLayerDto;
use crate::model::entity::drawings::Drawing;
use crate::model::entity::Map;
use crate::model::r#enum::layer_type::LayerType;
use crate::{
config::data::SharedPool,
error::ServiceError,
model::{
dto::layers::{LayerDto, LayerSearchParameters},
entity::layers::Layer,
},
};
pub async fn find(
search_parameters: LayerSearchParameters,
pool: &SharedPool,
) -> Result<Vec<LayerDto>, ServiceError> {
let mut conn = pool.get().await?;
let result = Layer::find(search_parameters, &mut conn).await?;
Ok(result)
}
pub async fn find_by_id(id: Uuid, pool: &SharedPool) -> Result<LayerDto, ServiceError> {
let mut conn = pool.get().await?;
let result = Layer::find_by_id(id, &mut conn).await?;
Ok(result.into())
}
pub async fn create(
map_id: i32,
new_layer: LayerDto,
pool: &SharedPool,
) -> Result<LayerDto, ServiceError> {
let mut conn = pool.get().await?;
_ = Map::find_by_id(map_id, &mut conn).await?;
let result = Layer::create(map_id, new_layer, &mut conn).await?;
Ok(result)
}
async fn assert_layer_on_map(
map_id: i32,
layer_id: Uuid,
conn: &mut AsyncPgConnection,
) -> Result<(), ServiceError> {
let layer = Layer::find_by_id(layer_id, conn).await?;
if layer.map_id != map_id {
return Err(ServiceError::new(
StatusCode::CONFLICT,
"map_id of path and dto doesn't match",
));
}
Ok(())
}
async fn assert_all_layers_on_map(
map_id: i32,
layer_ids: &[Uuid],
conn: &mut AsyncPgConnection,
) -> Result<(), ServiceError> {
let layer_ids_in_map: Vec<Uuid> = Layer::find(
LayerSearchParameters {
map_id: Some(map_id),
type_: None,
is_alternative: None,
only_non_deleted: Some(()),
},
conn,
)
.await?
.into_iter()
.map(|layer| layer.id)
.collect();
for layer_id in layer_ids {
if !layer_ids_in_map.contains(layer_id) {
return Err(ServiceError::new(
StatusCode::CONFLICT,
"map_id of path and dto doesn't match",
));
}
}
Ok(())
}
pub async fn update(
map_id: i32,
update: UpdateLayerDto,
pool: &SharedPool,
) -> Result<ActionType, ServiceError> {
let mut conn = pool.get().await?;
let action = match update {
UpdateLayerDto::Rename(dto) => {
assert_layer_on_map(map_id, dto.id, &mut conn).await?;
Layer::rename(dto.clone(), &mut conn).await?;
ActionType::RenameLayer(dto)
}
UpdateLayerDto::Reorder(new_order) => {
assert_all_layers_on_map(map_id, &new_order, &mut conn).await?;
Layer::reorder(new_order.clone(), &mut conn).await?;
ActionType::ReorderLayers(new_order)
}
UpdateLayerDto::RestoreDrawingLayer(dto) => {
assert_layer_on_map(map_id, dto.id, &mut conn).await?;
let layer = Layer::find_by_id(dto.id, &mut conn).await?;
if layer.marked_deleted.is_none() {
return Err(ServiceError::new(
StatusCode::CONFLICT,
"layer is not marked deleted",
));
}
Layer::restore(map_id, dto.id, &mut conn).await?;
let drawings = Drawing::find_in_layer(dto.id, &mut conn).await?;
let drawing_dtos = drawings
.into_iter()
.map(DrawingDto::try_from)
.collect::<Result<Vec<DrawingDto>, ServiceError>>()?;
ActionType::RestoreDrawingLayer(RestoreDrawingLayerActionPayload::new(
dto.id,
drawing_dtos,
))
}
};
Ok(action)
}
pub async fn delete_by_id(
map_id: i32,
layer_id: Uuid,
pool: &SharedPool,
) -> Result<(), ServiceError> {
let mut conn = pool.get().await?;
let layer = Layer::find_by_id(layer_id, &mut conn).await?;
if layer.type_ != LayerType::Drawing {
return Err(ServiceError::new(
StatusCode::FORBIDDEN,
"can only delete drawing layer",
));
}
Layer::delete(map_id, layer_id, &mut conn).await?;
Ok(())
}