Repository: juspay/hyperswitch
File: crates/router/src/core/payment_methods.rs (Rust)

Code before:
    let payment_method_data =
        domain::PaymentMethodVaultingData::try_from(req.payment_method_data.clone())?
            .populate_bin_details_for_payment_method(state)
            .await;

    let fingerprint_id = vault::get_fingerprint_id_from_vault(
        state,
        &payment_method_data,
        customer_id.get_string_repr().to_owned(),
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Failed to get fingerprint_id from vault")?;

    match db
        .find_payment_method_by_fingerprint_id(
            platform.get_provider().get_key_store(),
            &fingerprint_id,
        )
        .await
    {
        Ok(existing_pm) => {
            logger::info!("Payment method is duplicated, returning existing payment method");
            return Ok(PaymentMethodResolver {
                resolution: PaymentMethodResolution::Get(Box::new(existing_pm)),
            });
        }
        Err(err) => {
            if !err.current_context().is_db_not_found() {
                logger::error!(
                    "Error while checking for existing payment method: {:?}",
                    err
                );
                return Err(err)
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to check for existing payment method in db");
            }
            logger::debug!("Payment method not found, falling back to creation");
        }
    }

    Ok(PaymentMethodResolver {
        resolution: PaymentMethodResolution::Create {
            fingerprint_id,
            payment_method_data,
        },
    })
}

#[cfg(feature = "v2")]
pub enum PaymentMethodResolution {

Review comment (suggestion):
Avoid `return`, it gets complex to understand what's happening

The match case can be the final statement, which directly returns the values 

Code after:
) -> RouterResult<PaymentMethodResolver> {
    let db = &*state.store;

    match db
        .find_payment_method_by_fingerprint_id(
            platform.get_provider().get_key_store(),
            &fingerprint_id,
        )
        .await
    {
        Ok(existing_pm) => {
            logger::info!("Payment method is duplicated, returning existing payment method");
            Ok(PaymentMethodResolver(PaymentMethodResolution::Get(
                Box::new(existing_pm),
            )))
        }
        Err(err) => {
            when(!err.current_context().is_db_not_found(), || {
                Err(err)
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to find payment method by fingerprint id")
            })?;

            logger::debug!("Payment method not found, falling back to creation");
            Ok(PaymentMethodResolver(PaymentMethodResolution::Create {
                fingerprint_id,
                payment_method_data,
            }))
        }
    }
}

#[cfg(feature = "v2")]
pub enum PaymentMethodResolution {
    Get(Box<domain::PaymentMethod>),
    Create {
        fingerprint_id: String,
        payment_method_data: domain::PaymentMethodVaultingData,
    },
}

#[cfg(feature = "v2")]
pub struct PaymentMethodResolver(PaymentMethodResolution);

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
async fn create_or_fetch_payment_method_core(
    state: &SessionState,
    req: api::PaymentMethodCreate,
    platform: &domain::Platform,