nodedb_crdt/
constraint.rs1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11pub enum ConstraintKind {
12 Unique,
15
16 ForeignKey {
19 ref_collection: String,
21 ref_key: String,
23 },
24
25 NotNull,
28
29 Check {
32 description: String,
34 },
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct Constraint {
40 pub name: String,
42 pub collection: String,
44 pub field: String,
46 pub kind: ConstraintKind,
48}
49
50#[derive(Debug, Clone, Default)]
52pub struct ConstraintSet {
53 constraints: Vec<Constraint>,
54}
55
56impl ConstraintSet {
57 pub fn new() -> Self {
58 Self::default()
59 }
60
61 pub fn add(&mut self, constraint: Constraint) {
63 self.constraints.push(constraint);
64 }
65
66 pub fn add_unique(&mut self, name: &str, collection: &str, field: &str) {
68 self.add(Constraint {
69 name: name.to_string(),
70 collection: collection.to_string(),
71 field: field.to_string(),
72 kind: ConstraintKind::Unique,
73 });
74 }
75
76 pub fn add_foreign_key(
78 &mut self,
79 name: &str,
80 collection: &str,
81 field: &str,
82 ref_collection: &str,
83 ref_key: &str,
84 ) {
85 self.add(Constraint {
86 name: name.to_string(),
87 collection: collection.to_string(),
88 field: field.to_string(),
89 kind: ConstraintKind::ForeignKey {
90 ref_collection: ref_collection.to_string(),
91 ref_key: ref_key.to_string(),
92 },
93 });
94 }
95
96 pub fn add_not_null(&mut self, name: &str, collection: &str, field: &str) {
98 self.add(Constraint {
99 name: name.to_string(),
100 collection: collection.to_string(),
101 field: field.to_string(),
102 kind: ConstraintKind::NotNull,
103 });
104 }
105
106 pub fn for_collection(&self, collection: &str) -> Vec<&Constraint> {
108 self.constraints
109 .iter()
110 .filter(|c| c.collection == collection)
111 .collect()
112 }
113
114 pub fn all(&self) -> &[Constraint] {
116 &self.constraints
117 }
118
119 pub fn len(&self) -> usize {
121 self.constraints.len()
122 }
123
124 pub fn is_empty(&self) -> bool {
125 self.constraints.is_empty()
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn constraint_set_operations() {
135 let mut cs = ConstraintSet::new();
136 cs.add_unique("users_email_unique", "users", "email");
137 cs.add_not_null("users_name_nn", "users", "name");
138 cs.add_foreign_key("posts_author_fk", "posts", "author_id", "users", "id");
139
140 assert_eq!(cs.len(), 3);
141 assert_eq!(cs.for_collection("users").len(), 2);
142 assert_eq!(cs.for_collection("posts").len(), 1);
143 assert_eq!(cs.for_collection("missing").len(), 0);
144 }
145}