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}