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
This commit is contained in:
Dandelion Mané 2018-06-14 11:18:47 -07:00 committed by GitHub
parent 95c5af36d9
commit 1a08a48c03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 6 deletions

View File

@ -301,19 +301,26 @@ export class Graph {
return result;
}
nodes(): Iterator<NodeAddressT> {
const result = this._nodesIterator(this._modificationCount);
nodes(options?: {|+prefix: NodeAddressT|}): Iterator<NodeAddressT> {
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<NodeAddressT> {
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();

View File

@ -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();