feat: add primary key not null query to generic filter function (#7785)

This commit is contained in:
Hrithikesh
2025-04-17 10:34:46 +05:30
committed by GitHub
parent 0607baa083
commit 8738f19067
3 changed files with 154 additions and 7 deletions

View File

@ -44,3 +44,4 @@ pub mod user;
pub mod user_authentication_method; pub mod user_authentication_method;
pub mod user_key_store; pub mod user_key_store;
pub mod user_role; pub mod user_role;
mod utils;

View File

@ -4,7 +4,7 @@ use async_bb8_diesel::AsyncRunQueryDsl;
use diesel::{ use diesel::{
associations::HasTable, associations::HasTable,
debug_query, debug_query,
dsl::{Find, Limit}, dsl::{Find, IsNotNull, Limit},
helper_types::{Filter, IntoBoxed}, helper_types::{Filter, IntoBoxed},
insertable::CanInsertInSingleQuery, insertable::CanInsertInSingleQuery,
pg::{Pg, PgConnection}, pg::{Pg, PgConnection},
@ -17,12 +17,12 @@ use diesel::{
LoadQuery, RunQueryDsl, LoadQuery, RunQueryDsl,
}, },
result::Error as DieselError, result::Error as DieselError,
Expression, Insertable, QueryDsl, QuerySource, Table, Expression, ExpressionMethods, Insertable, QueryDsl, QuerySource, Table,
}; };
use error_stack::{report, ResultExt}; use error_stack::{report, ResultExt};
use router_env::logger; use router_env::logger;
use crate::{errors, PgPooledConn, StorageResult}; use crate::{errors, query::utils::GetPrimaryKey, PgPooledConn, StorageResult};
pub mod db_metrics { pub mod db_metrics {
#[derive(Debug)] #[derive(Debug)]
@ -401,7 +401,7 @@ where
to_optional(generic_find_one_core::<T, _, _>(conn, predicate).await) to_optional(generic_find_one_core::<T, _, _>(conn, predicate).await)
} }
pub async fn generic_filter<T, P, O, R>( pub(super) async fn generic_filter<T, P, O, R>(
conn: &PgPooledConn, conn: &PgPooledConn,
predicate: P, predicate: P,
limit: Option<i64>, limit: Option<i64>,
@ -409,8 +409,9 @@ pub async fn generic_filter<T, P, O, R>(
order: Option<O>, order: Option<O>,
) -> StorageResult<Vec<R>> ) -> StorageResult<Vec<R>>
where where
T: HasTable<Table = T> + Table + BoxedDsl<'static, Pg> + 'static, T: HasTable<Table = T> + Table + BoxedDsl<'static, Pg> + GetPrimaryKey + 'static,
IntoBoxed<'static, T, Pg>: FilterDsl<P, Output = IntoBoxed<'static, T, Pg>> IntoBoxed<'static, T, Pg>: FilterDsl<P, Output = IntoBoxed<'static, T, Pg>>
+ FilterDsl<IsNotNull<T::PK>, Output = IntoBoxed<'static, T, Pg>>
+ LimitDsl<Output = IntoBoxed<'static, T, Pg>> + LimitDsl<Output = IntoBoxed<'static, T, Pg>>
+ OffsetDsl<Output = IntoBoxed<'static, T, Pg>> + OffsetDsl<Output = IntoBoxed<'static, T, Pg>>
+ OrderDsl<O, Output = IntoBoxed<'static, T, Pg>> + OrderDsl<O, Output = IntoBoxed<'static, T, Pg>>
@ -421,8 +422,9 @@ where
R: Send + 'static, R: Send + 'static,
{ {
let mut query = T::table().into_boxed(); let mut query = T::table().into_boxed();
query = query.filter(predicate); query = query
.filter(predicate)
.filter(T::table().get_primary_key().is_not_null());
if let Some(limit) = limit { if let Some(limit) = limit {
query = query.limit(limit); query = query.limit(limit);
} }

View File

@ -0,0 +1,144 @@
use diesel;
use crate::{schema, schema_v2};
/// This trait will return a single column as primary key even in case of composite primary key.
///
/// In case of composite key, it will return the column that is used as local unique.
pub(super) trait GetPrimaryKey: diesel::Table {
type PK: diesel::ExpressionMethods;
fn get_primary_key(&self) -> Self::PK;
}
/// This trait must be implemented for all composite keys.
pub(super) trait CompositeKey {
type UK;
/// It will return the local unique key of the composite key.
///
/// If `(attempt_id, merchant_id)` is the composite key for `payment_attempt` table, then it will return `attempt_id`.
fn get_local_unique_key(&self) -> Self::UK;
}
/// implementation of `CompositeKey` trait for all the composite keys must be done here.
mod composite_key {
use super::{schema, schema_v2, CompositeKey};
impl CompositeKey for <schema::payment_attempt::table as diesel::Table>::PrimaryKey {
type UK = schema::payment_attempt::dsl::attempt_id;
fn get_local_unique_key(&self) -> Self::UK {
self.0
}
}
impl CompositeKey for <schema::refund::table as diesel::Table>::PrimaryKey {
type UK = schema::refund::dsl::refund_id;
fn get_local_unique_key(&self) -> Self::UK {
self.1
}
}
impl CompositeKey for <schema::customers::table as diesel::Table>::PrimaryKey {
type UK = schema::customers::dsl::customer_id;
fn get_local_unique_key(&self) -> Self::UK {
self.0
}
}
impl CompositeKey for <schema::blocklist::table as diesel::Table>::PrimaryKey {
type UK = schema::blocklist::dsl::fingerprint_id;
fn get_local_unique_key(&self) -> Self::UK {
self.1
}
}
impl CompositeKey for <schema::incremental_authorization::table as diesel::Table>::PrimaryKey {
type UK = schema::incremental_authorization::dsl::authorization_id;
fn get_local_unique_key(&self) -> Self::UK {
self.0
}
}
impl CompositeKey for <schema_v2::incremental_authorization::table as diesel::Table>::PrimaryKey {
type UK = schema_v2::incremental_authorization::dsl::authorization_id;
fn get_local_unique_key(&self) -> Self::UK {
self.0
}
}
impl CompositeKey for <schema_v2::blocklist::table as diesel::Table>::PrimaryKey {
type UK = schema_v2::blocklist::dsl::fingerprint_id;
fn get_local_unique_key(&self) -> Self::UK {
self.1
}
}
}
/// This macro will implement the `GetPrimaryKey` trait for all the tables with single primary key.
macro_rules! impl_get_primary_key {
($($table:ty),*) => {
$(
impl GetPrimaryKey for $table
{
type PK = <$table as diesel::Table>::PrimaryKey;
fn get_primary_key(&self) -> Self::PK {
<Self as diesel::Table>::primary_key(self)
}
}
)*
};
}
impl_get_primary_key!(
// v1 tables
schema::dashboard_metadata::table,
schema::merchant_connector_account::table,
schema::merchant_key_store::table,
schema::payment_methods::table,
schema::user_authentication_methods::table,
schema::user_key_store::table,
schema::users::table,
schema::api_keys::table,
schema::captures::table,
schema::business_profile::table,
schema::mandate::dsl::mandate,
schema::dispute::table,
schema::events::table,
schema::merchant_account::table,
schema::process_tracker::table,
// v2 tables
schema_v2::dashboard_metadata::table,
schema_v2::merchant_connector_account::table,
schema_v2::merchant_key_store::table,
schema_v2::payment_methods::table,
schema_v2::user_authentication_methods::table,
schema_v2::user_key_store::table,
schema_v2::users::table,
schema_v2::api_keys::table,
schema_v2::captures::table,
schema_v2::business_profile::table,
schema_v2::mandate::table,
schema_v2::dispute::table,
schema_v2::events::table,
schema_v2::merchant_account::table,
schema_v2::process_tracker::table,
schema_v2::refund::table,
schema_v2::customers::table,
schema_v2::payment_attempt::table
);
/// This macro will implement the `GetPrimaryKey` trait for all the tables with composite key.
macro_rules! impl_get_primary_key_for_composite {
($($table:ty),*) => {
$(
impl GetPrimaryKey for $table
{
type PK = <<$table as diesel::Table>::PrimaryKey as CompositeKey>::UK;
fn get_primary_key(&self) -> Self::PK {
<Self as diesel::Table>::primary_key(self).get_local_unique_key()
}
}
)*
};
}
impl_get_primary_key_for_composite!(
schema::payment_attempt::table,
schema::refund::table,
schema::customers::table,
schema::blocklist::table,
schema::incremental_authorization::table,
schema_v2::incremental_authorization::table,
schema_v2::blocklist::table
);