Migrate product photo db
This commit is contained in:
parent
500dac9b2e
commit
e426fd5f31
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user