Load single product
This commit is contained in:
parent
c7e9b25b97
commit
7bec8534e4
@ -10,9 +10,7 @@ pub mod detailed_product {
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Output2 {
|
||||
pub product: model::Product,
|
||||
pub stocks: Vec<Stock>,
|
||||
pub photos: Vec<Photo>,
|
||||
pub product: DetailedProduct,
|
||||
}
|
||||
|
||||
pub type Output = Result<Output2, Error>;
|
||||
|
@ -18,6 +18,8 @@ pub static CLIENT_NAME: &str = "stocks";
|
||||
pub enum Error {
|
||||
#[error("Something went wrong")]
|
||||
InternalServerError,
|
||||
#[error("Failed to load product {0:?}")]
|
||||
ProductNotFound(ProductId),
|
||||
#[error("Failed to load products")]
|
||||
Products,
|
||||
#[error("Failed to load products for products {0:?}")]
|
||||
|
@ -1,21 +1,67 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use channels::stocks::{detailed_product, detailed_products};
|
||||
use channels::stocks::{detailed_product, detailed_products, Error};
|
||||
use channels::AsyncClient;
|
||||
use config::SharedAppConfig;
|
||||
use db_utils::PgT;
|
||||
use model::v2::{DetailedProduct, DetailedProductVariant, Product, ProductVariant};
|
||||
use model::Limit;
|
||||
|
||||
use crate::db::{Database, PhotosForProductVariants, ProductVariantsStock, ProductsVariants};
|
||||
use crate::{begin_t, dbm_run};
|
||||
|
||||
pub async fn detailed_product(
|
||||
_input: detailed_product::Input,
|
||||
_db: Database,
|
||||
input: detailed_product::Input,
|
||||
db: Database,
|
||||
_mqtt: AsyncClient,
|
||||
_config: SharedAppConfig,
|
||||
) -> detailed_product::Output {
|
||||
todo!()
|
||||
let mut t = begin_t!(db, Error::InternalServerError);
|
||||
|
||||
let res = inner_detailed_product(input, &mut t, Some(_mqtt), Some(_config)).await;
|
||||
|
||||
t.commit().await.ok();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
async fn inner_detailed_product(
|
||||
input: detailed_product::Input,
|
||||
t: &mut PgT<'_>,
|
||||
_mqtt: Option<AsyncClient>,
|
||||
_config: Option<SharedAppConfig>,
|
||||
) -> detailed_product::Output {
|
||||
let dbm = crate::db::FindProduct {
|
||||
product_id: input.product_id,
|
||||
};
|
||||
let product = dbm_run!(dbm, &mut *t, Error::ProductNotFound(input.product_id));
|
||||
let dbm = ProductsVariants {
|
||||
product_ids: vec![input.product_id],
|
||||
limit: Some(10.into()),
|
||||
offset: Some(0.into()),
|
||||
};
|
||||
let variants = dbm_run!(dbm, &mut *t, Error::ProductVariants(vec![input.product_id]));
|
||||
let dbm = ProductVariantsStock {
|
||||
product_variant_ids: variants.iter().map(|p| p.id).collect(),
|
||||
};
|
||||
let stocks = dbm_run!(
|
||||
dbm,
|
||||
t,
|
||||
Error::VariantStocks(variants.into_iter().map(|p| p.id).collect())
|
||||
);
|
||||
let dbm = PhotosForProductVariants {
|
||||
product_variant_ids: variants.iter().map(|p| p.id).collect(),
|
||||
};
|
||||
let photos = dbm_run!(
|
||||
dbm,
|
||||
t,
|
||||
Error::VariantPhotos(variants.into_iter().map(|p| p.id).collect())
|
||||
);
|
||||
|
||||
let mut variants = utils::vec_to_hash_vec(variants, 10, |p| p.product_id);
|
||||
let mut stocks = utils::vec_to_hash_vec(stocks, 10, |s| s.product_variant_id);
|
||||
let mut photos = utils::vec_to_hash_vec(photos, 10, |p| p.product_variant_id);
|
||||
|
||||
let product = utils::map_product(product, &mut variants, &mut stocks, &mut photos);
|
||||
|
||||
Ok(detailed_product::Output2 { product })
|
||||
}
|
||||
|
||||
pub async fn detailed_products(
|
||||
@ -24,13 +70,7 @@ pub async fn detailed_products(
|
||||
_mqtt: AsyncClient,
|
||||
_config: SharedAppConfig,
|
||||
) -> detailed_products::Output {
|
||||
let mut t = match db.pool().begin().await {
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err(detailed_products::Error::InternalServerError);
|
||||
}
|
||||
Ok(t) => t,
|
||||
};
|
||||
let mut t = begin_t!(db, Error::InternalServerError);
|
||||
|
||||
let res = inner_detailed_products(input, &mut t, Some(_mqtt), Some(_config)).await;
|
||||
|
||||
@ -49,27 +89,17 @@ async fn inner_detailed_products(
|
||||
limit: input.limit,
|
||||
offset: input.offset,
|
||||
};
|
||||
let products = match dbm.run(&mut *t).await {
|
||||
Ok(products) => products,
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err(detailed_products::Error::Products);
|
||||
}
|
||||
};
|
||||
let products = dbm_run!(dbm, &mut *t, Error::Products);
|
||||
let dbm = ProductsVariants {
|
||||
product_ids: products.iter().map(|p| p.id).collect(),
|
||||
limit: Some(Limit::from_u32(products.len() as u32 * 10)),
|
||||
offset: Some(0.into()),
|
||||
};
|
||||
let variants = match dbm.run(&mut *t).await {
|
||||
Ok(variants) => variants,
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err(detailed_products::Error::ProductVariants(
|
||||
products.into_iter().map(|p| p.id).collect(),
|
||||
));
|
||||
}
|
||||
};
|
||||
let variants = dbm_run!(
|
||||
dbm,
|
||||
&mut *t,
|
||||
Error::ProductVariants(products.into_iter().map(|p| p.id).collect(),)
|
||||
);
|
||||
let dbm = ProductVariantsStock {
|
||||
product_variant_ids: variants.iter().map(|p| p.id).collect(),
|
||||
};
|
||||
@ -77,7 +107,7 @@ async fn inner_detailed_products(
|
||||
Ok(stocks) => stocks,
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err(detailed_products::Error::VariantStocks(
|
||||
return Err(Error::VariantStocks(
|
||||
variants.into_iter().map(|p| p.id).collect(),
|
||||
));
|
||||
}
|
||||
@ -89,89 +119,88 @@ async fn inner_detailed_products(
|
||||
Ok(photos) => photos,
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err(detailed_products::Error::VariantPhotos(
|
||||
return Err(Error::VariantPhotos(
|
||||
variants.into_iter().map(|p| p.id).collect(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut variants = {
|
||||
let len = variants.len();
|
||||
variants
|
||||
.into_iter()
|
||||
.fold(HashMap::with_capacity(len), |mut h, variant| {
|
||||
h.entry(variant.product_id)
|
||||
.or_insert_with(|| Vec::with_capacity(10))
|
||||
.push(variant);
|
||||
h
|
||||
})
|
||||
};
|
||||
|
||||
let mut stocks = {
|
||||
let len = stocks.len();
|
||||
stocks
|
||||
.into_iter()
|
||||
.fold(HashMap::with_capacity(len), |mut h, stock| {
|
||||
h.entry(stock.product_variant_id)
|
||||
.or_insert_with(|| Vec::with_capacity(10))
|
||||
.push(stock);
|
||||
h
|
||||
})
|
||||
};
|
||||
|
||||
let mut photos =
|
||||
photos
|
||||
.into_iter()
|
||||
.fold(HashMap::with_capacity(stocks.len()), |mut h, photo| {
|
||||
h.entry(photo.product_variant_id)
|
||||
.or_insert_with(|| Vec::with_capacity(10))
|
||||
.push(photo);
|
||||
h
|
||||
});
|
||||
let mut variants = utils::vec_to_hash_vec(variants, 10, |p| p.product_id);
|
||||
let mut stocks = utils::vec_to_hash_vec(stocks, 10, |s| s.product_variant_id);
|
||||
let mut photos = utils::vec_to_hash_vec(photos, 10, |p| p.product_variant_id);
|
||||
|
||||
let products = products
|
||||
.into_iter()
|
||||
.map(
|
||||
|Product {
|
||||
id,
|
||||
name,
|
||||
category,
|
||||
deliver_days_flag,
|
||||
}| DetailedProduct {
|
||||
id,
|
||||
name,
|
||||
category,
|
||||
deliver_days_flag,
|
||||
variants: variants
|
||||
.remove(&id)
|
||||
.unwrap_or(vec![])
|
||||
.into_iter()
|
||||
.map(
|
||||
|ProductVariant {
|
||||
id,
|
||||
product_id: _,
|
||||
name,
|
||||
short_description,
|
||||
long_description,
|
||||
price,
|
||||
}| DetailedProductVariant {
|
||||
id,
|
||||
name,
|
||||
short_description,
|
||||
long_description,
|
||||
price,
|
||||
stocks: stocks.remove(&id).unwrap_or_default(),
|
||||
photos: photos.remove(&id).unwrap_or_default(),
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
.map(|product| utils::map_product(product, &mut variants, &mut stocks, &mut photos))
|
||||
.collect();
|
||||
|
||||
Ok(detailed_products::Details { products })
|
||||
}
|
||||
|
||||
mod utils {
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
use model::v2::*;
|
||||
|
||||
pub fn vec_to_hash_vec<Id: Hash + Eq, R, F: Fn(&R) -> Id>(
|
||||
v: Vec<R>,
|
||||
cap: usize,
|
||||
f: F,
|
||||
) -> HashMap<Id, Vec<R>> {
|
||||
let len = v.len();
|
||||
v.into_iter().fold(HashMap::with_capacity(len), |mut h, r| {
|
||||
h.entry(f(&r))
|
||||
.or_insert_with(|| Vec::with_capacity(cap))
|
||||
.push(r);
|
||||
h
|
||||
})
|
||||
}
|
||||
|
||||
pub fn map_product(
|
||||
product: Product,
|
||||
variants: &mut HashMap<ProductId, Vec<ProductVariant>>,
|
||||
stocks: &mut HashMap<ProductVariantId, Vec<Stock>>,
|
||||
photos: &mut HashMap<ProductVariantId, Vec<ProductLinkedPhoto>>,
|
||||
) -> DetailedProduct {
|
||||
let Product {
|
||||
id,
|
||||
name,
|
||||
category,
|
||||
deliver_days_flag,
|
||||
} = product;
|
||||
DetailedProduct {
|
||||
id,
|
||||
name,
|
||||
category,
|
||||
deliver_days_flag,
|
||||
variants: variants
|
||||
.remove(&id)
|
||||
.unwrap_or(vec![])
|
||||
.into_iter()
|
||||
.map(
|
||||
|ProductVariant {
|
||||
id,
|
||||
product_id: _,
|
||||
name,
|
||||
short_description,
|
||||
long_description,
|
||||
price,
|
||||
}| DetailedProductVariant {
|
||||
id,
|
||||
name,
|
||||
short_description,
|
||||
long_description,
|
||||
price,
|
||||
stocks: stocks.remove(&id).unwrap_or_default(),
|
||||
photos: photos.remove(&id).unwrap_or_default(),
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use channels::stocks::detailed_products;
|
||||
@ -313,6 +342,7 @@ mod tests {
|
||||
|
||||
assert_eq!(res.products.len(), 3);
|
||||
let product = res.products.remove(0);
|
||||
|
||||
assert_eq!(product.variants.len(), 3);
|
||||
for variant in product.variants {
|
||||
assert_eq!(variant.photos.len(), 3);
|
||||
|
@ -9,3 +9,29 @@ pub use product::*;
|
||||
pub use product_photo::*;
|
||||
pub use product_stock::*;
|
||||
pub use product_variant::*;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! begin_t {
|
||||
($db: ident, $err: expr) => {
|
||||
match $db.pool().begin().await {
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err(detailed_products::Error::InternalServerError);
|
||||
}
|
||||
Ok(t) => t,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! dbm_run {
|
||||
($dbm: ident, $t: expr, $err: expr) => {
|
||||
match $dbm.run($t).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
tracing::error!("{}", e);
|
||||
return Err($err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user