Keats / validator

Simple validation for Rust structs
MIT License
1.91k stars 140 forks source link

Migration possible from 0.16 to 0.17 without named fields? #298

Closed snaeil closed 4 months ago

snaeil commented 4 months ago

Summary

I didn't find a good way to migrate a struct without named fields to validator of version 0.17. See below my previous version and what I tried to do (but failed). Is it still possible to use a struct without named fields as in 0.16.0?

How it was with 0.16

use validator::validate_email;

#[derive(Debug)]
pub struct SubscriberEmail(String);

impl SubscriberEmail {
    pub fn parse(s: String) -> Result<SubscriberEmail, String> {
        if validate_email(&s) {
            Ok(Self(s))
        } else {
            Err(format!("{} is not a valid subscriber email.", s))
        }
    }
}

impl AsRef<str> for SubscriberEmail {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

What I tried with 0.17 (failing)

use validator::{Validate, ValidationError};

#[derive(Debug, Clone, Validate)]
#[validate(email(message = "This field must be a valid email address."))]
pub struct SubscriberEmail(String);

impl SubscriberEmail {
    pub fn parse(s: String) -> Result<SubscriberEmail, String> {
        Ok(Self(s))
    }
}

impl AsRef<str> for SubscriberEmail {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

I am getting

error: Unknown field: `email`

and

error: Unsupported shape `one unnamed field`. Expected named fields.
Keats commented 4 months ago

You are not using validator in the 0.16 example, just calling one validator function. You can import https://docs.rs/validator/latest/validator/trait.ValidateEmail.html and the code would be very similar to the 0.16 example.

As for structs with no named fields I don't believe they were supported in 0.16 (I think? I can't remember) and still aren't in 0.17. It could be added but first we need to revamp the whole error interface since it does expect a name

snaeil commented 4 months ago

Thanks @Keats !

I now managed to make it work like this:

use validator::ValidateEmail;

#[derive(Debug, Clone)]
pub struct SubscriberEmail(String);

impl SubscriberEmail {
    pub fn parse(s: String) -> Result<SubscriberEmail, String> {
        let result = Self(s.clone());
        if result.validate_email() {
            Ok(result)
        } else {
            Err(format!("{} is not a valid subscriber email.", s))
        }
    }
}

impl ValidateEmail for SubscriberEmail {
    fn as_email_string(&self) -> Option<std::borrow::Cow<str>> {
        Some(self.0.as_str().into())
    }
}

impl AsRef<str> for SubscriberEmail {
    fn as_ref(&self) -> &str {
        &self.0
    }
}