Skip to main content

gn_core/
merge.rs

1use crate::note::Note;
2use std::collections::HashMap;
3
4pub trait MergeStrategy: Send + Sync {
5    fn merge(&self, local: &[Note], remote: &[Note]) -> Vec<Note>;
6    fn name(&self) -> &'static str;
7}
8
9pub struct UnionStrategy;
10
11impl MergeStrategy for UnionStrategy {
12    fn merge(&self, local: &[Note], remote: &[Note]) -> Vec<Note> {
13        let mut notes_map = HashMap::new();
14
15        for note in local {
16            notes_map.insert(note.id, note.clone());
17        }
18        for note in remote {
19            notes_map.insert(note.id, note.clone());
20        }
21
22        notes_map.into_values().collect()
23    }
24
25    fn name(&self) -> &'static str {
26        "union"
27    }
28}
29
30pub struct LwwStrategy;
31
32impl MergeStrategy for LwwStrategy {
33    fn merge(&self, local: &[Note], remote: &[Note]) -> Vec<Note> {
34        let mut notes_map: HashMap<_, Note> = HashMap::new();
35
36        for note in local.iter().chain(remote.iter()) {
37            notes_map
38                .entry(note.id)
39                .and_modify(|existing| {
40                    if note.timestamp > existing.timestamp {
41                        *existing = note.clone();
42                    }
43                })
44                .or_insert_with(|| note.clone());
45        }
46
47        notes_map.into_values().collect()
48    }
49
50    fn name(&self) -> &'static str {
51        "lww"
52    }
53}
54
55pub struct CompositeStrategy;
56
57impl MergeStrategy for CompositeStrategy {
58    fn merge(&self, local: &[Note], remote: &[Note]) -> Vec<Note> {
59        // Simple composite: LWW handles existing overlapping notes, union effectively merges disjoint notes.
60        // For our implementation, LwwStrategy does both.
61        let lww = LwwStrategy;
62        lww.merge(local, remote)
63    }
64
65    fn name(&self) -> &'static str {
66        "composite"
67    }
68}