nodedb_crdt/
pre_validate.rs1use crate::state::CrdtState;
18use crate::validator::{ProposedChange, ValidationOutcome, Validator};
19
20#[derive(Debug)]
22pub enum PreValidationResult {
23 Proceed,
25 FastReject { constraint: String, reason: String },
27}
28
29pub fn pre_validate(
35 validator: &Validator,
36 state: &CrdtState,
37 change: &ProposedChange,
38) -> PreValidationResult {
39 match validator.validate(state, change) {
40 ValidationOutcome::Accepted => PreValidationResult::Proceed,
41 ValidationOutcome::Rejected(violations) => {
42 let v = &violations[0];
43 PreValidationResult::FastReject {
44 constraint: v.constraint_name.clone(),
45 reason: v.reason.clone(),
46 }
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::constraint::ConstraintSet;
55 use loro::LoroValue;
56
57 #[test]
58 fn pre_validate_fast_rejects_not_null() {
59 let state = CrdtState::new(1).unwrap();
60 let mut cs = ConstraintSet::new();
61 cs.add_not_null("name_nn", "users", "name");
62 let validator = Validator::new(cs, 10);
63
64 let change = ProposedChange {
65 collection: "users".into(),
66 row_id: "u1".into(),
67 surrogate: nodedb_types::Surrogate::ZERO,
68 fields: vec![("email".into(), LoroValue::String("a@b.com".into()))],
69 };
70
71 match pre_validate(&validator, &state, &change) {
72 PreValidationResult::FastReject { constraint, .. } => {
73 assert_eq!(constraint, "name_nn");
74 }
75 _ => panic!("expected fast reject"),
76 }
77 }
78
79 #[test]
80 fn pre_validate_proceeds_when_valid() {
81 let state = CrdtState::new(1).unwrap();
82 let mut cs = ConstraintSet::new();
83 cs.add_not_null("name_nn", "users", "name");
84 let validator = Validator::new(cs, 10);
85
86 let change = ProposedChange {
87 collection: "users".into(),
88 row_id: "u1".into(),
89 surrogate: nodedb_types::Surrogate::ZERO,
90 fields: vec![("name".into(), LoroValue::String("Alice".into()))],
91 };
92
93 assert!(matches!(
94 pre_validate(&validator, &state, &change),
95 PreValidationResult::Proceed
96 ));
97 }
98}