use serde_json::{Map, Value};
use super::entry::{BufferEntry, BufferOp};
use super::merge::Conflict;
#[derive(Debug, Clone, PartialEq)]
pub enum Resolution {
Ours(String),
Theirs(String),
Custom(Value),
}
pub fn resolve(conflict: &Conflict, choice: Resolution) -> BufferEntry {
match choice {
Resolution::Ours(source) | Resolution::Theirs(source) => conflict
.versions
.iter()
.find(|(s, _)| *s == source)
.map(|(_, entry)| entry.clone())
.unwrap_or_else(|| panic!("no version from source \"{source}\" in this conflict")),
Resolution::Custom(data) => BufferEntry {
table: conflict.table.clone(),
key: conflict.key.clone(),
op: BufferOp::Put,
data: Some(as_object(data)),
buffered_at: chrono::Utc::now().timestamp_millis(),
source: "resolution".to_string(),
},
}
}
fn as_object(value: Value) -> Map<String, Value> {
match value {
Value::Object(map) => map,
other => {
let mut map = Map::new();
map.insert("value".into(), other);
map
}
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
fn conflict() -> Conflict {
let ours = BufferEntry {
table: "users".into(),
key: "u1".into(),
op: BufferOp::Put,
data: Some(json!({ "name": "Ania" }).as_object().unwrap().clone()),
buffered_at: 100,
source: "branch-a".into(),
};
let theirs = BufferEntry {
table: "users".into(),
key: "u1".into(),
op: BufferOp::Put,
data: Some(json!({ "name": "Zosia" }).as_object().unwrap().clone()),
buffered_at: 200,
source: "branch-b".into(),
};
Conflict {
table: "users".into(),
key: "u1".into(),
versions: vec![("branch-a".into(), ours), ("branch-b".into(), theirs)],
}
}
#[test]
fn ours_picks_the_named_version() {
let resolved = resolve(&conflict(), Resolution::Ours("branch-a".into()));
assert_eq!(resolved.source, "branch-a");
assert_eq!(resolved.data.unwrap().get("name"), Some(&json!("Ania")));
}
#[test]
fn theirs_picks_the_named_version() {
let resolved = resolve(&conflict(), Resolution::Theirs("branch-b".into()));
assert_eq!(resolved.source, "branch-b");
assert_eq!(resolved.data.unwrap().get("name"), Some(&json!("Zosia")));
}
#[test]
fn custom_builds_a_fresh_put_from_the_given_value() {
let resolved = resolve(&conflict(), Resolution::Custom(json!({ "name": "Kasia" })));
assert_eq!(resolved.op, BufferOp::Put);
assert_eq!(resolved.key, "u1");
assert_eq!(resolved.data.unwrap().get("name"), Some(&json!("Kasia")));
}
}