hayson_engine/buffer/
resolve.rs1use serde_json::{Map, Value};
2
3use super::entry::{BufferEntry, BufferOp};
4use super::merge::Conflict;
5
6#[derive(Debug, Clone, PartialEq)]
7pub enum Resolution {
8 Ours(String),
9 Theirs(String),
10 Custom(Value),
11}
12
13pub fn resolve(conflict: &Conflict, choice: Resolution) -> BufferEntry {
19 match choice {
20 Resolution::Ours(source) | Resolution::Theirs(source) => conflict
21 .versions
22 .iter()
23 .find(|(s, _)| *s == source)
24 .map(|(_, entry)| entry.clone())
25 .unwrap_or_else(|| panic!("no version from source \"{source}\" in this conflict")),
26 Resolution::Custom(data) => BufferEntry {
27 table: conflict.table.clone(),
28 key: conflict.key.clone(),
29 op: BufferOp::Put,
30 data: Some(as_object(data)),
31 buffered_at: chrono::Utc::now().timestamp_millis(),
32 source: "resolution".to_string(),
33 },
34 }
35}
36
37fn as_object(value: Value) -> Map<String, Value> {
38 match value {
39 Value::Object(map) => map,
40 other => {
41 let mut map = Map::new();
42 map.insert("value".into(), other);
43 map
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use serde_json::json;
51
52 use super::*;
53
54 fn conflict() -> Conflict {
55 let ours = BufferEntry {
56 table: "users".into(),
57 key: "u1".into(),
58 op: BufferOp::Put,
59 data: Some(json!({ "name": "Ania" }).as_object().unwrap().clone()),
60 buffered_at: 100,
61 source: "branch-a".into(),
62 };
63 let theirs = BufferEntry {
64 table: "users".into(),
65 key: "u1".into(),
66 op: BufferOp::Put,
67 data: Some(json!({ "name": "Zosia" }).as_object().unwrap().clone()),
68 buffered_at: 200,
69 source: "branch-b".into(),
70 };
71 Conflict {
72 table: "users".into(),
73 key: "u1".into(),
74 versions: vec![("branch-a".into(), ours), ("branch-b".into(), theirs)],
75 }
76 }
77
78 #[test]
79 fn ours_picks_the_named_version() {
80 let resolved = resolve(&conflict(), Resolution::Ours("branch-a".into()));
81 assert_eq!(resolved.source, "branch-a");
82 assert_eq!(resolved.data.unwrap().get("name"), Some(&json!("Ania")));
83 }
84
85 #[test]
86 fn theirs_picks_the_named_version() {
87 let resolved = resolve(&conflict(), Resolution::Theirs("branch-b".into()));
88 assert_eq!(resolved.source, "branch-b");
89 assert_eq!(resolved.data.unwrap().get("name"), Some(&json!("Zosia")));
90 }
91
92 #[test]
93 fn custom_builds_a_fresh_put_from_the_given_value() {
94 let resolved = resolve(&conflict(), Resolution::Custom(json!({ "name": "Kasia" })));
95 assert_eq!(resolved.op, BufferOp::Put);
96 assert_eq!(resolved.key, "u1");
97 assert_eq!(resolved.data.unwrap().get("name"), Some(&json!("Kasia")));
98 }
99}