softprops/dynomite

The trait bound `_: dynomite::Item` is not satisfied even with derive

phrohdoh opened this issue ยท 3 comments

๐Ÿ› Bug description

With the following code I get the following compilation error.

use dynomite::{
    Item,
};

#[derive(Debug, Clone, Item)]
pub struct User {
    #[hash]
    pub email_address: EmailAddress,
}

/// The partition key for [`User`]s
///
/// [`User`]: struct.User.html
#[derive(Debug, Clone, PartialEq, Item)]
pub struct EmailAddress {
    // This is a named field instead of being a newtype because
    // `dynomite::Item` requires, at the time of writing this,
    // named fields.
    pub value: String,
}
error[E0277]: the trait bound `models::dynamodb::EmailAddress: dynomite::Item` is not satisfied
 --> components/ubdgt-types/src/models/dynamodb.rs:5:24
  |
5 | #[derive(Debug, Clone, Item)]
  |                        ^^^^ the trait `dynomite::Item` is not implemented for `models::dynamodb::EmailAddress`
  |
  = note: required because of the requirements on the impl of `dynomite::Attribute` for `models::dynamodb::EmailAddress`
  = note: required by `dynomite::Attribute::into_attr`

Either I do not understand what the notes are trying to tell me or something is busted. I assume the former.

๐Ÿค” Expected Behavior

I expect this to compile as-is.

๐Ÿ‘Ÿ Steps to reproduce

Run cargo check against a Cargo project containing the above code.

Version Info

Relevant dependencies:

[dependencies.dynomite]
version = "^0.5" # 0.5.1 in Cargo.lock
default_features = false
features = [ "rustls" ]
optional = true

[dependencies.rusoto_core]
version = "^0.40"
default_features = false
features = [ "rustls" ]
optional = true

rustc version: rustc 1.36.0 (a53f9df32 2019-07-03)

Note that I would really rather prefer to keep email_address: EmailAddress as-is instead of changing to email_address: String if at all possible.

The solution was manually implementing Attribute for EmailAddress.

impl Attribute for EmailAddress {
    fn into_attr(self) -> AttributeValue {
        AttributeValue {
            s: Some(self.value),
            ..AttributeValue::default()
        }
    }

    fn from_attr(attr: AttributeValue) -> Result<Self, AttributeError> {
        attr
            .s
            .ok_or(AttributeError::InvalidType)
            .and_then(|s| Ok(EmailAddress { value: s }))
    }
}

Sorry for the noise!

@phrohdoh no worries. I actually feel like you made the right assumption at first and that this should "just" work but it doesn't currently :/

What you ended out implementing feels like boiler plate. The goal if this crate is to reduce that. I'll give some though to this an open a separate issue