pub trait InteractionWriter: Send + Sync {
// Required methods
fn insert<'life0, 'async_trait>(
&'life0 self,
interaction: Interaction,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn insert_replacing_blocking<'life0, 'async_trait>(
&'life0 self,
interaction: Interaction,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn begin_resolution<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
id: &'life2 InteractionId,
expected_status: InteractionStatus,
option_id: OptionId,
resolved_by: TurnId,
) -> Pin<Box<dyn Future<Output = Result<InteractionRecord, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn finish_resolution<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
id: &'life2 InteractionId,
outcome: ResolutionOutcome,
) -> Pin<Box<dyn Future<Output = Result<InteractionRecord, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn invalidate_for_case<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
case_key: &'life2 CaseKey,
new_revision: CaseRevision,
reason: InvalidationReason,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn invalidate_case_cards<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
case_key: &'life2 CaseKey,
reason: InvalidationReason,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn expire_due<'life0, 'async_trait>(
&'life0 self,
now: DateTime<Utc>,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}Expand description
The write half of the interaction contract.
Required Methods§
Sourcefn insert<'life0, 'async_trait>(
&'life0 self,
interaction: Interaction,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn insert<'life0, 'async_trait>(
&'life0 self,
interaction: Interaction,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Inserts a new Active interaction.
§Errors
Other(INVALID_RECORD)wheninteraction.statusis notActive.Conflictwhen the identifier exists for the account, or when the interaction is blocking and its case already has an open blocking interaction (I5).
Sourcefn insert_replacing_blocking<'life0, 'async_trait>(
&'life0 self,
interaction: Interaction,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn insert_replacing_blocking<'life0, 'async_trait>(
&'life0 self,
interaction: Interaction,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Inserts a new Active interaction, invalidating the Active blocking
occupant of the same case when there is one. Returns the identifiers it
invalidated (empty when the slot was free or the new card is not
blocking).
§Errors
Other(INVALID_RECORD)wheninteraction.statusis notActive.Conflictwhen the identifier exists, or when the occupant isResolving(its commands are executing; it cannot be replaced).
Sourcefn begin_resolution<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
id: &'life2 InteractionId,
expected_status: InteractionStatus,
option_id: OptionId,
resolved_by: TurnId,
) -> Pin<Box<dyn Future<Output = Result<InteractionRecord, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn begin_resolution<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
id: &'life2 InteractionId,
expected_status: InteractionStatus,
option_id: OptionId,
resolved_by: TurnId,
) -> Pin<Box<dyn Future<Output = Result<InteractionRecord, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Compare-and-swap expected_status → Resolving, recording the chosen
option and the resolving turn. The only legal source status is
Active; the explicit parameter makes a lost race visible to the
caller instead of hiding it behind a re-read.
§Errors
NotFoundwhen the interaction does not exist foraccount.Conflictwhen the current status differs fromexpected_status, or whenexpected_status → Resolvingis not a legal transition.
Sourcefn finish_resolution<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
id: &'life2 InteractionId,
outcome: ResolutionOutcome,
) -> Pin<Box<dyn Future<Output = Result<InteractionRecord, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn finish_resolution<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
id: &'life2 InteractionId,
outcome: ResolutionOutcome,
) -> Pin<Box<dyn Future<Output = Result<InteractionRecord, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Settles a Resolving interaction.
Repeating the call with an outcome whose target status is already the
current status and whose data (event ids, failure code) matches is
accepted without change. RestoreActive clears the resolving turn, the
chosen option and resolved_at so the card is answerable again.
Resolved and Failed leave resolved_at as
InteractionWriter::begin_resolution stamped it: it means “when the
answer was accepted”. When the commands actually committed is recorded
by the command journal and by the events, and is not duplicated here.
§Errors
NotFoundwhen the interaction does not exist foraccount.Conflictwhen the status is neitherResolvingnor the outcome’s target, or when the target status matches but the data differs.
Sourcefn invalidate_for_case<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
case_key: &'life2 CaseKey,
new_revision: CaseRevision,
reason: InvalidationReason,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn invalidate_for_case<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
case_key: &'life2 CaseKey,
new_revision: CaseRevision,
reason: InvalidationReason,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Invalidates every Active interaction of the case that is bound to a
revision other than new_revision and does not declare revision
independence. Returns the invalidated identifiers in list order.
§Errors
StoreErrorwhen the sweep could not be written.
Sourcefn invalidate_case_cards<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
case_key: &'life2 CaseKey,
reason: InvalidationReason,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn invalidate_case_cards<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
account: &'life1 AccountId,
case_key: &'life2 CaseKey,
reason: InvalidationReason,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Invalidates every Active interaction of the case, whatever revision it
is bound to, and whether or not it declares revision independence.
Returns the invalidated identifiers in list order.
This is the operator’s path, not the runtime’s, and it exists because
invalidate_for_case cannot express it: a
card is invalidated there for having been bound to a revision the case
has left, so a decision that has nothing to do with the revision — a
workflow rolled back to a version that cannot compile the option the
card offers, an account suspended, a card withdrawn — has no way to run.
Without it the honest rollback step is to leave the user holding an
option nothing will honour.
A Resolving interaction is deliberately left alone: a command it
authorized is in flight, and taking the card away underneath it would
settle nothing while making the outcome unattributable.
§Errors
StoreErrorwhen the sweep could not be written.
Sourcefn expire_due<'life0, 'async_trait>(
&'life0 self,
now: DateTime<Utc>,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn expire_due<'life0, 'async_trait>(
&'life0 self,
now: DateTime<Utc>,
) -> Pin<Box<dyn Future<Output = Result<Vec<InteractionId>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Moves every Active interaction whose expires_at <= now to Expired,
across all accounts. Returns the expired identifiers in list order.
§Errors
StoreErrorwhen the sweep could not be written.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".