From 95dcf0bae1c0160fb340f72217997930776495e2 Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Tue, 23 Jul 2024 19:18:58 +0530 Subject: [PATCH] feat: db port to check for duplicate order IDs --- .../adapters/output/db/order_id_exists.rs | 89 +++++++++++++++++++ .../application/port/output/db/errors.rs | 3 + .../application/port/output/db/mod.rs | 1 + .../port/output/db/order_id_exists.rs | 57 ++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 src/ordering/adapters/output/db/order_id_exists.rs create mode 100644 src/ordering/application/port/output/db/order_id_exists.rs diff --git a/src/ordering/adapters/output/db/order_id_exists.rs b/src/ordering/adapters/output/db/order_id_exists.rs new file mode 100644 index 0000000..9510030 --- /dev/null +++ b/src/ordering/adapters/output/db/order_id_exists.rs @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use uuid::Uuid; + +use super::OrderingDBPostgresAdapter; +use crate::ordering::application::port::output::db::{errors::*, order_id_exists::*}; + +#[async_trait::async_trait] +impl OrderIDExistsDBPort for OrderingDBPostgresAdapter { + async fn order_id_exists(&self, order_id: &Uuid) -> OrderingDBResult { + let res = sqlx::query!( + "SELECT EXISTS ( + SELECT 1 + FROM cqrs_ordering_order_query + WHERE + order_id = $1 + );", + order_id + ) + .fetch_one(&self.pool) + .await?; + if let Some(x) = res.exists { + Ok(x) + } else { + Ok(false) + } + } +} + +#[cfg(test)] +pub mod tests { + + use super::*; + // use crate::ordering::domain::add_order_command::tests::get_customizations; + use crate::ordering::domain::order_aggregate::*; + + async fn create_dummy_order(order: &Order, db: &OrderingDBPostgresAdapter) { + sqlx::query!( + "INSERT INTO cqrs_ordering_order_query ( + version, + order_id, + customer_name, + created_time, + deleted + ) VALUES ( + $1, $2, $3, $4, $5 + );", + 1, + order.order_id(), + order.customer_name(), + order.created_time(), + order.deleted().clone(), + ) + .execute(&db.pool) + .await + .unwrap(); + } + + #[actix_rt::test] + async fn test_postgres_order_exists() { + let settings = crate::settings::tests::get_settings().await; + settings.create_db().await; + let db = super::OrderingDBPostgresAdapter::new( + sqlx::postgres::PgPool::connect(&settings.database.url) + .await + .unwrap(), + ); + + let order = Order::default(); + + // state doesn't exist + assert!(!db + .order_id_exists(order.order_id()) + .await + .unwrap()); + + create_dummy_order(&order, &db).await; + + // state exists + assert!(db + .order_id_exists(order.order_id()) + .await + .unwrap()); + + settings.drop_db().await; + } +} diff --git a/src/ordering/application/port/output/db/errors.rs b/src/ordering/application/port/output/db/errors.rs index db03945..b383b4c 100644 --- a/src/ordering/application/port/output/db/errors.rs +++ b/src/ordering/application/port/output/db/errors.rs @@ -12,4 +12,7 @@ pub enum OrderingDBError { DuplicateLineItemID, LineItemIDNotFound, InternalError, + DuplicateOrderID, + OrderIDNotFound, + } diff --git a/src/ordering/application/port/output/db/mod.rs b/src/ordering/application/port/output/db/mod.rs index 7c397a6..2db807b 100644 --- a/src/ordering/application/port/output/db/mod.rs +++ b/src/ordering/application/port/output/db/mod.rs @@ -4,3 +4,4 @@ pub mod errors; pub mod line_item_id_exists; +pub mod order_id_exists; diff --git a/src/ordering/application/port/output/db/order_id_exists.rs b/src/ordering/application/port/output/db/order_id_exists.rs new file mode 100644 index 0000000..97e7951 --- /dev/null +++ b/src/ordering/application/port/output/db/order_id_exists.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use mockall::predicate::*; +use mockall::*; +use uuid::Uuid; + +use super::errors::*; +#[cfg(test)] +#[allow(unused_imports)] +pub use tests::*; + +#[automock] +#[async_trait::async_trait] +pub trait OrderIDExistsDBPort: Send + Sync { + async fn order_id_exists(&self, order_id: &Uuid) -> OrderingDBResult; +} + +pub type OrderIDExistsDBPortObj = std::sync::Arc; + +#[cfg(test)] +pub mod tests { + use super::*; + + use std::sync::Arc; + + pub fn mock_order_id_exists_db_port_false( + times: Option, + ) -> OrderIDExistsDBPortObj { + let mut m = MockOrderIDExistsDBPort::new(); + if let Some(times) = times { + m.expect_order_id_exists() + .times(times) + .returning(|_| Ok(false)); + } else { + m.expect_order_id_exists().returning(|_| Ok(false)); + } + + Arc::new(m) + } + + pub fn mock_order_id_exists_db_port_true( + times: Option, + ) -> OrderIDExistsDBPortObj { + let mut m = MockOrderIDExistsDBPort::new(); + if let Some(times) = times { + m.expect_order_id_exists() + .times(times) + .returning(|_| Ok(true)); + } else { + m.expect_order_id_exists().returning(|_| Ok(true)); + } + + Arc::new(m) + } +}