surrealdb_sql/cf/
mutations.rs

1use crate::array::Array;
2use crate::object::Object;
3use crate::statements::DefineTableStatement;
4use crate::thing::Thing;
5use crate::value::Value;
6use crate::vs::to_u128_be;
7use derive::Store;
8use revision::revisioned;
9use serde::{Deserialize, Serialize};
10use std::collections::{BTreeMap, HashMap};
11use std::fmt::{self, Display, Formatter};
12
13// Mutation is a single mutation to a table.
14#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
15#[revisioned(revision = 1)]
16pub enum TableMutation {
17	// Although the Value is supposed to contain a field "id" of Thing,
18	// we do include it in the first field for convenience.
19	Set(Thing, Value),
20	Del(Thing),
21	Def(DefineTableStatement),
22}
23
24impl From<DefineTableStatement> for Value {
25	#[inline]
26	fn from(v: DefineTableStatement) -> Self {
27		let mut h = HashMap::<&str, Value>::new();
28		if let Some(id) = v.id {
29			h.insert("id", id.into());
30		}
31		h.insert("name", v.name.0.into());
32		Value::Object(Object::from(h))
33	}
34}
35
36#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
37#[revisioned(revision = 1)]
38pub struct TableMutations(pub String, pub Vec<TableMutation>);
39
40impl TableMutations {
41	pub fn new(tb: String) -> Self {
42		Self(tb, Vec::new())
43	}
44}
45
46#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
47#[revisioned(revision = 1)]
48pub struct DatabaseMutation(pub Vec<TableMutations>);
49
50impl DatabaseMutation {
51	pub fn new() -> Self {
52		Self(Vec::new())
53	}
54}
55
56impl Default for DatabaseMutation {
57	fn default() -> Self {
58		Self::new()
59	}
60}
61// Change is a set of mutations made to a table at the specific timestamp.
62#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
63#[revisioned(revision = 1)]
64pub struct ChangeSet(pub [u8; 10], pub DatabaseMutation);
65
66impl TableMutation {
67	pub fn into_value(self) -> Value {
68		let (k, v) = match self {
69			TableMutation::Set(_t, v) => ("update".to_string(), v),
70			TableMutation::Del(t) => {
71				let mut h = BTreeMap::<String, Value>::new();
72				h.insert("id".to_string(), Value::Thing(t));
73				let o = Object::from(h);
74				("delete".to_string(), Value::Object(o))
75			}
76			TableMutation::Def(t) => ("define_table".to_string(), Value::from(t)),
77		};
78
79		let mut h = BTreeMap::<String, Value>::new();
80		h.insert(k, v);
81		let o = crate::object::Object::from(h);
82		Value::Object(o)
83	}
84}
85
86impl DatabaseMutation {
87	pub fn into_value(self) -> Value {
88		let mut changes = Vec::<Value>::new();
89		for tbs in self.0 {
90			for tb in tbs.1 {
91				changes.push(tb.into_value());
92			}
93		}
94		Value::Array(Array::from(changes))
95	}
96}
97
98impl ChangeSet {
99	pub fn into_value(self) -> Value {
100		let mut m = BTreeMap::<String, Value>::new();
101		let vs = to_u128_be(self.0);
102		m.insert("versionstamp".to_string(), Value::from(vs));
103		m.insert("changes".to_string(), self.1.into_value());
104		let so: Object = m.into();
105		Value::Object(so)
106	}
107}
108
109impl Display for TableMutation {
110	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
111		match self {
112			TableMutation::Set(id, v) => write!(f, "SET {} {}", id, v),
113			TableMutation::Del(id) => write!(f, "DEL {}", id),
114			TableMutation::Def(t) => write!(f, "{}", t),
115		}
116	}
117}
118
119impl Display for TableMutations {
120	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
121		let tb = &self.0;
122		let muts = &self.1;
123		write!(f, "{}", tb)?;
124		muts.iter().try_for_each(|v| write!(f, "{}", v))
125	}
126}
127
128impl Display for DatabaseMutation {
129	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
130		let x = &self.0;
131
132		x.iter().try_for_each(|v| write!(f, "{}", v))
133	}
134}
135
136impl Display for ChangeSet {
137	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
138		let x = &self.1;
139
140		write!(f, "{}", x)
141	}
142}
143
144// WriteMutationSet is a set of mutations to be to a table at the specific timestamp.
145#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
146#[revisioned(revision = 1)]
147pub struct WriteMutationSet(pub Vec<TableMutations>);
148
149impl WriteMutationSet {
150	pub fn new() -> Self {
151		Self(Vec::new())
152	}
153}
154
155impl Default for WriteMutationSet {
156	fn default() -> Self {
157		Self::new()
158	}
159}
160
161#[cfg(test)]
162mod tests {
163	#[test]
164	fn serialization() {
165		use super::*;
166		use std::collections::HashMap;
167		let cs = ChangeSet(
168			[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
169			DatabaseMutation(vec![TableMutations(
170				"mytb".to_string(),
171				vec![
172					TableMutation::Set(
173						Thing::from(("mytb".to_string(), "tobie".to_string())),
174						Value::Object(Object::from(HashMap::from([
175							(
176								"id",
177								Value::from(Thing::from(("mytb".to_string(), "tobie".to_string()))),
178							),
179							("note", Value::from("surreal")),
180						]))),
181					),
182					TableMutation::Del(Thing::from(("mytb".to_string(), "tobie".to_string()))),
183					TableMutation::Def(DefineTableStatement {
184						name: "mytb".into(),
185						..DefineTableStatement::default()
186					}),
187				],
188			)]),
189		);
190		let v = cs.into_value().into_json();
191		let s = serde_json::to_string(&v).unwrap();
192		assert_eq!(
193			s,
194			r#"{"changes":[{"update":{"id":"mytb:tobie","note":"surreal"}},{"delete":{"id":"mytb:tobie"}},{"define_table":{"name":"mytb"}}],"versionstamp":1}"#
195		);
196	}
197}