tablo_core/declaration/many_to_many.rs
1//! The declaration mistakes of a many-to-many field or relation, and their wording.
2
3use std::fmt;
4
5/// Why a many-to-many field or relation cannot link records:
6/// [`DeclarationErrorKind::ManyToMany`](super::DeclarationErrorKind::ManyToMany).
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum ManyToManyFault {
10 /// The field is no `#[has_many(via = joins.target)]` stepping through a `has_many` to a join
11 /// model, then the join model's `belongs_to` to the target.
12 ///
13 /// Declare it through a `has_many` to the join model and the join model's `belongs_to`.
14 NotJoinModel,
15 /// A foreign key of the join model spans several columns, or references no single-column
16 /// primary key.
17 ///
18 /// Key each side by one column.
19 CompositeKey,
20 /// The join model has a column a new link cannot fill: not nullable, not `#[auto]`, and not
21 /// one of its two foreign keys.
22 ///
23 /// Make it nullable or `#[auto]`, or link the records in your own record fn.
24 UnwritableColumn {
25 /// The join model.
26 model: String,
27 /// The column.
28 column: String,
29 },
30 /// The form's control for the field is not a multiple choice over a relationship.
31 ///
32 /// Declare `.choice().relationship::<R>().multiple()`.
33 NotMultipleChoice,
34 /// The relationship's records are not the target's.
35 ///
36 /// Point the relationship at the target's resource.
37 OtherSource,
38 /// A multiple choice in a resource's form over no many-to-many field, which no column stores.
39 ///
40 /// Bind it to a `#[has_many(via = ..)]` field.
41 NoJoin,
42}
43
44/// [`DeclarationErrorKind::ManyToMany`](super::DeclarationErrorKind::ManyToMany)'s sentence.
45pub(super) fn fmt_many_to_many(
46 f: &mut fmt::Formatter<'_>,
47 field: &str,
48 fault: &ManyToManyFault,
49) -> fmt::Result {
50 match fault {
51 ManyToManyFault::NotJoinModel => write!(
52 f,
53 "`{field}` is no many-to-many field: declare it \
54 `#[has_many(via = joins.target)]`, through a `has_many` to a join model and \
55 the join model's `belongs_to` to the target"
56 ),
57 ManyToManyFault::CompositeKey => write!(
58 f,
59 "`{field}`'s join model holds a key of several columns, or one referencing no \
60 single-column primary key: a link writes one column per side"
61 ),
62 ManyToManyFault::UnwritableColumn { model, column } => write!(
63 f,
64 "`{field}`'s join model `{model}` has a column `{column}` a new link cannot \
65 fill: make it nullable or `#[auto]`, or link the records in your own record fn"
66 ),
67 ManyToManyFault::NotMultipleChoice => write!(
68 f,
69 "`{field}` is a many-to-many field, so its control is a multiple choice over \
70 a relationship: `.choice().relationship::<R>().multiple()`"
71 ),
72 ManyToManyFault::OtherSource => write!(
73 f,
74 "`{field}` offers another model's records than the ones its join model links"
75 ),
76 ManyToManyFault::NoJoin => write!(
77 f,
78 "multiple choice `{field}` names no many-to-many field of the model, so \
79 nothing would store its records: bind it to a `#[has_many(via = ..)]` field"
80 ),
81 }
82}