Migrate product photo db

This commit is contained in:
eraden 2022-11-10 06:52:48 +01:00
parent 500dac9b2e
commit e426fd5f31
2 changed files with 195 additions and 4 deletions

View File

@ -1 +1,192 @@
use db_utils::PgT;
use model::v2::*; use model::v2::*;
use crate::db::products::AllProducts;
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, thiserror::Error)]
pub enum Error {
#[error("Failed to attach photo to product")]
Create,
#[error("Failed to load all product photos")]
All,
#[error("Failed to delete product photo {0:?}")]
Delete(ProductPhotoId),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct AllProductPhotos {
pub limit: Option<i32>,
pub offset: Option<i32>,
}
impl AllProductPhotos {
pub async fn run(self, pool: &mut PgT<'_>) -> Result<Vec<ProductPhoto>> {
sqlx::query_as(
r#"
SELECT id, product_variant_id, photo_id
FROM product_photos
ORDER BY id ASC
LIMIT $1 OFFSET $2
"#,
)
.bind(self.limit)
.bind(self.offset)
.fetch_all(pool)
.await
.map_err(|e| {
tracing::error!("{e:?}");
Error::All
})
}
}
#[derive(Debug)]
pub struct CreateProductPhoto {
pub product_variant_id: ProductVariantId,
pub photo_id: PhotoId,
}
impl CreateProductPhoto {
pub async fn run(self, pool: &mut PgT<'_>) -> Result<ProductPhoto> {
sqlx::query_as(
r#"
INSERT INTO product_photos(product_variant_id, photo_id)
VALUES ($1, $2)
RETURNING id, product_variant_id, photo_id
"#,
)
.bind(self.product_variant_id)
.bind(self.photo_id)
.fetch_one(pool)
.await
.map_err(|e| {
tracing::error!("{:?}", e);
Error::Create
})
}
}
#[derive(Debug)]
pub struct DeleteProductPhoto {
pub id: ProductPhotoId,
}
impl DeleteProductPhoto {
pub async fn run(self, pool: &mut PgT<'_>) -> Result<Option<ProductPhoto>> {
sqlx::query_as(
r#"
DELETE FROM product_photos
WHERE id = $1
RETURNING id, product_variant_id, photo_id
"#,
)
.bind(self.id)
.fetch_optional(pool)
.await
.map_err(|e| {
tracing::error!("{:?}", e);
Error::Delete(self.id)
})
}
}
#[cfg(test)]
mod tests {
use config::UpdateConfig;
use model::v2::*;
use model::Day;
use uuid::Uuid;
use crate::db::product_variants::CreateProductVariant;
pub struct NoOpts;
impl UpdateConfig for NoOpts {}
use super::*;
use crate::db::products::*;
async fn test_product(t: &mut PgT<'_>) -> Product {
CreateProduct {
name: ProductName::new(format!("{}", Uuid::new_v4())),
category: None,
deliver_days_flag: Days(vec![Day::Friday, Day::Sunday]),
}
.run(t)
.await
.unwrap()
}
async fn test_product_variant(product_id: ProductId, t: &mut PgT<'_>) -> ProductVariant {
CreateProductVariant {
product_id,
name: ProductName::new(format!("{}", Uuid::new_v4())),
short_description: ProductShortDesc::new("ajs9d8ua9sdu9ahsd98has"),
long_description: ProductLongDesc::new("hja89sdy9yha9sdy98ayusd9hya9sy8dh"),
price: Default::default(),
}
.run(t)
.await
.unwrap()
}
async fn test_photo(t: &mut PgT<'_>) -> Photo {
CreatePhoto {
local_path: LocalPath::new(format!("{}", Uuid::new_v4())),
file_name: FileName::new(format!("{}", Uuid::new_v4())),
unique_name: UniqueName::new(format!("{}", Uuid::new_v4())),
}
.run(t)
.await
.unwrap()
}
async fn test_product_photo(t: &mut PgT<'_>) -> ProductPhoto {
let product = test_product(t).await;
let product_variant = test_product_variant(product.id, t).await;
let photo = test_photo(t).await;
CreateProductPhoto {
product_variant_id: product_variant.id,
photo_id: photo.id,
}
.run(t)
.await
.unwrap()
}
#[actix::test]
async fn create_photo() {
testx::db_t_ref!(t);
test_product_photo(&mut t).await;
testx::db_rollback!(t);
}
#[actix::test]
async fn delete() {
testx::db_t_ref!(t);
let p1 = test_product_photo(&mut t).await;
let p2 = test_product_photo(&mut t).await;
let p3 = test_product_photo(&mut t).await;
let deleted = DeleteProductPhoto { id: p2.id }.run(&mut t).await.unwrap();
testx::db_rollback!(t);
assert_ne!(deleted, Some(p1));
assert_eq!(deleted, Some(p2));
assert_ne!(deleted, Some(p3));
}
#[actix::test]
async fn create() {
testx::db_t_ref!(t);
test_product_photo(&mut t).await;
testx::db_rollback!(t);
}
}

View File

@ -28,7 +28,7 @@ pub struct AllProducts {
} }
impl AllProducts { impl AllProducts {
pub async fn run<'e, E>(self, pool: E) -> Result<Vec<model::Product>> pub async fn run<'e, E>(self, pool: E) -> Result<Vec<Product>>
where where
E: sqlx::Executor<'e, Database = sqlx::Postgres>, E: sqlx::Executor<'e, Database = sqlx::Postgres>,
{ {
@ -60,7 +60,7 @@ pub struct FindProduct {
} }
impl FindProduct { impl FindProduct {
pub async fn run<'e, E>(self, pool: E) -> Result<model::Product> pub async fn run<'e, E>(self, pool: E) -> Result<Product>
where where
E: sqlx::Executor<'e, Database = sqlx::Postgres>, E: sqlx::Executor<'e, Database = sqlx::Postgres>,
{ {
@ -92,7 +92,7 @@ pub struct CreateProduct {
} }
impl CreateProduct { impl CreateProduct {
pub async fn run<'e, E>(self, pool: E) -> Result<model::Product> pub async fn run<'e, E>(self, pool: E) -> Result<Product>
where where
E: sqlx::Executor<'e, Database = sqlx::Postgres>, E: sqlx::Executor<'e, Database = sqlx::Postgres>,
{ {
@ -264,7 +264,7 @@ WHERE
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use config::UpdateConfig; use config::UpdateConfig;
use model::*; use model::v2::*;
use uuid::Uuid; use uuid::Uuid;
pub struct NoOpts; pub struct NoOpts;