Skip to content

Patch recursively #97

@dnsl48

Description

@dnsl48

Hi, thank you for the great crate! It's really neat and is quite useful as it is!

I was wondering if I missed it in the docs and if not, whether you thought about adding support for recursive patches.

E.g. I have a DTO that contains a couple of other DTOs as fields. Each of those also implements "Patch" trait.
At the moment, when I call "into_patch_by_diff" for the top-level structure, it does correctly identify the changes in the included entities (as long as they implement PartialEq).
However, the top-level patch then includes the entire struct, not its own patch.

It would be neat to support included structs (that derive Patch even without PartialEq) to capture the specific changes in there. That would reduce the unnecessary data duplication in the multi-layered structs and open up better handling for structures with #[serde(flatten)] and #[diesel(embed)].

What do you think?

Code snippet for the use case

#[derive(Clone, Debug, Deserialize, Serialize, Patch)]
#[patch(attribute(derive(Serialize, Deserialize, Debug)))]
pub struct ProfileDTO {
    // meta
    #[patch(skip)]
    pub id: Uuid,

    #[serde(flatten)]
    #[patch(attribute(serde(flatten)))]
    pub identity_fields: ProfileIdentityFieldsDTO,

    #[serde(flatten)]
    #[patch(attribute(serde(flatten)))]
    pub contact_fields: ProfileContactFieldsDTO,
}

#[derive(Clone, Debug, Deserialize, Serialize, Patch, Eq, PartialEq)]
#[patch(attribute(derive(Serialize, Deserialize, Debug)))]
pub struct ProfileIdentityFieldsDTO {
    #[patch(attribute(serde(skip_serializing_if = "Option::is_none")))]
    pub first_name: Option<String>,

    #[patch(attribute(serde(skip_serializing_if = "Option::is_none")))]
    pub last_name: Option<String>,

    #[patch(attribute(serde(skip_serializing_if = "Option::is_none")))]
    pub middle_name: Option<String>,
}


#[derive(Clone, Debug, Deserialize, Serialize, Patch, Eq, PartialEq)]
#[patch(attribute(derive(Serialize, Deserialize, Debug)))]
pub struct ProfileContactFieldsDTO {
    #[patch(attribute(serde(skip_serializing_if = "Option::is_none")))]
    pub email: Option<String>,
    
    #[patch(attribute(serde(skip_serializing_if = "Option::is_none")))]
    pub phone_number: Option<String>,
}

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