// File: crates/router/tests/connectors/paybox.rs
// Module: router

use masking::Secret;
use router::types::{self, api, domain, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct PayboxTest;
impl ConnectorActions for PayboxTest {}
impl utils::Connector for PayboxTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Paybox;
        utils::construct_connector_data_old(
            Box::new(Paybox::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .paybox
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "paybox".to_string()
    }
}

static CONNECTOR: PayboxTest = PayboxTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


// Struct: NexixpayCompleteAuthorizeRequest
// File: crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NexixpayCompleteAuthorizeRequest


// Implementation: impl api::PaymentCapture for for Mpgs
// File: crates/hyperswitch_connectors/src/connectors/mpgs.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Mpgs


// File: crates/external_services/src/http_client/metrics.rs
// Module: external_services

use router_env::{counter_metric, global_meter, histogram_metric_f64};

global_meter!(GLOBAL_METER, "ROUTER_API");

counter_metric!(REQUEST_BUILD_FAILURE, GLOBAL_METER);

histogram_metric_f64!(EXTERNAL_REQUEST_TIME, GLOBAL_METER);

counter_metric!(AUTO_RETRY_CONNECTION_CLOSED, GLOBAL_METER);


// Implementation: impl PaymentIntentUpdate
// File: crates/hyperswitch_domain_models/src/payments/payment_intent.rs
// Module: hyperswitch_domain_models
// Methods: 1 total (1 public)

impl PaymentIntentUpdate


// Function: execute_dsl_and_get_conditional_config
// File: crates/router/src/core/payment_methods/surcharge_decision_configs.rs
// Module: router

pub fn execute_dsl_and_get_conditional_config(
    backend_input: dsl_inputs::BackendInput,
    interpreter: &backend::VirInterpreterBackend<SurchargeDecisionConfigs>,
) -> ConditionalConfigResult<SurchargeDecisionConfigs>


// Struct: CardDetails
// File: crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CardDetails


// Struct: TokenizedCardDetails
// File: crates/hyperswitch_connectors/src/connectors/silverflow/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TokenizedCardDetails


// Struct: RevenueRecoveryMetadata
// File: crates/api_models/src/admin.rs
// Module: api_models
// Implementations: 0

// Documentation: Revenue recovery metadata for merchant connector account

pub struct RevenueRecoveryMetadata


// Function: log_payout_delete
// File: crates/router/src/services/kafka.rs
// Module: router

pub fn log_payout_delete(
        &self,
        delete_old_payout: &KafkaPayout<'_>,
        tenant_id: TenantID,
    ) -> MQResult<()>


// File: crates/currency_conversion/src/conversion.rs
// Module: currency_conversion
// Public functions: 1

use common_enums::Currency;
use rust_decimal::Decimal;
use rusty_money::Money;

use crate::{
    error::CurrencyConversionError,
    types::{currency_match, ExchangeRates},
};

pub fn convert(
    ex_rates: &ExchangeRates,
    from_currency: Currency,
    to_currency: Currency,
    amount: i64,
) -> Result<Decimal, CurrencyConversionError> {
    let money_minor = Money::from_minor(amount, currency_match(from_currency));
    let base_currency = ex_rates.base_currency;
    if to_currency == base_currency {
        ex_rates.forward_conversion(*money_minor.amount(), from_currency)
    } else if from_currency == base_currency {
        ex_rates.backward_conversion(*money_minor.amount(), to_currency)
    } else {
        let base_conversion_amt =
            ex_rates.forward_conversion(*money_minor.amount(), from_currency)?;
        ex_rates.backward_conversion(base_conversion_amt, to_currency)
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::expect_used, clippy::print_stdout)]
    use std::collections::HashMap;

    use crate::types::CurrencyFactors;
    #[test]
    fn currency_to_currency_conversion() {
        use super::*;
        let mut conversion: HashMap<Currency, CurrencyFactors> = HashMap::new();
        let inr_conversion_rates =
            CurrencyFactors::new(Decimal::new(823173, 4), Decimal::new(1214, 5));
        let szl_conversion_rates =
            CurrencyFactors::new(Decimal::new(194423, 4), Decimal::new(514, 4));
        let convert_from = Currency::SZL;
        let convert_to = Currency::INR;
        let amount = 2000;
        let base_currency = Currency::USD;
        conversion.insert(convert_from, inr_conversion_rates);
        conversion.insert(convert_to, szl_conversion_rates);
        let sample_rate = ExchangeRates::new(base_currency, conversion);
        let res =
            convert(&sample_rate, convert_from, convert_to, amount).expect("converted_currency");
        println!("The conversion from {amount} {convert_from} to {convert_to} is {res:?}");
    }

    #[test]
    fn currency_to_base_conversion() {
        use super::*;
        let mut conversion: HashMap<Currency, CurrencyFactors> = HashMap::new();
        let inr_conversion_rates =
            CurrencyFactors::new(Decimal::new(823173, 4), Decimal::new(1214, 5));
        let usd_conversion_rates = CurrencyFactors::new(Decimal::new(1, 0), Decimal::new(1, 0));
        let convert_from = Currency::INR;
        let convert_to = Currency::USD;
        let amount = 2000;
        let base_currency = Currency::USD;
        conversion.insert(convert_from, inr_conversion_rates);
        conversion.insert(convert_to, usd_conversion_rates);
        let sample_rate = ExchangeRates::new(base_currency, conversion);
        let res =
            convert(&sample_rate, convert_from, convert_to, amount).expect("converted_currency");
        println!("The conversion from {amount} {convert_from} to {convert_to} is {res:?}");
    }

    #[test]
    fn base_to_currency_conversion() {
        use super::*;
        let mut conversion: HashMap<Currency, CurrencyFactors> = HashMap::new();
        let inr_conversion_rates =
            CurrencyFactors::new(Decimal::new(823173, 4), Decimal::new(1214, 5));
        let usd_conversion_rates = CurrencyFactors::new(Decimal::new(1, 0), Decimal::new(1, 0));
        let convert_from = Currency::USD;
        let convert_to = Currency::INR;
        let amount = 2000;
        let base_currency = Currency::USD;
        conversion.insert(convert_from, usd_conversion_rates);
        conversion.insert(convert_to, inr_conversion_rates);
        let sample_rate = ExchangeRates::new(base_currency, conversion);
        let res =
            convert(&sample_rate, convert_from, convert_to, amount).expect("converted_currency");
        println!("The conversion from {amount} {convert_from} to {convert_to} is {res:?}");
    }
}


