feat(router): add gateway_status_map interface (#2804)

This commit is contained in:
Sai Harsha Vardhan
2023-11-08 15:54:50 +05:30
committed by GitHub
parent 7623ea93be
commit a429b23c7f
11 changed files with 436 additions and 4 deletions

View File

@ -0,0 +1,97 @@
//! Gateway status mapping
use common_utils::custom_serde;
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
use time::PrimitiveDateTime;
use crate::schema::gateway_status_map;
#[derive(
Clone,
Debug,
Eq,
PartialEq,
router_derive::DebugAsDisplay,
Identifiable,
Queryable,
serde::Serialize,
)]
#[diesel(table_name = gateway_status_map, primary_key(connector, flow, sub_flow, code, message))]
pub struct GatewayStatusMap {
pub connector: String,
pub flow: String,
pub sub_flow: String,
pub code: String,
pub message: String,
pub status: String,
pub router_error: Option<String>,
pub decision: String,
#[serde(with = "custom_serde::iso8601")]
pub created_at: PrimitiveDateTime,
#[serde(with = "custom_serde::iso8601")]
pub last_modified: PrimitiveDateTime,
pub step_up_possible: bool,
}
#[derive(Clone, Debug, Eq, PartialEq, Insertable)]
#[diesel(table_name = gateway_status_map)]
pub struct GatewayStatusMappingNew {
pub connector: String,
pub flow: String,
pub sub_flow: String,
pub code: String,
pub message: String,
pub status: String,
pub router_error: Option<String>,
pub decision: String,
pub step_up_possible: bool,
}
#[derive(
Clone,
Debug,
PartialEq,
Eq,
AsChangeset,
router_derive::DebugAsDisplay,
Default,
serde::Deserialize,
)]
#[diesel(table_name = gateway_status_map)]
pub struct GatewayStatusMapperUpdateInternal {
pub connector: Option<String>,
pub flow: Option<String>,
pub sub_flow: Option<String>,
pub code: Option<String>,
pub message: Option<String>,
pub status: Option<String>,
pub router_error: Option<Option<String>>,
pub decision: Option<String>,
pub step_up_possible: Option<bool>,
}
#[derive(Debug)]
pub struct GatewayStatusMappingUpdate {
pub status: Option<String>,
pub router_error: Option<Option<String>>,
pub decision: Option<String>,
pub step_up_possible: Option<bool>,
}
impl From<GatewayStatusMappingUpdate> for GatewayStatusMapperUpdateInternal {
fn from(value: GatewayStatusMappingUpdate) -> Self {
let GatewayStatusMappingUpdate {
decision,
status,
router_error,
step_up_possible,
} = value;
Self {
status,
router_error,
decision,
step_up_possible,
..Default::default()
}
}
}

View File

@ -15,6 +15,7 @@ pub mod events;
pub mod file;
#[allow(unused)]
pub mod fraud_check;
pub mod gsm;
#[cfg(feature = "kv_store")]
pub mod kv;
pub mod locker_mock_up;

View File

@ -11,6 +11,7 @@ pub mod events;
pub mod file;
pub mod fraud_check;
pub mod generics;
pub mod gsm;
pub mod locker_mock_up;
pub mod mandate;
pub mod merchant_account;

View File

