Bug: [FEATURE] Implement `AddressInterface` for `MockDb`



Spin out from #172. Please refer to that issue for more information.
diff --git a/Cargo.lock b/Cargo.lock
index fb22127838b..44a48169ffd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -876,6 +876,7 @@ version = "0.55.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "22d2a2bcc16e5c4d949ffd2b851da852b9bbed4bb364ed4ae371b42137ca06d9"
 dependencies = [
+ "aws-smithy-eventstream",
  "aws-smithy-types",
  "bytes",
  "crc32fast",
diff --git a/crates/router/src/db.rs b/crates/router/src/db.rs
index 2b55db74a62..6863ddf1eb6 100644
--- a/crates/router/src/db.rs
+++ b/crates/router/src/db.rs
@@ -73,6 +73,7 @@ impl StorageInterface for Store {}
 
 #[derive(Clone)]
 pub struct MockDb {
+    addresses: Arc<Mutex<Vec<storage::Address>>>,
     merchant_accounts: Arc<Mutex<Vec<storage::MerchantAccount>>>,
     merchant_connector_accounts: Arc<Mutex<Vec<storage::MerchantConnectorAccount>>>,
     payment_attempts: Arc<Mutex<Vec<storage::PaymentAttempt>>>,
@@ -88,6 +89,7 @@ pub struct MockDb {
 impl MockDb {
     pub async fn new(redis: &crate::configs::settings::Settings) -> Self {
         Self {
+            addresses: Default::default(),
             merchant_accounts: Default::default(),
             merchant_connector_accounts: Default::default(),
             payment_attempts: Default::default(),
diff --git a/crates/router/src/db/address.rs b/crates/router/src/db/address.rs
index d0049d8b4bb..0f7d457005e 100644
--- a/crates/router/src/db/address.rs
+++ b/crates/router/src/db/address.rs
@@ -1,4 +1,5 @@
 use error_stack::IntoReport;
+use storage_models::address::AddressUpdateInternal;
 
 use super::{MockDb, Store};
 use crate::{
@@ -93,36 +94,110 @@ impl AddressInterface for Store {
 impl AddressInterface for MockDb {
     async fn find_address(
         &self,
-        _address_id: &str,
+        address_id: &str,
     ) -> CustomResult<storage::Address, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        match self
+            .addresses
+            .lock()
+            .await
+            .iter()
+            .find(|address| address.address_id == address_id)
+        {
+            Some(address) => return Ok(address.clone()),
+            None => {
+                return Err(
+                    errors::StorageError::ValueNotFound("address not found".to_string()).into(),
+                )
+            }
+        }
     }
 
     async fn update_address(
         &self,
-        _address_id: String,
-        _address: storage::AddressUpdate,
+        address_id: String,
+        address_update: storage::AddressUpdate,
     ) -> CustomResult<storage::Address, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        match self
+            .addresses
+            .lock()
+            .await
+            .iter_mut()
+            .find(|address| address.address_id == address_id)
+            .map(|a| {
+                let address_updated =
+                    AddressUpdateInternal::from(address_update).create_address(a.clone());
+                *a = address_updated.clone();
+                address_updated
+            }) {
+            Some(address_updated) => Ok(address_updated),
+            None => {
+                return Err(errors::StorageError::ValueNotFound(
+                    "cannot find address to update".to_string(),
+                )
+                .into())
+            }
+        }
     }
 
     async fn insert_address(
         &self,
-        _address: storage::AddressNew,
+        address_new: storage::AddressNew,
     ) -> CustomResult<storage::Address, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        let mut addresses = self.addresses.lock().await;
+        let now = common_utils::date_time::now();
+
+        let address = storage::Address {
+            #[allow(clippy::as_conversions)]
+            id: addresses.len() as i32,
+            address_id: address_new.address_id,
+            city: address_new.city,
+            country: address_new.country,
+            line1: address_new.line1,
+            line2: address_new.line2,
+            line3: address_new.line3,
+            state: address_new.state,
+            zip: address_new.zip,
+            first_name: address_new.first_name,
+            last_name: address_new.last_name,
+            phone_number: address_new.phone_number,
+            country_code: address_new.country_code,
+            created_at: now,
+            modified_at: now,
+            customer_id: address_new.customer_id,
+            merchant_id: address_new.merchant_id,
+        };
+
+        addresses.push(address.clone());
+
+        Ok(address)
     }
 
     async fn update_address_by_merchant_id_customer_id(
         &self,
-        _customer_id: &str,
-        _merchant_id: &str,
-        _address: storage::AddressUpdate,
+        customer_id: &str,
+        merchant_id: &str,
+        address_update: storage::AddressUpdate,
     ) -> CustomResult<Vec<storage::Address>, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        match self
+            .addresses
+            .lock()
+            .await
+            .iter_mut()
+            .find(|address| {
+                address.customer_id == customer_id && address.merchant_id == merchant_id
+            })
+            .map(|a| {
+                let address_updated =
+                    AddressUpdateInternal::from(address_update).create_address(a.clone());
+                *a = address_updated.clone();
+                address_updated
+            }) {
+            Some(address) => Ok(vec![address]),
+            None => {
+                return Err(
+                    errors::StorageError::ValueNotFound("address not found".to_string()).into(),
+                )
+            }
+        }
     }
 }
diff --git a/crates/storage_models/src/address.rs b/crates/storage_models/src/address.rs
index 3b3a8c46284..091b5dc1497 100644
--- a/crates/storage_models/src/address.rs
+++ b/crates/storage_models/src/address.rs
@@ -88,6 +88,27 @@ pub struct AddressUpdateInternal {
     modified_at: PrimitiveDateTime,
 }
 
+impl AddressUpdateInternal {
+    pub fn create_address(self, source: Address) -> Address {
+        Address {
+            city: self.city,
+            country: self.country,
+            line1: self.line1,
+            line2: self.line2,
+            line3: self.line3,
+            state: self.state,
+            zip: self.zip,
+            first_name: self.first_name,
+            last_name: self.last_name,
+            phone_number: self.phone_number,
+            country_code: self.country_code,
+            modified_at: self.modified_at,
+
+            ..source
+        }
+    }
+}
+
 impl From<AddressUpdate> for AddressUpdateInternal {
     fn from(address_update: AddressUpdate) -> Self {
         match address_update {

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [x] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->


### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!-- 
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
The main motivation is to have MockDb stubs, help to void mocking, and invocation of external database api's. 
For more information check [#172](https://github.com/juspay/hyperswitch/issues/172)

Fixes #954.

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
