//! Utility macros #[allow(missing_docs)] #[macro_export] macro_rules! newtype_impl { ($is_pub:vis, $name:ident, $ty_path:path) => { impl core::ops::Deref for $name { type Target = $ty_path; fn deref(&self) -> &Self::Target { &self.0 } } impl core::ops::DerefMut for $name { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From<$ty_path> for $name { fn from(ty: $ty_path) -> Self { Self(ty) } } impl $name { pub fn into_inner(self) -> $ty_path { self.0 } } }; } #[allow(missing_docs)] #[macro_export] macro_rules! newtype { ($is_pub:vis $name:ident = $ty_path:path) => { $is_pub struct $name(pub $ty_path); $crate::newtype_impl!($is_pub, $name, $ty_path); }; ($is_pub:vis $name:ident = $ty_path:path, derives = ($($trt:path),*)) => { #[derive($($trt),*)] $is_pub struct $name(pub $ty_path); $crate::newtype_impl!($is_pub, $name, $ty_path); }; } /// Use this to ensure that the corresponding /// openapi route has been implemented in the openapi crate #[macro_export] macro_rules! openapi_route { ($route_name: ident) => {{ #[cfg(feature = "openapi")] use openapi::routes::$route_name as _; $route_name }}; } #[allow(missing_docs)] #[macro_export] macro_rules! fallback_reverse_lookup_not_found { ($a:expr,$b:expr) => { match $a { Ok(res) => res, Err(err) => { router_env::logger::error!(reverse_lookup_fallback = ?err); match err.current_context() { errors::StorageError::ValueNotFound(_) => return $b, errors::StorageError::DatabaseError(data_err) => { match data_err.current_context() { diesel_models::errors::DatabaseError::NotFound => return $b, _ => return Err(err) } } _=> return Err(err) } } }; }; } /// 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)),+] => { { let mut keys: Vec<&'static str> = Vec::new(); $( if $option.is_none() { keys.push($key); } )* 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) => { #[allow(unused_qualifications)] impl diesel::serialize::ToSql<$diesel_type, diesel::pg::Pg> for $type { fn to_sql<'b>( &'b self, out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>, ) -> diesel::serialize::Result { let value = serde_json::to_value(self)?; // the function `reborrow` only works in case of `Pg` backend. But, in case of other backends // please refer to the diesel migration blog: // https://github.com/Diesel-rs/Diesel/blob/master/guide_drafts/migration_guide.md#changed-tosql-implementations >::to_sql(&value, &mut out.reborrow()) } } #[allow(unused_qualifications)] impl diesel::deserialize::FromSql<$diesel_type, diesel::pg::Pg> for $type { fn from_sql( bytes: ::RawValue<'_>, ) -> diesel::deserialize::Result { let value = >::from_sql(bytes)?; Ok(serde_json::from_value(value)?) } } }; ($type: ty) => { $crate::impl_to_sql_from_sql_json!($type, diesel::sql_types::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>` trait on the specified ID type. #[macro_export] macro_rules! impl_try_from_cow_str_id_type { ($type:ty, $field_name:literal) => { impl TryFrom> for $type { type Error = error_stack::Report<$crate::errors::ValidationError>; fn try_from(value: std::borrow::Cow<'static, str>) -> Result { 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 `GenerateId` trait on the specified ID type. #[macro_export] macro_rules! impl_generate_id_id_type { ($type:ty, $prefix:literal) => { impl $crate::id_type::GenerateId for $type { fn generate() -> 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 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 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 { $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 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 { Ok(row) } } }; ($type:ty) => { $crate::impl_queryable_id_type!($type, diesel::sql_types::Text); }; } } /// Get the type name for a type #[macro_export] macro_rules! type_name { ($type:ty) => { std::any::type_name::<$type>() .rsplit("::") .nth(1) .unwrap_or_default(); }; }