feat(domain): add OrgId newtype
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
/// Identifier for an organization (tenant).
|
||||||
|
///
|
||||||
|
/// A newtype over [`Uuid`] so it can never be confused with another entity's id.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct OrgId(Uuid);
|
||||||
|
|
||||||
|
impl OrgId {
|
||||||
|
/// Generate a fresh random id.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(Uuid::new_v4())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap an existing [`Uuid`].
|
||||||
|
pub fn from_uuid(uuid: Uuid) -> Self {
|
||||||
|
Self(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The underlying [`Uuid`].
|
||||||
|
pub fn as_uuid(&self) -> Uuid {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OrgId {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for OrgId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for OrgId {
|
||||||
|
type Err = uuid::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self(Uuid::parse_str(s)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_and_displays_round_trip() {
|
||||||
|
let text = "550e8400-e29b-41d4-a716-446655440000";
|
||||||
|
let id: OrgId = text.parse().expect("valid uuid should parse");
|
||||||
|
assert_eq!(id.to_string(), text);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_invalid_uuid() {
|
||||||
|
assert!("not-a-uuid".parse::<OrgId>().is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,5 @@
|
|||||||
//! Core domain types and invariants. No I/O dependencies.
|
//! Core domain types and invariants. No I/O dependencies.
|
||||||
|
|
||||||
|
mod id;
|
||||||
|
|
||||||
|
pub use id::OrgId;
|
||||||
|
|||||||
Reference in New Issue
Block a user