mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 20:23:43 +08:00
refactor(id_type): use macros for defining ID types and implementing common traits (#5471)
This commit is contained in:
@ -1,9 +1,10 @@
|
||||
#![allow(missing_docs)]
|
||||
//! Utility macros
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[macro_export]
|
||||
macro_rules! newtype_impl {
|
||||
($is_pub:vis, $name:ident, $ty_path:path) => {
|
||||
impl std::ops::Deref for $name {
|
||||
impl core::ops::Deref for $name {
|
||||
type Target = $ty_path;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@ -11,7 +12,7 @@ macro_rules! newtype_impl {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for $name {
|
||||
impl core::ops::DerefMut for $name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
@ -31,6 +32,7 @@ macro_rules! newtype_impl {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[macro_export]
|
||||
macro_rules! newtype {
|
||||
($is_pub:vis $name:ident = $ty_path:path) => {
|
||||
@ -59,6 +61,7 @@ macro_rules! openapi_route {
|
||||
}};
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[macro_export]
|
||||
macro_rules! fallback_reverse_lookup_not_found {
|
||||
($a:expr,$b:expr) => {
|
||||
@ -81,6 +84,8 @@ macro_rules! fallback_reverse_lookup_not_found {
|
||||
};
|
||||
}
|
||||
|
||||
/// Collects names of all optional fields that are `None`.
|
||||
/// This is typically useful for constructing error messages including a list of all missing fields.
|
||||
#[macro_export]
|
||||
macro_rules! collect_missing_value_keys {
|
||||
[$(($key:literal, $option:expr)),+] => {
|
||||
@ -96,6 +101,8 @@ macro_rules! collect_missing_value_keys {
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `ToSql` and `FromSql` traits on a type to allow it to be serialized/deserialized
|
||||
/// to/from JSON data in the database.
|
||||
#[macro_export]
|
||||
macro_rules! impl_to_sql_from_sql_json {
|
||||
($type:ty, $diesel_type:ty) => {
|
||||
@ -135,3 +142,162 @@ macro_rules! impl_to_sql_from_sql_json {
|
||||
$crate::impl_to_sql_from_sql_json!($type, diesel::sql_types::Jsonb);
|
||||
};
|
||||
}
|
||||
|
||||
mod id_type {
|
||||
/// Defines an ID type.
|
||||
#[macro_export]
|
||||
macro_rules! id_type {
|
||||
($type:ident, $doc:literal, $diesel_type:ty, $max_length:expr, $min_length:expr) => {
|
||||
#[doc = $doc]
|
||||
#[derive(
|
||||
Clone,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
diesel::expression::AsExpression,
|
||||
)]
|
||||
#[diesel(sql_type = $diesel_type)]
|
||||
pub struct $type($crate::id_type::LengthId<$max_length, $min_length>);
|
||||
};
|
||||
($type:ident, $doc:literal) => {
|
||||
$crate::id_type!(
|
||||
$type,
|
||||
$doc,
|
||||
diesel::sql_types::Text,
|
||||
{ $crate::consts::MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH },
|
||||
{ $crate::consts::MIN_REQUIRED_MERCHANT_REFERENCE_ID_LENGTH }
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements common methods on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_id_type_methods {
|
||||
($type:ty, $field_name:literal) => {
|
||||
impl $type {
|
||||
/// Get the string representation of the ID type.
|
||||
pub fn get_string_repr(&self) -> &str {
|
||||
&self.0 .0 .0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `Debug` trait on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_debug_id_type {
|
||||
($type:ty) => {
|
||||
impl core::fmt::Debug for $type {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_tuple(stringify!($type))
|
||||
.field(&self.0 .0 .0)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `TryFrom<Cow<'static, str>>` trait on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_try_from_cow_str_id_type {
|
||||
($type:ty, $field_name:literal) => {
|
||||
impl TryFrom<std::borrow::Cow<'static, str>> for $type {
|
||||
type Error = error_stack::Report<$crate::errors::ValidationError>;
|
||||
|
||||
fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
|
||||
use error_stack::ResultExt;
|
||||
|
||||
let merchant_ref_id = $crate::id_type::LengthId::from(value).change_context(
|
||||
$crate::errors::ValidationError::IncorrectValueProvided {
|
||||
field_name: $field_name,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Self(merchant_ref_id))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `Default` trait on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_default_id_type {
|
||||
($type:ty, $prefix:literal) => {
|
||||
impl Default for $type {
|
||||
fn default() -> Self {
|
||||
Self($crate::generate_ref_id_with_default_length($prefix))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `SerializableSecret` trait on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_serializable_secret_id_type {
|
||||
($type:ty) => {
|
||||
impl masking::SerializableSecret for $type {}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `ToSql` and `FromSql` traits on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_to_sql_from_sql_id_type {
|
||||
($type:ty, $diesel_type:ty, $max_length:expr, $min_length:expr) => {
|
||||
impl<DB> diesel::serialize::ToSql<$diesel_type, DB> for $type
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
$crate::id_type::LengthId<$max_length, $min_length>:
|
||||
diesel::serialize::ToSql<$diesel_type, DB>,
|
||||
{
|
||||
fn to_sql<'b>(
|
||||
&'b self,
|
||||
out: &mut diesel::serialize::Output<'b, '_, DB>,
|
||||
) -> diesel::serialize::Result {
|
||||
self.0.to_sql(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> diesel::deserialize::FromSql<$diesel_type, DB> for $type
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
$crate::id_type::LengthId<$max_length, $min_length>:
|
||||
diesel::deserialize::FromSql<$diesel_type, DB>,
|
||||
{
|
||||
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||
$crate::id_type::LengthId::<$max_length, $min_length>::from_sql(value).map(Self)
|
||||
}
|
||||
}
|
||||
};
|
||||
($type:ty) => {
|
||||
$crate::impl_to_sql_from_sql_id_type!(
|
||||
$type,
|
||||
diesel::sql_types::Text,
|
||||
{ $crate::consts::MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH },
|
||||
{ $crate::consts::MIN_REQUIRED_MERCHANT_REFERENCE_ID_LENGTH }
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `Queryable` trait on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_queryable_id_type {
|
||||
($type:ty, $diesel_type:ty) => {
|
||||
impl<DB> diesel::Queryable<$diesel_type, DB> for $type
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
Self: diesel::deserialize::FromSql<$diesel_type, DB>,
|
||||
{
|
||||
type Row = Self;
|
||||
|
||||
fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
|
||||
Ok(row)
|
||||
}
|
||||
}
|
||||
};
|
||||
($type:ty) => {
|
||||
$crate::impl_queryable_id_type!($type, diesel::sql_types::Text);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user