diff --git a/src/core/graph.js b/src/core/graph.js index 7b99e71..474132e 100644 --- a/src/core/graph.js +++ b/src/core/graph.js @@ -148,7 +148,7 @@ export opaque type GraphJSON = Compatible<{| +edges: IndexedEdgeJSON[], |}>; -type ModificationCount = number; +export type ModificationCount = number; export class Graph { _nodes: Set; @@ -204,6 +204,26 @@ export class Graph { this._maybeCheckInvariants(); } + /** + * Returns how many times the graph has been modified. + * + * This value is exposed so that users of Graph can cache computations over + * the graph with confidence, knowing that they will be able to check the + * modification count to know when their cache is potentially invalid. + * + * This value may increase any time the graph is potentially modified, even + * if no modification actually occurs; for example, if a client calls + * `addNode`, the modification count may increase even if the added node was + * already present in the graph. + * + * This value is not serialized, and is ignored when checking equality, i.e. + * two graphs may be semantically equal even when they have different + * modification counts. + */ + modificationCount(): ModificationCount { + return this._modificationCount; + } + /** * Adds a new node to the graph. * diff --git a/src/core/graph.test.js b/src/core/graph.test.js index f55cc95..82ce949 100644 --- a/src/core/graph.test.js +++ b/src/core/graph.test.js @@ -74,6 +74,29 @@ describe("core/graph", () => { }).toThrow("modification count in the future"); }); + describe("modification count retrieval", () => { + it("modification count starts at 0", () => { + const g = new Graph(); + expect(g.modificationCount()).toEqual(0); + }); + it("modification count increases after any potential modification", () => { + const g = new Graph(); + expect(g.modificationCount()).toEqual(0); + g.addNode(NodeAddress.empty); + expect(g.modificationCount()).toEqual(1); + g.addNode(NodeAddress.empty); + expect(g.modificationCount()).toEqual(2); + }); + it("graphs can be equal despite unequal modification count", () => { + const g1 = new Graph() + .addNode(NodeAddress.empty) + .removeNode(NodeAddress.empty); + const g2 = new Graph(); + expect(g1.equals(g2)).toEqual(true); + expect(g1.modificationCount()).not.toEqual(g2.modificationCount()); + }); + }); + describe("automated invariant checking", () => { const src = NodeAddress.fromParts(["src"]); const dst = NodeAddress.fromParts(["dst"]);