// Function: build_form_from_struct
// File: crates/hyperswitch_connectors/src/connectors/hipay.rs
// Module: hyperswitch_connectors

pub fn build_form_from_struct<T: Serialize>(data: T) -> Result<Form, common_errors::ParsingError>


// Trait: OperationSessionGetters
// File: crates/router/src/core/payments.rs
// Module: router

pub trait OperationSessionGetters<F>


// Function: payments_update_intent
// File: crates/openapi/src/routes/payments.rs
// Module: openapi

pub fn payments_update_intent()


// Implementation: impl Responder
// File: crates/router/src/routes/payment_link.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Struct: CardNetworkTokenizeForm
// File: crates/router/src/core/payment_methods/tokenize.rs
// Module: router
// Implementations: 0

pub struct CardNetworkTokenizeForm


// Implementation: impl api::PaymentCapture for for Klarna
// File: crates/hyperswitch_connectors/src/connectors/klarna.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Klarna


// Struct: RevenueRecoveryDataBackfillForm
// File: crates/api_models/src/revenue_recovery_data_backfill.rs
// Module: api_models
// Implementations: 1

pub struct RevenueRecoveryDataBackfillForm


        api_models::blocklist::ListBlocklistQuery,
        api_models::enums::BlocklistDataKind,
        api_models::enums::ErrorCategory,
        api_models::webhook_events::EventListConstraints,
        api_models::webhook_events::EventListItemResponse,
        api_models::webhook_events::EventRetrieveResponse,
        api_models::webhook_events::OutgoingWebhookRequestContent,
        api_models::webhook_events::OutgoingWebhookResponseContent,
        api_models::webhook_events::TotalEventsResponse,
        api_models::enums::WebhookDeliveryAttempt,
        api_models::enums::PaymentChargeType,
        api_models::enums::StripeChargeType,
        api_models::payments::CustomerDetailsResponse,
        api_models::payments::SdkType,
        api_models::payments::OpenBankingData,
        api_models::payments::OpenBankingSessionToken,
        api_models::payments::BankDebitResponse,
        api_models::payments::BankRedirectResponse,
        api_models::payments::BankTransferResponse,
        api_models::payments::CardRedirectResponse,
        api_models::payments::CardTokenResponse,
        api_models::payments::CryptoResponse,
        api_models::payments::GiftCardResponse,
        api_models::payments::OpenBankingResponse,
        api_models::payments::RealTimePaymentDataResponse,
        api_models::payments::UpiResponse,
        api_models::payments::VoucherResponse,
        api_models::payments::additional_info::CardTokenAdditionalData,
        api_models::payments::additional_info::BankDebitAdditionalData,
        api_models::payments::additional_info::AchBankDebitAdditionalData,
        api_models::payments::additional_info::BacsBankDebitAdditionalData,
        api_models::payments::additional_info::BecsBankDebitAdditionalData,
        api_models::payments::additional_info::SepaBankDebitAdditionalData,
        api_models::payments::additional_info::BankRedirectDetails,
        api_models::payments::additional_info::BancontactBankRedirectAdditionalData,
        api_models::payments::additional_info::BlikBankRedirectAdditionalData,
        api_models::payments::additional_info::GiropayBankRedirectAdditionalData,
        api_models::payments::additional_info::BankTransferAdditionalData,
        api_models::payments::additional_info::PixBankTransferAdditionalData,
        api_models::payments::additional_info::LocalBankTransferAdditionalData,
        api_models::payments::additional_info::GiftCardAdditionalData,
        api_models::payments::additional_info::GivexGiftCardAdditionalData,
        api_models::payments::additional_info::UpiAdditionalData,
        api_models::payments::additional_info::UpiCollectAdditionalData,
        api_models::payments::additional_info::WalletAdditionalDataForCard,
        api_models::payments::PaymentsDynamicTaxCalculationRequest,
        api_models::payments::WalletResponse,
        api_models::payments::WalletResponseData,
        api_models::payments::PaymentsDynamicTaxCalculationResponse,
        api_models::payments::DisplayAmountOnSdk,
        api_models::payments::PaymentsPostSessionTokensRequest,
        api_models::payments::PaymentsPostSessionTokensResponse,
        api_models::payments::PaymentsUpdateMetadataRequest,
        api_models::payments::PaymentsUpdateMetadataResponse,
        api_models::payments::CtpServiceDetails,
        api_models::payments::AdyenConnectorMetadata,
        api_models::payments::AdyenTestingData,
        api_models::feature_matrix::FeatureMatrixListResponse,
        api_models::feature_matrix::FeatureMatrixRequest,
        api_models::feature_matrix::ConnectorFeatureMatrixResponse,
        api_models::feature_matrix::PaymentMethodSpecificFeatures,
        api_models::feature_matrix::CardSpecificFeatures,
        api_models::feature_matrix::SupportedPaymentMethod,
        api_models::open_router::DecisionEngineSuccessRateData,
        api_models::open_router::DecisionEngineGatewayWiseExtraScore,
        api_models::open_router::DecisionEngineSRSubLevelInputConfig,
        api_models::open_router::DecisionEngineEliminationData,
        api_models::profile_acquirer::ProfileAcquirerCreate,
        api_models::profile_acquirer::ProfileAcquirerUpdate,
        api_models::profile_acquirer::ProfileAcquirerResponse,
        euclid::frontend::dir::enums::CustomerDevicePlatform,
        euclid::frontend::dir::enums::CustomerDeviceType,
        euclid::frontend::dir::enums::CustomerDeviceDisplaySize,
        api_models::authentication::AuthenticationCreateRequest,
        api_models::authentication::AuthenticationResponse,
        api_models::authentication::AcquirerDetails,
        api_models::authentication::NextAction,
        common_utils::request::Method,
        api_models::authentication::EligibilityResponseParams,
        api_models::authentication::ThreeDsData,
        api_models::authentication::AuthenticationEligibilityRequest,
        api_models::authentication::AuthenticationEligibilityResponse,
        api_models::authentication::AuthenticationSyncRequest,
        api_models::authentication::AuthenticationSyncResponse,
        api_models::open_router::OpenRouterDecideGatewayRequest,
        api_models::open_router::DecideGatewayResponse,
        api_models::open_router::UpdateScorePayload,
        api_models::open_router::UpdateScoreResponse,
        api_models::routing::RoutingEvaluateRequest,
        api_models::routing::RoutingEvaluateResponse,
        api_models::routing::ValueType,
        api_models::routing::DeRoutableConnectorChoice,
        api_models::routing::RoutableConnectorChoice,
        api_models::open_router::PaymentInfo,
        common_utils::id_type::PaymentId,
        common_utils::id_type::ProfileId,
        api_models::open_router::RankingAlgorithm,
        api_models::open_router::TxnStatus,
        api_models::open_router::PriorityLogicOutput,
        api_models::open_router::PriorityLogicData,
        api_models::user::PlatformAccountCreateRequest,
        api_models::user::PlatformAccountCreateResponse,
    )),
    modifiers(&SecurityAddon)
)]
// Bypass clippy lint for not being constructed
#[allow(dead_code)]
pub(crate) struct ApiDoc;

