use evidentsource_core::domain::{DatabaseName, EventSelector, StateView, StateViewName};
use crate::com::evidentsource as proto;
use super::error::ConversionError;
use super::timestamps::timestamp_to_datetime;
impl TryFrom<proto::StateView> for StateView {
type Error = ConversionError;
fn try_from(proto: proto::StateView) -> Result<Self, Self::Error> {
let identity = proto
.identity
.ok_or_else(|| ConversionError::missing_field("StateView", "identity"))?;
let database = DatabaseName::new(&identity.database_name)?;
let name = StateViewName::new(&identity.state_view_name)?;
let event_selector_proto = proto
.event_selector
.ok_or_else(|| ConversionError::missing_field("StateView", "event_selector"))?;
let event_selector = EventSelector::try_from(event_selector_proto)?;
let last_modified_timestamp = proto.last_modified.map(timestamp_to_datetime).transpose()?;
let last_modified_revision = if proto.last_modified_revision > 0 {
Some(proto.last_modified_revision)
} else {
None
};
let content = match proto.content {
Some(proto::state_view::Content::Data(bytes)) => Some(bytes),
Some(proto::state_view::Content::Url(_)) => {
None
}
None => None,
};
Ok(StateView {
database,
name,
version: identity.state_view_version,
event_selector,
last_modified_revision,
last_modified_timestamp,
content_type: proto.content_type,
content_schema_url: proto.content_schema_url.filter(|s| !s.is_empty()),
content,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_view_conversion() {
let proto = proto::StateView {
identity: Some(proto::StateViewIdentity {
database_name: "test-db".to_string(),
state_view_name: "test-view".to_string(),
state_view_version: 1,
}),
event_selector: Some(proto::EventSelector {
selector: Some(proto::event_selector::Selector::Equals(
proto::EventAttribute {
attribute: Some(proto::event_attribute::Attribute::Stream(
"my-stream".to_string(),
)),
},
)),
}),
last_modified: None,
last_modified_revision: 0,
content_type: "application/json".to_string(),
content_schema_url: None,
content: Some(proto::state_view::Content::Data(
b"{\"count\": 42}".to_vec(),
)),
};
let domain: StateView = proto.try_into().unwrap();
assert_eq!(domain.database.as_str(), "test-db");
assert_eq!(domain.name.as_str(), "test-view");
assert_eq!(domain.version, 1);
assert_eq!(domain.content_type, "application/json");
assert!(domain.content.is_some());
}
}