tablo_core/tenancy/
tenant_id.rs1use toasty::{
4 Error,
5 codegen_support::index::IndexableField,
6 schema::{Field, Load},
7 stmt::{self, Assign, Assignment, Expr, IntoExpr, List, Path, Projection, Value},
8};
9
10use crate::toasty_compat::Assignments;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
34pub struct TenantId(uuid::Uuid);
35
36impl TenantId {
37 pub const fn new(id: uuid::Uuid) -> Self {
39 Self(id)
40 }
41
42 pub fn get(self) -> uuid::Uuid {
44 self.0
45 }
46}
47
48impl From<uuid::Uuid> for TenantId {
49 fn from(id: uuid::Uuid) -> Self {
50 Self(id)
51 }
52}
53
54impl std::fmt::Display for TenantId {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 self.0.fmt(f)
57 }
58}
59
60impl std::str::FromStr for TenantId {
61 type Err = uuid::Error;
62
63 fn from_str(text: &str) -> Result<Self, Self::Err> {
64 uuid::Uuid::from_str(text).map(Self)
65 }
66}
67
68impl Load for TenantId {
69 type Output = Self;
70
71 fn ty() -> stmt::Type {
72 stmt::Type::Uuid
73 }
74
75 fn load(value: stmt::Value) -> Result<Self::Output, Error> {
76 match value {
77 stmt::Value::Uuid(id) => Ok(Self(id)),
78 _ => Err(Error::type_conversion(value, "TenantId")),
79 }
80 }
81
82 fn reload(target: &mut Self::Output, value: stmt::Value) -> Result<(), Error> {
83 *target = Self::load(value)?;
84 Ok(())
85 }
86}
87
88impl Field for TenantId {
89 type ExprTarget = Self;
90 type Path<Origin> = Path<Origin, Self>;
91 type ListPath<Origin> = Path<Origin, List<Self::ExprTarget>>;
92 type Update<'a> = ();
93 type Inner = Self;
94
95 fn new_path<Origin>(path: Path<Origin, Self>) -> Self::Path<Origin> {
96 path
97 }
98
99 fn new_list_path<Origin>(path: Path<Origin, List<Self::ExprTarget>>) -> Self::ListPath<Origin> {
100 path
101 }
102
103 fn new_update<'a>(
104 _assignments: &'a mut Assignments,
105 _projection: Projection,
106 ) -> Self::Update<'a> {
107 }
108
109 fn key_constraint<Origin>(&self, target: Path<Origin, Self::Inner>) -> Expr<bool> {
110 target.eq(*self)
111 }
112}
113
114impl IndexableField for TenantId {}
115
116impl IntoExpr<TenantId> for TenantId {
117 fn into_expr(self) -> Expr<TenantId> {
118 tenant_expr(self.0)
119 }
120
121 fn by_ref(&self) -> Expr<TenantId> {
122 tenant_expr(self.0)
123 }
124}
125
126impl Assign<TenantId> for TenantId {
127 fn into_assignment(self) -> Assignment<TenantId> {
128 toasty::stmt::set(IntoExpr::<TenantId>::into_expr(self))
129 }
130}
131
132fn tenant_expr(id: uuid::Uuid) -> Expr<TenantId> {
133 Expr::from_untyped(Value::Uuid(id))
134}
135
136#[diagnostic::on_unimplemented(
143 message = "`{Self}` is not a tenant column",
144 label = "not a tenant column",
145 note = "type the model's tenant field as `TenantId`, or `Option<TenantId>` for a nullable one"
146)]
147pub trait TenantColumn: Sized + Field + IntoExpr<Self> + Send + Sync + 'static {
148 fn from_tenant(id: TenantId) -> Self;
150}
151
152impl TenantColumn for TenantId {
153 fn from_tenant(id: TenantId) -> Self {
154 id
155 }
156}
157
158impl TenantColumn for Option<TenantId> {
159 fn from_tenant(id: TenantId) -> Self {
160 Some(id)
161 }
162}