struct SecurityAddon;

impl utoipa::Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        use utoipa::openapi::security::{
            ApiKey, ApiKeyValue, HttpAuthScheme, HttpBuilder, SecurityScheme,
        };

        if let Some(components) = openapi.components.as_mut() {
            components.add_security_schemes_from_iter([
                (
                    "api_key",
                    SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::with_description(
                        "api-key",
                        "Use the API key created under your merchant account from the HyperSwitch dashboard. API key is used to authenticate API requests from your merchant server only. Don't expose this key on a website or embed it in a mobile application."
                    ))),
                ),
                (
                    "admin_api_key",
                    SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::with_description(
                        "api-key",
                        "Admin API keys allow you to perform some privileged actions such as \
                        creating a merchant account and Merchant Connector account."
                    ))),
                ),
                (
                    "publishable_key",
                    SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::with_description(
                        "api-key",
                        "Publishable keys are a type of keys that can be public and have limited \
                        scope of usage."
                    ))),
                ),
                (
                    "ephemeral_key",
                    SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::with_description(
                        "api-key",
                        "Ephemeral keys provide temporary access to singular data, such as access \
                        to a single customer object for a short period of time."
                    ))),
                ),
                (
                    "jwt_key",
                    SecurityScheme::Http(HttpBuilder::new().scheme(HttpAuthScheme::Bearer).bearer_format("JWT").build())
                )
            ]);
        }
    }
}


        })
    }
}

#[cfg(feature = "v2")]
impl transformers::ForeignTryFrom<domain::PaymentMethod> for PaymentMethodResponseItem {
    type Error = error_stack::Report<errors::ValidationError>;

    fn foreign_try_from(item: domain::PaymentMethod) -> Result<Self, Self::Error> {
        // For payment methods that are active we should always have the payment method subtype
        let payment_method_subtype =
            item.payment_method_subtype
                .ok_or(errors::ValidationError::MissingRequiredField {
                    field_name: "payment_method_subtype".to_string(),
                })?;

        // For payment methods that are active we should always have the payment method type
        let payment_method_type =
            item.payment_method_type
                .ok_or(errors::ValidationError::MissingRequiredField {
                    field_name: "payment_method_type".to_string(),
                })?;

        let payment_method_data = item
            .payment_method_data
            .map(|payment_method_data| payment_method_data.into_inner())
            .map(|payment_method_data| match payment_method_data {
                api_models::payment_methods::PaymentMethodsData::Card(
                    card_details_payment_method,
                ) => {
                    let card_details = api::CardDetailFromLocker::from(card_details_payment_method);
                    api_models::payment_methods::PaymentMethodListData::Card(card_details)
                }
                api_models::payment_methods::PaymentMethodsData::BankDetails(..) => todo!(),
                api_models::payment_methods::PaymentMethodsData::WalletDetails(..) => {
                    todo!()
                }
            });

        let payment_method_billing = item
            .payment_method_billing_address
            .clone()
            .map(|billing| billing.into_inner())
            .map(From::from);

        let network_token_pmd = item
            .network_token_payment_method_data
            .clone()
            .map(|data| data.into_inner())
            .and_then(|data| match data {
                domain::PaymentMethodsData::NetworkToken(token) => {
                    Some(api::NetworkTokenDetailsPaymentMethod::from(token))
                }
                _ => None,
            });

        let network_token_resp = network_token_pmd.map(|pmd| api::NetworkTokenResponse {
            payment_method_data: pmd,
        });

        // TODO: check how we can get this field
        let recurring_enabled = Some(true);

        let psp_tokenization_enabled = item.connector_mandate_details.and_then(|details| {
            details.payments.map(|payments| {
                payments.values().any(|connector_token_reference| {
                    connector_token_reference.connector_token_status
                        == api_enums::ConnectorTokenStatus::Active
                })
            })
        });

        Ok(Self {
            id: item.id,
            customer_id: item.customer_id,
            payment_method_type,
            payment_method_subtype,
            created: item.created_at,
            last_used_at: item.last_used_at,
            recurring_enabled,
            payment_method_data,
            bank: None,
            requires_cvv: true,
            is_default: false,
            billing: payment_method_billing,
            network_tokenization: network_token_resp,
            psp_tokenization_enabled: psp_tokenization_enabled.unwrap_or(false),
        })
    }
}

