//! Identifiers. //! //! Newtypes rather than bare `String`s, so a feed id cannot be passed where a //! user id belongs. They are stored as TEXT: v1 declared //! `external_calendars.user_id INTEGER` against a TEXT `users.id`, and because //! SQLite does not enforce foreign key types the constraint silently could //! never match. use serde::{Deserialize, Serialize}; use std::fmt; macro_rules! id_type { ($name:ident, $entity:literal) => { #[doc = concat!("The identity of a ", $entity, ".")] #[derive( Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, sqlx::Type, )] #[serde(transparent)] #[sqlx(transparent)] pub struct $name(pub String); impl $name { /// A fresh random identifier. pub fn new() -> Self { Self(uuid::Uuid::new_v4().to_string()) } pub fn as_str(&self) -> &str { &self.0 } } impl Default for $name { fn default() -> Self { Self::new() } } impl fmt::Display for $name { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } } impl From for $name { fn from(value: String) -> Self { Self(value) } } impl From<&str> for $name { fn from(value: &str) -> Self { Self(value.to_owned()) } } }; } id_type!(UserId, "user"); id_type!(FeedId, "subscribed feed");