From 1a08a48c0333ec0ecffdc378bc6d24a2661d3556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Thu, 14 Jun 2018 11:18:47 -0700 Subject: [PATCH] Implement prefix filtering for `Graph.nodes` (#390) Simple API addition to match v1/v2 semantics. In the future, we can perf optimize this if we switch graph to store nodes organized by shared prefixes. Test plan: Unit tests were added. `yarn travis` passes. Paired with @wchargin --- src/v3/core/graph.js | 19 +++++++++++++------ src/v3/core/graph.test.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/v3/core/graph.js b/src/v3/core/graph.js index d4a67ba..482be01 100644 --- a/src/v3/core/graph.js +++ b/src/v3/core/graph.js @@ -301,19 +301,26 @@ export class Graph { return result; } - nodes(): Iterator { - const result = this._nodesIterator(this._modificationCount); + nodes(options?: {|+prefix: NodeAddressT|}): Iterator { + const prefix = options != null ? options.prefix : NodeAddress.fromParts([]); + if (prefix == null) { + throw new Error(`Invalid prefix: ${String(prefix)}`); + } + const result = this._nodesIterator(this._modificationCount, prefix); this._maybeCheckInvariants(); return result; } *_nodesIterator( - initialModificationCount: ModificationCount + initialModificationCount: ModificationCount, + prefix: NodeAddressT ): Iterator { for (const node of this._nodes) { - this._checkForComodification(initialModificationCount); - this._maybeCheckInvariants(); - yield node; + if (NodeAddress.hasPrefix(node, prefix)) { + this._checkForComodification(initialModificationCount); + this._maybeCheckInvariants(); + yield node; + } } this._checkForComodification(initialModificationCount); this._maybeCheckInvariants(); diff --git a/src/v3/core/graph.test.js b/src/v3/core/graph.test.js index 2c55c5c..50239a8 100644 --- a/src/v3/core/graph.test.js +++ b/src/v3/core/graph.test.js @@ -402,6 +402,39 @@ describe("core/graph", () => { }); }); + describe("node prefix filtering", () => { + const n1 = NodeAddress.fromParts([]); + const n2 = NodeAddress.fromParts(["foo"]); + const n3 = NodeAddress.fromParts(["foo", "bar"]); + const n4 = NodeAddress.fromParts(["zod", "bar"]); + const graph = () => + new Graph() + .addNode(n1) + .addNode(n2) + .addNode(n3) + .addNode(n4); + function expectSortedNodes( + options: {|+prefix: NodeAddressT|} | void, + expected: NodeAddressT[] + ) { + const actual = graph().nodes(options); + expect(Array.from(actual).sort()).toEqual(expected.slice().sort()); + } + it("uses empty prefix when no options object", () => { + expectSortedNodes(undefined, [n1, n2, n3, n4]); + }); + it("requires a prefix when options are specified", () => { + // $ExpectFlowError + expect(() => graph().nodes({})).toThrow("prefix"); + }); + it("does a prefix filter", () => { + expectSortedNodes({prefix: n2}, [n2, n3]); + }); + it("yields nothing when prefix matches nothing", () => { + expectSortedNodes({prefix: NodeAddress.fromParts(["2"])}, []); + }); + }); + describe("change the modification count", () => { it("on addNode, when a node is added", () => { const g = new Graph();