#[cfg(feature = "v2")]
pub fn generate_payment_method_session_response(
    payment_method_session: hyperswitch_domain_models::payment_methods::PaymentMethodSession,
    client_secret: Secret<String>,
    associated_payment: Option<api_models::payments::PaymentsResponse>,
    tokenization_service_response: Option<api_models::tokenization::GenericTokenizationResponse>,
) -> api_models::payment_methods::PaymentMethodSessionResponse {
    let next_action = associated_payment
        .as_ref()
        .and_then(|payment| payment.next_action.clone());

    let authentication_details =
        associated_payment.map(
            |payment| api_models::payment_methods::AuthenticationDetails {
                status: payment.status,
                error: payment.error,
            },
        );

    let token_id = tokenization_service_response
        .as_ref()
        .map(|tokenization_service_response| tokenization_service_response.id.clone());

    api_models::payment_methods::PaymentMethodSessionResponse {
        id: payment_method_session.id,
        customer_id: payment_method_session.customer_id,
        billing: payment_method_session
            .billing
            .map(|address| address.into_inner())
            .map(From::from),
        psp_tokenization: payment_method_session.psp_tokenization,
        network_tokenization: payment_method_session.network_tokenization,
        tokenization_data: payment_method_session.tokenization_data,
        expires_at: payment_method_session.expires_at,
        client_secret,
        next_action,
        return_url: payment_method_session.return_url,
        associated_payment_methods: payment_method_session.associated_payment_methods,
        authentication_details,
        associated_token_id: token_id,
    }
}

#[cfg(feature = "v2")]
impl transformers::ForeignFrom<api_models::payment_methods::ConnectorTokenDetails>
    for hyperswitch_domain_models::mandates::ConnectorTokenReferenceRecord
{
    fn foreign_from(item: api_models::payment_methods::ConnectorTokenDetails) -> Self {
        let api_models::payment_methods::ConnectorTokenDetails {
            status,
            connector_token_request_reference_id,
            original_payment_authorized_amount,
            original_payment_authorized_currency,
            metadata,
            token,
            ..
        } = item;

        Self {
            connector_token: token.expose().clone(),
            // TODO: check why do we need this field
            payment_method_subtype: None,
            original_payment_authorized_amount,
            original_payment_authorized_currency,
            metadata,
            connector_token_status: status,
            connector_token_request_reference_id,
        }
    }
}

#[cfg(feature = "v2")]
impl
    transformers::ForeignFrom<(
        id_type::MerchantConnectorAccountId,
        hyperswitch_domain_models::mandates::ConnectorTokenReferenceRecord,
    )> for api_models::payment_methods::ConnectorTokenDetails
{
    fn foreign_from(
        (connector_id, mandate_reference_record): (
            id_type::MerchantConnectorAccountId,
            hyperswitch_domain_models::mandates::ConnectorTokenReferenceRecord,
        ),
    ) -> Self {
        let hyperswitch_domain_models::mandates::ConnectorTokenReferenceRecord {
            connector_token_request_reference_id,
            original_payment_authorized_amount,
            original_payment_authorized_currency,
            metadata,
            connector_token,
            connector_token_status,
            ..
        } = mandate_reference_record;

        Self {
            connector_id,
            status: connector_token_status,
            connector_token_request_reference_id,
            original_payment_authorized_amount,
            original_payment_authorized_currency,
            metadata,
            token: Secret::new(connector_token),
            // Token that is derived from payments mandate reference will always be multi use token
            token_type: common_enums::TokenizationType::MultiUse,
        }
    }
}

#[cfg(feature = "v2")]
impl transformers::ForeignFrom<&payment_method_data::SingleUsePaymentMethodToken>
    for api_models::payment_methods::ConnectorTokenDetails
{
    fn foreign_from(token: &payment_method_data::SingleUsePaymentMethodToken) -> Self {
        Self {
            connector_id: token.clone().merchant_connector_id,
            token_type: common_enums::TokenizationType::SingleUse,
            status: api_enums::ConnectorTokenStatus::Active,
            connector_token_request_reference_id: None,
            original_payment_authorized_amount: None,
            original_payment_authorized_currency: None,
            metadata: None,
            token: token.clone().token,
        }
    }
}


// Function: get_single_org_id
// File: crates/router/src/utils/user_role.rs
// Module: router

pub fn get_single_org_id(
    state: &SessionState,
    user_role: &UserRole,
) -> UserResult<id_type::OrganizationId>


// Function: proxy_for_payments_operation_core
// File: crates/router/src/core/payments.rs
// Module: router

pub fn proxy_for_payments_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile_id_from_auth_layer: Option<id_type::ProfileId>,
    operation: Op,
    req: Req,
    call_connector_action: CallConnectorAction,
    auth_flow: services::AuthFlow,
    header_payload: HeaderPayload,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<(D, Req, Option<domain::Customer>, Option<u16>, Option<u128>)>
where
    F: Send + Clone + Sync,
    Req: Authenticate + Clone,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
    FData: Send + Sync + Clone,


// Struct: BrowserInfoCollected
// File: crates/hyperswitch_connectors/src/connectors/gpayments/gpayments_types.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BrowserInfoCollected


// Function: get_merchant_id
// File: crates/hyperswitch_interfaces/src/events/routing_api_logs.rs
// Module: hyperswitch_interfaces

// Documentation: Returns the merchant ID of the event.

pub fn get_merchant_id(&self) -> &str


// File: crates/router/src/types/api/fraud_check_v2.rs
// Module: router

