teaql-core 4.2.0

TeaQL core, SQL, runtime, dialect, and macro crates for model-driven data access
Documentation
use serde::{Deserialize, Deserializer, Serializer};

pub mod trimmed_string {
    use super::*;

    pub fn serialize<S>(value: &str, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(value.trim())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        Ok(s.trim().to_owned())
    }
}

pub mod trimmed_opt_string {
    use super::*;

    pub fn serialize<S>(value: &Option<String>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match value {
            Some(v) => serializer.serialize_str(v.trim()),
            None => serializer.serialize_none(),
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let opt = Option::<String>::deserialize(deserializer)?;
        Ok(opt.map(|s| s.trim().to_owned()))
    }
}

#[cfg(test)]
mod tests {
    use serde::{Deserialize, Serialize};

    use super::{trimmed_opt_string, trimmed_string};

    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    struct TrimmedFields {
        #[serde(with = "trimmed_string")]
        required: String,
        #[serde(default, with = "trimmed_opt_string")]
        optional: Option<String>,
    }

    #[test]
    fn trimmed_string_helpers_trim_during_serialization() {
        let fields = TrimmedFields {
            required: "  required value\n".to_owned(),
            optional: Some("\toptional value  ".to_owned()),
        };

        assert_eq!(
            serde_json::to_value(fields).expect("trimmed fields should serialize"),
            serde_json::json!({
                "required": "required value",
                "optional": "optional value"
            })
        );
    }

    #[test]
    fn trimmed_optional_string_preserves_none_during_serialization() {
        let fields = TrimmedFields {
            required: " value ".to_owned(),
            optional: None,
        };

        assert_eq!(
            serde_json::to_value(fields).expect("trimmed fields should serialize"),
            serde_json::json!({
                "required": "value",
                "optional": null
            })
        );
    }

    #[test]
    fn trimmed_string_helpers_trim_during_deserialization() {
        let fields: TrimmedFields = serde_json::from_value(serde_json::json!({
            "required": "  required value\n",
            "optional": "\toptional value  "
        }))
        .expect("trimmed fields should deserialize");

        assert_eq!(
            fields,
            TrimmedFields {
                required: "required value".to_owned(),
                optional: Some("optional value".to_owned()),
            }
        );
    }

    #[test]
    fn trimmed_optional_string_keeps_whitespace_only_input_as_some_empty() {
        let fields: TrimmedFields = serde_json::from_value(serde_json::json!({
            "required": " value ",
            "optional": " \t\n "
        }))
        .expect("trimmed fields should deserialize");

        assert_eq!(fields.required, "value");
        assert_eq!(fields.optional, Some(String::new()));
    }
}