The trait `From<Option<std::string::String>>` is not implemented for `Option<Email>`

I am trying to use the newtype pattern with sqlx and running into errors with optional/nullable types.

I have defined a User struct as so:

pub struct User {
    pub id: UserId,
    pub username: Username,
    pub email: Option<Email>,

With custom types like:

#[derive(Debug, From, Into)]
pub struct UserId(pub i64);

#[derive(Debug, From, FromStr, Into, AsRef)]
pub struct Username(pub String);

#[derive(Debug, From, FromStr, Into, AsRef)]
pub struct Email(pub String);

I am using the derive_more crate for the impls. However, when I attempt to insert a User without an Email I receive the error that Option<String> is not implemented for Option<Email>. But I'm confused because Email has the string derives. It works fine if I change my User struct to have email: Option<String> instead.

async fn create_user(pool: &PgPool, username: Username) -> anyhow::Result<User> {
    sqlx::query_file_as!(User, "src/sql/create_user.sql", username.as_ref())

Where create_user.sql is simply:

insert into "user" (
values (
  $1 -- username
returning *

The email column in the table is just email text default null

What am I missing to convert the Option<String> back into my Option<Email>?


Email may implement From<String>, but Option<Email> does not implement From<Option<String>> (as your title says). Email and Option<Email> are distinct types. Since you can't implement a foreign trait on a foreign type, just implmenting From<Option<String>> for Option<Email> is off the table, unfortunately. As an alternative, maybe you can add another layer of wrapping with a struct MaybeEmail(Option<Email>) and derive From<Option<String>> for that (maybe manually instead of using derive_more).

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.