use jiff::Timestamp as JiffTimestamp;
use smol_str::SmolStr;
use crate::{
buffa::error::BuffaError,
domain::{Uuid7, WatchedLocation},
generated::media::v1 as wire,
};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
#[allow(unused_imports)]
use std::{
borrow::ToOwned,
string::{String, ToString},
};
impl TryFrom<&wire::WatchedLocation> for WatchedLocation<Uuid7> {
type Error = BuffaError;
fn try_from(w: &wire::WatchedLocation) -> Result<Self, Self::Error> {
let id_wire = w
.id
.as_option()
.ok_or(BuffaError::MissingRequiredField("WatchedLocation.id"))?;
let id = Uuid7::try_from(id_wire)?;
let loc_wire = w
.location
.as_option()
.ok_or(BuffaError::MissingRequiredField("WatchedLocation.location"))?;
let local = match &loc_wire.kind {
Some(wire::location::Kind::Local(local)) => local.as_ref(),
None => return Err(BuffaError::MissingRequiredField("WatchedLocation.location")),
#[allow(unreachable_patterns)]
Some(_) => return Err(BuffaError::UnsupportedLocationKind),
};
let vol_wire = local
.volume
.as_option()
.ok_or(BuffaError::MissingLocationVolume)?;
let volume = Uuid7::try_from(vol_wire)?;
let added_at = ms_to_jiff(w.created_at)?;
WatchedLocation::try_new(id, volume, added_at).map_err(WatchedLocationConvert::from_err)
}
}
impl From<&WatchedLocation<Uuid7>> for wire::WatchedLocation {
fn from(d: &WatchedLocation<Uuid7>) -> Self {
let id = wire::Id::from(d.id_ref());
let location = wire::Location {
kind: Some(wire::location::Kind::Local(
::buffa::alloc::boxed::Box::new(wire::Local {
volume: ::buffa::MessageField::some(wire::Id::from(d.volume_ref())),
components: std::vec::Vec::new(),
__buffa_unknown_fields: Default::default(),
}),
)),
__buffa_unknown_fields: Default::default(),
};
let created_at = jiff_to_ms(d.added_at_ref());
wire::WatchedLocation {
id: ::buffa::MessageField::some(id),
location: ::buffa::MessageField::some(location),
name: SmolStr::default(),
status: 0,
created_at,
deleted_at: None,
total_files: 0,
indexed_files: 0,
total_videos: 0,
indexed_videos: 0,
total_scenes: 0,
total_audios: 0,
indexed_audios: 0,
total_failed_files: 0,
failed_videos: 0,
failed_audios: 0,
__buffa_unknown_fields: Default::default(),
}
}
}
fn ms_to_jiff(ms: i64) -> Result<JiffTimestamp, BuffaError> {
JiffTimestamp::from_millisecond(ms).map_err(|_| BuffaError::TimestampOutOfRange(ms))
}
fn jiff_to_ms(t: &JiffTimestamp) -> i64 {
t.as_millisecond()
}
mod watched_location_convert_impl {
use crate::{
buffa::error::BuffaError, domain::aggregates::watched_location::WatchedLocationError,
};
pub(super) struct WatchedLocationConvert;
impl WatchedLocationConvert {
pub(super) fn from_err(e: WatchedLocationError) -> BuffaError {
match e {
WatchedLocationError::NilId | WatchedLocationError::NilVolume => {
BuffaError::IdInvalid(crate::domain::primitives::Uuid7Error::Nil)
}
}
}
}
}
use watched_location_convert_impl::WatchedLocationConvert;
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
fn build_domain() -> WatchedLocation<Uuid7> {
WatchedLocation::try_new(
Uuid7::new(),
Uuid7::new(),
JiffTimestamp::from_millisecond(1_700_000_000_000).unwrap(),
)
.unwrap()
}
#[test]
fn domain_to_wire_to_domain_preserves_modelled_fields() {
let d = build_domain();
let w: wire::WatchedLocation = (&d).into();
let d2 = WatchedLocation::try_from(&w).expect("roundtrip");
assert_eq!(d.id_ref(), d2.id_ref());
assert_eq!(d.volume_ref(), d2.volume_ref());
assert_eq!(d.added_at_ref(), d2.added_at_ref());
assert!(!d2.is_recursive());
assert!(!d2.is_enabled());
assert!(!d2.is_ejectable());
assert!(d2.last_reconciled_at_ref().is_none());
assert!(d2.last_reconcile_status_ref().is_none());
assert!(d2.last_error_ref().is_none());
}
#[test]
fn wire_only_fields_emit_as_proto3_default() {
let d = build_domain();
let w: wire::WatchedLocation = (&d).into();
assert!(w.name.is_empty());
assert_eq!(w.status, 0);
assert!(w.deleted_at.is_none());
assert_eq!(w.total_files, 0);
assert_eq!(w.indexed_files, 0);
assert_eq!(w.total_videos, 0);
assert_eq!(w.indexed_audios, 0);
assert_eq!(w.failed_videos, 0);
}
fn wire_local(volume: &Uuid7) -> wire::Location {
wire::Location {
kind: Some(wire::location::Kind::Local(
::buffa::alloc::boxed::Box::new(wire::Local {
volume: ::buffa::MessageField::some(wire::Id::from(volume)),
components: std::vec::Vec::new(),
__buffa_unknown_fields: Default::default(),
}),
)),
__buffa_unknown_fields: Default::default(),
}
}
#[test]
fn wire_to_domain_missing_id_errors() {
let vol = Uuid7::new();
let w = wire::WatchedLocation {
id: ::buffa::MessageField::none(),
location: ::buffa::MessageField::some(wire_local(&vol)),
created_at: 0,
..Default::default()
};
let err = WatchedLocation::try_from(&w).unwrap_err();
assert!(err.is_missing_required_field());
}
#[test]
fn wire_to_domain_missing_location_errors() {
let id = Uuid7::new();
let w = wire::WatchedLocation {
id: ::buffa::MessageField::some(wire::Id::from(&id)),
location: ::buffa::MessageField::none(),
created_at: 0,
..Default::default()
};
let err = WatchedLocation::try_from(&w).unwrap_err();
assert!(err.is_missing_required_field());
}
}