Skip to main content

tablo_core/declaration/
tenancy.rs

1//! The declaration mistakes of a resource's tenancy, and their wording.
2
3use std::fmt;
4
5/// Why a resource's tenancy cannot scope its rows:
6/// [`DeclarationErrorKind::Tenancy`](super::DeclarationErrorKind::Tenancy).
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum TenancyFault {
10    /// No tenancy declared over a model with a `TenantId` column, which would serve every
11    /// tenant's rows.
12    ///
13    /// Declare `Tenancy::column` over that field, or `Tenancy::none()` to serve every tenant.
14    Undeclared {
15        /// The model's name.
16        model: &'static str,
17        /// The model's tenant columns.
18        columns: Vec<&'static str>,
19    },
20    /// No tenancy declared over a model that belongs to one a mounted resource scopes by tenant,
21    /// which would serve every tenant's children.
22    ///
23    /// Declare `Tenancy::via` through that relation, or `Tenancy::none()` to serve every tenant.
24    UndeclaredChild {
25        /// The model's name.
26        model: &'static str,
27        /// The `belongs_to` relation to the tenant-owned parent.
28        relation: String,
29    },
30    /// A `Tenancy::column` lens that names no field of the model.
31    ///
32    /// Name the model's `TenantId` field, or use `Tenancy::via`.
33    ColumnNotAField,
34    /// A `Tenancy::via` lens that names one field of the model.
35    ///
36    /// Use `Tenancy::column`.
37    ViaOwnColumn,
38    /// A `Tenancy::via` lens whose first step is no `belongs_to` relation.
39    ///
40    /// Start at the relation whose parent holds the tenant.
41    ViaWithoutBelongsTo,
42    /// A `Tenancy::via` resource whose form writes the parent's foreign key other than through a
43    /// relationship field over a tenant-scoped resource of the parent's model.
44    ///
45    /// Write the key through such a choice, so the write re-checks its tenant.
46    UnguardedForeignKey {
47        /// The `belongs_to` relation the lens steps through.
48        relation: String,
49        /// The foreign-key columns written another way.
50        keys: Vec<String>,
51    },
52}
53
54impl fmt::Display for TenancyFault {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match self {
57            Self::Undeclared { model, columns } => write!(
58                f,
59                "`{model}` has the tenant column `{}` and the resource declares no tenancy, so \
60                 it would serve every tenant's rows: declare \
61                 `Tenancy::column(lens!({model}.{}))`, or `Tenancy::none()` to serve every \
62                 tenant on purpose",
63                columns.join("`, `"),
64                columns.first().copied().unwrap_or_default(),
65            ),
66            Self::UndeclaredChild { model, relation } => write!(
67                f,
68                "`{model}` belongs to `{relation}`, whose rows a tenant-scoped resource serves, \
69                 and the resource declares no tenancy, so it would serve every tenant's rows: \
70                 declare `Tenancy::via({model}::fields().{relation}().<tenant column>())`, or \
71                 `Tenancy::none()` to serve every tenant on purpose"
72            ),
73            Self::ColumnNotAField => f.write_str(
74                "the `Tenancy::column` lens names no field of the model: name a field typed \
75                 `TenantId`, or use `Tenancy::via` for a tenant reached through a relation",
76            ),
77            Self::ViaOwnColumn => f.write_str(
78                "the `Tenancy::via` lens names one field of the model: use `Tenancy::column` for \
79                 the model's own tenant column",
80            ),
81            Self::ViaWithoutBelongsTo => f.write_str(
82                "the `Tenancy::via` lens does not start at a `belongs_to` relation: the tenant \
83                 must be the parent's its foreign key names",
84            ),
85            Self::UnguardedForeignKey { relation, keys } => write!(
86                f,
87                "foreign key `{}` is not written through a relationship field over a \
88                 tenant-scoped resource of `{relation}`'s model: the write re-checks only such a \
89                 field's key, so any other could attach the row to another tenant's parent",
90                keys.join("`, `")
91            ),
92        }
93    }
94}