1use super::*;
2
3#[derive(Debug, PartialEq)]
4pub struct Batch {
5 doc: Doc,
6 before_state: StateVector,
7 after_state: StateVector,
8 changed: HashMap<YTypeRef, Vec<SmolStr>>,
9}
10
11impl Batch {
12 pub fn new(doc: Doc) -> Self {
13 let current_state = doc.get_state_vector();
14
15 Batch {
16 doc,
17 before_state: current_state.clone(),
18 after_state: current_state,
19 changed: HashMap::new(),
20 }
21 }
22
23 pub fn with_batch<T, F>(&mut self, f: F) -> T
24 where
25 F: FnOnce(Doc) -> T,
26 {
27 let ret = f(self.doc.clone());
28 for (k, v) in self.doc.get_changed() {
29 self.changed.entry(k).or_default().extend(v.iter().cloned());
30 }
31 ret
32 }
33}
34
35pub fn batch_commit<T, F>(mut doc: Doc, f: F) -> Option<T>
36where
37 F: FnOnce(Doc) -> T,
38{
39 let mut batch_cleanups = vec![];
41
42 let mut initial_call = false;
44
45 {
46 if doc.batch.is_none() {
47 initial_call = true;
48
49 let batch = Batch::new(doc.clone());
51 doc.batch = Somr::new(batch);
52 batch_cleanups.push(doc.batch.clone());
53 }
54 }
55
56 let batch = doc.batch.get_mut()?;
57 let result = Some(batch.with_batch(f));
58
59 if initial_call
60 && let Some(current_batch) = doc.batch.get()
61 && Some(current_batch) == batch_cleanups[0].get()
62 {
63 cleanup_batches(&mut batch_cleanups);
65 doc.batch.swap_take();
66 }
67
68 result
69}
70
71fn cleanup_batches(batch_cleanups: &mut Vec<Somr<Batch>>) {
72 for batch in batch_cleanups.drain(..) {
73 if let Some(batch) = batch.get() {
74 println!("changed: {:?}", batch.changed);
75 } else {
76 panic!("Batch not initialized");
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn should_get_changed_items() {
87 loom_model!({
88 let doc = DocOptions::new().with_client_id(1).build();
89
90 batch_commit(doc.clone(), |d| {
91 let mut arr = d.get_or_create_array("arr").unwrap();
92 let mut text = d.create_text().unwrap();
93 let mut map = d.create_map().unwrap();
94
95 batch_commit(doc.clone(), |_| {
96 arr.insert(0, Value::from(text.clone())).unwrap();
97 arr.insert(1, Value::from(map.clone())).unwrap();
98 });
99
100 batch_commit(doc.clone(), |_| {
101 text.insert(0, "hello world").unwrap();
102 text.remove(5, 6).unwrap();
103 });
104
105 batch_commit(doc.clone(), |_| {
106 map.insert("key".into(), 123).unwrap();
107 });
108
109 batch_commit(doc.clone(), |_| {
110 map.remove("key");
111 });
112
113 batch_commit(doc.clone(), |_| {
114 arr.remove(0, 1).unwrap();
115 });
116 });
117 });
118 }
119}