use serde::{Deserialize, Serialize}; use time::{Date, OffsetDateTime}; use crate::ObjectId; /// Publication state of a catalogue record. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(rename_all = "lowercase")] pub enum Visibility { /// Work in progress; not shown anywhere public. #[default] Draft, /// Complete but internal-only. Internal, /// Published; eligible for the public API. Public, } impl Visibility { pub fn as_str(&self) -> &'static str { match self { Visibility::Draft => "draft", Visibility::Internal => "internal", Visibility::Public => "public", } } pub fn from_db(s: &str) -> Option { match s { "draft" => Some(Visibility::Draft), "internal" => Some(Visibility::Internal), "public" => Some(Visibility::Public), _ => None, } } } /// The mutable inventory-minimum fields of a catalogue object. #[derive(Debug, Clone, PartialEq)] pub struct ObjectInput { pub object_number: String, pub object_name: String, pub number_of_objects: i32, pub brief_description: Option, pub current_location: Option, pub current_owner: Option, pub recorder: Option, pub recording_date: Option, pub visibility: Visibility, } /// A catalogue object (or group of objects), read back from storage. #[derive(Debug, Clone, PartialEq)] pub struct CatalogueObject { pub id: ObjectId, pub object_number: String, pub object_name: String, pub number_of_objects: i32, pub brief_description: Option, pub current_location: Option, pub current_owner: Option, pub recorder: Option, pub recording_date: Option, pub visibility: Visibility, pub created_at: OffsetDateTime, pub updated_at: OffsetDateTime, } impl CatalogueObject { /// The mutable fields as an [`ObjectInput`] (used to diff against an update). pub fn to_input(&self) -> ObjectInput { ObjectInput { object_number: self.object_number.clone(), object_name: self.object_name.clone(), number_of_objects: self.number_of_objects, brief_description: self.brief_description.clone(), current_location: self.current_location.clone(), current_owner: self.current_owner.clone(), recorder: self.recorder.clone(), recording_date: self.recording_date, visibility: self.visibility, } } } #[cfg(test)] mod tests { use super::*; #[test] fn visibility_round_trips_and_defaults_to_draft() { for v in [Visibility::Draft, Visibility::Internal, Visibility::Public] { assert_eq!(Visibility::from_db(v.as_str()), Some(v)); } assert_eq!(Visibility::from_db("secret"), None); assert_eq!(Visibility::default(), Visibility::Draft); } #[test] fn visibility_serde_matches_as_str() { for v in [Visibility::Draft, Visibility::Internal, Visibility::Public] { assert_eq!( serde_json::to_value(v).unwrap(), serde_json::Value::String(v.as_str().to_owned()) ); } } }