confique icon indicating copy to clipboard operation
confique copied to clipboard

Automatic support for `skip_serializing_if` on each field

Open milesj opened this issue 1 year ago • 0 comments

Hey 👋 very excited for this crate. The way it was implemented is very similar to ideas I had for my own crate... which I never started.

One thing I would love to see is support for serialization, but more specifically, the skip_serializing_if field setting. We use this extensively on pretty much every field, because we don't want to write back to our config fields with empty or default values.

For example, here's a current config struct of ours:

#[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize, Validate)]
#[schemars(default)]
#[serde(default, rename_all = "camelCase")]
pub struct ProjectConfig {
    #[serde(skip_serializing_if = "is_default")]
    pub depends_on: Vec<ProjectDependsOn>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub env: Option<FxHashMap<String, String>>,

    #[serde(skip_serializing_if = "is_default")]
    #[validate(custom = "validate_file_groups")]
    pub file_groups: FileGroups,

    #[serde(
        deserialize_with = "deserialize_language",
        skip_serializing_if = "is_default"
    )]
    pub language: ProjectLanguage,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub platform: Option<PlatformType>,

    #[serde(skip_serializing_if = "Option::is_none")]
    #[validate]
    pub project: Option<ProjectMetadataConfig>,

    #[serde(skip_serializing_if = "is_default")]
    #[validate(custom = "validate_tags")]
    pub tags: Vec<String>,

    #[serde(skip_serializing_if = "is_default")]
    #[validate(custom = "validate_tasks")]
    #[validate]
    pub tasks: BTreeMap<String, TaskConfig>,

    #[serde(skip_serializing_if = "is_default")]
    #[validate]
    pub toolchain: ProjectToolchainConfig,

    #[serde(skip_serializing_if = "is_default")]
    #[serde(rename = "type")]
    pub type_of: ProjectType,

    #[serde(skip_serializing_if = "is_default")]
    #[validate]
    pub workspace: ProjectWorkspaceConfig,

    /// JSON schema URI
    #[serde(rename = "$schema", skip_serializing_if = "is_default")]
    pub schema: String,

    /// Unknown fields
    #[serde(flatten)]
    #[schemars(skip)]
    pub unknown: BTreeMap<String, serde_yaml::Value>,
}

In a perfect confique world, I could see it looking something like this:

#[derive(Config)]
#[config(json_schema = true, typescript = true)]
#[serde(rename_all = "camelCase")]
pub struct ProjectConfig {
    #[config]
    pub depends_on: Vec<ProjectDependsOn>,

    #[config]
    pub env: Option<FxHashMap<String, String>>,

    #[config(validate = "validate_file_groups")]
    pub file_groups: FileGroups,

    #[config]
    #[serde(deserialize_with = "deserialize_language")]
    pub language: ProjectLanguage,

    #[config]
    pub platform: Option<PlatformType>,

    #[config]
    pub project: Option<ProjectMetadataConfig>,

    #[config(validate = "validate_tags")]
    pub tags: Vec<String>,

    #[config(validate = "validate_tasks")]
    pub tasks: BTreeMap<String, TaskConfig>,

    #[config]
    pub toolchain: ProjectToolchainConfig,

    #[config]
    #[serde(rename = "type")]
    pub type_of: ProjectType,

    #[config]
    pub workspace: ProjectWorkspaceConfig,

    /// JSON schema URI
    #[config]
    #[serde(rename = "$schema")]
    pub schema: String,

    /// Unknown fields
    #[serde(flatten)]
    #[schemars(skip)]
    pub unknown: BTreeMap<String, serde_yaml::Value>,
}

milesj avatar Mar 23 '23 20:03 milesj