rustapi_validate/v2/
group.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum ValidationGroup {
38 Create,
40 Update,
42 Custom(String),
44 #[default]
46 Default,
47}
48
49impl ValidationGroup {
50 pub fn custom(name: impl Into<String>) -> Self {
52 Self::Custom(name.into())
53 }
54
55 pub fn matches(&self, other: &ValidationGroup) -> bool {
59 match (self, other) {
60 (ValidationGroup::Default, _) => true,
61 (_, ValidationGroup::Default) => true,
62 (a, b) => a == b,
63 }
64 }
65
66 pub fn name(&self) -> &str {
68 match self {
69 ValidationGroup::Create => "create",
70 ValidationGroup::Update => "update",
71 ValidationGroup::Custom(name) => name,
72 ValidationGroup::Default => "default",
73 }
74 }
75}
76
77impl From<&str> for ValidationGroup {
78 fn from(s: &str) -> Self {
79 match s.to_lowercase().as_str() {
80 "create" => ValidationGroup::Create,
81 "update" => ValidationGroup::Update,
82 "default" => ValidationGroup::Default,
83 other => ValidationGroup::Custom(other.to_string()),
84 }
85 }
86}
87
88impl std::fmt::Display for ValidationGroup {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 write!(f, "{}", self.name())
91 }
92}
93
94#[derive(Debug, Clone)]
96pub struct GroupedRule<R> {
97 pub rule: R,
99 pub group: ValidationGroup,
101}
102
103impl<R> GroupedRule<R> {
104 pub fn new(rule: R, group: ValidationGroup) -> Self {
106 Self { rule, group }
107 }
108
109 pub fn for_create(rule: R) -> Self {
111 Self::new(rule, ValidationGroup::Create)
112 }
113
114 pub fn for_update(rule: R) -> Self {
116 Self::new(rule, ValidationGroup::Update)
117 }
118
119 pub fn for_default(rule: R) -> Self {
121 Self::new(rule, ValidationGroup::Default)
122 }
123
124 pub fn applies_to(&self, group: &ValidationGroup) -> bool {
126 self.group.matches(group)
127 }
128}
129
130#[derive(Debug, Clone, Default)]
132pub struct GroupedRules<R> {
133 rules: Vec<GroupedRule<R>>,
134}
135
136impl<R> GroupedRules<R> {
137 pub fn new() -> Self {
139 Self { rules: Vec::new() }
140 }
141
142 pub fn add(mut self, rule: R, group: ValidationGroup) -> Self {
144 self.rules.push(GroupedRule::new(rule, group));
145 self
146 }
147
148 pub fn on_create(self, rule: R) -> Self {
150 self.add(rule, ValidationGroup::Create)
151 }
152
153 pub fn on_update(self, rule: R) -> Self {
155 self.add(rule, ValidationGroup::Update)
156 }
157
158 pub fn always(self, rule: R) -> Self {
160 self.add(rule, ValidationGroup::Default)
161 }
162
163 pub fn for_group<'a>(&'a self, group: &'a ValidationGroup) -> impl Iterator<Item = &'a R> + 'a {
165 self.rules
166 .iter()
167 .filter(move |gr| gr.applies_to(group))
168 .map(|gr| &gr.rule)
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn group_from_str() {
178 assert_eq!(ValidationGroup::from("create"), ValidationGroup::Create);
179 assert_eq!(ValidationGroup::from("update"), ValidationGroup::Update);
180 assert_eq!(ValidationGroup::from("default"), ValidationGroup::Default);
181 assert_eq!(
182 ValidationGroup::from("custom_group"),
183 ValidationGroup::Custom("custom_group".to_string())
184 );
185 }
186
187 #[test]
188 fn group_matches() {
189 assert!(ValidationGroup::Default.matches(&ValidationGroup::Create));
190 assert!(ValidationGroup::Create.matches(&ValidationGroup::Default));
191 assert!(ValidationGroup::Create.matches(&ValidationGroup::Create));
192 assert!(!ValidationGroup::Create.matches(&ValidationGroup::Update));
193 }
194
195 #[test]
196 fn group_name() {
197 assert_eq!(ValidationGroup::Create.name(), "create");
198 assert_eq!(ValidationGroup::Update.name(), "update");
199 assert_eq!(ValidationGroup::Default.name(), "default");
200 assert_eq!(ValidationGroup::Custom("test".to_string()).name(), "test");
201 }
202
203 #[test]
204 fn group_serialization() {
205 let group = ValidationGroup::Create;
206 let json = serde_json::to_string(&group).unwrap();
207 assert_eq!(json, "\"create\"");
208
209 let parsed: ValidationGroup = serde_json::from_str(&json).unwrap();
210 assert_eq!(parsed, ValidationGroup::Create);
211 }
212
213 #[test]
214 fn grouped_rule_applies_to() {
215 let create_rule = GroupedRule::for_create("rule1");
216 let update_rule = GroupedRule::for_update("rule2");
217 let default_rule = GroupedRule::for_default("rule3");
218
219 assert!(create_rule.applies_to(&ValidationGroup::Create));
220 assert!(!create_rule.applies_to(&ValidationGroup::Update));
221 assert!(create_rule.applies_to(&ValidationGroup::Default));
222
223 assert!(!update_rule.applies_to(&ValidationGroup::Create));
224 assert!(update_rule.applies_to(&ValidationGroup::Update));
225 assert!(update_rule.applies_to(&ValidationGroup::Default));
226
227 assert!(default_rule.applies_to(&ValidationGroup::Create));
228 assert!(default_rule.applies_to(&ValidationGroup::Update));
229 assert!(default_rule.applies_to(&ValidationGroup::Default));
230 }
231
232 #[test]
233 fn grouped_rules_for_group() {
234 let rules = GroupedRules::new()
235 .on_create("create_only")
236 .on_update("update_only")
237 .always("always");
238
239 let create_rules: Vec<_> = rules.for_group(&ValidationGroup::Create).collect();
240 assert_eq!(create_rules.len(), 2);
241 assert!(create_rules.contains(&&"create_only"));
242 assert!(create_rules.contains(&&"always"));
243
244 let update_rules: Vec<_> = rules.for_group(&ValidationGroup::Update).collect();
245 assert_eq!(update_rules.len(), 2);
246 assert!(update_rules.contains(&&"update_only"));
247 assert!(update_rules.contains(&&"always"));
248 }
249}