diff --git a/light9/rdfdb/grapheditapi.py b/light9/rdfdb/grapheditapi.py --- a/light9/rdfdb/grapheditapi.py +++ b/light9/rdfdb/grapheditapi.py @@ -1,7 +1,7 @@ import random, logging from itertools import chain from rdflib import URIRef, RDF -from light9.rdfdb.patch import Patch +from light9.rdfdb.patch import Patch, quadsWithContextUris log = logging.getLogger('graphedit') class GraphEditApi(object): @@ -32,6 +32,16 @@ class GraphEditApi(object): p = self.getObjectPatch(context, subject, predicate, newObject) log.info("patchObject %r" % p.jsonRepr) self.patch(p) + + def patchSubgraph(self, context, newGraph): + """ + replace all statements in 'context' with the quads in newGraph. + This is not cooperating with currentState. + """ + old = set(quadsWithContextUris(self._graph.quads((None, None, None, context)))) + new = set(quadsWithContextUris(newGraph)) + p = Patch(delQuads=old - new, addQuads=new - old) + self.patch(p) def patchMapping(self, context, subject, predicate, nodeClass, keyPred, valuePred, newKey, newValue): """ @@ -88,3 +98,21 @@ class GraphEditApi(object): self._graph.triples((node, None, None), context=context))]) self.patch(p) + +import unittest +from rdflib import ConjunctiveGraph +class TestPatchSubgraph(unittest.TestCase): + def testCollapsesIdenticalQuads(self): + appliedPatches = [] + class Obj(GraphEditApi): + def patch(self, p): + appliedPatches.append(p) + obj = Obj() + obj._graph = ConjunctiveGraph() + stmt1 = (URIRef('s'), URIRef('p'), URIRef('o'), URIRef('g')) + obj._graph.addN([stmt1]) + obj.patchSubgraph(URIRef('g'), [stmt1]) + self.assertEqual(len(appliedPatches), 1) + p = appliedPatches[0] + self.assert_(p.isNoop()) + self.assertEqual(p.jsonRepr, '{"patch": {"adds": "", "deletes": ""}}') diff --git a/light9/rdfdb/patch.py b/light9/rdfdb/patch.py --- a/light9/rdfdb/patch.py +++ b/light9/rdfdb/patch.py @@ -10,6 +10,8 @@ def quadsWithContextUris(quads): yield the given quads, correcting any context values that are Graphs into URIRefs """ + if isinstance(quads, ConjunctiveGraph): + quads = quads.quads(ALLSTMTS) for s,p,o,c in quads: if isinstance(c, Graph): c = c.identifier @@ -66,8 +68,8 @@ class Patch(object): """ make a patch that changes oldGraph to newGraph """ - old = set(quadsWithContextUris(oldGraph.quads(ALLSTMTS))) - new = set(quadsWithContextUris(newGraph.quads(ALLSTMTS))) + old = set(quadsWithContextUris(oldGraph)) + new = set(quadsWithContextUris(newGraph)) return cls(addQuads=list(new - old), delQuads=list(old - new)) def __nonzero__(self): @@ -194,7 +196,12 @@ class TestPatchFromDiff(unittest.TestCas p = Patch.fromDiff(g1, g2) self.assertEqual(p.addQuads, []) self.assertEqual(p.delQuads, [stmt1]) - + + def testQuadSequenceOkInsteadOfGraph(self): + p = Patch.fromDiff([stmt1], ConjunctiveGraph()) + self.assertEqual(p.delQuads, [stmt1]) + p = Patch.fromDiff(ConjunctiveGraph(), [stmt1]) + self.assertEqual(p.addQuads, [stmt1]) class TestPatchGetContext(unittest.TestCase): def testEmptyPatchCantGiveContext(self): diff --git a/light9/rdfdb/rdflibpatch.py b/light9/rdfdb/rdflibpatch.py --- a/light9/rdfdb/rdflibpatch.py +++ b/light9/rdfdb/rdflibpatch.py @@ -93,15 +93,20 @@ def serializeQuad(g): def inContext(graph, newContext): """ make a ConjunctiveGraph where all the triples in the given graph - are now in newContext + (or collection) are now in newContext (a uri) """ - return graphFromQuads([(s,p,o,newContext) for s,p,o in graph]) + return graphFromQuads((s,p,o,newContext) for s,p,o in graph) def contextsForStatement(graph, triple): return [q[3] for q in graph.quads(triple)] A = U("http://a"); B = U("http://b") +class TestInContext(unittest.TestCase): + def testResultHasQuads(self): + g = inContext([(A,A,A)], B) + self.assertEqual(list(g.quads())[0], (A,A,A,B)) + class TestContextsForStatement(unittest.TestCase): def testNotFound(self): g = graphFromQuads([(A,A,A,A)])