Skip to content

Showcase how I use this crate to crate a mapping between (secured) business object and serializable dto #21

@tisonkun

Description

@tisonkun
use derivative::Derivative;
use secrecy::ExposeSecret;
use secrecy::SecretString;
use serde::Deserialize;

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct TableProps {
    pub storage: Option<StorageProps>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum StorageProps {
    Redacted_0(Redacted_0Props),
    Redacted_1(Redacted_1Props),
}

#[derive(Debug, Clone, Derivative, Deserialize)]
#[derivative(PartialEq)]
pub struct Redacted_0Props {
    pub normal_field: String,
    pub another_normal_field: String,
    #[derivative(PartialEq(compare_with = "compare_secret_string"))]
    pub secured_field: SecretString,
    #[derivative(PartialEq(compare_with = "compare_secret_string"))]
    pub another_secured_field: SecretString,
}

impl Eq for Redacted_0Props {}

#[derive(Debug, Clone, Derivative, Deserialize)]
#[derivative(PartialEq)]
pub struct Redacted_1Props {
    pub normal_field: String,
    pub another_normal_field: String,
    #[derivative(PartialEq(compare_with = "compare_secret_string"))]
    pub secured_field: SecretString,
    #[derivative(PartialEq(compare_with = "compare_secret_string"))]
    pub access_key_secret: SecretString,
}

fn compare_secret_string(a: &SecretString, b: &SecretString) -> bool {
    a.expose_secret() == b.expose_secret()
}

impl Eq for Redacted_1Props {}

/// Expose secret strings in props for serde. Struct defs must be kept in sync.
pub mod storage_exposed {
    use secrecy::ExposeSecret;
    use serde::Deserialize;
    use serde::Serialize;

    use crate::props::Redacted_1Props;
    use crate::props::Redacted_0Props;
    use crate::props::StorageProps;
    use crate::props::TableProps;

    fn secret_to_string(secret: secrecy::SecretString) -> String {
        secret.expose_secret().to_string()
    }

    #[derive(Serialize, Deserialize, o2o::o2o)]
    #[map_owned(TableProps)]
    pub struct TablePropsExposed {
        #[map(~.map(|props| props.into()))]
        pub storage: Option<StoragePropsExposed>,
    }

    #[derive(Serialize, Deserialize, o2o::o2o)]
    #[map_owned(StorageProps)]
    #[serde(tag = "type", rename_all = "snake_case")]
    pub enum StoragePropsExposed {
        Redacted_0(#[map(~.into())] Redacted_0PropsExposed),
        Redacted_1(#[map(~.into())] Redacted_1PropsExposed),
    }

    #[derive(Serialize, Deserialize, o2o::o2o)]
    #[map_owned(Redacted_0Props)]
    pub struct Redacted_0PropsExposed {
        pub normal_field: String,
        pub another_normal_field: String,

        #[from(secret_to_string(~))]
        #[into(~.into())]
        pub secured_field: String,

        #[from(secret_to_string(~))]
        #[into(~.into())]
        pub another_secured_field: String,
    }

    #[derive(Serialize, Deserialize, o2o::o2o)]
    #[map_owned(Redacted_1Props)]
    pub struct Redacted_1PropsExposed {
        pub normal_field: String,
        pub another_normal_field: String,

        #[from(secret_to_string(~))]
        #[into(~.into())]
        pub secured_field: String,

        #[from(secret_to_string(~))]
        #[into(~.into())]
        pub access_key_secret: String,
    }
}

Works perfectly so far.

I may have some further ideas like use mapstruct to keep fields update in sync. But with o2o the compiler can guard the convert bound. And I'd like a replacement for derivative which seems to be unmaintained but its current code works well. educe is weird and drive_more doesn't support PartialEq. Anyway, these seems out of the scope of this crate. Just share some related thoughts.

Thanks for this excellent crate. I'll adopt it further if it reaches 1.0 and stable API with considered.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions