use chrono::NaiveDate;
use diesel::{
debug_query, pg::Pg, BoolExpressionMethods, ExpressionMethods, QueryDsl, QueryResult,
};
use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
use log::debug;
use uuid::Uuid;
use crate::{
model::{
dto::areas::{AreaDto, AreaKind},
entity::areas::{
Hydrology, Shading, SoilTexture, UpdateHydrology, UpdateShading, UpdateSoilTexture,
},
},
schema::{hydrologies, shadings, soil_textures},
};
pub struct FindAreaParameters {
pub area_kind: AreaKind,
pub layer_id: Option<Uuid>,
pub from: NaiveDate,
pub to: NaiveDate,
}
pub async fn find_area(
search_parameters: FindAreaParameters,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
match search_parameters.area_kind {
AreaKind::Shade => {
let mut query = shadings::table.select(shadings::all_columns).into_boxed();
if let Some(id) = search_parameters.layer_id {
query = query.filter(shadings::layer_id.eq(id));
}
let added_before_date = shadings::add_date
.is_null()
.or(shadings::add_date.lt(search_parameters.to));
let removed_after_date = shadings::remove_date
.is_null()
.or(shadings::remove_date.gt(search_parameters.from));
query = query.filter(added_before_date.and(removed_after_date));
debug!("{}", debug_query::<Pg, _>(&query));
Ok(query
.load::<Shading>(conn)
.await?
.into_iter()
.map(Into::into)
.collect())
}
AreaKind::Hydrology => {
let mut query = hydrologies::table
.select(hydrologies::all_columns)
.into_boxed();
if let Some(id) = search_parameters.layer_id {
query = query.filter(hydrologies::layer_id.eq(id));
}
let added_before_date = hydrologies::add_date
.is_null()
.or(hydrologies::add_date.lt(search_parameters.to));
let removed_after_date = hydrologies::remove_date
.is_null()
.or(hydrologies::remove_date.gt(search_parameters.from));
query = query.filter(added_before_date.and(removed_after_date));
debug!("{}", debug_query::<Pg, _>(&query));
Ok(query
.load::<Hydrology>(conn)
.await?
.into_iter()
.map(Into::into)
.collect())
}
AreaKind::SoilTexture => {
let mut query = soil_textures::table
.select(soil_textures::all_columns)
.into_boxed();
if let Some(id) = search_parameters.layer_id {
query = query.filter(soil_textures::layer_id.eq(id));
}
let added_before_date = soil_textures::add_date
.is_null()
.or(soil_textures::add_date.lt(search_parameters.to));
let removed_after_date = soil_textures::remove_date
.is_null()
.or(soil_textures::remove_date.gt(search_parameters.from));
query = query.filter(added_before_date.and(removed_after_date));
debug!("{}", debug_query::<Pg, _>(&query));
Ok(query
.load::<SoilTexture>(conn)
.await?
.into_iter()
.map(Into::into)
.collect())
}
}
}
pub async fn create_shadings(
new_shadings: Vec<Shading>,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
let query = diesel::insert_into(shadings::table).values(&new_shadings);
debug!("{}", debug_query::<Pg, _>(&query));
let shadings = query
.get_results::<Shading>(conn)
.await?
.into_iter()
.map(Into::into)
.collect::<Vec<AreaDto>>();
Ok(shadings)
}
pub async fn create_hydrologies(
new_hydrologies: Vec<Hydrology>,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
let query = diesel::insert_into(hydrologies::table).values(&new_hydrologies);
debug!("{}", debug_query::<Pg, _>(&query));
let hydrologies = query
.get_results::<Hydrology>(conn)
.await?
.into_iter()
.map(Into::into)
.collect::<Vec<AreaDto>>();
Ok(hydrologies)
}
pub async fn create_soil_textures(
new_soil_textures: Vec<SoilTexture>,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
let query = diesel::insert_into(soil_textures::table).values(&new_soil_textures);
debug!("{}", debug_query::<Pg, _>(&query));
let soil_textures = query
.get_results::<SoilTexture>(conn)
.await?
.into_iter()
.map(Into::into)
.collect::<Vec<AreaDto>>();
Ok(soil_textures)
}
pub async fn update_shadings(
updates: Vec<UpdateShading>,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
conn.transaction(|transaction| {
Box::pin(async {
let mut results = Vec::with_capacity(updates.len());
for update in updates {
results.push(AreaDto::from(
diesel::update(shadings::table.find(update.id))
.set(update)
.get_result::<Shading>(transaction)
.await?,
));
}
Ok(results) as QueryResult<Vec<AreaDto>>
})
})
.await
}
pub async fn update_hydrologies(
updates: Vec<UpdateHydrology>,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
conn.transaction(|transaction| {
Box::pin(async {
let mut results = Vec::with_capacity(updates.len());
for update in updates {
results.push(AreaDto::from(
diesel::update(hydrologies::table.find(update.id))
.set(update)
.get_result::<Hydrology>(transaction)
.await?,
));
}
Ok(results) as QueryResult<Vec<AreaDto>>
})
})
.await
}
pub async fn update_soil_textures(
updates: Vec<UpdateSoilTexture>,
conn: &mut AsyncPgConnection,
) -> QueryResult<Vec<AreaDto>> {
conn.transaction(|transaction| {
Box::pin(async {
let mut results = Vec::with_capacity(updates.len());
for update in updates {
results.push(AreaDto::from(
diesel::update(soil_textures::table.find(update.id))
.set(update)
.get_result::<SoilTexture>(transaction)
.await?,
));
}
Ok(results) as QueryResult<Vec<AreaDto>>
})
})
.await
}
pub async fn delete_areas_by_ids(
area_kind: AreaKind,
ids: Vec<Uuid>,
conn: &mut AsyncPgConnection,
) -> QueryResult<usize> {
let result = match area_kind {
AreaKind::Shade => {
let query = diesel::delete(shadings::table.filter(shadings::id.eq_any(ids)));
debug!("{}", debug_query::<Pg, _>(&query));
query.execute(conn).await?
}
AreaKind::Hydrology => {
let query = diesel::delete(hydrologies::table.filter(hydrologies::id.eq_any(ids)));
debug!("{}", debug_query::<Pg, _>(&query));
query.execute(conn).await?
}
AreaKind::SoilTexture => {
let query = diesel::delete(soil_textures::table.filter(soil_textures::id.eq_any(ids)));
debug!("{}", debug_query::<Pg, _>(&query));
query.execute(conn).await?
}
};
Ok(result)
}