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