(
&self,
state: &CrdtState,
change: &ProposedChange,
constraint: &Constraint,
)
| 38 | } |
| 39 | |
| 40 | pub(crate) fn check_unique( |
| 41 | &self, |
| 42 | state: &CrdtState, |
| 43 | change: &ProposedChange, |
| 44 | constraint: &Constraint, |
| 45 | ) -> Option<Violation> { |
| 46 | let field_value = change.fields.iter().find(|(f, _)| f == &constraint.field)?; |
| 47 | |
| 48 | let value = &field_value.1; |
| 49 | |
| 50 | // Bitemporal collections: only consider live (non-superseded) rows, |
| 51 | // so a new version of the same logical row with the same value does |
| 52 | // not spuriously collide with its prior version. |
| 53 | let exists = if self.is_bitemporal(&change.collection) { |
| 54 | state.field_value_exists_live(&change.collection, &constraint.field, value) |
| 55 | } else { |
| 56 | state.field_value_exists(&change.collection, &constraint.field, value) |
| 57 | }; |
| 58 | |
| 59 | if exists { |
| 60 | let value_str = format!("{:?}", value); |
| 61 | Some(Violation { |
| 62 | constraint_name: constraint.name.clone(), |
| 63 | reason: format!( |
| 64 | "value {} for field `{}` already exists in `{}`", |
| 65 | value_str, constraint.field, constraint.collection |
| 66 | ), |
| 67 | hint: CompensationHint::RetryWithDifferentValue { |
| 68 | field: constraint.field.clone(), |
| 69 | conflicting_value: value_str.clone(), |
| 70 | suggestion: format!("{value_str}-dedup"), |
| 71 | }, |
| 72 | }) |
| 73 | } else { |
| 74 | None |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | pub(crate) fn check_foreign_key( |
| 79 | &self, |
no test coverage detected