Use new unified addresses in Graph V3 (#361)

Summary:
This is basically a textual substitution.

Test Plan:
Existing unit tests suffice. Note that `_address.js` (with underscore)
is no longer imported except from its own tests.

wchargin-branch: unified-addresses-in-graph
This commit is contained in:
William Chargin 2018-06-07 09:32:06 -07:00 committed by GitHub
parent fe1dd326ed
commit 70c1f64854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 102 deletions

View File

@ -1,36 +1,27 @@
// @flow
import type {NodeAddress, EdgeAddress} from "./_address";
import * as Address from "./_address";
import {makeAddressModule, type AddressModule} from "./address";
export type {NodeAddress, EdgeAddress} from "./_address";
// New-style node and edge address types and modules. Will be made
// public once implementation is complete.
export opaque type _NodeAddressT: string = string;
export opaque type _EdgeAddressT: string = string;
export const _NodeAddress: AddressModule<_NodeAddressT> = (makeAddressModule({
export opaque type NodeAddressT: string = string;
export opaque type EdgeAddressT: string = string;
export const NodeAddress: AddressModule<NodeAddressT> = (makeAddressModule({
name: "NodeAddress",
nonce: "N",
otherNonces: new Map().set("E", "EdgeAddress"),
}): AddressModule<string>);
export const _EdgeAddress: AddressModule<_EdgeAddressT> = (makeAddressModule({
export const EdgeAddress: AddressModule<EdgeAddressT> = (makeAddressModule({
name: "EdgeAddress",
nonce: "E",
otherNonces: new Map().set("N", "NodeAddress"),
}): AddressModule<string>);
Object.freeze(Address);
export {Address};
export type Edge = {|
+address: EdgeAddress,
+src: NodeAddress,
+dst: NodeAddress,
+address: EdgeAddressT,
+src: NodeAddressT,
+dst: NodeAddressT,
|};
export type Neighbor = {|+node: NodeAddress, +edge: Edge|};
export type Neighbor = {|+node: NodeAddressT, +edge: Edge|};
export opaque type DirectionT = Symbol;
export const Direction: {|
@ -45,8 +36,8 @@ export const Direction: {|
export type NeighborsOptions = {|
+direction: DirectionT,
+nodePrefix: NodeAddress,
+edgePrefix: EdgeAddress,
+nodePrefix: NodeAddressT,
+edgePrefix: EdgeAddressT,
|};
export opaque type GraphJSON = any; // TODO
@ -59,10 +50,10 @@ export class Graph {
//
// Invariant: If an edge `e` is in the graph, then `e.src` and `e.dst`
// are both in the graph.
_nodes: Set<NodeAddress>;
_edges: Map<EdgeAddress, Edge>;
_inEdges: Map<NodeAddress, Edge[]>;
_outEdges: Map<NodeAddress, Edge[]>;
_nodes: Set<NodeAddressT>;
_edges: Map<EdgeAddressT, Edge>;
_inEdges: Map<NodeAddressT, Edge[]>;
_outEdges: Map<NodeAddressT, Edge[]>;
constructor(): void {
this._nodes = new Set();
@ -71,14 +62,14 @@ export class Graph {
this._outEdges = new Map();
}
addNode(a: NodeAddress): this {
Address.assertNodeAddress(a);
addNode(a: NodeAddressT): this {
NodeAddress.assertValid(a);
this._nodes.add(a);
return this;
}
removeNode(a: NodeAddress): this {
Address.assertNodeAddress(a);
removeNode(a: NodeAddressT): this {
NodeAddress.assertValid(a);
for (const e of this.edges()) {
if (e.src === a || e.dst === a) {
const srcOrDst = e.src === a ? "src" : "dst";
@ -91,19 +82,19 @@ export class Graph {
return this;
}
hasNode(a: NodeAddress): boolean {
Address.assertNodeAddress(a);
hasNode(a: NodeAddressT): boolean {
NodeAddress.assertValid(a);
return this._nodes.has(a);
}
*nodes(): Iterator<NodeAddress> {
*nodes(): Iterator<NodeAddressT> {
yield* this._nodes;
}
addEdge(edge: Edge): this {
Address.assertNodeAddress(edge.src, "edge.src");
Address.assertNodeAddress(edge.dst, "edge.dst");
Address.assertEdgeAddress(edge.address, "edge.address");
NodeAddress.assertValid(edge.src, "edge.src");
NodeAddress.assertValid(edge.dst, "edge.dst");
EdgeAddress.assertValid(edge.address, "edge.address");
const srcMissing = !this._nodes.has(edge.src);
const dstMissing = !this._nodes.has(edge.dst);
@ -129,19 +120,19 @@ export class Graph {
return this;
}
removeEdge(address: EdgeAddress): this {
Address.assertEdgeAddress(address);
removeEdge(address: EdgeAddressT): this {
EdgeAddress.assertValid(address);
this._edges.delete(address);
return this;
}
hasEdge(address: EdgeAddress): boolean {
Address.assertEdgeAddress(address);
hasEdge(address: EdgeAddressT): boolean {
EdgeAddress.assertValid(address);
return this._edges.has(address);
}
edge(address: EdgeAddress): ?Edge {
Address.assertEdgeAddress(address);
edge(address: EdgeAddressT): ?Edge {
EdgeAddress.assertValid(address);
return this._edges.get(address);
}
@ -149,7 +140,7 @@ export class Graph {
yield* this._edges.values();
}
neighbors(node: NodeAddress, options: NeighborsOptions): Iterator<Neighbor> {
neighbors(node: NodeAddressT, options: NeighborsOptions): Iterator<Neighbor> {
const _ = {node, options};
throw new Error("neighbors");
}
@ -174,8 +165,8 @@ export class Graph {
}
export function edgeToString(edge: Edge): string {
const address = Address.edgeToString(edge.address);
const src = Address.nodeToString(edge.src);
const dst = Address.nodeToString(edge.dst);
const address = EdgeAddress.toString(edge.address);
const src = NodeAddress.toString(edge.src);
const dst = NodeAddress.toString(edge.dst);
return `{address: ${address}, src: ${src}, dst: ${dst}}`;
}

View File

@ -1,48 +1,21 @@
// @flow
import {
type EdgeAddress,
type NodeAddress,
type _EdgeAddressT,
type _NodeAddressT,
Address,
type EdgeAddressT,
type NodeAddressT,
Direction,
EdgeAddress,
Graph,
NodeAddress,
edgeToString,
} from "./graph";
describe("core/graph", () => {
const {nodeAddress, edgeAddress} = Address;
describe("Address re-exports", () => {
it("exist", () => {
expect(Address).toEqual(expect.anything());
});
it("include distinct NodeAddress and EdgeAddress types", () => {
const node: NodeAddress = nodeAddress([]);
const edge: EdgeAddress = edgeAddress([]);
// $ExpectFlowError
const _unused_badNodeAddress: NodeAddress = edge;
// $ExpectFlowError
const _unused_badEdgeAddress: EdgeAddress = node;
});
it("are read-only", () => {
const originalToParts = Address.toParts;
const wonkyToParts: typeof originalToParts = (a) => [
...originalToParts(a),
"wat",
];
expect(() => {
// $ExpectFlowError
Address.toParts = wonkyToParts;
}).toThrow(/read.only property/);
});
});
function _unused_itExportsDistinctNodeAddressAndEdgeAddressTypes() {
// $ExpectFlowError
const _unused_nodeToEdge = (x: _NodeAddressT): _EdgeAddressT => x;
const _unused_nodeToEdge = (x: NodeAddressT): EdgeAddressT => x;
// $ExpectFlowError
const _unused_edgeToNode = (x: _EdgeAddressT): _NodeAddressT => x;
const _unused_edgeToNode = (x: EdgeAddressT): NodeAddressT => x;
}
describe("Direction values", () => {
@ -80,7 +53,7 @@ describe("core/graph", () => {
describe("edge addresses", () => {
function rejectsEdgeAddress(f) {
it(`${f.name} rejects EdgeAddress`, () => {
const e = edgeAddress(["foo"]);
const e = EdgeAddress.fromParts(["foo"]);
// $ExpectFlowError
expect(() => f.call(new Graph(), e)).toThrow("got EdgeAddress");
});
@ -88,9 +61,9 @@ describe("core/graph", () => {
nodeMethods.forEach(rejectsEdgeAddress);
});
describe("remove a node that is some edge's", () => {
const src = nodeAddress(["src"]);
const dst = nodeAddress(["dst"]);
const address = edgeAddress(["edge"]);
const src = NodeAddress.fromParts(["src"]);
const dst = NodeAddress.fromParts(["dst"]);
const address = EdgeAddress.fromParts(["edge"]);
const edge = () => ({src, dst, address});
const graph = () =>
new Graph()
@ -111,7 +84,7 @@ describe("core/graph", () => {
});
describe("work on", () => {
const n1 = nodeAddress(["foo"]);
const n1 = NodeAddress.fromParts(["foo"]);
it("a graph with no nodes", () => {
const graph = new Graph();
expect(graph.hasNode(n1)).toBe(false);
@ -146,7 +119,7 @@ describe("core/graph", () => {
expect(Array.from(graph.nodes())).toHaveLength(0);
});
it("a graph with two nodes", () => {
const n2 = nodeAddress([""]);
const n2 = NodeAddress.fromParts([""]);
const graph = new Graph().addNode(n1).addNode(n2);
expect(graph.hasNode(n1)).toBe(true);
expect(graph.hasNode(n2)).toBe(true);
@ -167,7 +140,7 @@ describe("core/graph", () => {
describe("node addresses", () => {
function rejectsNodeAddress(f) {
it(`${f.name} rejects NodeAddress`, () => {
const e = nodeAddress(["foo"]);
const e = NodeAddress.fromParts(["foo"]);
// $ExpectFlowError
expect(() => f.call(new Graph(), e)).toThrow("got NodeAddress");
});
@ -177,9 +150,9 @@ describe("core/graph", () => {
describe("addEdge edge validation", () => {
describe("throws on absent", () => {
const src = nodeAddress(["src"]);
const dst = nodeAddress(["dst"]);
const address = edgeAddress(["hi"]);
const src = NodeAddress.fromParts(["src"]);
const dst = NodeAddress.fromParts(["dst"]);
const address = EdgeAddress.fromParts(["hi"]);
it("src", () => {
expect(() =>
new Graph().addNode(dst).addEdge({src, dst, address})
@ -193,8 +166,8 @@ describe("core/graph", () => {
});
describe("throws on edge with", () => {
const n = nodeAddress(["foo"]);
const e = edgeAddress(["bar"]);
const n = NodeAddress.fromParts(["foo"]);
const e = EdgeAddress.fromParts(["bar"]);
const x = "foomlio";
const badEdges = [
{
@ -240,9 +213,9 @@ describe("core/graph", () => {
});
describe("on a graph", () => {
const src = nodeAddress(["foo"]);
const dst = nodeAddress(["bar"]);
const address = edgeAddress(["yay"]);
const src = NodeAddress.fromParts(["foo"]);
const dst = NodeAddress.fromParts(["bar"]);
const address = EdgeAddress.fromParts(["yay"]);
describe("that has no edges or nodes", () => {
it("`hasEdge` is false for some address", () => {
@ -298,8 +271,8 @@ describe("core/graph", () => {
});
describe("with multiple loop edges", () => {
const e1 = edgeAddress(["e1"]);
const e2 = edgeAddress(["e2"]);
const e1 = EdgeAddress.fromParts(["e1"]);
const e2 = EdgeAddress.fromParts(["e2"]);
const edge1 = {src, dst: src, address: e1};
const edge2 = {src, dst: src, address: e2};
const quiver = () =>
@ -325,9 +298,9 @@ describe("core/graph", () => {
});
describe("idempotency of", () => {
const src = nodeAddress(["src"]);
const dst = nodeAddress(["dst"]);
const address = edgeAddress(["hi"]);
const src = NodeAddress.fromParts(["src"]);
const dst = NodeAddress.fromParts(["dst"]);
const address = EdgeAddress.fromParts(["hi"]);
it("`addEdge`", () => {
const g = new Graph()
.addNode(src)
@ -352,15 +325,15 @@ describe("core/graph", () => {
describe("edgeToString", () => {
it("works", () => {
const edge = {
address: Address.edgeAddress(["one", "two"]),
dst: Address.nodeAddress(["five", "six"]),
src: Address.nodeAddress(["three", "four"]),
address: EdgeAddress.fromParts(["one", "two"]),
dst: NodeAddress.fromParts(["five", "six"]),
src: NodeAddress.fromParts(["three", "four"]),
};
const expected =
"{" +
'address: edgeAddress(["one","two"]), ' +
'src: nodeAddress(["three","four"]), ' +
'dst: nodeAddress(["five","six"])' +
'address: EdgeAddress["one","two"], ' +
'src: NodeAddress["three","four"], ' +
'dst: NodeAddress["five","six"]' +
"}";
expect(edgeToString(edge)).toEqual(expected);
});