pub use hyperswitch_domain_models::router_flow_types::fraud_check::{
    Checkout, Fulfillment, RecordReturn, Sale, Transaction,
};
pub use hyperswitch_interfaces::api::fraud_check_v2::{
    FraudCheckCheckoutV2, FraudCheckFulfillmentV2, FraudCheckRecordReturnV2, FraudCheckSaleV2,
    FraudCheckTransactionV2, FraudCheckV2,
};


// Implementation: impl ConnectorConfig
// File: crates/connector_configs/src/connector.rs
// Module: connector_configs
// Methods: 6 total (5 public)

impl ConnectorConfig


// Struct: PaymentsUpdateMetadataData
// File: crates/hyperswitch_domain_models/src/router_request_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PaymentsUpdateMetadataData


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/finix/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse


// Implementation: impl ConnectorRedirectResponse for for Novalnet
// File: crates/hyperswitch_connectors/src/connectors/novalnet.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl ConnectorRedirectResponse for for Novalnet


// Implementation: impl api::PaymentCapture for for Adyenplatform
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Adyenplatform


// Struct: Payee
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Payee


// Implementation: impl api::ConnectorRedirectResponse for for Checkout
// File: crates/hyperswitch_connectors/src/connectors/checkout.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl api::ConnectorRedirectResponse for for Checkout


// Struct: CallbackMapper
// File: crates/hyperswitch_domain_models/src/callback_mapper.rs
// Module: hyperswitch_domain_models
// Implementations: 1

pub struct CallbackMapper


// File: crates/router/src/services/connector_integration_interface.rs
// Module: router

pub use hyperswitch_interfaces::{
    authentication::ExternalAuthenticationPayload, connector_integration_interface::*,
    connector_integration_v2::ConnectorIntegrationV2, webhooks::IncomingWebhookFlowError,
};


// Struct: DeleteCardResponse
// File: crates/router/src/core/payment_methods/transformers.rs
// Module: router
// Implementations: 0

pub struct DeleteCardResponse


// File: crates/router/src/types/api/disputes.rs
// Module: router
// Public structs: 6

pub use hyperswitch_interfaces::{
    api::disputes::{
        AcceptDispute, DefendDispute, Dispute, DisputeSync, FetchDisputes, SubmitEvidence,
    },
    disputes::DisputePayload,
};
use masking::{Deserialize, Serialize};

use crate::types;

