Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(storage): remove id from payment intent, attempt and remove datamodel ext from payment intent #4923

Merged
merged 16 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions crates/common_utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ readme = "README.md"
license.workspace = true

[features]
signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env", "dep:futures"]
async_ext = ["dep:futures", "dep:async-trait"]
signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env"]
async_ext = ["dep:async-trait"]
logs = ["dep:router_env"]
metrics = ["dep:router_env"]

[dependencies]
async-trait = { version = "0.1.79", optional = true }
bytes = "1.6.0"
diesel = "2.1.5"
error-stack = "0.4.1"
futures = { version = "0.3.30", optional = true }
futures = { version = "0.3.30" }
Narayanbhat166 marked this conversation as resolved.
Show resolved Hide resolved
hex = "0.4.3"
http = "0.2.12"
md5 = "0.7.0"
Expand Down
3 changes: 3 additions & 0 deletions crates/common_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ pub mod static_cache;
pub mod types;
pub mod validation;

#[cfg(feature = "metrics")]
pub mod metrics;

/// Date-time utilities.
pub mod date_time {
#[cfg(feature = "async_ext")]
Expand Down
2 changes: 2 additions & 0 deletions crates/common_utils/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//! Utilities for metrics
pub mod utils;
33 changes: 33 additions & 0 deletions crates/common_utils/src/metrics/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! metric utility functions

use std::time;

use router_env::opentelemetry;

/// Record the time taken by the future to execute
#[inline]
pub async fn time_future<F, R>(future: F) -> (R, time::Duration)
where
F: futures::Future<Output = R>,
{
let start = time::Instant::now();
let result = future.await;
let time_spent = start.elapsed();
(result, time_spent)
}

/// Record the time taken (in seconds) by the operation for the given context
#[inline]
pub async fn record_operation_time<F, R>(
future: F,
metric: &opentelemetry::metrics::Histogram<f64>,
metric_context: &opentelemetry::Context,
key_value: &[opentelemetry::KeyValue],
) -> R
where
F: futures::Future<Output = R>,
{
let (result, time) = time_future(future).await;
metric.record(metric_context, time.as_secs_f64(), key_value);
result
}
3 changes: 1 addition & 2 deletions crates/diesel_models/src/payment_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ use crate::{
};

#[derive(Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Serialize, Deserialize)]
#[diesel(table_name = payment_attempt)]
#[diesel(table_name = payment_attempt, primary_key(attempt_id, merchant_id))]
pub struct PaymentAttempt {
pub id: i32,
pub payment_id: String,
pub merchant_id: String,
pub attempt_id: String,
Expand Down
15 changes: 3 additions & 12 deletions crates/diesel_models/src/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ use time::PrimitiveDateTime;
use crate::{enums as storage_enums, schema::payment_intent};

#[derive(Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Serialize, Deserialize)]
#[diesel(table_name = payment_intent)]
#[diesel(table_name = payment_intent, primary_key(payment_id, merchant_id))]
pub struct PaymentIntent {
pub id: i32,
pub payment_id: String,
pub merchant_id: String,
pub status: storage_enums::IntentStatus,
Expand Down Expand Up @@ -233,18 +232,15 @@ pub struct PaymentIntentUpdateInternal {
#[diesel(deserialize_as = super::OptionalDieselArray<pii::SecretSerdeValue>)]
pub order_details: Option<Vec<pii::SecretSerdeValue>>,
pub attempt_count: Option<i16>,
pub profile_id: Option<String>,
jarnura marked this conversation as resolved.
Show resolved Hide resolved
merchant_decision: Option<String>,
payment_confirm_source: Option<storage_enums::PaymentSource>,

pub merchant_decision: Option<String>,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub updated_by: String,
pub surcharge_applicable: Option<bool>,
pub incremental_authorization_allowed: Option<bool>,
pub authorization_count: Option<i32>,
pub session_expiry: Option<PrimitiveDateTime>,
pub fingerprint_id: Option<String>,
pub request_external_three_ds_authentication: Option<bool>,
pub charges: Option<pii::SecretSerdeValue>,
jarnura marked this conversation as resolved.
Show resolved Hide resolved
pub frm_metadata: Option<pii::SecretSerdeValue>,
}

Expand All @@ -271,7 +267,6 @@ impl PaymentIntentUpdate {
statement_descriptor_suffix,
order_details,
attempt_count,
profile_id,
merchant_decision,
payment_confirm_source,
updated_by,
Expand All @@ -281,7 +276,6 @@ impl PaymentIntentUpdate {
session_expiry,
fingerprint_id,
request_external_three_ds_authentication,
charges,
frm_metadata,
} = self.into();
PaymentIntent {
Expand All @@ -307,7 +301,6 @@ impl PaymentIntentUpdate {
.or(source.statement_descriptor_suffix),
order_details: order_details.or(source.order_details),
attempt_count: attempt_count.unwrap_or(source.attempt_count),
profile_id: profile_id.or(source.profile_id),
merchant_decision: merchant_decision.or(source.merchant_decision),
payment_confirm_source: payment_confirm_source.or(source.payment_confirm_source),
updated_by,
Expand All @@ -320,8 +313,6 @@ impl PaymentIntentUpdate {
session_expiry: session_expiry.or(source.session_expiry),
request_external_three_ds_authentication: request_external_three_ds_authentication
.or(source.request_external_three_ds_authentication),
charges: charges.or(source.charges),

frm_metadata: frm_metadata.or(source.frm_metadata),
..source
}
Expand Down
6 changes: 2 additions & 4 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,8 +712,7 @@ diesel::table! {
use diesel::sql_types::*;
use crate::enums::diesel_exports::*;

payment_attempt (id) {
id -> Int4,
payment_attempt (attempt_id, merchant_id) {
#[max_length = 64]
payment_id -> Varchar,
#[max_length = 64]
Expand Down Expand Up @@ -802,8 +801,7 @@ diesel::table! {
use diesel::sql_types::*;
use crate::enums::diesel_exports::*;

payment_intent (id) {
id -> Int4,
payment_intent (payment_id, merchant_id) {
#[max_length = 64]
payment_id -> Varchar,
#[max_length = 64]
Expand Down
9 changes: 5 additions & 4 deletions crates/hyperswitch_domain_models/Cargo.toml
Narayanbhat166 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ payouts = ["api_models/payouts"]
# First party deps
api_models = { version = "0.1.0", path = "../api_models", features = ["errors"] }
common_enums = { version = "0.1.0", path = "../common_enums" }
common_utils = { version = "0.1.0", path = "../common_utils" }
common_utils = { version = "0.1.0", path = "../common_utils", features = ["async_ext", "metrics"] }
masking = { version = "0.1.0", path = "../masking" }
diesel_models = { version = "0.1.0", path = "../diesel_models", features = ["kv_store"] }
cards = {version = "0.1.0", path = "../cards"}
router_derive = {version = "0.1.0", path = "../router_derive"}
cards = { version = "0.1.0", path = "../cards" }
router_derive = { version = "0.1.0", path = "../router_derive" }
router_env = { version = "0.1.0", path = "../router_env" }

# Third party deps
actix-web = "4.5.1"
Expand All @@ -35,4 +36,4 @@ thiserror = "1.0.58"
time = { version = "0.3.35", features = ["serde", "serde-well-known", "std"] }
url = { version = "2.5.0", features = ["serde"] }
utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] }

futures = "0.3.30"
31 changes: 31 additions & 0 deletions crates/hyperswitch_domain_models/src/behaviour.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use common_utils::errors::{CustomResult, ValidationError};
use masking::Secret;

/// Trait for converting domain types to storage models
#[async_trait::async_trait]
pub trait Conversion {
type DstType;
type NewDstType;
async fn convert(self) -> CustomResult<Self::DstType, ValidationError>;

async fn convert_back(
item: Self::DstType,
key: &Secret<Vec<u8>>,
) -> CustomResult<Self, ValidationError>
where
Self: Sized;

async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError>;
}

#[async_trait::async_trait]
pub trait ReverseConversion<SrcType: Conversion> {
async fn convert(self, key: &Secret<Vec<u8>>) -> CustomResult<SrcType, ValidationError>;
}

#[async_trait::async_trait]
impl<T: Send, U: Conversion<DstType = T>> ReverseConversion<U> for T {
async fn convert(self, key: &Secret<Vec<u8>>) -> CustomResult<U, ValidationError> {
U::convert_back(self, key).await
}
}
4 changes: 4 additions & 0 deletions crates/hyperswitch_domain_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ pub mod router_flow_types;
pub mod router_request_types;
pub mod router_response_types;

pub mod behaviour;
pub mod merchant_key_store;
pub mod type_encryption;

#[cfg(not(feature = "payouts"))]
pub trait PayoutAttemptInterface {}

Expand Down
57 changes: 57 additions & 0 deletions crates/hyperswitch_domain_models/src/merchant_key_store.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use common_utils::{
crypto::{Encryptable, GcmAes256},
custom_serde, date_time,
errors::{CustomResult, ValidationError},
};
use error_stack::ResultExt;
use masking::{PeekInterface, Secret};
use time::PrimitiveDateTime;

use crate::type_encryption::TypeEncryption;

#[derive(Clone, Debug, serde::Serialize)]
pub struct MerchantKeyStore {
pub merchant_id: String,
pub key: Encryptable<Secret<Vec<u8>>>,
#[serde(with = "custom_serde::iso8601")]
pub created_at: PrimitiveDateTime,
}

#[async_trait::async_trait]
impl super::behaviour::Conversion for MerchantKeyStore {
type DstType = diesel_models::merchant_key_store::MerchantKeyStore;
type NewDstType = diesel_models::merchant_key_store::MerchantKeyStoreNew;
async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
Ok(diesel_models::merchant_key_store::MerchantKeyStore {
key: self.key.into(),
merchant_id: self.merchant_id,
created_at: self.created_at,
})
}

async fn convert_back(
item: Self::DstType,
key: &Secret<Vec<u8>>,
) -> CustomResult<Self, ValidationError>
where
Self: Sized,
{
Ok(Self {
key: Encryptable::decrypt(item.key, key.peek(), GcmAes256)
.await
.change_context(ValidationError::InvalidValue {
message: "Failed while decrypting customer data".to_string(),
})?,
merchant_id: item.merchant_id,
created_at: item.created_at,
})
}

async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
Ok(diesel_models::merchant_key_store::MerchantKeyStoreNew {
merchant_id: self.merchant_id,
key: self.key.into(),
created_at: date_time::now(),
})
}
}
1 change: 0 additions & 1 deletion crates/hyperswitch_domain_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::RemoteStorageObject;

#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub struct PaymentIntent {
pub id: i32,
pub payment_id: String,
pub merchant_id: String,
pub status: storage_enums::IntentStatus,
Expand Down
Loading
Loading