mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 20:23:43 +08:00
refactor(redis_interface): separating redis functionality and dependent functionalities outside router crate (#15)
Co-authored-by: Sanchith Hegde
This commit is contained in:
40
crates/common_utils/src/errors.rs
Normal file
40
crates/common_utils/src/errors.rs
Normal file
@ -0,0 +1,40 @@
|
||||
//!
|
||||
//! errors and error specific types for universal use
|
||||
|
||||
/// Custom Result
|
||||
/// A custom datatype that wraps the error variant <E> into a report, allowing
|
||||
/// error_stack::Report<E> specific extendability
|
||||
///
|
||||
/// Effectively, equivalent to `Result<T, error_stack::Report<E>>`
|
||||
///
|
||||
pub type CustomResult<T, E> = error_stack::Result<T, E>;
|
||||
|
||||
macro_rules! impl_error_display {
|
||||
($st: ident, $arg: tt) => {
|
||||
impl std::fmt::Display for $st {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.write_str(&format!(
|
||||
"{{ error_type: {:?}, error_description: {} }}",
|
||||
self, $arg
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_error_type {
|
||||
($name: ident, $arg: tt) => {
|
||||
#[doc = ""]
|
||||
#[doc = stringify!(Error variant $name)]
|
||||
#[doc = stringify!(Custom error variant for $arg)]
|
||||
#[doc = ""]
|
||||
#[derive(Debug)]
|
||||
pub struct $name;
|
||||
|
||||
impl_error_display!($name, $arg);
|
||||
|
||||
impl std::error::Error for $name {}
|
||||
};
|
||||
}
|
||||
|
||||
impl_error_type!(ParsingError, "Parsing error");
|
||||
279
crates/common_utils/src/ext_traits.rs
Normal file
279
crates/common_utils/src/ext_traits.rs
Normal file
@ -0,0 +1,279 @@
|
||||
//!
|
||||
//! This module holds traits for extending functionalities for existing datatypes
|
||||
//! & inbuilt datatypes.
|
||||
//!
|
||||
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use masking::{ExposeInterface, Secret, Strategy};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::errors::{self, CustomResult};
|
||||
|
||||
///
|
||||
/// Encode interface
|
||||
/// An interface for performing type conversions and serialization
|
||||
///
|
||||
pub trait Encode<'e, P>
|
||||
where
|
||||
Self: 'e + std::fmt::Debug,
|
||||
{
|
||||
// If needed get type information/custom error implementation.
|
||||
///
|
||||
/// Converting `Self` into an intermediate representation `<P>`
|
||||
/// and then performing encoding operation using the `Serialize` trait from `serde`
|
||||
/// Specifically to convert into json, by using `serde_json`
|
||||
///
|
||||
fn convert_and_encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
P: TryFrom<&'e Self> + Serialize,
|
||||
Result<P, <P as TryFrom<&'e Self>>::Error>: error_stack::ResultExt,
|
||||
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize;
|
||||
|
||||
///
|
||||
/// Converting `Self` into an intermediate representation `<P>`
|
||||
/// and then performing encoding operation using the `Serialize` trait from `serde`
|
||||
/// Specifically, to convert into urlencoded, by using `serde_urlencoded`
|
||||
///
|
||||
fn convert_and_url_encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
P: TryFrom<&'e Self> + Serialize,
|
||||
Result<P, <P as TryFrom<&'e Self>>::Error>: error_stack::ResultExt,
|
||||
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize;
|
||||
|
||||
///
|
||||
/// Functionality, for specifically encoding `Self` into `String`
|
||||
/// after serialization by using `serde::Serialize`
|
||||
///
|
||||
fn encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize;
|
||||
|
||||
///
|
||||
/// Functionality, for specifically encoding `Self` into `String`
|
||||
/// after serialization by using `serde::Serialize`
|
||||
/// specifically, to convert into JSON `String`.
|
||||
///
|
||||
fn encode_to_string_of_json(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize;
|
||||
|
||||
///
|
||||
/// Functionality, for specifically encoding `Self` into `serde_json::Value`
|
||||
/// after serialization by using `serde::Serialize`
|
||||
///
|
||||
fn encode_to_value(&'e self) -> CustomResult<serde_json::Value, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize;
|
||||
|
||||
///
|
||||
/// Functionality, for specifically encoding `Self` into `Vec<u8>`
|
||||
/// after serialization by using `serde::Serialize`
|
||||
///
|
||||
fn encode_to_vec(&'e self) -> CustomResult<Vec<u8>, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize;
|
||||
}
|
||||
|
||||
impl<'e, P, A> Encode<'e, P> for A
|
||||
where
|
||||
Self: 'e + std::fmt::Debug,
|
||||
{
|
||||
fn convert_and_encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
P: TryFrom<&'e Self> + Serialize,
|
||||
Result<P, <P as TryFrom<&'e Self>>::Error>: error_stack::ResultExt,
|
||||
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize,
|
||||
{
|
||||
serde_json::to_string(&P::try_from(self).change_context(errors::ParsingError)?)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self))
|
||||
}
|
||||
|
||||
fn convert_and_url_encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
P: TryFrom<&'e Self> + Serialize,
|
||||
Result<P, <P as TryFrom<&'e Self>>::Error>: error_stack::ResultExt,
|
||||
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize,
|
||||
{
|
||||
serde_urlencoded::to_string(&P::try_from(self).change_context(errors::ParsingError)?)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self))
|
||||
}
|
||||
|
||||
// Check without two functions can we combine this
|
||||
fn encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize,
|
||||
{
|
||||
serde_urlencoded::to_string(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self))
|
||||
}
|
||||
|
||||
fn encode_to_string_of_json(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize,
|
||||
{
|
||||
serde_json::to_string(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self))
|
||||
}
|
||||
|
||||
fn encode_to_value(&'e self) -> CustomResult<serde_json::Value, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize,
|
||||
{
|
||||
serde_json::to_value(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to convert {:?} to a value", self))
|
||||
}
|
||||
|
||||
fn encode_to_vec(&'e self) -> CustomResult<Vec<u8>, errors::ParsingError>
|
||||
where
|
||||
Self: Serialize,
|
||||
{
|
||||
serde_json::to_vec(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to convert {:?} to a value", self))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Extending functionalities of `bytes::Bytes`
|
||||
///
|
||||
pub trait BytesExt<T> {
|
||||
///
|
||||
/// Convert `bytes::Bytes` into type `<T>` using `serde::Deserialize`
|
||||
///
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>;
|
||||
}
|
||||
|
||||
impl<T> BytesExt<T> for bytes::Bytes {
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
use bytes::Buf;
|
||||
|
||||
serde_json::from_slice::<T>(self.chunk())
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to parse {type_name} from bytes"))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Extending functionalities of `[u8]` for performing parsing
|
||||
///
|
||||
pub trait ByteSliceExt<T> {
|
||||
///
|
||||
/// Convert `[u8]` into type `<T>` by using `serde::Deserialize`
|
||||
///
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>;
|
||||
}
|
||||
|
||||
impl<T> ByteSliceExt<T> for [u8] {
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
serde_json::from_slice(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to parse {type_name} from &[u8]"))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Extending functionalities of `serde_json::Value` for performing parsing
|
||||
///
|
||||
pub trait ValueExt<T> {
|
||||
///
|
||||
/// Convert `serde_json::Value` into type `<T>` by using `serde::Deserialize`
|
||||
///
|
||||
fn parse_value(self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: serde::de::DeserializeOwned;
|
||||
}
|
||||
|
||||
impl<T> ValueExt<T> for serde_json::Value {
|
||||
fn parse_value(self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
let debug = format!(
|
||||
"Unable to parse {type_name} from serde_json::Value: {:?}",
|
||||
&self
|
||||
);
|
||||
serde_json::from_value::<T>(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| debug)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, MaskingStrategy> ValueExt<T> for Secret<serde_json::Value, MaskingStrategy>
|
||||
where
|
||||
MaskingStrategy: Strategy<serde_json::Value>,
|
||||
{
|
||||
fn parse_value(self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
self.expose().parse_value(type_name)
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Extending functionalities of `String` for performing parsing
|
||||
///
|
||||
pub trait StringExt<T> {
|
||||
///
|
||||
/// Convert `String` into type `<T>` (which being an `enum`)
|
||||
///
|
||||
fn parse_enum(self, enum_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: std::str::FromStr,
|
||||
// Requirement for converting the `Err` variant of `FromStr` to `Report<Err>`
|
||||
<T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static;
|
||||
|
||||
///
|
||||
/// Convert `serde_json::Value` into type `<T>` by using `serde::Deserialize`
|
||||
///
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>;
|
||||
}
|
||||
|
||||
impl<T> StringExt<T> for String {
|
||||
fn parse_enum(self, enum_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: std::str::FromStr,
|
||||
<T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
T::from_str(&self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Invalid enum variant {self:?} for enum {enum_name}"))
|
||||
}
|
||||
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
serde_json::from_str::<T>(self)
|
||||
.into_report()
|
||||
.change_context(errors::ParsingError)
|
||||
.attach_printable_lazy(|| format!("Unable to parse {type_name} from string"))
|
||||
}
|
||||
}
|
||||
17
crates/common_utils/src/lib.rs
Normal file
17
crates/common_utils/src/lib.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#![warn(
|
||||
missing_docs,
|
||||
rust_2018_idioms,
|
||||
missing_debug_implementations,
|
||||
clippy::expect_used,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::panic,
|
||||
clippy::panic_in_result_fn,
|
||||
clippy::panicking_unwrap,
|
||||
clippy::unreachable,
|
||||
clippy::unwrap_in_result,
|
||||
clippy::unwrap_used
|
||||
)]
|
||||
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR" ), "/", "README.md"))]
|
||||
|
||||
pub mod errors;
|
||||
pub mod ext_traits;
|
||||
Reference in New Issue
Block a user