#[derive(Default, Debug, Deserialize, Serialize)]
pub struct DisputeId {
    pub dispute_id: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DisputeFetchQueryData {
    pub fetch_from: String,
    pub fetch_till: String,
}

pub use hyperswitch_domain_models::router_flow_types::dispute::{
    Accept, Defend, Dsync, Evidence, Fetch,
};

pub use super::disputes_v2::{
    AcceptDisputeV2, DefendDisputeV2, DisputeSyncV2, DisputeV2, FetchDisputesV2, SubmitEvidenceV2,
};

#[derive(Default, Debug, Deserialize, Serialize)]
pub struct DisputeEvidence {
    pub cancellation_policy: Option<String>,
    pub customer_communication: Option<String>,
    pub customer_signature: Option<String>,
    pub receipt: Option<String>,
    pub refund_policy: Option<String>,
    pub service_documentation: Option<String>,
    pub shipping_documentation: Option<String>,
    pub invoice_showing_distinct_transactions: Option<String>,
    pub recurring_transaction_agreement: Option<String>,
    pub uncategorized_file: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct AttachEvidenceRequest {
    pub create_file_request: types::api::CreateFileRequest,
    pub evidence_type: EvidenceType,
}

#[derive(Debug, serde::Deserialize, strum::Display, strum::EnumString, Clone, serde::Serialize)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum EvidenceType {
    CancellationPolicy,
    CustomerCommunication,
    CustomerSignature,
    Receipt,
    RefundPolicy,
    ServiceDocumentation,
    ShippingDocumentation,
    InvoiceShowingDistinctTransactions,
    RecurringTransactionAgreement,
    UncategorizedFile,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct ProcessDisputePTData {
    pub connector_name: String,
    pub dispute_payload: types::DisputeSyncResponse,
    pub merchant_id: common_utils::id_type::MerchantId,
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct DisputeListPTData {
    pub connector_name: String,
    pub merchant_connector_id: common_utils::id_type::MerchantConnectorAccountId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub profile_id: common_utils::id_type::ProfileId,
    pub created_from: time::PrimitiveDateTime,
    pub created_till: time::PrimitiveDateTime,
}


// Function: filter_payment_methods
// File: crates/router/src/core/payment_methods/cards.rs
// Module: router

pub fn filter_payment_methods(
    graph: &cgraph::ConstraintGraph<dir::DirValue>,
    mca_id: id_type::MerchantConnectorAccountId,
    payment_methods: &[Secret<serde_json::Value>],
    req: &mut api::PaymentMethodListRequest,
    resp: &mut Vec<ResponsePaymentMethodIntermediate>,
    payment_intent: Option<&storage::PaymentIntent>,
    payment_attempt: Option<&storage::PaymentAttempt>,
    address: Option<&domain::Address>,
    connector: String,
    configs: &settings::Settings<RawSecret>,
) -> errors::CustomResult<(), errors::ApiErrorResponse>


// Function: contract_based_routing_setup_config
// File: crates/router/src/routes/routing.rs
// Module: router

pub fn contract_based_routing_setup_config(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
    query: web::Query<api_models::routing::ToggleDynamicRoutingQuery>,
    json_payload: Option<web::Json<routing_types::ContractBasedRoutingConfig>>,
) -> impl Responder


// Struct: IatapayAuthUpdateRequest
// File: crates/hyperswitch_connectors/src/connectors/iatapay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct IatapayAuthUpdateRequest


// Implementation: impl api::RefundExecute for for Novalnet
// File: crates/hyperswitch_connectors/src/connectors/novalnet.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Novalnet


// Struct: FlexitiPurchase
// File: crates/hyperswitch_connectors/src/connectors/flexiti/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FlexitiPurchase


// Implementation: impl SPTFlow
// File: crates/router/src/types/domain/user/decision_manager.rs
// Module: router
// Methods: 2 total (0 public)

impl SPTFlow


// Struct: MerchantAccount
// File: crates/diesel_models/src/merchant_account.rs
// Module: diesel_models
// Implementations: 1

pub struct MerchantAccount


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/bitpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse


// Struct: SquareTokenizeData
// File: crates/hyperswitch_connectors/src/connectors/square/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SquareTokenizeData


// Function: extract_action_url
// File: crates/router/src/types/api/connector_onboarding/paypal.rs
// Module: router

pub fn extract_action_url(self) -> RouterResult<String>


// Struct: NameDescription
// File: crates/api_models/src/analytics.rs
// Module: api_models
// Implementations: 0

pub struct NameDescription


// Implementation: impl Default for for ShouldCollectCvvDuringPayment
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Methods: 1 total (0 public)

impl Default for for ShouldCollectCvvDuringPayment


// File: crates/analytics/src/sqlx.rs
// Module: analytics
// Public functions: 1
// Public structs: 1

use std::{fmt::Display, str::FromStr};

use api_models::{
    analytics::{frm::FrmTransactionType, refunds::RefundType},
    enums::{DisputeStage, DisputeStatus},
};
use common_enums::{
    AuthenticationConnectors, AuthenticationStatus, DecoupledAuthenticationType, TransactionStatus,
};
use common_utils::{
    errors::{CustomResult, ParsingError},
    DbConnectionParams,
};
use diesel_models::enums::{
    AttemptStatus, AuthenticationType, Currency, FraudCheckStatus, IntentStatus, PaymentMethod,
    RefundStatus, RoutingApproach,
};
use error_stack::ResultExt;
use sqlx::{
    postgres::{PgArgumentBuffer, PgPoolOptions, PgRow, PgTypeInfo, PgValueRef},
    Decode, Encode,
    Error::ColumnNotFound,
    FromRow, Pool, Postgres, Row,
};
use storage_impl::config::Database;
use time::PrimitiveDateTime;

use super::{
    health_check::HealthCheck,
    query::{Aggregate, ToSql, Window},
    types::{
        AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, QueryExecutionError,
        TableEngine,
    },
};

#[derive(Debug, Clone)]
pub struct SqlxClient {
    pool: Pool<Postgres>,
}

impl Default for SqlxClient {
    fn default() -> Self {
        let database_url = format!(
            "postgres://{}:{}@{}:{}/{}",
            "db_user", "db_pass", "localhost", 5432, "hyperswitch_db"
        );
        Self {
            #[allow(clippy::expect_used)]
            pool: PgPoolOptions::new()
                .connect_lazy(&database_url)
                .expect("SQLX Pool Creation failed"),
        }
    }
}

impl SqlxClient {
    pub async fn from_conf(conf: &Database, schema: &str) -> Self {
        let database_url = conf.get_database_url(schema);
        #[allow(clippy::expect_used)]
        let pool = PgPoolOptions::new()
            .max_connections(conf.pool_size)
            .acquire_timeout(std::time::Duration::from_secs(conf.connection_timeout))
            .connect_lazy(&database_url)
            .expect("SQLX Pool Creation failed");
        Self { pool }
    }
}

pub trait DbType {
    fn name() -> &'static str;
}

macro_rules! db_type {
    ($a: ident, $str: tt) => {
        impl DbType for $a {
            fn name() -> &'static str {
                stringify!($str)
            }
        }
    };
    ($a:ident) => {
        impl DbType for $a {
            fn name() -> &'static str {
                stringify!($a)
            }
        }
    };
}

db_type!(Currency);
db_type!(AuthenticationType);
db_type!(AttemptStatus);
db_type!(IntentStatus);
db_type!(PaymentMethod, TEXT);
db_type!(RefundStatus);
db_type!(RefundType);
db_type!(FraudCheckStatus);
db_type!(FrmTransactionType);
db_type!(DisputeStage);
db_type!(DisputeStatus);
db_type!(AuthenticationStatus);
db_type!(TransactionStatus);
db_type!(AuthenticationConnectors);
db_type!(DecoupledAuthenticationType);
db_type!(RoutingApproach);

impl<'q, Type> Encode<'q, Postgres> for DBEnumWrapper<Type>
where
    Type: DbType + FromStr + Display,
{
    fn encode_by_ref(
        &self,
        buf: &mut PgArgumentBuffer,
    ) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync + 'static>> {
        <String as Encode<'q, Postgres>>::encode(self.0.to_string(), buf)
    }
    fn size_hint(&self) -> usize {
        <String as Encode<'q, Postgres>>::size_hint(&self.0.to_string())
    }
}

impl<'r, Type> Decode<'r, Postgres> for DBEnumWrapper<Type>
where
    Type: DbType + FromStr + Display,
{
    fn decode(
        value: PgValueRef<'r>,
    ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
        let str_value = <&'r str as Decode<'r, Postgres>>::decode(value)?;
        Type::from_str(str_value).map(DBEnumWrapper).or(Err(format!(
            "invalid value {:?} for enum {}",
            str_value,
            Type::name()
        )
        .into()))
    }
}

impl<Type> sqlx::Type<Postgres> for DBEnumWrapper<Type>
where
    Type: DbType + FromStr + Display,
{
    fn type_info() -> PgTypeInfo {
        PgTypeInfo::with_name(Type::name())
    }
}

impl<T> LoadRow<T> for SqlxClient
where
    for<'a> T: FromRow<'a, PgRow>,
{
    fn load_row(row: PgRow) -> CustomResult<T, QueryExecutionError> {
        T::from_row(&row).change_context(QueryExecutionError::RowExtractionFailure)
    }
}

