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