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