@ -0,0 +1,100 @@
use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods};
use error_stack::report;
use crate::{
errors, gsm::*, query::generics, schema::gateway_status_map::dsl, PgPooledConn, StorageResult,
};
impl GatewayStatusMappingNew {
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<GatewayStatusMap> {
generics::generic_insert(conn, self).await
}
}
impl GatewayStatusMap {
pub async fn find(
conn: &PgPooledConn,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> StorageResult<Self> {
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
conn,
dsl::connector
.eq(connector)
.and(dsl::flow.eq(flow))
.and(dsl::sub_flow.eq(sub_flow))
.and(dsl::code.eq(code))
.and(dsl::message.eq(message)),
)
.await
}
pub async fn retrieve_decision(
conn: &PgPooledConn,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> StorageResult<String> {
Self::find(conn, connector, flow, sub_flow, code, message)
.await
.map(|item| item.decision)
}
pub async fn update(
conn: &PgPooledConn,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
gsm: GatewayStatusMappingUpdate,
) -> StorageResult<Self> {
generics::generic_update_with_results::<
<Self as HasTable>::Table,
GatewayStatusMapperUpdateInternal,
_,
_,
>(
conn,
dsl::connector
.eq(connector)
.and(dsl::flow.eq(flow))
.and(dsl::sub_flow.eq(sub_flow))
.and(dsl::code.eq(code))
.and(dsl::message.eq(message)),
gsm.into(),
)
.await?
.first()
.cloned()
.ok_or_else(|| {
report!(errors::DatabaseError::NotFound)
.attach_printable("Error while updating gsm entry")
})
}
pub async fn delete(
conn: &PgPooledConn,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> StorageResult<bool> {
generics::generic_delete::<<Self as HasTable>::Table, _>(
conn,
dsl::connector
.eq(connector)
.and(dsl::flow.eq(flow))
.and(dsl::sub_flow.eq(sub_flow))
.and(dsl::code.eq(code))
.and(dsl::message.eq(message)),
)
.await
}
}

View File

@ -332,6 +332,33 @@ diesel::table! {
}
}
diesel::table! {
use diesel::sql_types::*;
use crate::enums::diesel_exports::*;
gateway_status_map (connector, flow, sub_flow, code, message) {
#[max_length = 64]
connector -> Varchar,
#[max_length = 64]
flow -> Varchar,
#[max_length = 64]
sub_flow -> Varchar,
#[max_length = 255]
code -> Varchar,
#[max_length = 1024]
message -> Varchar,
#[max_length = 64]
status -> Varchar,
#[max_length = 64]
router_error -> Nullable<Varchar>,
#[max_length = 64]
decision -> Varchar,
created_at -> Timestamp,
last_modified -> Timestamp,
step_up_possible -> Bool,
}
}
diesel::table! {
use diesel::sql_types::*;
use crate::enums::diesel_exports::*;
@ -909,6 +936,7 @@ diesel::allow_tables_to_appear_in_same_query!(
events,
file_metadata,
fraud_check,
gateway_status_map,
locker_mock_up,
mandate,
merchant_account,

View File

@ -12,6 +12,7 @@ pub mod ephemeral_key;
pub mod events;
pub mod file;
pub mod fraud_check;
pub mod gsm;
pub mod locker_mock_up;
pub mod mandate;
pub mod merchant_account;
@ -80,6 +81,7 @@ pub trait StorageInterface:
+ business_profile::BusinessProfileInterface
+ organization::OrganizationInterface
+ routing_algorithm::RoutingAlgorithmInterface
+ gsm::GsmInterface
+ 'static
{
fn get_scheduler_db(&self) -> Box<dyn scheduler::SchedulerInterface>;

180
crates/router/src/db/gsm.rs Normal file
View File

@ -0,0 +1,180 @@
use diesel_models::gsm as storage;
use error_stack::IntoReport;
use super::MockDb;
use crate::{
connection,
core::errors::{self, CustomResult},
services::Store,
};
#[async_trait::async_trait]
pub trait GsmInterface {
async fn add_gsm_rule(
&self,
rule: storage::GatewayStatusMappingNew,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError>;
async fn find_gsm_decision(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> CustomResult<String, errors::StorageError>;
async fn find_gsm_rule(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError>;
async fn update_gsm_rule(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
data: storage::GatewayStatusMappingUpdate,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError>;
async fn delete_gsm_rule(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> CustomResult<bool, errors::StorageError>;
}
#[async_trait::async_trait]
impl GsmInterface for Store {
async fn add_gsm_rule(
&self,
rule: storage::GatewayStatusMappingNew,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?;
rule.insert(&conn).await.map_err(Into::into).into_report()
}
async fn find_gsm_decision(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> CustomResult<String, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
storage::GatewayStatusMap::retrieve_decision(
&conn, connector, flow, sub_flow, code, message,
)
.await
.map_err(Into::into)
.into_report()
}
async fn find_gsm_rule(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
storage::GatewayStatusMap::find(&conn, connector, flow, sub_flow, code, message)
.await
.map_err(Into::into)
.into_report()
}
async fn update_gsm_rule(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
data: storage::GatewayStatusMappingUpdate,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?;
storage::GatewayStatusMap::update(&conn, connector, flow, sub_flow, code, message, data)
.await
.map_err(Into::into)
.into_report()
}
async fn delete_gsm_rule(
&self,
connector: String,
flow: String,
sub_flow: String,
code: String,
message: String,
) -> CustomResult<bool, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?;
storage::GatewayStatusMap::delete(&conn, connector, flow, sub_flow, code, message)
.await
.map_err(Into::into)
.into_report()
}
}
#[async_trait::async_trait]
impl GsmInterface for MockDb {
async fn add_gsm_rule(
&self,
_rule: storage::GatewayStatusMappingNew,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
}
async fn find_gsm_decision(
&self,
_connector: String,
_flow: String,
_sub_flow: String,
_code: String,
_message: String,
) -> CustomResult<String, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
}
async fn find_gsm_rule(
&self,
_connector: String,
_flow: String,
_sub_flow: String,
_code: String,
_message: String,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
}
async fn update_gsm_rule(
&self,
_connector: String,
_flow: String,
_sub_flow: String,
_code: String,
_message: String,
_data: storage::GatewayStatusMappingUpdate,
) -> CustomResult<storage::GatewayStatusMap, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
}
async fn delete_gsm_rule(
&self,
_connector: String,
_flow: String,
_sub_flow: String,
_code: String,
_message: String,
) -> CustomResult<bool, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
}
}

View File

@ -11,6 +11,7 @@ pub mod enums;
pub mod ephemeral_key;
pub mod events;
pub mod file;
pub mod gsm;
#[cfg(feature = "kv_store")]
pub mod kv;
pub mod locker_mock_up;
@ -41,10 +42,10 @@ pub use data_models::payments::{
pub use self::{
address::*, api_keys::*, capture::*, cards_info::*, configs::*, connector_response::*,
customers::*, dispute::*, ephemeral_key::*, events::*, file::*, locker_mock_up::*, mandate::*,
merchant_account::*, merchant_connector_account::*, merchant_key_store::*, payment_link::*,
payment_method::*, payout_attempt::*, payouts::*, process_tracker::*, refund::*,
reverse_lookup::*, routing_algorithm::*,
customers::*, dispute::*, ephemeral_key::*, events::*, file::*, gsm::*, locker_mock_up::*,
mandate::*, merchant_account::*, merchant_connector_account::*, merchant_key_store::*,
payment_link::*, payment_method::*, payout_attempt::*, payouts::*, process_tracker::*,
refund::*, reverse_lookup::*, routing_algorithm::*,
};
use crate::types::api::routing;

View File

@ -0,0 +1,4 @@
pub use diesel_models::gsm::{
GatewayStatusMap, GatewayStatusMapperUpdateInternal, GatewayStatusMappingNew,
GatewayStatusMappingUpdate,
};

View File

@ -0,0 +1,2 @@
-- Tables
DROP TABLE gateway_status_map;

View File

@ -0,0 +1,16 @@
-- Your SQL goes here
-- Tables
CREATE TABLE IF NOT EXISTS gateway_status_map (
connector VARCHAR(64) NOT NULL,
flow VARCHAR(64) NOT NULL,
sub_flow VARCHAR(64) NOT NULL,
code VARCHAR(255) NOT NULL,
message VARCHAR(1024),
status VARCHAR(64) NOT NULL,
router_error VARCHAR(64),
decision VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now()::TIMESTAMP,
last_modified TIMESTAMP NOT NULL DEFAULT now()::TIMESTAMP,
step_up_possible BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (connector, flow, sub_flow, code, message)
);