zino_core/model/
mutation.rs1use crate::{
2 JsonValue, Map,
3 extension::{JsonObjectExt, JsonValueExt},
4 validation::Validation,
5};
6
7#[derive(Debug, Clone, Default)]
9pub struct Mutation {
10 fields: Vec<String>,
12 updates: Map,
14}
15
16impl Mutation {
17 #[inline]
19 pub fn new(updates: impl Into<JsonValue>) -> Self {
20 Self {
21 fields: Vec::new(),
22 updates: updates.into().into_map_opt().unwrap_or_default(),
23 }
24 }
25
26 #[inline]
28 pub fn from_entry(key: impl Into<String>, value: impl Into<JsonValue>) -> Self {
29 Self::new(Map::from_entry(key, value))
30 }
31
32 #[must_use]
34 pub fn read_map(&mut self, data: &Map) -> Validation {
35 let mut validation = Validation::new();
36 let updates = &mut self.updates;
37 for (key, value) in data {
38 match key.as_str() {
39 "fields" => {
40 if let Some(fields) = value.parse_str_array() {
41 if fields.is_empty() {
42 validation.record("fields", "must be nonempty");
43 } else {
44 self.fields.clear();
45 self.fields.extend(fields.into_iter().map(|s| s.to_owned()));
46 }
47 }
48 }
49 _ => {
50 if !key.starts_with('$') && value != "" {
51 updates.insert(key.to_owned(), value.to_owned());
52 }
53 }
54 }
55 }
56 validation
57 }
58
59 #[inline]
62 pub fn allow_fields(&mut self, fields: &[&str]) {
63 if self.fields.is_empty() {
64 self.fields.extend(fields.iter().map(|&key| key.to_owned()));
65 } else {
66 self.fields
67 .retain(|field| fields.iter().any(|key| field == key))
68 }
69 }
70
71 #[inline]
73 pub fn deny_fields(&mut self, fields: &[&str]) {
74 self.fields
75 .retain(|field| !fields.iter().any(|key| field == key))
76 }
77
78 #[inline]
80 pub fn add_update(&mut self, key: impl Into<String>, value: impl Into<JsonValue>) {
81 self.updates.upsert(key, value);
82 }
83
84 #[inline]
86 pub fn append_updates(&mut self, updates: &mut Map) {
87 self.updates.append(updates);
88 }
89
90 #[inline]
92 pub fn fields(&self) -> &[String] {
93 self.fields.as_slice()
94 }
95
96 #[inline]
98 pub fn updates(&self) -> &Map {
99 &self.updates
100 }
101}