Skip to content

Commit 9f446bc

Browse files
feat(router): add kv implementation for update address in update payments flow (#2542)
1 parent 81cb8da commit 9f446bc

File tree

8 files changed

+203
-8
lines changed

8 files changed

+203
-8
lines changed

crates/diesel_models/src/address.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub struct Address {
4949
pub payment_id: Option<String>,
5050
}
5151

52-
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
52+
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, Serialize, Deserialize)]
5353
#[diesel(table_name = address)]
5454
pub struct AddressUpdateInternal {
5555
pub city: Option<String>,

crates/diesel_models/src/kv.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use error_stack::{IntoReport, ResultExt};
22
use serde::{Deserialize, Serialize};
33

44
use crate::{
5-
address::AddressNew,
5+
address::{Address, AddressNew, AddressUpdateInternal},
66
connector_response::{ConnectorResponse, ConnectorResponseNew, ConnectorResponseUpdate},
77
errors,
88
payment_attempt::{PaymentAttempt, PaymentAttemptNew, PaymentAttemptUpdate},
@@ -54,6 +54,7 @@ pub enum Updateable {
5454
PaymentAttemptUpdate(PaymentAttemptUpdateMems),
5555
RefundUpdate(RefundUpdateMems),
5656
ConnectorResponseUpdate(ConnectorResponseUpdateMems),
57+
AddressUpdate(Box<AddressUpdateMems>),
5758
}
5859

5960
#[derive(Debug, Serialize, Deserialize)]
@@ -62,6 +63,12 @@ pub struct ConnectorResponseUpdateMems {
6263
pub update_data: ConnectorResponseUpdate,
6364
}
6465

66+
#[derive(Debug, Serialize, Deserialize)]
67+
pub struct AddressUpdateMems {
68+
pub orig: Address,
69+
pub update_data: AddressUpdateInternal,
70+
}
71+
6572
#[derive(Debug, Serialize, Deserialize)]
6673
pub struct PaymentIntentUpdateMems {
6774
pub orig: PaymentIntent,

crates/diesel_models/src/query/address.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,32 @@ impl Address {
5656
}
5757
}
5858

59+
#[instrument(skip(conn))]
60+
pub async fn update(
61+
self,
62+
conn: &PgPooledConn,
63+
address_update_internal: AddressUpdateInternal,
64+
) -> StorageResult<Self> {
65+
match generics::generic_update_with_unique_predicate_get_result::<
66+
<Self as HasTable>::Table,
67+
_,
68+
_,
69+
_,
70+
>(
71+
conn,
72+
dsl::address_id.eq(self.address_id.clone()),
73+
address_update_internal,
74+
)
75+
.await
76+
{
77+
Err(error) => match error.current_context() {
78+
errors::DatabaseError::NoFieldsToUpdate => Ok(self),
79+
_ => Err(error),
80+
},
81+
result => result,
82+
}
83+
}
84+
5985
#[instrument(skip(conn))]
6086
pub async fn delete_by_address_id(
6187
conn: &PgPooledConn,

crates/drainer/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,11 @@ async fn drainer(
271271
update_op,
272272
connector_response
273273
),
274+
kv::Updateable::AddressUpdate(a) => macro_util::handle_resp!(
275+
a.orig.update(&conn, a.update_data).await,
276+
update_op,
277+
address
278+
),
274279
}
275280
})
276281
.await;

crates/router/src/core/payments/helpers.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,27 @@ pub async fn create_or_update_address_for_payment_by_request(
181181
.await
182182
.change_context(errors::ApiErrorResponse::InternalServerError)
183183
.attach_printable("Failed while encrypting address")?;
184+
let address = db
185+
.find_address_by_merchant_id_payment_id_address_id(
186+
merchant_id,
187+
payment_id,
188+
id,
189+
merchant_key_store,
190+
storage_scheme,
191+
)
192+
.await
193+
.change_context(errors::ApiErrorResponse::InternalServerError)
194+
.attach_printable("Error while fetching address")?;
184195
Some(
185-
db.update_address(id.to_owned(), address_update, merchant_key_store)
186-
.await
187-
.to_not_found_response(errors::ApiErrorResponse::AddressNotFound)?,
196+
db.update_address_for_payments(
197+
address,
198+
address_update,
199+
payment_id.to_string(),
200+
merchant_key_store,
201+
storage_scheme,
202+
)
203+
.await
204+
.to_not_found_response(errors::ApiErrorResponse::AddressNotFound)?,
188205
)
189206
}
190207
None => Some(

crates/router/src/db/address.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ where
2828
key_store: &domain::MerchantKeyStore,
2929
) -> CustomResult<domain::Address, errors::StorageError>;
3030

