backbone-events 0.5.3

Events core + the sale/booth/crm/sms/desk overlay — registrations under one authoritative seat counter, the sale seam (order-minted registrations, forward-only paid heal, SO-cancel mirror cascade), booth bookings with the DB exclusivity wall, closed-vocabulary lead rules through a host sink port, the dual-channel (mail/sms) self-arming scheduler, and the exact-match desk verb (Odoo event port, core + overlay)
//! The write guard of Registration (generated by metaphor-schema; do not edit). It lives in a
//! file of its own because `registration_service.rs` is hand-owned.

#[allow(unused_imports)]
use super::*;
use crate::domain::entity::Registration;

/// The row rules the schema declares for Registration, checked against the row a create or
/// update would store. The generated build attaches it to [`RegistrationService`]. Every rule
/// runs in shadow: a break is logged under `backbone::write_guard` and the write goes ahead.
pub struct RegistrationRowRules;

#[async_trait::async_trait]
impl backbone_core::write_guard::WriteGuard<Registration> for RegistrationRowRules {
    async fn check(
        &self,
        ctx: &backbone_core::write_guard::WriteCtx<'_, Registration>,
    ) -> backbone_core::write_guard::GuardOutcome {
        use backbone_core::row_rule as r;
        use backbone_core::violation::Violation;
        use backbone_core::write_guard::{GuardOutcome, WriteKind};
        let (create, update) = (ctx.kind == WriteKind::Create, ctx.kind == WriteKind::Update);
        let Some(after) = ctx.after.filter(|_| create || update) else {
            return GuardOutcome::allow();
        };
        let Ok(row) = serde_json::to_value(after) else {
            return GuardOutcome::allow();
        };
        let row = &row;
        let old = ctx.before.and_then(|b| serde_json::to_value(b).ok());
        let mut shadow = Vec::new();
        // `state` belongs to a state machine: only its verbs move it
        if update && ctx.transition.is_none() && r::changed(old.as_ref(), row, &["state"]) {
            shadow.push(Violation::new("state", "state_field_verbs_only", "the state field moves only through its verbs"));
        }
        GuardOutcome { refuse: Vec::new(), shadow }
    }
}