impl super::payments::filters::PaymentFilterAnalytics for SqlxClient {}
impl super::payments::metrics::PaymentMetricAnalytics for SqlxClient {}
impl super::payments::distribution::PaymentDistributionAnalytics for SqlxClient {}
impl super::payment_intents::filters::PaymentIntentFilterAnalytics for SqlxClient {}
impl super::payment_intents::metrics::PaymentIntentMetricAnalytics for SqlxClient {}
impl super::refunds::metrics::RefundMetricAnalytics for SqlxClient {}
impl super::refunds::filters::RefundFilterAnalytics for SqlxClient {}
impl super::refunds::distribution::RefundDistributionAnalytics for SqlxClient {}
impl super::disputes::filters::DisputeFilterAnalytics for SqlxClient {}
impl super::disputes::metrics::DisputeMetricAnalytics for SqlxClient {}
impl super::frm::metrics::FrmMetricAnalytics for SqlxClient {}
impl super::frm::filters::FrmFilterAnalytics for SqlxClient {}
impl super::auth_events::metrics::AuthEventMetricAnalytics for SqlxClient {}
impl super::auth_events::filters::AuthEventFilterAnalytics for SqlxClient {}

#[async_trait::async_trait]
impl AnalyticsDataSource for SqlxClient {
    type Row = PgRow;

    async fn load_results<T>(&self, query: &str) -> CustomResult<Vec<T>, QueryExecutionError>
    where
        Self: LoadRow<T>,
    {
        sqlx::query(&format!("{query};"))
            .fetch_all(&self.pool)
            .await
            .change_context(QueryExecutionError::DatabaseError)
            .attach_printable_lazy(|| format!("Failed to run query {query}"))?
            .into_iter()
            .map(Self::load_row)
            .collect::<Result<Vec<_>, _>>()
            .change_context(QueryExecutionError::RowExtractionFailure)
    }
}
#[async_trait::async_trait]
impl HealthCheck for SqlxClient {
    async fn deep_health_check(&self) -> CustomResult<(), QueryExecutionError> {
        sqlx::query("SELECT 1")
            .fetch_all(&self.pool)
            .await
            .map(|_| ())
            .change_context(QueryExecutionError::DatabaseError)
    }
}

