private ChangesCollection CollectChanges() { if (_changes == null) { var target = Target; var added = new HashSet <Item>(); var deleted = new HashSet <Item>(); var delta = new List <Delta>(); var keys = new Dictionary <string, ChangeKey>(); _changes = new ChangesCollection { Added = added, Deleted = deleted, Delta = delta, Keys = keys }; if (!Transaction.Changed.TryGetValue(Target, out var changed)) { changed = new HashSet <string>(); Transaction.Changed[Target] = changed; } if (changed.Contains(null)) { Delta lastOp = null; void packOp() { if (lastOp != null) { delta.Add(lastOp); } } for (var item = Target._start; item != null; item = item.Right as Item) { if (item.Deleted) { if (Deletes(item) && !Adds(item)) { if (lastOp == null || lastOp.Delete == null) { packOp(); lastOp = new Delta { Delete = 0 }; } lastOp.Delete += item.Length; deleted.Add(item); } else { // Do nothing. } } else { if (Adds(item)) { if (lastOp == null || lastOp.Insert == null) { packOp(); lastOp = new Delta { Insert = new List <object>(1) }; } (lastOp.Insert as List <object>).AddRange(item.Content.GetContent()); added.Add(item); } else { if (lastOp == null || lastOp.Retain == null) { packOp(); lastOp = new Delta { Retain = 0 }; } lastOp.Retain += item.Length; } } } if (lastOp != null && lastOp.Retain == null) { packOp(); } } foreach (var key in changed) { if (key != null) { ChangeAction action; object oldValue; var item = target._map[key]; if (Adds(item)) { var prev = item.Left; while (prev != null && Adds(prev)) { prev = (prev as Item).Left; } if (Deletes(item)) { if (prev != null && Deletes(prev)) { action = ChangeAction.Delete; oldValue = (prev as Item).Content.GetContent().Last(); } else { break; } } else { if (prev != null && Deletes(prev)) { action = ChangeAction.Update; oldValue = (prev as Item).Content.GetContent().Last(); } else { action = ChangeAction.Add; oldValue = null; } } } else { if (Deletes(item)) { action = ChangeAction.Delete; oldValue = item.Content.GetContent().Last(); } else { break; } } keys[key] = new ChangeKey { Action = action, OldValue = oldValue }; } } } return(_changes); }
public void TestChangeEvent() { Init(users: 2); var map0 = Maps[Users[0]]; ChangesCollection changes = null; ChangeKey keyChange = null; map0.EventHandler += (s, e) => { changes = e.Event.Changes; }; map0.Set("a", 1); Assert.IsTrue(changes.Keys.TryGetValue("a", out keyChange)); Assert.AreEqual(ChangeAction.Add, keyChange.Action); Assert.IsNull(keyChange.OldValue); changes = null; map0.Set("a", 2); Assert.IsTrue(changes.Keys.TryGetValue("a", out keyChange)); Assert.AreEqual(ChangeAction.Update, keyChange.Action); Assert.AreEqual(1, keyChange.OldValue); changes = null; Users[0].Transact(tr => { map0.Set("a", 3); map0.Set("a", 4); }); Assert.IsTrue(changes.Keys.TryGetValue("a", out keyChange)); Assert.AreEqual(ChangeAction.Update, keyChange.Action); Assert.AreEqual(2, keyChange.OldValue); changes = null; Users[0].Transact(tr => { map0.Set("b", 1); map0.Set("b", 2); }); Assert.IsTrue(changes.Keys.TryGetValue("b", out keyChange)); Assert.AreEqual(ChangeAction.Add, keyChange.Action); Assert.IsNull(keyChange.OldValue); changes = null; Users[0].Transact(tr => { map0.Set("c", 1); map0.Delete("c"); }); Assert.AreEqual(0, changes.Keys.Count); changes = null; Users[0].Transact(tr => { map0.Set("d", 1); map0.Set("d", 2); }); Assert.IsTrue(changes.Keys.TryGetValue("d", out keyChange)); Assert.AreEqual(ChangeAction.Add, keyChange.Action); Assert.IsNull(keyChange.OldValue); changes = null; CompareUsers(); }