Skip to main content

tablo_core/schema/fields/builders/
comparisons.rs

1//! The text builder's comparisons with another field of its form.
2
3use super::{
4    super::super::comparison::{Comparison, Relation},
5    TextField,
6};
7
8impl<F> TextField<F> {
9    fn compare(mut self, relation: Relation, other: &TextField<F>) -> Self {
10        let other = other.name().to_string();
11        self.text().comparisons.push(Comparison { relation, other });
12        self
13    }
14
15    /// Refuse a value not above `other`'s, a field of the same form and type that orders: a
16    /// number, or a `jiff` date, time, date and time, or timestamp.
17    ///
18    /// ```rust
19    /// # #[derive(Debug, Clone, toasty::Model, tablo_core::ModelColumns)]
20    /// # struct Trip {
21    /// #     #[key] #[auto] id: uuid::Uuid,
22    /// #     starts_on: jiff::civil::Date,
23    /// #     ends_on: Option<jiff::civil::Date>,
24    /// # }
25    /// # use tablo_core::{Field, Schema, lens};
26    /// let starts = Field::text(lens!(Trip.starts_on));
27    /// let ends = Field::text(lens!(Trip.ends_on)).gte(&starts);
28    /// Schema::new((starts, ends));
29    /// ```
30    ///
31    /// - Only the server checks it, in the same round as the controls' other rules, and the error
32    ///   renders on this field, naming the other by its label.
33    /// - The other's value is its posted one, else the one the record stores, as a field disabled
34    ///   on edit posts none. A blank value on either side, or another field a condition hides,
35    ///   skips the comparison: whether a value is required is the field's type to say.
36    /// - An edit that changes neither field does not check them again, as a value the record
37    ///   already stores is not; changing either one does.
38    /// - An edit checks a repeater row's comparisons again unless the row's two fields keep the
39    ///   values the record stores at the same row position.
40    /// - A field of `Option<T>` compares with one of `T`. Mounting refuses the field itself,
41    ///   another field the schema does not place, one of another type or control, and a type
42    ///   without an order. A repeater's row field compares with another field of the same row.
43    /// - The refusal tells what the other field holds, so mounting also refuses one that a
44    ///   [`FieldAccess`](crate::FieldAccess) `view` rule hides from some user:
45    ///   [`FieldAccessFault::Watched`](crate::FieldAccessFault::Watched).
46    pub fn gt(self, other: &TextField<F>) -> Self {
47        self.compare(Relation::Gt, other)
48    }
49
50    /// Refuse a value below `other`'s: [`gt`](Self::gt) has the rules.
51    pub fn gte(self, other: &TextField<F>) -> Self {
52        self.compare(Relation::Gte, other)
53    }
54
55    /// Refuse a value not below `other`'s: [`gt`](Self::gt) has the rules.
56    pub fn lt(self, other: &TextField<F>) -> Self {
57        self.compare(Relation::Lt, other)
58    }
59
60    /// Refuse a value above `other`'s: [`gt`](Self::gt) has the rules.
61    pub fn lte(self, other: &TextField<F>) -> Self {
62        self.compare(Relation::Lte, other)
63    }
64
65    /// Refuse a value equal to `other`'s, as the field's type reads both: `01` equals `1` for an
66    /// integer, but text compares as typed, so `Ada` differs from `ada`. [`gt`](Self::gt) has the
67    /// rules, but any type compares.
68    pub fn different(self, other: &TextField<F>) -> Self {
69        self.compare(Relation::Different, other)
70    }
71}