31+
async fn update_address_for_payments(
32+
&self,
33+
this: domain::Address,
34+
address: domain::AddressUpdate,
35+
payment_id: String,
36+
key_store: &domain::MerchantKeyStore,
37+
storage_scheme: MerchantStorageScheme,
38+
) -> CustomResult<domain::Address, errors::StorageError>;
39+
3140
async fn find_address_by_address_id(
3241
&self,
3342
address_id: &str,
@@ -155,6 +164,32 @@ mod storage {
155164
.await
156165
}
157166

167+
async fn update_address_for_payments(
168+
&self,
169+
this: domain::Address,
170+
address_update: domain::AddressUpdate,
171+
_payment_id: String,
172+
key_store: &domain::MerchantKeyStore,
173+
_storage_scheme: MerchantStorageScheme,
174+
) -> CustomResult<domain::Address, errors::StorageError> {
175+
let conn = connection::pg_connection_write(self).await?;
176+
let address = Conversion::convert(this)
177+
.await
178+
.change_context(errors::StorageError::EncryptionError)?;
179+
address
180+
.update(&conn, address_update.into())
181+
.await
182+
.map_err(Into::into)
183+
.into_report()
184+
.async_and_then(|address| async {
185+
address
186+
.convert(key_store.key.get_inner())
187+
.await
188+
.change_context(errors::StorageError::DecryptionError)
189+
})
190+
.await
191+
}
192+
158193
async fn insert_address_for_payments(
159194
&self,
160195
_payment_id: &str,
@@ -241,6 +276,7 @@ mod storage {
241276
mod storage {
242277
use common_utils::ext_traits::AsyncExt;
243278
use data_models::MerchantStorageScheme;
279+
use diesel_models::AddressUpdateInternal;
244280
use error_stack::{IntoReport, ResultExt};
245281
use redis_interface::HsetnxReply;
246282
use router_env::{instrument, tracing};
@@ -348,6 +384,79 @@ mod storage {
348384
.await
349385
}
350386

387+
async fn update_address_for_payments(
388+
&self,
389+
this: domain::Address,
390+
address_update: domain::AddressUpdate,
391+
payment_id: String,
392+
key_store: &domain::MerchantKeyStore,
393+
storage_scheme: MerchantStorageScheme,
394+
) -> CustomResult<domain::Address, errors::StorageError> {
395+
let conn = connection::pg_connection_write(self).await?;
396+
let address = Conversion::convert(this)
397+
.await
398+
.change_context(errors::StorageError::EncryptionError)?;
399+
match storage_scheme {
400+
MerchantStorageScheme::PostgresOnly => {
401+
address
402+
.update(&conn, address_update.into())
403+
.await
404+
.map_err(Into::into)
405+
.into_report()
406+
.async_and_then(|address| async {
407+
address
408+
.convert(key_store.key.get_inner())
409+
.await
410+
.change_context(errors::StorageError::DecryptionError)
411+
})
412+
.await
413+
}
414+
MerchantStorageScheme::RedisKv => {
415+
let key = format!("mid_{}_pid_{}", address.merchant_id.clone(), payment_id);
416+
let field = format!("add_{}", address.address_id);
417+
let updated_address = AddressUpdateInternal::from(address_update.clone())
418+
.create_address(address.clone());
419+
let redis_value = serde_json::to_string(&updated_address)
420+
.into_report()
421+
.change_context(errors::StorageError::KVError)?;
422+
kv_wrapper::<(), _, _>(
423+
self,
424+
KvOperation::Hset::<storage_types::Address>((&field, redis_value)),
425+
&key,
426+
)
427+
.await
428+
.change_context(errors::StorageError::KVError)?
429+
.try_into_hset()
430+
.change_context(errors::StorageError::KVError)?;
431+
432+
let redis_entry = kv::TypedSql {
433+
op: kv::DBOperation::Update {
434+
updatable: kv::Updateable::AddressUpdate(Box::new(
435+
kv::AddressUpdateMems {
436+
orig: address,
437+
update_data: address_update.into(),
438+
},
439+
)),
440+
},
441+
};
442+
443+
self.push_to_drainer_stream::<storage_types::Address>(
444+
redis_entry,
445+
PartitionKey::MerchantIdPaymentId {
446+
merchant_id: &updated_address.merchant_id,
447+
payment_id: &payment_id,
448+
},
449+
)
450+
.await
451+
.change_context(errors::StorageError::KVError)?;
452+
updated_address
453+
.convert(key_store.key.get_inner())
454+
.await
455+
.change_context(errors::StorageError::DecryptionError)
456+
}
457+
}
458+
}
459+
351460
async fn insert_address_for_payments(
352461
&self,
353462
payment_id: &str,
@@ -584,6 +693,37 @@ impl AddressInterface for MockDb {
584693
}
585694
}
586695

696+
async fn update_address_for_payments(
697+
&self,
698+
this: domain::Address,
699+
address_update: domain::AddressUpdate,
700+
_payment_id: String,
701+
key_store: &domain::MerchantKeyStore,
702+
_storage_scheme: MerchantStorageScheme,
703+
) -> CustomResult<domain::Address, errors::StorageError> {
704+
match self
705+
.addresses
706+
.lock()
707+
.await
708+
.iter_mut()
709+
.find(|address| address.address_id == this.address_id)
710+
.map(|a| {
711+
let address_updated =
712+
AddressUpdateInternal::from(address_update).create_address(a.clone());
713+
*a = address_updated.clone();
714+
address_updated
715+
}) {
716+
Some(address_updated) => address_updated
717+
.convert(key_store.key.get_inner())
718+
.await
719+
.change_context(errors::StorageError::DecryptionError),
720+
None => Err(errors::StorageError::ValueNotFound(
721+
"cannot find address to update".to_string(),
722+
)
723+
.into()),
724+
}
725+
}
726+
587727
async fn insert_address_for_payments(
588728
&self,
589729
_payment_id: &str,

crates/router/src/types/domain/address.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl behaviour::Conversion for Address {
125125
}
126126
}
127127

128-
#[derive(Debug)]
128+
#[derive(Debug, Clone)]
129129
pub enum AddressUpdate {
130130
Update {
131131
city: Option<String>,

crates/router/src/types/storage/kv.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
pub use diesel_models::kv::{
2-
ConnectorResponseUpdateMems, DBOperation, Insertable, PaymentAttemptUpdateMems,
3-
PaymentIntentUpdateMems, RefundUpdateMems, TypedSql, Updateable,
2+
AddressUpdateMems, ConnectorResponseUpdateMems, DBOperation, Insertable,
3+
PaymentAttemptUpdateMems, PaymentIntentUpdateMems, RefundUpdateMems, TypedSql, Updateable,
44
};

0 commit comments

Comments
 (0)