1use crate::fflags::FFLAGS;
2use crate::sql::array::Array;
3use crate::sql::object::Object;
4use crate::sql::statements::DefineTableStatement;
5use crate::sql::thing::Thing;
6use crate::sql::value::Value;
7use crate::sql::Operation;
8use crate::vs::VersionStamp;
9use revision::revisioned;
10use serde::{Deserialize, Serialize};
11use std::collections::{BTreeMap, HashMap};
12use std::fmt::{self, Display, Formatter};
13
14#[revisioned(revision = 2)]
16#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
17#[non_exhaustive]
18#[allow(clippy::large_enum_variant)]
19pub enum TableMutation {
20 Set(Thing, Value),
23 Del(Thing),
24 Def(DefineTableStatement),
25 #[revision(start = 2)]
26 SetWithDiff(Thing, Value, Vec<Operation>),
31 #[revision(start = 2)]
32 DelWithOriginal(Thing, Value),
34}
35
36impl From<DefineTableStatement> for Value {
37 #[inline]
38 fn from(v: DefineTableStatement) -> Self {
39 let mut h = HashMap::<&str, Value>::new();
40 if let Some(id) = v.id {
41 h.insert("id", id.into());
42 }
43 h.insert("name", v.name.0.into());
44 Value::Object(Object::from(h))
45 }
46}
47
48#[revisioned(revision = 1)]
49#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
50#[non_exhaustive]
51pub struct TableMutations(pub String, pub Vec<TableMutation>);
52
53impl TableMutations {
54 pub fn new(tb: String) -> Self {
55 Self(tb, Vec::new())
56 }
57}
58
59#[revisioned(revision = 1)]
60#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
61#[non_exhaustive]
62pub struct DatabaseMutation(pub Vec<TableMutations>);
63
64impl DatabaseMutation {
65 pub fn new() -> Self {
66 Self(Vec::new())
67 }
68}
69
70impl Default for DatabaseMutation {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76#[revisioned(revision = 1)]
78#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
79#[non_exhaustive]
80pub struct ChangeSet(pub VersionStamp, pub DatabaseMutation);
81
82impl TableMutation {
83 pub fn into_value(self) -> Value {
86 let mut h = BTreeMap::<String, Value>::new();
87 let h = match self {
88 TableMutation::Set(_thing, v) => {
89 if FFLAGS.change_feed_live_queries.enabled() {
90 h.insert("create".to_string(), v);
91 } else {
92 h.insert("update".to_string(), v);
93 }
94 h
95 }
96 TableMutation::SetWithDiff(_thing, current, operations) => {
97 h.insert("current".to_string(), current);
98 h.insert(
99 "update".to_string(),
100 Value::Array(Array(
101 operations
102 .clone()
103 .into_iter()
104 .map(|x| Value::Object(Object::from(x)))
105 .collect(),
106 )),
107 );
108 h
109 }
110 TableMutation::Del(t) => {
111 h.insert(
112 "delete".to_string(),
113 Value::Object(Object::from(map! {
114 "id".to_string() => Value::Thing(t)
115 })),
116 );
117 h
118 }
119 TableMutation::Def(t) => {
120 h.insert("define_table".to_string(), Value::from(t));
121 h
122 }
123 TableMutation::DelWithOriginal(id, _val) => {
124 h.insert(
125 "delete".to_string(),
126 Value::Object(Object::from(map! {
127 "id".to_string() => Value::Thing(id),
128 })),
129 );
130 h
131 }
132 };
133 let o = crate::sql::object::Object::from(h);
134 Value::Object(o)
135 }
136}
137
138impl DatabaseMutation {
139 pub fn into_value(self) -> Value {
140 let mut changes = Vec::<Value>::new();
141 for tbs in self.0 {
142 for tb in tbs.1 {
143 changes.push(tb.into_value());
144 }
145 }
146 Value::Array(Array::from(changes))
147 }
148}
149
150impl ChangeSet {
151 pub fn into_value(self) -> Value {
152 let mut m = BTreeMap::<String, Value>::new();
153 m.insert("versionstamp".to_string(), Value::from(self.0.into_u128()));
154 m.insert("changes".to_string(), self.1.into_value());
155 let so: Object = m.into();
156 Value::Object(so)
157 }
158}
159
160impl Display for TableMutation {
161 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
162 match self {
163 TableMutation::Set(id, v) => write!(f, "SET {} {}", id, v),
164 TableMutation::SetWithDiff(id, _previous, v) => write!(f, "SET {} {:?}", id, v),
165 TableMutation::Del(id) => write!(f, "DEL {}", id),
166 TableMutation::DelWithOriginal(id, _) => write!(f, "DEL {}", id),
167 TableMutation::Def(t) => write!(f, "{}", t),
168 }
169 }
170}
171
172impl Display for TableMutations {
173 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
174 let tb = &self.0;
175 let muts = &self.1;
176 write!(f, "{}", tb)?;
177 muts.iter().try_for_each(|v| write!(f, "{}", v))
178 }
179}
180
181impl Display for DatabaseMutation {
182 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
183 let x = &self.0;
184
185 x.iter().try_for_each(|v| write!(f, "{}", v))
186 }
187}
188
189impl Display for ChangeSet {
190 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
191 let x = &self.1;
192
193 write!(f, "{}", x)
194 }
195}
196
197#[revisioned(revision = 1)]
199#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
200#[non_exhaustive]
201pub struct WriteMutationSet(pub Vec<TableMutations>);
202
203impl WriteMutationSet {
204 pub fn new() -> Self {
205 Self(Vec::new())
206 }
207}
208
209impl Default for WriteMutationSet {
210 fn default() -> Self {
211 Self::new()
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 #[test]
218 fn serialization() {
219 use super::*;
220 use std::collections::HashMap;
221 let cs = ChangeSet(
222 VersionStamp::from_u64(1),
223 DatabaseMutation(vec![TableMutations(
224 "mytb".to_string(),
225 vec![
226 TableMutation::Set(
227 Thing::from(("mytb".to_string(), "tobie".to_string())),
228 Value::Object(Object::from(HashMap::from([
229 (
230 "id",
231 Value::from(Thing::from(("mytb".to_string(), "tobie".to_string()))),
232 ),
233 ("note", Value::from("surreal")),
234 ]))),
235 ),
236 TableMutation::Del(Thing::from(("mytb".to_string(), "tobie".to_string()))),
237 TableMutation::Def(DefineTableStatement {
238 name: "mytb".into(),
239 ..DefineTableStatement::default()
240 }),
241 ],
242 )]),
243 );
244 let v = cs.into_value().into_json();
245 let s = serde_json::to_string(&v).unwrap();
246 assert_eq!(
247 s,
248 r#"{"changes":[{"update":{"id":"mytb:tobie","note":"surreal"}},{"delete":{"id":"mytb:tobie"}},{"define_table":{"name":"mytb"}}],"versionstamp":65536}"#
249 );
250 }
251
252 #[test]
253 fn serialization_rev2() {
254 use super::*;
255 use std::collections::HashMap;
256 let cs = ChangeSet(
257 VersionStamp::from_u64(1),
258 DatabaseMutation(vec![TableMutations(
259 "mytb".to_string(),
260 vec![
261 TableMutation::SetWithDiff(
262 Thing::from(("mytb".to_string(), "tobie".to_string())),
263 Value::Object(Object::from(HashMap::from([
264 (
265 "id",
266 Value::from(Thing::from(("mytb".to_string(), "tobie".to_string()))),
267 ),
268 ("note", Value::from("surreal")),
269 ]))),
270 vec![Operation::Add {
271 path: "/note".into(),
272 value: Value::from("surreal"),
273 }],
274 ),
275 TableMutation::SetWithDiff(
276 Thing::from(("mytb".to_string(), "tobie".to_string())),
277 Value::Object(Object::from(HashMap::from([
278 (
279 "id",
280 Value::from(Thing::from((
281 "mytb".to_string(),
282 "tobie2".to_string(),
283 ))),
284 ),
285 ("note", Value::from("surreal")),
286 ]))),
287 vec![Operation::Remove {
288 path: "/temp".into(),
289 }],
290 ),
291 TableMutation::Del(Thing::from(("mytb".to_string(), "tobie".to_string()))),
292 TableMutation::DelWithOriginal(
293 Thing::from(("mytb".to_string(), "tobie".to_string())),
294 Value::Object(Object::from(map! {
295 "id" => Value::from(Thing::from(("mytb".to_string(), "tobie".to_string()))),
296 "note" => Value::from("surreal"),
297 })),
298 ),
299 TableMutation::Def(DefineTableStatement {
300 name: "mytb".into(),
301 ..DefineTableStatement::default()
302 }),
303 ],
304 )]),
305 );
306 let v = cs.into_value().into_json();
307 let s = serde_json::to_string(&v).unwrap();
308 assert_eq!(
309 s,
310 r#"{"changes":[{"current":{"id":"mytb:tobie","note":"surreal"},"update":[{"op":"add","path":"/`/note`","value":"surreal"}]},{"current":{"id":"mytb:tobie2","note":"surreal"},"update":[{"op":"remove","path":"/`/temp`"}]},{"delete":{"id":"mytb:tobie"}},{"delete":{"id":"mytb:tobie"}},{"define_table":{"name":"mytb"}}],"versionstamp":65536}"#
311 );
312 }
313}