impl<'a> FromRow<'a, PgRow> for super::auth_events::metrics::AuthEventMetricRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let authentication_status: Option<DBEnumWrapper<AuthenticationStatus>> =
            row.try_get("authentication_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let trans_status: Option<DBEnumWrapper<TransactionStatus>> =
            row.try_get("trans_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let authentication_type: Option<DBEnumWrapper<DecoupledAuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let error_message: Option<String> = row.try_get("error_message").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_connector: Option<DBEnumWrapper<AuthenticationConnectors>> = row
            .try_get("authentication_connector")
            .or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let message_version: Option<String> =
            row.try_get("message_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;

        let platform: Option<String> = row.try_get("platform").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let acs_reference_number: Option<String> =
            row.try_get("acs_reference_number").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let mcc: Option<String> = row.try_get("mcc").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let merchant_country: Option<String> =
            row.try_get("merchant_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let billing_country: Option<String> =
            row.try_get("billing_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let shipping_country: Option<String> =
            row.try_get("shipping_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let issuer_country: Option<String> =
            row.try_get("issuer_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let earliest_supported_version: Option<String> = row
            .try_get("earliest_supported_version")
            .or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let latest_supported_version: Option<String> = row
            .try_get("latest_supported_version")
            .or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let whitelist_decision: Option<bool> =
            row.try_get("whitelist_decision").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let device_manufacturer: Option<String> =
            row.try_get("device_manufacturer").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let device_type: Option<String> = row.try_get("device_type").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let device_brand: Option<String> = row.try_get("device_brand").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let device_os: Option<String> = row.try_get("device_os").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let device_display: Option<String> =
            row.try_get("device_display").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let browser_name: Option<String> = row.try_get("browser_name").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let browser_version: Option<String> =
            row.try_get("browser_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let issuer_id: Option<String> = row.try_get("issuer_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let scheme_name: Option<String> = row.try_get("scheme_name").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let exemption_requested: Option<bool> =
            row.try_get("exemption_requested").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let exemption_accepted: Option<bool> =
            row.try_get("exemption_accepted").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;

        Ok(Self {
            authentication_status,
            trans_status,
            authentication_type,
            error_message,
            authentication_connector,
            message_version,
            acs_reference_number,
            platform,
            count,
            start_bucket,
            end_bucket,
            mcc,
            currency,
            merchant_country,
            billing_country,
            shipping_country,
            issuer_country,
            earliest_supported_version,
            latest_supported_version,
            whitelist_decision,
            device_manufacturer,
            device_type,
            device_brand,
            device_os,
            device_display,
            browser_name,
            browser_version,
            issuer_id,
            scheme_name,
            exemption_requested,
            exemption_accepted,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::auth_events::filters::AuthEventFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let authentication_status: Option<DBEnumWrapper<AuthenticationStatus>> =
            row.try_get("authentication_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let trans_status: Option<DBEnumWrapper<TransactionStatus>> =
            row.try_get("trans_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let authentication_type: Option<DBEnumWrapper<DecoupledAuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let error_message: Option<String> = row.try_get("error_message").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_connector: Option<DBEnumWrapper<AuthenticationConnectors>> = row
            .try_get("authentication_connector")
            .or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let message_version: Option<String> =
            row.try_get("message_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let acs_reference_number: Option<String> =
            row.try_get("acs_reference_number").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let platform: Option<String> = row.try_get("platform").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let mcc: Option<String> = row.try_get("mcc").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let merchant_country: Option<String> =
            row.try_get("merchant_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let billing_country: Option<String> =
            row.try_get("billing_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let shipping_country: Option<String> =
            row.try_get("shipping_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let issuer_country: Option<String> =
            row.try_get("issuer_country").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let earliest_supported_version: Option<String> = row
            .try_get("earliest_supported_version")
            .or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let latest_supported_version: Option<String> = row
            .try_get("latest_supported_version")
            .or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let whitelist_decision: Option<bool> =
            row.try_get("whitelist_decision").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let device_manufacturer: Option<String> =
            row.try_get("device_manufacturer").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let device_type: Option<String> = row.try_get("device_type").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let device_brand: Option<String> = row.try_get("device_brand").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let device_os: Option<String> = row.try_get("device_os").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let device_display: Option<String> =
            row.try_get("device_display").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let browser_name: Option<String> = row.try_get("browser_name").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let browser_version: Option<String> =
            row.try_get("browser_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let issuer_id: Option<String> = row.try_get("issuer_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let scheme_name: Option<String> = row.try_get("scheme_name").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let exemption_requested: Option<bool> =
            row.try_get("exemption_requested").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let exemption_accepted: Option<bool> =
            row.try_get("exemption_accepted").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;

        Ok(Self {
            authentication_status,
            trans_status,
            authentication_type,
            error_message,
            authentication_connector,
            message_version,
            platform,
            acs_reference_number,
            mcc,
            currency,
            merchant_country,
            billing_country,
            shipping_country,
            issuer_country,
            earliest_supported_version,
            latest_supported_version,
            whitelist_decision,
            device_manufacturer,
            device_type,
            device_brand,
            device_os,
            device_display,
            browser_name,
            browser_version,
            issuer_id,
            scheme_name,
            exemption_requested,
            exemption_accepted,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::refunds::metrics::RefundMetricRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let refund_status: Option<DBEnumWrapper<RefundStatus>> =
            row.try_get("refund_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_type: Option<DBEnumWrapper<RefundType>> =
            row.try_get("refund_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_reason: Option<String> = row.try_get("refund_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_error_message: Option<String> =
            row.try_get("refund_error_message").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            currency,
            refund_status,
            connector,
            refund_type,
            profile_id,
            refund_reason,
            refund_error_message,
            total,
            count,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::frm::metrics::FrmMetricRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let frm_name: Option<String> = row.try_get("frm_name").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let frm_status: Option<DBEnumWrapper<FraudCheckStatus>> =
            row.try_get("frm_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let frm_transaction_type: Option<DBEnumWrapper<FrmTransactionType>> =
            row.try_get("frm_transaction_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            frm_name,
            frm_status,
            frm_transaction_type,
            total,
            count,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::payments::metrics::PaymentMetricRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let status: Option<DBEnumWrapper<AttemptStatus>> =
            row.try_get("status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_type: Option<DBEnumWrapper<AuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method: Option<String> =
            row.try_get("payment_method").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method_type: Option<String> =
            row.try_get("payment_method_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let client_source: Option<String> = row.try_get("client_source").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let client_version: Option<String> =
            row.try_get("client_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_network: Option<String> = row.try_get("card_network").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let merchant_id: Option<String> = row.try_get("merchant_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_last_4: Option<String> = row.try_get("card_last_4").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_issuer: Option<String> = row.try_get("card_issuer").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let error_reason: Option<String> = row.try_get("error_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let first_attempt: Option<bool> = row.try_get("first_attempt").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let routing_approach: Option<DBEnumWrapper<RoutingApproach>> =
            row.try_get("routing_approach").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let signature_network: Option<String> =
            row.try_get("signature_network").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let is_issuer_regulated: Option<bool> =
            row.try_get("is_issuer_regulated").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let is_debit_routed: Option<bool> =
            row.try_get("is_debit_routed").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            currency,
            status,
            connector,
            authentication_type,
            payment_method,
            payment_method_type,
            client_source,
            client_version,
            profile_id,
            card_network,
            merchant_id,
            card_last_4,
            card_issuer,
            error_reason,
            first_attempt,
            routing_approach,
            signature_network,
            is_issuer_regulated,
            is_debit_routed,
            total,
            count,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::payments::distribution::PaymentDistributionRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let status: Option<DBEnumWrapper<AttemptStatus>> =
            row.try_get("status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_type: Option<DBEnumWrapper<AuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method: Option<String> =
            row.try_get("payment_method").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method_type: Option<String> =
            row.try_get("payment_method_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let client_source: Option<String> = row.try_get("client_source").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let client_version: Option<String> =
            row.try_get("client_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_network: Option<String> = row.try_get("card_network").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let merchant_id: Option<String> = row.try_get("merchant_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_last_4: Option<String> = row.try_get("card_last_4").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_issuer: Option<String> = row.try_get("card_issuer").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let error_reason: Option<String> = row.try_get("error_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let routing_approach: Option<DBEnumWrapper<RoutingApproach>> =
            row.try_get("routing_approach").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;

        let signature_network: Option<String> =
            row.try_get("signature_network").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let is_issuer_regulated: Option<bool> =
            row.try_get("is_issuer_regulated").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let is_debit_routed: Option<bool> =
            row.try_get("is_debit_routed").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let error_message: Option<String> = row.try_get("error_message").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let first_attempt: Option<bool> = row.try_get("first_attempt").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            currency,
            status,
            connector,
            authentication_type,
            payment_method,
            payment_method_type,
            client_source,
            client_version,
            profile_id,
            card_network,
            merchant_id,
            card_last_4,
            card_issuer,
            error_reason,
            first_attempt,
            total,
            count,
            error_message,
            routing_approach,
            signature_network,
            is_issuer_regulated,
            is_debit_routed,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::payments::filters::PaymentFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),


// Struct: TransactionData
// File: crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TransactionData


// Struct: TotalPaymentMethodCountResponse
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 1
// Traits: common_utils::events::ApiEventMetric

pub struct TotalPaymentMethodCountResponse