From 9dc71c1d9716fdede0c4da3545293f0bdbfefe51 Mon Sep 17 00:00:00 2001 From: Victor Login Date: Sat, 28 Sep 2024 23:35:43 +0300 Subject: [PATCH] currency: refactoring Signed-off-by: Victor Login --- boundaries/billing/currency/src/cache/test.rs | 52 +++++++++++--- .../src/infrastructure/http/handlers.rs | 4 +- .../src/infrastructure/http/routes.rs | 11 +-- .../currency/src/infrastructure/http/test.rs | 72 +++++++++++++------ boundaries/billing/currency/src/main.rs | 10 +-- .../{converter => }/converter.rs | 13 ++-- .../currency_conversion/converter/mod.rs | 5 -- .../src/usecases/currency_conversion/mod.rs | 6 +- .../{converter => }/traits.rs | 0 .../{fetcher => }/external_rate_provider.rs | 0 .../src/usecases/exchange_rate/fetcher/mod.rs | 12 ---- .../{fetcher => }/mock_bloomberg_provider.rs | 0 .../{fetcher => }/mock_yahoo_provider.rs | 0 .../src/usecases/exchange_rate/mod.rs | 13 +++- .../{fetcher => }/rate_fetcher_use_case.rs | 2 +- .../exchange_rate/{fetcher => }/tests.rs | 12 ++-- .../exchange_rate/{fetcher => }/traits.rs | 2 +- 17 files changed, 137 insertions(+), 77 deletions(-) rename boundaries/billing/currency/src/usecases/currency_conversion/{converter => }/converter.rs (86%) delete mode 100644 boundaries/billing/currency/src/usecases/currency_conversion/converter/mod.rs rename boundaries/billing/currency/src/usecases/currency_conversion/{converter => }/traits.rs (100%) rename boundaries/billing/currency/src/usecases/exchange_rate/{fetcher => }/external_rate_provider.rs (100%) delete mode 100644 boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mod.rs rename boundaries/billing/currency/src/usecases/exchange_rate/{fetcher => }/mock_bloomberg_provider.rs (100%) rename boundaries/billing/currency/src/usecases/exchange_rate/{fetcher => }/mock_yahoo_provider.rs (100%) rename boundaries/billing/currency/src/usecases/exchange_rate/{fetcher => }/rate_fetcher_use_case.rs (98%) rename boundaries/billing/currency/src/usecases/exchange_rate/{fetcher => }/tests.rs (93%) rename boundaries/billing/currency/src/usecases/exchange_rate/{fetcher => }/traits.rs (100%) diff --git a/boundaries/billing/currency/src/cache/test.rs b/boundaries/billing/currency/src/cache/test.rs index 1d9860bab6b..d942efe2f42 100644 --- a/boundaries/billing/currency/src/cache/test.rs +++ b/boundaries/billing/currency/src/cache/test.rs @@ -1,16 +1,22 @@ #[cfg(test)] mod tests { use super::*; + use crate::cache::CacheService; use crate::domain::exchange_rate::entities::{Currency, ExchangeRate}; use rust_decimal_macros::dec; - use crate::cache::CacheService; #[tokio::test] async fn test_set_and_get_rate() { let cache = CacheService::new(); let rate = ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, dec!(0.85), ); @@ -31,15 +37,27 @@ mod tests { async fn test_update_rate() { let cache = CacheService::new(); let rate1 = ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, dec!(0.85), ); cache.set_rate(&rate1).await.unwrap(); let rate2 = ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, dec!(0.90), ); cache.set_rate(&rate2).await.unwrap(); @@ -52,13 +70,25 @@ mod tests { async fn test_multiple_rates() { let cache = CacheService::new(); let rate_usd_eur = ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, dec!(0.85), ); let rate_gbp_jpy = ExchangeRate::new( - Currency { code: "GBP".to_string(), symbol: "£".to_string() }, - Currency { code: "JPY".to_string(), symbol: "¥".to_string() }, + Currency { + code: "GBP".to_string(), + symbol: "£".to_string(), + }, + Currency { + code: "JPY".to_string(), + symbol: "¥".to_string(), + }, dec!(150.0), ); diff --git a/boundaries/billing/currency/src/infrastructure/http/handlers.rs b/boundaries/billing/currency/src/infrastructure/http/handlers.rs index dadd1e44e1e..9ba614c0d4d 100644 --- a/boundaries/billing/currency/src/infrastructure/http/handlers.rs +++ b/boundaries/billing/currency/src/infrastructure/http/handlers.rs @@ -1,6 +1,6 @@ -use crate::usecases::currency_conversion::converter::traits::ICurrencyConversionUseCase; -use crate::usecases::exchange_rate::fetcher::traits::IRateFetcherUseCase; use crate::domain::exchange_rate::entities::{Currency, ExchangeRate}; +use crate::usecases::currency_conversion::traits::ICurrencyConversionUseCase; +use crate::usecases::exchange_rate::traits::IRateFetcherUseCase; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use std::sync::Arc; diff --git a/boundaries/billing/currency/src/infrastructure/http/routes.rs b/boundaries/billing/currency/src/infrastructure/http/routes.rs index 021a4706f79..6f68b5950cb 100644 --- a/boundaries/billing/currency/src/infrastructure/http/routes.rs +++ b/boundaries/billing/currency/src/infrastructure/http/routes.rs @@ -1,6 +1,6 @@ use super::handlers::{get_current_exchange_rate, get_historical_exchange_rate}; -use crate::usecases::currency_conversion::converter::traits::ICurrencyConversionUseCase; -use crate::usecases::exchange_rate::fetcher::traits::IRateFetcherUseCase; +use crate::usecases::currency_conversion::traits::ICurrencyConversionUseCase; +use crate::usecases::exchange_rate::traits::IRateFetcherUseCase; use std::sync::Arc; use warp::Filter; @@ -34,7 +34,8 @@ pub fn api( /// * `rate_fetcher` - An `Arc` pointing to a trait object implementing `IRateFetcherUseCase`. fn with_rate_fetcher( rate_fetcher: Arc, -) -> impl Filter,), Error = std::convert::Infallible> + Clone { +) -> impl Filter,), Error = std::convert::Infallible> + Clone +{ warp::any().map(move || rate_fetcher.clone()) } @@ -45,7 +46,7 @@ fn with_rate_fetcher( /// * `conversion_service` - An `Arc` pointing to a trait object implementing `ICurrencyConversionUseCase`. fn with_conversion_service( conversion_service: Arc, -) -> impl Filter,), Error = std::convert::Infallible> + Clone -{ +) -> impl Filter,), Error = std::convert::Infallible> + + Clone { warp::any().map(move || conversion_service.clone()) } diff --git a/boundaries/billing/currency/src/infrastructure/http/test.rs b/boundaries/billing/currency/src/infrastructure/http/test.rs index 26691fabf8e..507773291af 100644 --- a/boundaries/billing/currency/src/infrastructure/http/test.rs +++ b/boundaries/billing/currency/src/infrastructure/http/test.rs @@ -1,15 +1,15 @@ #[cfg(test)] mod tests { - use crate::usecases::currency_conversion::converter::traits::ICurrencyConversionUseCase; - use crate::usecases::exchange_rate::fetcher::traits::IRateFetcherUseCase; + use crate::domain::exchange_rate::entities::{Currency, ExchangeRate}; use crate::infrastructure::http::routes::api; - use warp::http::StatusCode; - use warp::test::request; - use serde_json::json; + use crate::usecases::currency_conversion::traits::ICurrencyConversionUseCase; + use crate::usecases::exchange_rate::traits::IRateFetcherUseCase; use rust_decimal::Decimal; + use serde_json::json; use std::sync::Arc; + use warp::http::StatusCode; + use warp::test::request; use warp::Filter; - use crate::domain::exchange_rate::entities::{Currency, ExchangeRate}; /// Mock implementation of `IRateFetcherUseCase` struct MockRateFetcherUseCase; @@ -20,8 +20,14 @@ mod tests { async fn fetch_rate(&self, from: &str, to: &str) -> Option { if from.eq_ignore_ascii_case("USD") && to.eq_ignore_ascii_case("EUR") { Some(ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, Decimal::new(85, 2), // 0.85 )) } else { @@ -30,7 +36,10 @@ mod tests { } /// Mock save_rate does nothing - async fn save_rate(&self, _rate: ExchangeRate) -> Result<(), Box> { + async fn save_rate( + &self, + _rate: ExchangeRate, + ) -> Result<(), Box> { Ok(()) } } @@ -48,16 +57,30 @@ mod tests { start_date: &str, end_date: &str, ) -> Option> { - if base_currency.eq_ignore_ascii_case("USD") && target_currency.eq_ignore_ascii_case("EUR") { + if base_currency.eq_ignore_ascii_case("USD") + && target_currency.eq_ignore_ascii_case("EUR") + { Some(vec![ ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, Decimal::new(84, 2), // 0.84 ), ExchangeRate::new( - Currency { code: "USD".to_string(), symbol: "$".to_string() }, - Currency { code: "EUR".to_string(), symbol: "€".to_string() }, + Currency { + code: "USD".to_string(), + symbol: "$".to_string(), + }, + Currency { + code: "EUR".to_string(), + symbol: "€".to_string(), + }, Decimal::new(85, 2), // 0.85 ), ]) @@ -70,15 +93,18 @@ mod tests { /// Helper function to inject `IRateFetcherUseCase` mock fn with_rate_fetcher( rate_fetcher: Arc, - ) -> impl warp::Filter,), Error = std::convert::Infallible> + Clone { + ) -> impl warp::Filter,), Error = std::convert::Infallible> + + Clone { warp::any().map(move || rate_fetcher.clone()) } /// Helper function to inject `ICurrencyConversionUseCase` mock fn with_conversion_service( conversion_service: Arc, - ) -> impl warp::Filter,), Error = std::convert::Infallible> + Clone - { + ) -> impl warp::Filter< + Extract = (Arc,), + Error = std::convert::Infallible, + > + Clone { warp::any().map(move || conversion_service.clone()) } @@ -86,7 +112,8 @@ mod tests { async fn test_get_current_exchange_rate_success() { // Setup mocks let mock_rate_fetcher = Arc::new(MockRateFetcherUseCase) as Arc; - let mock_conversion_service = Arc::new(MockCurrencyConversionUseCase) as Arc; + let mock_conversion_service = + Arc::new(MockCurrencyConversionUseCase) as Arc; // Build API filter let api_filter = api(mock_rate_fetcher.clone(), mock_conversion_service.clone()); @@ -114,7 +141,8 @@ mod tests { async fn test_get_current_exchange_rate_not_found() { // Setup mocks let mock_rate_fetcher = Arc::new(MockRateFetcherUseCase) as Arc; - let mock_conversion_service = Arc::new(MockCurrencyConversionUseCase) as Arc; + let mock_conversion_service = + Arc::new(MockCurrencyConversionUseCase) as Arc; // Build API filter let api_filter = api(mock_rate_fetcher.clone(), mock_conversion_service.clone()); @@ -134,7 +162,8 @@ mod tests { async fn test_get_historical_exchange_rate_success() { // Setup mocks let mock_rate_fetcher = Arc::new(MockRateFetcherUseCase) as Arc; - let mock_conversion_service = Arc::new(MockCurrencyConversionUseCase) as Arc; + let mock_conversion_service = + Arc::new(MockCurrencyConversionUseCase) as Arc; // Build API filter let api_filter = api(mock_rate_fetcher.clone(), mock_conversion_service.clone()); @@ -166,7 +195,8 @@ mod tests { async fn test_invalid_currency_code() { // Setup mocks let mock_rate_fetcher = Arc::new(MockRateFetcherUseCase) as Arc; - let mock_conversion_service = Arc::new(MockCurrencyConversionUseCase) as Arc; + let mock_conversion_service = + Arc::new(MockCurrencyConversionUseCase) as Arc; // Build API filter let api_filter = api(mock_rate_fetcher.clone(), mock_conversion_service.clone()); diff --git a/boundaries/billing/currency/src/main.rs b/boundaries/billing/currency/src/main.rs index 7267128f431..4b97b56d3b2 100644 --- a/boundaries/billing/currency/src/main.rs +++ b/boundaries/billing/currency/src/main.rs @@ -10,8 +10,8 @@ use std::sync::Arc; use tracing::info; use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::EnvFilter; -use usecases::currency_conversion::converter::ICurrencyConversionUseCase; -use usecases::exchange_rate::fetcher::RateFetcherUseCase; +use usecases::currency_conversion::ICurrencyConversionUseCase; +use usecases::exchange_rate::RateFetcherUseCase; use utoipa::OpenApi; use warp::Filter; @@ -23,9 +23,9 @@ use std::env; use crate::cache::CacheService; use crate::repository::exchange_rate::in_memory_repository::InMemoryExchangeRateRepository; use crate::repository::exchange_rate::repository::ExchangeRateRepository; -use usecases::exchange_rate::fetcher::mock_bloomberg_provider::MockBloombergProvider; -use usecases::exchange_rate::fetcher::mock_yahoo_provider::MockYahooProvider; -use crate::usecases::currency_conversion::converter::converter::CurrencyConversionUseCase; +use crate::usecases::currency_conversion::converter::CurrencyConversionUseCase; +use usecases::exchange_rate::mock_bloomberg_provider::MockBloombergProvider; +use usecases::exchange_rate::mock_yahoo_provider::MockYahooProvider; #[derive(OpenApi)] #[openapi( diff --git a/boundaries/billing/currency/src/usecases/currency_conversion/converter/converter.rs b/boundaries/billing/currency/src/usecases/currency_conversion/converter.rs similarity index 86% rename from boundaries/billing/currency/src/usecases/currency_conversion/converter/converter.rs rename to boundaries/billing/currency/src/usecases/currency_conversion/converter.rs index c7c468ec547..4b45a8db35e 100644 --- a/boundaries/billing/currency/src/usecases/currency_conversion/converter/converter.rs +++ b/boundaries/billing/currency/src/usecases/currency_conversion/converter.rs @@ -1,9 +1,9 @@ use crate::domain::currency_conversion::entities::{Amount, ConvertedAmount}; -use crate::usecases::exchange_rate::fetcher::RateFetcherUseCase; -use std::sync::Arc; -use async_trait::async_trait; -use crate::usecases::currency_conversion::converter::traits::ICurrencyConversionUseCase; use crate::domain::exchange_rate::entities::ExchangeRate; +use crate::usecases::currency_conversion::traits::ICurrencyConversionUseCase; +use crate::usecases::exchange_rate::RateFetcherUseCase; +use async_trait::async_trait; +use std::sync::Arc; pub struct CurrencyConversionUseCase { pub rate_fetcher: Arc, @@ -40,6 +40,7 @@ impl ICurrencyConversionUseCase for CurrencyConversionUseCase { start_date: &str, end_date: &str, ) -> Option> { - self.get_historical_rates(base_currency, target_currency, start_date, end_date).await + self.get_historical_rates(base_currency, target_currency, start_date, end_date) + .await } -} \ No newline at end of file +} diff --git a/boundaries/billing/currency/src/usecases/currency_conversion/converter/mod.rs b/boundaries/billing/currency/src/usecases/currency_conversion/converter/mod.rs deleted file mode 100644 index 57557ddec00..00000000000 --- a/boundaries/billing/currency/src/usecases/currency_conversion/converter/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod converter; -pub mod traits; - -// Re-export the trait for easier access -pub use traits::ICurrencyConversionUseCase; \ No newline at end of file diff --git a/boundaries/billing/currency/src/usecases/currency_conversion/mod.rs b/boundaries/billing/currency/src/usecases/currency_conversion/mod.rs index c04d1d5bab2..ce0dc11964e 100644 --- a/boundaries/billing/currency/src/usecases/currency_conversion/mod.rs +++ b/boundaries/billing/currency/src/usecases/currency_conversion/mod.rs @@ -1 +1,5 @@ -pub mod converter; \ No newline at end of file +pub mod converter; +pub mod traits; + +// Re-export the trait for easier access +pub use traits::ICurrencyConversionUseCase; diff --git a/boundaries/billing/currency/src/usecases/currency_conversion/converter/traits.rs b/boundaries/billing/currency/src/usecases/currency_conversion/traits.rs similarity index 100% rename from boundaries/billing/currency/src/usecases/currency_conversion/converter/traits.rs rename to boundaries/billing/currency/src/usecases/currency_conversion/traits.rs diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/external_rate_provider.rs b/boundaries/billing/currency/src/usecases/exchange_rate/external_rate_provider.rs similarity index 100% rename from boundaries/billing/currency/src/usecases/exchange_rate/fetcher/external_rate_provider.rs rename to boundaries/billing/currency/src/usecases/exchange_rate/external_rate_provider.rs diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mod.rs b/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mod.rs deleted file mode 100644 index 3396637185d..00000000000 --- a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod external_rate_provider; -pub mod mock_bloomberg_provider; -pub mod mock_yahoo_provider; -pub mod rate_fetcher_use_case; -pub mod traits; - -// Re-export RateFetcherUseCase for easier access -pub use rate_fetcher_use_case::RateFetcherUseCase; -pub use traits::IRateFetcherUseCase; - -#[cfg(test)] -pub mod tests; \ No newline at end of file diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mock_bloomberg_provider.rs b/boundaries/billing/currency/src/usecases/exchange_rate/mock_bloomberg_provider.rs similarity index 100% rename from boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mock_bloomberg_provider.rs rename to boundaries/billing/currency/src/usecases/exchange_rate/mock_bloomberg_provider.rs diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mock_yahoo_provider.rs b/boundaries/billing/currency/src/usecases/exchange_rate/mock_yahoo_provider.rs similarity index 100% rename from boundaries/billing/currency/src/usecases/exchange_rate/fetcher/mock_yahoo_provider.rs rename to boundaries/billing/currency/src/usecases/exchange_rate/mock_yahoo_provider.rs diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/mod.rs b/boundaries/billing/currency/src/usecases/exchange_rate/mod.rs index 44bd8a70752..a11045e2f6f 100644 --- a/boundaries/billing/currency/src/usecases/exchange_rate/mod.rs +++ b/boundaries/billing/currency/src/usecases/exchange_rate/mod.rs @@ -1 +1,12 @@ -pub mod fetcher; +pub mod external_rate_provider; +pub mod mock_bloomberg_provider; +pub mod mock_yahoo_provider; +pub mod rate_fetcher_use_case; +pub mod traits; + +// Re-export RateFetcherUseCase for easier access +pub use rate_fetcher_use_case::RateFetcherUseCase; +pub use traits::IRateFetcherUseCase; + +#[cfg(test)] +pub mod tests; diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/rate_fetcher_use_case.rs b/boundaries/billing/currency/src/usecases/exchange_rate/rate_fetcher_use_case.rs similarity index 98% rename from boundaries/billing/currency/src/usecases/exchange_rate/fetcher/rate_fetcher_use_case.rs rename to boundaries/billing/currency/src/usecases/exchange_rate/rate_fetcher_use_case.rs index 28fa0587405..951876366dc 100644 --- a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/rate_fetcher_use_case.rs +++ b/boundaries/billing/currency/src/usecases/exchange_rate/rate_fetcher_use_case.rs @@ -2,7 +2,7 @@ use super::external_rate_provider::ExternalRateProvider; use crate::cache::cache_service::CacheService; use crate::domain::exchange_rate::entities::ExchangeRate; use crate::repository::exchange_rate::repository::ExchangeRateRepository; -use crate::usecases::exchange_rate::fetcher::traits::IRateFetcherUseCase; +use crate::usecases::exchange_rate::traits::IRateFetcherUseCase; use async_trait::async_trait; use std::error::Error; use std::sync::Arc; diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/tests.rs b/boundaries/billing/currency/src/usecases/exchange_rate/tests.rs similarity index 93% rename from boundaries/billing/currency/src/usecases/exchange_rate/fetcher/tests.rs rename to boundaries/billing/currency/src/usecases/exchange_rate/tests.rs index f6288f4f404..fa74f21810b 100644 --- a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/tests.rs +++ b/boundaries/billing/currency/src/usecases/exchange_rate/tests.rs @@ -4,16 +4,16 @@ mod tests { use crate::cache::CacheService; use crate::domain::exchange_rate::entities::{Currency, ExchangeRate}; use crate::repository::exchange_rate::in_memory_repository::InMemoryExchangeRateRepository; - use crate::usecases::exchange_rate::fetcher::external_rate_provider::ExternalRateProvider; - use crate::usecases::exchange_rate::fetcher::mock_bloomberg_provider::MockBloombergProvider; - use crate::usecases::exchange_rate::fetcher::mock_yahoo_provider::MockYahooProvider; + use crate::repository::exchange_rate::repository::ExchangeRateRepository; + use crate::usecases::exchange_rate::external_rate_provider::ExternalRateProvider; + use crate::usecases::exchange_rate::mock_bloomberg_provider::MockBloombergProvider; + use crate::usecases::exchange_rate::mock_yahoo_provider::MockYahooProvider; + use crate::usecases::exchange_rate::RateFetcherUseCase; + use async_trait::async_trait; use rust_decimal_macros::dec; use std::error::Error; use std::sync::Arc; - use async_trait::async_trait; use tokio::sync::Mutex; - use crate::repository::exchange_rate::repository::ExchangeRateRepository; - use crate::usecases::exchange_rate::fetcher::RateFetcherUseCase; /// A mock provider that always fails to fetch exchange rates. struct FailingProvider; diff --git a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/traits.rs b/boundaries/billing/currency/src/usecases/exchange_rate/traits.rs similarity index 100% rename from boundaries/billing/currency/src/usecases/exchange_rate/fetcher/traits.rs rename to boundaries/billing/currency/src/usecases/exchange_rate/traits.rs index 1a237ef485e..cd222a09f27 100644 --- a/boundaries/billing/currency/src/usecases/exchange_rate/fetcher/traits.rs +++ b/boundaries/billing/currency/src/usecases/exchange_rate/traits.rs @@ -1,6 +1,6 @@ use crate::domain::exchange_rate::entities::ExchangeRate; -use std::error::Error; use async_trait::async_trait; +use std::error::Error; /// Trait defining the interface for fetching exchange rates. #[async_trait]