Mercurial > code > home > repos > rdfdb
changeset 132:453726e6f891
write compactPatches
author | drewp@bigasterisk.com |
---|---|
date | Mon, 29 May 2023 22:26:18 -0700 |
parents | a47c8224e97f |
children | f11770a0a797 |
files | rdfdb/patch.py rdfdb/patch_test.py |
diffstat | 2 files changed, 47 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/rdfdb/patch.py Mon May 29 16:15:46 2023 -0700 +++ b/rdfdb/patch.py Mon May 29 22:26:18 2023 -0700 @@ -1,6 +1,6 @@ import itertools import json -from typing import Iterable, Optional, Tuple, cast +from typing import Iterable, Optional, Sequence, Tuple, cast from rdflib import ConjunctiveGraph, Graph, Literal, Namespace, URIRef @@ -10,11 +10,11 @@ ALLSTMTS = (None, None, None) + class EmptyPatch(ValueError): pass - def quadsWithContextUris(quads): """ yield the given quads, correcting any context values that are @@ -70,6 +70,10 @@ if cast(Literal, q[2]).datatype in [XSD['double'], XSD['float']]: raise ValueError(f'fix creation of quad {q} to use xsd:decimal, or comparisons will fail') + def __eq__(self, other: 'Patch') -> bool: + # doesn't cancel out quads + return set(self.delQuads) == set(other.delQuads) and set(self.addQuads) == set(other.addQuads) + def __str__(self): def shorten(n): @@ -107,9 +111,7 @@ """ does this patch do anything to a graph? """ - if self._jsonRepr and self._jsonRepr.strip(): - raise NotImplementedError() - return bool(self._addQuads or self._delQuads or self._addGraph or self._delGraph) + return not self.isEmpty() @property def addQuads(self): @@ -170,27 +172,6 @@ return self return Patch(addQuads=adds - both, delQuads=dels - both) - def concat(self, more): - """ - new Patch with the result of applying this patch and the - sequence of other Patches - """ - # not working yet - adds = set(self.addQuads) - dels = set(self.delQuads) - for p2 in more: - for q in p2.delQuads: - if q in adds: - adds.remove(q) - else: - dels.add(q) - for q in p2.addQuads: - if q in dels: - dels.remove(q) - else: - adds.add(q) - return Patch(delQuads=dels, addQuads=adds) - def getContext(self): """assumes that all the edits are on the same context""" ctx = None @@ -207,3 +188,20 @@ def isEmpty(self): return set(self.addQuads) == set(self.delQuads) + + def update(self, other: 'Patch') -> 'Patch': + return Patch(delQuads=set(self.delQuads).union(other.delQuads), addQuads=set(self.addQuads).union(other.addQuads)) + + +def compactPatches(ps: Sequence[Patch]) -> Sequence[Patch]: + if not ps: + return ps + combined = ps[0] + for p in ps[1:]: + combined = combined.update(p) + dels = set(combined.delQuads) + adds = set(combined.addQuads) + inter = dels.intersection(adds) + dels.difference_update(inter) + adds.difference_update(inter) + return [Patch(delQuads=dels, addQuads=adds)] \ No newline at end of file
--- a/rdfdb/patch_test.py Mon May 29 16:15:46 2023 -0700 +++ b/rdfdb/patch_test.py Mon May 29 22:26:18 2023 -0700 @@ -3,10 +3,12 @@ from rdflib import ConjunctiveGraph from rdflib import URIRef as U -from rdfdb.patch import Patch +from rdfdb.patch import Patch, compactPatches from rdfdb.rdflibpatch import graphFromQuads stmt1 = U('http://a'), U('http://b'), U('http://c'), U('http://ctx1') +stmt2 = U('http://a'), U('http://b'), U('http://c2'), U('http://ctx1') +stmt3 = U('http://a'), U('http://b'), U('http://c3'), U('http://ctx1') class TestPatchFromDiff(unittest.TestCase): @@ -57,7 +59,26 @@ p = Patch(addQuads=[stmt1[:3] + (U('http://ctx1'),), stmt1[:3] + (U('http://ctx2'),)]) self.assertRaises(ValueError, p.getContext) + class TestPatchDoesntConsumeIterators: + def test(self): p = Patch(addQuads=iter(stmt1)) - assert not p.isEmpty() \ No newline at end of file + assert not p.isEmpty() + + +class TestCompactPatches: + + def testHalfPatchesMerge(self): + assert (compactPatches([ + Patch(delQuads=[stmt1]), # + Patch(addQuads=[stmt2]) + ]) == [Patch(delQuads=[stmt1], addQuads=[stmt2])]) + + def testTypicalEditsOfObject(self): + step1 = Patch(delQuads=[stmt1], addQuads=[stmt2]) + step2 = Patch(delQuads=[stmt2], addQuads=[stmt3]) + assert compactPatches([step1, step2]) == [Patch(delQuads=[stmt1], addQuads=[stmt3])] + + def testEmpty(self): + assert compactPatches([]) == [] \ No newline at end of file