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:
parent
fe1dd326ed
commit
70c1f64854
|
@ -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}}`;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue