ValueMap { @NotNull static Map<Revision, String> create(@NotNull final NodeDocument doc, @NotNull final String property) { final SortedMap<Revision, String> map = doc.getLocalMap(property); if (doc.getPreviousRanges().isEmpty()) { return map; } final Set<Map.Entry<Revision, String>> entrySet = new AbstractSet<Map.Entry<Revision, String>>() { @Override @NotNull public Iterator<Map.Entry<Revision, String>> iterator() { final Comparator<? super Revision> c = map.comparator(); final Iterator<NodeDocument> docs; if (map.isEmpty()) { docs = doc.getPreviousDocs(property, null).iterator(); } else { List<Iterator<NodeDocument>> iterators = new ArrayList<Iterator<NodeDocument>>(2); iterators.add(Iterators.singletonIterator(doc)); iterators.add(doc.getPreviousDocs(property, null).iterator()); docs = Iterators.mergeSorted(iterators, new Comparator<NodeDocument>() { @Override public int compare(NodeDocument o1, NodeDocument o2) { Revision r1 = getFirstRevision(o1); Revision r2 = getFirstRevision(o2); return c.compare(r1, r2); } private Revision getFirstRevision(NodeDocument d) { Map<Revision, String> values; if (Objects.equal(d.getId(), doc.getId())) { values = d.getLocalMap(property); } else { values = d.getValueMap(property); } return values.keySet().iterator().next(); } }); } return new MergeSortedIterators<Map.Entry<Revision, String>>( new Comparator<Map.Entry<Revision, String>>() { @Override public int compare(Map.Entry<Revision, String> o1, Map.Entry<Revision, String> o2) { return c.compare(o1.getKey(), o2.getKey()); } } ) { @Override public Iterator<Map.Entry<Revision, String>> nextIterator() { NodeDocument d = docs.hasNext() ? docs.next() : null; if (d == null) { return null; } Map<Revision, String> values; if (Objects.equal(d.getId(), doc.getId())) { values = d.getLocalMap(property); } else { values = d.getValueMap(property); } return values.entrySet().iterator(); } @Override public String description() { return "Revisioned values for property " + doc.getId() + "/" + property + ":"; } }; } @Override public int size() { int size = map.size(); for (NodeDocument prev : doc.getPreviousDocs(property, null)) { size += prev.getValueMap(property).size(); } return size; } }; return new AbstractMap<Revision, String>() { private final Map<Revision, String> map = doc.getLocalMap(property); @Override @NotNull public Set<Entry<Revision, String>> entrySet() { return entrySet; } @Override public String get(Object key) { Revision r = (Revision) key; if (map.containsKey(r)) { return map.get(r); } for (NodeDocument prev : doc.getPreviousDocs(property, r)) { String value = prev.getValueMap(property).get(r); if (value != null) { return value; } } return null; } @Override public boolean containsKey(Object key) { if (map.containsKey(key)) { return true; } Revision r = (Revision) key; for (NodeDocument prev : doc.getPreviousDocs(property, r)) { if (prev.getValueMap(property).containsKey(key)) { return true; } } return false; } }; }    }
@Test public void mergeSorted1() throws Exception { MemoryDocumentStore store = new MemoryDocumentStore(); Revision r1 = new Revision(1, 0, 1); Revision r2 = new Revision(2, 0, 1); Revision r3 = new Revision(3, 0, 1); Revision r4 = new Revision(4, 0, 1); Revision r5 = new Revision(5, 0, 1); Revision r6 = new Revision(6, 0, 1); Revision r7 = new Revision(7, 0, 1); Range range1 = new Range(r7, r5, 0); Range range2 = new Range(r4, r1, 0); String prevId1 = Utils.getPreviousIdFor(ROOT, range1.high, 0); UpdateOp prevOp1 = new UpdateOp(prevId1, true); NodeDocument.setRevision(prevOp1, r5, "c"); NodeDocument.setRevision(prevOp1, r7, "c"); String prevId2 = Utils.getPreviousIdFor(ROOT, range2.high, 0); UpdateOp prevOp2 = new UpdateOp(prevId2, true); NodeDocument.setRevision(prevOp2, r1, "c"); NodeDocument.setRevision(prevOp2, r2, "c"); NodeDocument.setRevision(prevOp2, r4, "c"); String rootId = Utils.getIdFromPath("/"); UpdateOp op = new UpdateOp(rootId, true); NodeDocument.setRevision(op, r3, "c"); NodeDocument.setRevision(op, r6, "c"); NodeDocument.setPrevious(op, range1); NodeDocument.setPrevious(op, range2); store.create(NODES, Lists.newArrayList(op, prevOp1, prevOp2)); NodeDocument doc = store.find(NODES, rootId); Iterators.size(doc.getValueMap(NodeDocument.REVISIONS).entrySet().iterator()); }