diff --git a/src/core/graph.js b/src/core/graph.js index 730f36c..d8c509b 100644 --- a/src/core/graph.js +++ b/src/core/graph.js @@ -41,6 +41,10 @@ export class Graph { this._inEdges = new AddressMap(); } + copy(): Graph<$Supertype, $Supertype> { + return Graph.mergeConservative(new Graph(), this); + } + equals(that: Graph): boolean { return this._nodes.equals(that._nodes) && this._edges.equals(that._edges); } diff --git a/src/core/graph.test.js b/src/core/graph.test.js index 2ddd9bc..cf5b740 100644 --- a/src/core/graph.test.js +++ b/src/core/graph.test.js @@ -631,5 +631,32 @@ describe("graph", () => { }); }); }); + + describe("copy", () => { + it("separates references from the original", () => { + const g1 = demoData.advancedMealGraph(); + const g2 = g1.copy(); + const newNode = () => ({ + address: demoData.makeAddress("brand-new"), + payload: 777, + }); + g2.addNode(newNode()); + expect(g1.getNode(newNode().address)).toBeUndefined(); + expect(g2.getNode(newNode().address)).toEqual(newNode()); + }); + + it("yields a result equal to the original", () => { + const g1 = demoData.advancedMealGraph(); + const g2 = g1.copy(); + expect(g1.equals(g2)).toBe(true); + expect(g1.equals(demoData.advancedMealGraph())).toBe(true); + }); + + function itAllowsUpcastingPayloadTypes( + g: Graph<{x: string, y: number}, boolean> + ): Graph<{x: string}, ?boolean> { + return g.copy(); + } + }); }); });