Skip to content

chore: reorder v2 migrations folders #8671

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Aug 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fe828bb
chore: reorder v2 migrations
hrithikesh026 Jul 15, 2025
7990487
chore: remove unwanted v2 migrations
hrithikesh026 Jul 15, 2025
c18ca74
chore: update schema_v2.rs
hrithikesh026 Jul 16, 2025
65a1e9c
chore: re-arrange a few more migrations
hrithikesh026 Jul 16, 2025
b574fee
chore: remove unwanted v2 migrations
hrithikesh026 Jul 16, 2025
648ea6e
chore: add v2_migration guidelines
hrithikesh026 Jul 17, 2025
dc282ff
chore: remove all add not null constraints migrations
hrithikesh026 Jul 22, 2025
6f98a4a
chore: make changes to diesel models
hrithikesh026 Jul 22, 2025
9eb342e
chore: update domain models
hrithikesh026 Jul 27, 2025
4e0b67d
chore: add support for deserializing from nullable db column
hrithikesh026 Jul 28, 2025
9ae2c0e
chore: update error message
hrithikesh026 Jul 28, 2025
6d63c75
chore: implement deserialize with default
hrithikesh026 Jul 28, 2025
c32b635
Revert "chore: make changes to diesel models"
hrithikesh026 Jul 28, 2025
2bc494a
Revert "chore: update domain models"
hrithikesh026 Jul 28, 2025
d187bc9
chore: update diesel models
hrithikesh026 Jul 28, 2025
c784c3b
chore: address clippy lints
hrithikesh026 Jul 28, 2025
5617266
Merge branch 'main' into reorder-migrations
hrithikesh026 Jul 28, 2025
78ed4a3
chore: remove V2_MIGRATION_GUIDELINES.md file
hrithikesh026 Jul 28, 2025
d45cbe7
chore: add documentation
hrithikesh026 Jul 28, 2025
7c1f2e1
chore: address v1 clippy warnings
hrithikesh026 Jul 28, 2025
ff1c358
Merge branch 'main' into reorder-migrations
hrithikesh026 Jul 29, 2025
35290fd
chore: fix migrations
hrithikesh026 Jul 31, 2025
fb22cb7
chore: address review comments
hrithikesh026 Jul 31, 2025
e800615
chore: address nits
hrithikesh026 Aug 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7989,6 +7989,7 @@ pub enum UIWidgetFormLayout {
Clone,
Copy,
Debug,
Default,
Eq,
PartialEq,
serde::Deserialize,
Expand All @@ -8001,6 +8002,7 @@ pub enum UIWidgetFormLayout {
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum DeleteStatus {
#[default]
Active,
Redacted,
}
Expand Down
4 changes: 2 additions & 2 deletions crates/diesel_models/src/business_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,10 @@ pub struct Profile {
pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
pub is_external_vault_enabled: Option<bool>,
pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
pub revenue_recovery_retry_algorithm_type: Option<common_enums::RevenueRecoveryAlgorithmType>,
pub revenue_recovery_retry_algorithm_data: Option<RevenueRecoveryAlgorithmData>,
pub is_external_vault_enabled: Option<bool>,
pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
}

impl Profile {
Expand Down
5 changes: 4 additions & 1 deletion crates/diesel_models/src/customers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use time::PrimitiveDateTime;
#[cfg(feature = "v1")]
use crate::schema::customers;
#[cfg(feature = "v2")]
use crate::{enums::DeleteStatus, schema_v2::customers};
use crate::{
diesel_impl::RequiredFromNullableWithDefault, enums::DeleteStatus, schema_v2::customers,
};

#[cfg(feature = "v1")]
#[derive(
Expand Down Expand Up @@ -164,6 +166,7 @@ pub struct Customer {
pub merchant_reference_id: Option<common_utils::id_type::CustomerId>,
pub default_billing_address: Option<Encryption>,
pub default_shipping_address: Option<Encryption>,
#[diesel(deserialize_as = RequiredFromNullableWithDefault<DeleteStatus>)]
pub status: DeleteStatus,
pub id: common_utils::id_type::GlobalCustomerId,
}
Expand Down
121 changes: 120 additions & 1 deletion crates/diesel_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub mod user_key_store;
pub mod user_role;

use diesel_impl::{DieselArray, OptionalDieselArray};
#[cfg(feature = "v2")]
use diesel_impl::{RequiredFromNullable, RequiredFromNullableWithDefault};

pub type StorageResult<T> = error_stack::Result<T, errors::DatabaseError>;
pub type PgPooledConn = async_bb8_diesel::Connection<diesel::PgConnection>;
Expand All @@ -71,7 +73,6 @@ pub use self::{
payment_intent::*, payment_method::*, payout_attempt::*, payouts::*, process_tracker::*,
refund::*, reverse_lookup::*, user_authentication_method::*,
};

/// The types and implementations provided by this module are required for the schema generated by
/// `diesel_cli` 2.0 to work with the types defined in Rust code. This is because
/// [`diesel`][diesel] 2.0 [changed the nullability of array elements][diesel-2.0-array-nullability],
Expand All @@ -83,13 +84,18 @@ pub use self::{
/// [diesel-2.0-array-nullability]: https://diesel.rs/guides/migration_guide.html#2-0-0-nullability-of-array-elements
#[doc(hidden)]
pub(crate) mod diesel_impl {
#[cfg(feature = "v2")]
use common_utils::{id_type, types};
use diesel::{
deserialize::FromSql,
pg::Pg,
sql_types::{Array, Nullable},
Queryable,
};

#[cfg(feature = "v2")]
use crate::enums;

pub struct DieselArray<T>(Vec<Option<T>>);

impl<T> From<DieselArray<T>> for Vec<T> {
Expand Down Expand Up @@ -130,6 +136,119 @@ pub(crate) mod diesel_impl {
Ok(Self(row))
}
}
#[cfg(feature = "v2")]
/// If the DB value is null, this wrapper will return an error when deserializing.
///
/// This is useful when you want to ensure that a field is always present, even if the database
/// value is NULL. If the database column contains a NULL value, an error will be returned.
pub struct RequiredFromNullable<T>(T);

#[cfg(feature = "v2")]
impl<T> RequiredFromNullable<T> {
/// Extracts the inner value from the wrapper
pub fn into_inner(self) -> T {
self.0
}
}

#[cfg(feature = "v2")]
impl<T, ST, DB> Queryable<Nullable<ST>, DB> for RequiredFromNullable<T>
where
DB: diesel::backend::Backend,
T: Queryable<ST, DB>,
Option<T::Row>: FromSql<Nullable<ST>, DB>,
ST: diesel::sql_types::SingleValue,
{
type Row = Option<T::Row>;

fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
match row {
Some(inner_row) => {
let value = T::build(inner_row)?;
Ok(Self(value))
}
None => Err("Cannot deserialize NULL value for required field. Check if the database column that should not be NULL contains a NULL value.".into()),
}
}
}

#[cfg(feature = "v2")]
/// If the DB value is null, this wrapper will provide a default value for the type `T`.
///
/// This is useful when you want to ensure that a field is always present, even if the database
/// value is NULL. The default value is provided by the `Default` trait implementation of `T`.
pub struct RequiredFromNullableWithDefault<T>(T);
#[cfg(feature = "v2")]
impl<T> RequiredFromNullableWithDefault<T> {
/// Extracts the inner value from the wrapper
pub fn into_inner(self) -> T {
self.0
}
}
#[cfg(feature = "v2")]
impl<T, ST, DB> Queryable<Nullable<ST>, DB> for RequiredFromNullableWithDefault<T>
where
DB: diesel::backend::Backend,
T: Queryable<ST, DB>,
T: Default,
Option<T::Row>: FromSql<Nullable<ST>, DB>,
ST: diesel::sql_types::SingleValue,
{
type Row = Option<T::Row>;

fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
match row {
Some(inner_row) => {
let value = T::build(inner_row)?;
Ok(Self(value))
}
None => Ok(Self(T::default())),
}
}
}

#[cfg(feature = "v2")]
/// Macro to implement From trait for types wrapped in RequiredFromNullable
#[macro_export]
macro_rules! impl_from_required_from_nullable {
($($type:ty),* $(,)?) => {
$(
impl From<$crate::RequiredFromNullable<$type>> for $type {
fn from(wrapper: $crate::RequiredFromNullable<$type>) -> Self {
wrapper.into_inner()
}
}
)*
};
}

#[cfg(feature = "v2")]
/// Macro to implement From trait for types wrapped in RequiredFromNullableWithDefault
#[macro_export]
macro_rules! impl_from_required_from_nullable_with_default {
($($type:ty),* $(,)?) => {
$(
impl From<$crate::RequiredFromNullableWithDefault<$type>> for $type {
fn from(wrapper: $crate::RequiredFromNullableWithDefault<$type>) -> Self {
wrapper.into_inner()
}
}
)*
};
}
#[cfg(feature = "v2")]
crate::impl_from_required_from_nullable_with_default!(enums::DeleteStatus);

#[cfg(feature = "v2")]
crate::impl_from_required_from_nullable!(
enums::AuthenticationType,
types::MinorUnit,
enums::PaymentMethod,
enums::Currency,
id_type::ProfileId,
time::PrimitiveDateTime,
id_type::RefundReferenceId,
);
}

pub(crate) mod metrics {
Expand Down
4 changes: 4 additions & 0 deletions crates/diesel_models/src/merchant_connector_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ impl MerchantConnectorAccount {
}
}

#[cfg(feature = "v2")]
use crate::RequiredFromNullable;

#[cfg(feature = "v2")]
#[derive(
Clone,
Expand Down Expand Up @@ -91,6 +94,7 @@ pub struct MerchantConnectorAccount {
pub connector_webhook_details: Option<pii::SecretSerdeValue>,
#[diesel(deserialize_as = super::OptionalDieselArray<pii::SecretSerdeValue>)]
pub frm_config: Option<Vec<pii::SecretSerdeValue>>,
#[diesel(deserialize_as = RequiredFromNullable<id_type::ProfileId>)]
pub profile_id: id_type::ProfileId,
#[diesel(deserialize_as = super::OptionalDieselArray<String>)]
pub applepay_verified_domains: Option<Vec<String>>,
Expand Down
7 changes: 5 additions & 2 deletions crates/diesel_models/src/payment_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::enums as storage_enums;
#[cfg(feature = "v1")]
use crate::schema::payment_attempt;
#[cfg(feature = "v2")]
use crate::schema_v2::payment_attempt;
use crate::{schema_v2::payment_attempt, RequiredFromNullable};

common_utils::impl_to_sql_from_sql_json!(ConnectorMandateReferenceId);
#[derive(
Expand Down Expand Up @@ -48,6 +48,7 @@ pub struct PaymentAttempt {
pub error_message: Option<String>,
pub surcharge_amount: Option<MinorUnit>,
pub payment_method_id: Option<id_type::GlobalPaymentMethodId>,
#[diesel(deserialize_as = RequiredFromNullable<storage_enums::AuthenticationType>)]
pub authentication_type: storage_enums::AuthenticationType,
#[serde(with = "common_utils::custom_serde::iso8601")]
pub created_at: PrimitiveDateTime,
Expand All @@ -73,6 +74,7 @@ pub struct PaymentAttempt {
pub encoded_data: Option<masking::Secret<String>>,
pub unified_code: Option<String>,
pub unified_message: Option<String>,
#[diesel(deserialize_as = RequiredFromNullable<MinorUnit>)]
pub net_amount: MinorUnit,
pub external_three_ds_authentication_attempted: Option<bool>,
pub authentication_connector: Option<String>,
Expand All @@ -93,6 +95,8 @@ pub struct PaymentAttempt {
pub charges: Option<common_types::payments::ConnectorChargeResponseData>,
pub processor_merchant_id: Option<id_type::MerchantId>,
pub created_by: Option<String>,
pub connector_request_reference_id: Option<String>,
#[diesel(deserialize_as = RequiredFromNullable<storage_enums::PaymentMethod>)]
pub payment_method_type_v2: storage_enums::PaymentMethod,
pub connector_payment_id: Option<ConnectorTransactionId>,
pub payment_method_subtype: storage_enums::PaymentMethodType,
Expand All @@ -114,7 +118,6 @@ pub struct PaymentAttempt {
pub network_decline_code: Option<String>,
/// A string indicating how to proceed with an network error if payment gateway provide one. This is used to understand the network error code better.
pub network_error_message: Option<String>,
pub connector_request_reference_id: Option<String>,
}

#[cfg(feature = "v1")]
Expand Down
5 changes: 5 additions & 0 deletions crates/diesel_models/src/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::schema::payment_intent;
use crate::schema_v2::payment_intent;
#[cfg(feature = "v2")]
use crate::types::{FeatureMetadata, OrderDetailsWithAmount};
#[cfg(feature = "v2")]
use crate::RequiredFromNullable;
use crate::{business_profile::PaymentLinkBackgroundImageConfig, enums as storage_enums};

#[cfg(feature = "v2")]
Expand All @@ -20,6 +22,7 @@ pub struct PaymentIntent {
pub merchant_id: common_utils::id_type::MerchantId,
pub status: storage_enums::IntentStatus,
pub amount: MinorUnit,
#[diesel(deserialize_as = RequiredFromNullable<storage_enums::Currency>)]
pub currency: storage_enums::Currency,
pub amount_captured: Option<MinorUnit>,
pub customer_id: Option<common_utils::id_type::GlobalCustomerId>,
Expand All @@ -40,12 +43,14 @@ pub struct PaymentIntent {
pub connector_metadata: Option<pii::SecretSerdeValue>,
pub feature_metadata: Option<FeatureMetadata>,
pub attempt_count: i16,
#[diesel(deserialize_as = RequiredFromNullable<common_utils::id_type::ProfileId>)]
pub profile_id: common_utils::id_type::ProfileId,
pub payment_link_id: Option<String>,
pub updated_by: String,
pub surcharge_applicable: Option<bool>,
pub request_incremental_authorization: Option<RequestIncrementalAuthorization>,
pub authorization_count: Option<i32>,
#[diesel(deserialize_as = RequiredFromNullable<PrimitiveDateTime>)]
pub session_expiry: PrimitiveDateTime,
pub request_external_three_ds_authentication: Option<bool>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
Expand Down
Loading
Loading