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