pub struct StateExpectation {
pub case_id: CaseId,
pub path: String,
pub equals: Option<Value>,
pub one_of: Vec<Value>,
pub unchanged: bool,
pub absent: bool,
pub ignore_case: bool,
}Expand description
What a case’s state must say after the turn.
The path is a JSON Pointer into the workflow’s own state, because the state
is the workflow’s business and this crate cannot know its shape — so an item
says /fields/address_street/value and the library compares what it finds
there, with no opinion about what a field is.
Fields§
§case_id: CaseIdThe case this is about.
path: StringJSON Pointer into that case’s state, as the workflow serializes it.
equals: Option<Value>The value that path must hold afterwards.
one_of: Vec<Value>Values any one of which that path may hold afterwards: the user’s words read right in more than one form, such as with or without an article.
unchanged: boolThe value that path must still hold, whatever it was.
absent: boolNothing must be there: the path holds null, or does not resolve.
§Why this is not equals: null
Because that cannot be written. equals is an
Option, so a JSON null deserializes as «no expectation given» and
validate then refuses the whole entry for asserting
nothing. The absence had no way to be said at all.
§What could not be measured without it
«I do not have one» is an answer, not a silence, and a collecting workflow often turns on it: a person who declines their loyalty number has answered the question, and the flow moves on. What the turn must do is record the refusal — a field that ends with no value and a status that moved — and every expectation this crate had asserts that a value IS somewhere. A suite measuring those flows could state the value case and not its opposite, which is the half that goes wrong: a turn that quietly writes something into a field the user declined reads, to every other assertion, exactly like a turn that respected them.
Resolving to nothing counts as absent on purpose. A workflow may drop the key instead of nulling it, and an assertion that told those two apart would be about the serializer rather than about the record.
ignore_case: boolTwo strings differing only in case are the same value here.
Only meaningful beside equals, and only for a field
whose case the application does not decide. That is a real category and
not a loophole: a domain canonicalises what it owns, a booking reference
to upper case or a loyalty number to its letters and digits, and stores a
free-text field the way it was handed it, because nobody can guess how a
person or a place writes its own name.
On those fields the case is the model’s typography, not the record’s content. A person types «lisbon», one turn stores «lisbon» and the next «Lisbon», and both are the same answer to the same question: an assertion that told them apart would report the lane as wrong for capitalising a city. Leave it off — the default — wherever the application does canonicalise, because there the case IS the content and a lower-case booking reference is one the airline does not find.
It never applies to unchanged or absent, which compare no text.
Implementations§
Source§impl StateExpectation
impl StateExpectation
Sourcepub fn validate(&self) -> Result<(), CorpusError>
pub fn validate(&self) -> Result<(), CorpusError>
Checks the expectation asks exactly one thing.
§Errors
CorpusError::Invalid when it asks more than one thing, or none at
all. None is the dangerous one: it would read as a strict assertion and
check nothing.
Trait Implementations§
Source§impl Clone for StateExpectation
impl Clone for StateExpectation
Source§impl Debug for StateExpectation
impl Debug for StateExpectation
Source§impl<'de> Deserialize<'de> for StateExpectation
impl<'de> Deserialize<'de> for StateExpectation
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for StateExpectation
Source§impl PartialEq for StateExpectation
impl PartialEq for StateExpectation
Source§impl Serialize for StateExpectation
impl Serialize for StateExpectation
impl StructuralPartialEq for StateExpectation
Auto Trait Implementations§
impl Freeze for StateExpectation
impl RefUnwindSafe for StateExpectation
impl Send for StateExpectation
impl Sync for StateExpectation
impl Unpin for StateExpectation
impl UnsafeUnpin for StateExpectation
impl UnwindSafe for StateExpectation
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.