mirror of
https://github.com/status-im/sourcecred.git
synced 2025-02-17 06:56:36 +00:00
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
|
// @flow
|
||||||
|
|
||||||
import type {NodeAddress, EdgeAddress} from "./_address";
|
|
||||||
import * as Address from "./_address";
|
|
||||||
import {makeAddressModule, type AddressModule} from "./address";
|
import {makeAddressModule, type AddressModule} from "./address";
|
||||||
|
|
||||||
export type {NodeAddress, EdgeAddress} from "./_address";
|
export opaque type NodeAddressT: string = string;
|
||||||
|
export opaque type EdgeAddressT: string = string;
|
||||||
// New-style node and edge address types and modules. Will be made
|
export const NodeAddress: AddressModule<NodeAddressT> = (makeAddressModule({
|
||||||
// public once implementation is complete.
|
|
||||||
export opaque type _NodeAddressT: string = string;
|
|
||||||
export opaque type _EdgeAddressT: string = string;
|
|
||||||
export const _NodeAddress: AddressModule<_NodeAddressT> = (makeAddressModule({
|
|
||||||
name: "NodeAddress",
|
name: "NodeAddress",
|
||||||
nonce: "N",
|
nonce: "N",
|
||||||
otherNonces: new Map().set("E", "EdgeAddress"),
|
otherNonces: new Map().set("E", "EdgeAddress"),
|
||||||
}): AddressModule<string>);
|
}): AddressModule<string>);
|
||||||
export const _EdgeAddress: AddressModule<_EdgeAddressT> = (makeAddressModule({
|
export const EdgeAddress: AddressModule<EdgeAddressT> = (makeAddressModule({
|
||||||
name: "EdgeAddress",
|
name: "EdgeAddress",
|
||||||
nonce: "E",
|
nonce: "E",
|
||||||
otherNonces: new Map().set("N", "NodeAddress"),
|
otherNonces: new Map().set("N", "NodeAddress"),
|
||||||
}): AddressModule<string>);
|
}): AddressModule<string>);
|
||||||
|
|
||||||
Object.freeze(Address);
|
|
||||||
export {Address};
|
|
||||||
|
|
||||||
export type Edge = {|
|
export type Edge = {|
|
||||||
+address: EdgeAddress,
|
+address: EdgeAddressT,
|
||||||
+src: NodeAddress,
|
+src: NodeAddressT,
|
||||||
+dst: NodeAddress,
|
+dst: NodeAddressT,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export type Neighbor = {|+node: NodeAddress, +edge: Edge|};
|
export type Neighbor = {|+node: NodeAddressT, +edge: Edge|};
|
||||||
|
|
||||||
export opaque type DirectionT = Symbol;
|
export opaque type DirectionT = Symbol;
|
||||||
export const Direction: {|
|
export const Direction: {|
|
||||||
@ -45,8 +36,8 @@ export const Direction: {|
|
|||||||
|
|
||||||
export type NeighborsOptions = {|
|
export type NeighborsOptions = {|
|
||||||
+direction: DirectionT,
|
+direction: DirectionT,
|
||||||
+nodePrefix: NodeAddress,
|
+nodePrefix: NodeAddressT,
|
||||||
+edgePrefix: EdgeAddress,
|
+edgePrefix: EdgeAddressT,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export opaque type GraphJSON = any; // TODO
|
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`
|
// Invariant: If an edge `e` is in the graph, then `e.src` and `e.dst`
|
||||||
// are both in the graph.
|
// are both in the graph.
|
||||||
_nodes: Set<NodeAddress>;
|
_nodes: Set<NodeAddressT>;
|
||||||
_edges: Map<EdgeAddress, Edge>;
|
_edges: Map<EdgeAddressT, Edge>;
|
||||||
_inEdges: Map<NodeAddress, Edge[]>;
|
_inEdges: Map<NodeAddressT, Edge[]>;
|
||||||
_outEdges: Map<NodeAddress, Edge[]>;
|
_outEdges: Map<NodeAddressT, Edge[]>;
|
||||||
|
|
||||||
constructor(): void {
|
constructor(): void {
|
||||||
this._nodes = new Set();
|
this._nodes = new Set();
|
||||||
@ -71,14 +62,14 @@ export class Graph {
|
|||||||
this._outEdges = new Map();
|
this._outEdges = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
addNode(a: NodeAddress): this {
|
addNode(a: NodeAddressT): this {
|
||||||
Address.assertNodeAddress(a);
|
NodeAddress.assertValid(a);
|
||||||
this._nodes.add(a);
|
this._nodes.add(a);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeNode(a: NodeAddress): this {
|
removeNode(a: NodeAddressT): this {
|
||||||
Address.assertNodeAddress(a);
|
NodeAddress.assertValid(a);
|
||||||
for (const e of this.edges()) {
|
for (const e of this.edges()) {
|
||||||
if (e.src === a || e.dst === a) {
|
if (e.src === a || e.dst === a) {
|
||||||
const srcOrDst = e.src === a ? "src" : "dst";
|
const srcOrDst = e.src === a ? "src" : "dst";
|
||||||
@ -91,19 +82,19 @@ export class Graph {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNode(a: NodeAddress): boolean {
|
hasNode(a: NodeAddressT): boolean {
|
||||||
Address.assertNodeAddress(a);
|
NodeAddress.assertValid(a);
|
||||||
return this._nodes.has(a);
|
return this._nodes.has(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
*nodes(): Iterator<NodeAddress> {
|
*nodes(): Iterator<NodeAddressT> {
|
||||||
yield* this._nodes;
|
yield* this._nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
addEdge(edge: Edge): this {
|
addEdge(edge: Edge): this {
|
||||||
Address.assertNodeAddress(edge.src, "edge.src");
|
NodeAddress.assertValid(edge.src, "edge.src");
|
||||||
Address.assertNodeAddress(edge.dst, "edge.dst");
|
NodeAddress.assertValid(edge.dst, "edge.dst");
|
||||||
Address.assertEdgeAddress(edge.address, "edge.address");
|
EdgeAddress.assertValid(edge.address, "edge.address");
|
||||||
|
|
||||||
const srcMissing = !this._nodes.has(edge.src);
|
const srcMissing = !this._nodes.has(edge.src);
|
||||||
const dstMissing = !this._nodes.has(edge.dst);
|
const dstMissing = !this._nodes.has(edge.dst);
|
||||||
@ -129,19 +120,19 @@ export class Graph {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeEdge(address: EdgeAddress): this {
|
removeEdge(address: EdgeAddressT): this {
|
||||||
Address.assertEdgeAddress(address);
|
EdgeAddress.assertValid(address);
|
||||||
this._edges.delete(address);
|
this._edges.delete(address);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasEdge(address: EdgeAddress): boolean {
|
hasEdge(address: EdgeAddressT): boolean {
|
||||||
Address.assertEdgeAddress(address);
|
EdgeAddress.assertValid(address);
|
||||||
return this._edges.has(address);
|
return this._edges.has(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
edge(address: EdgeAddress): ?Edge {
|
edge(address: EdgeAddressT): ?Edge {
|
||||||
Address.assertEdgeAddress(address);
|
EdgeAddress.assertValid(address);
|
||||||
return this._edges.get(address);
|
return this._edges.get(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +140,7 @@ export class Graph {
|
|||||||
yield* this._edges.values();
|
yield* this._edges.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
neighbors(node: NodeAddress, options: NeighborsOptions): Iterator<Neighbor> {
|
neighbors(node: NodeAddressT, options: NeighborsOptions): Iterator<Neighbor> {
|
||||||
const _ = {node, options};
|
const _ = {node, options};
|
||||||
throw new Error("neighbors");
|
throw new Error("neighbors");
|
||||||
}
|
}
|
||||||
@ -174,8 +165,8 @@ export class Graph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function edgeToString(edge: Edge): string {
|
export function edgeToString(edge: Edge): string {
|
||||||
const address = Address.edgeToString(edge.address);
|
const address = EdgeAddress.toString(edge.address);
|
||||||
const src = Address.nodeToString(edge.src);
|
const src = NodeAddress.toString(edge.src);
|
||||||
const dst = Address.nodeToString(edge.dst);
|
const dst = NodeAddress.toString(edge.dst);
|
||||||
return `{address: ${address}, src: ${src}, dst: ${dst}}`;
|
return `{address: ${address}, src: ${src}, dst: ${dst}}`;
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,21 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type EdgeAddress,
|
type EdgeAddressT,
|
||||||
type NodeAddress,
|
type NodeAddressT,
|
||||||
type _EdgeAddressT,
|
|
||||||
type _NodeAddressT,
|
|
||||||
Address,
|
|
||||||
Direction,
|
Direction,
|
||||||
|
EdgeAddress,
|
||||||
Graph,
|
Graph,
|
||||||
|
NodeAddress,
|
||||||
edgeToString,
|
edgeToString,
|
||||||
} from "./graph";
|
} from "./graph";
|
||||||
|
|
||||||
describe("core/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() {
|
function _unused_itExportsDistinctNodeAddressAndEdgeAddressTypes() {
|
||||||
// $ExpectFlowError
|
// $ExpectFlowError
|
||||||
const _unused_nodeToEdge = (x: _NodeAddressT): _EdgeAddressT => x;
|
const _unused_nodeToEdge = (x: NodeAddressT): EdgeAddressT => x;
|
||||||
// $ExpectFlowError
|
// $ExpectFlowError
|
||||||
const _unused_edgeToNode = (x: _EdgeAddressT): _NodeAddressT => x;
|
const _unused_edgeToNode = (x: EdgeAddressT): NodeAddressT => x;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Direction values", () => {
|
describe("Direction values", () => {
|
||||||
@ -80,7 +53,7 @@ describe("core/graph", () => {
|
|||||||
describe("edge addresses", () => {
|
describe("edge addresses", () => {
|
||||||
function rejectsEdgeAddress(f) {
|
function rejectsEdgeAddress(f) {
|
||||||
it(`${f.name} rejects EdgeAddress`, () => {
|
it(`${f.name} rejects EdgeAddress`, () => {
|
||||||
const e = edgeAddress(["foo"]);
|
const e = EdgeAddress.fromParts(["foo"]);
|
||||||
// $ExpectFlowError
|
// $ExpectFlowError
|
||||||
expect(() => f.call(new Graph(), e)).toThrow("got EdgeAddress");
|
expect(() => f.call(new Graph(), e)).toThrow("got EdgeAddress");
|
||||||
});
|
});
|
||||||
@ -88,9 +61,9 @@ describe("core/graph", () => {
|
|||||||
nodeMethods.forEach(rejectsEdgeAddress);
|
nodeMethods.forEach(rejectsEdgeAddress);
|
||||||
});
|
});
|
||||||
describe("remove a node that is some edge's", () => {
|
describe("remove a node that is some edge's", () => {
|
||||||
const src = nodeAddress(["src"]);
|
const src = NodeAddress.fromParts(["src"]);
|
||||||
const dst = nodeAddress(["dst"]);
|
const dst = NodeAddress.fromParts(["dst"]);
|
||||||
const address = edgeAddress(["edge"]);
|
const address = EdgeAddress.fromParts(["edge"]);
|
||||||
const edge = () => ({src, dst, address});
|
const edge = () => ({src, dst, address});
|
||||||
const graph = () =>
|
const graph = () =>
|
||||||
new Graph()
|
new Graph()
|
||||||
@ -111,7 +84,7 @@ describe("core/graph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("work on", () => {
|
describe("work on", () => {
|
||||||
const n1 = nodeAddress(["foo"]);
|
const n1 = NodeAddress.fromParts(["foo"]);
|
||||||
it("a graph with no nodes", () => {
|
it("a graph with no nodes", () => {
|
||||||
const graph = new Graph();
|
const graph = new Graph();
|
||||||
expect(graph.hasNode(n1)).toBe(false);
|
expect(graph.hasNode(n1)).toBe(false);
|
||||||
@ -146,7 +119,7 @@ describe("core/graph", () => {
|
|||||||
expect(Array.from(graph.nodes())).toHaveLength(0);
|
expect(Array.from(graph.nodes())).toHaveLength(0);
|
||||||
});
|
});
|
||||||
it("a graph with two nodes", () => {
|
it("a graph with two nodes", () => {
|
||||||
const n2 = nodeAddress([""]);
|
const n2 = NodeAddress.fromParts([""]);
|
||||||
const graph = new Graph().addNode(n1).addNode(n2);
|
const graph = new Graph().addNode(n1).addNode(n2);
|
||||||
expect(graph.hasNode(n1)).toBe(true);
|
expect(graph.hasNode(n1)).toBe(true);
|
||||||
expect(graph.hasNode(n2)).toBe(true);
|
expect(graph.hasNode(n2)).toBe(true);
|
||||||
@ -167,7 +140,7 @@ describe("core/graph", () => {
|
|||||||
describe("node addresses", () => {
|
describe("node addresses", () => {
|
||||||
function rejectsNodeAddress(f) {
|
function rejectsNodeAddress(f) {
|
||||||
it(`${f.name} rejects NodeAddress`, () => {
|
it(`${f.name} rejects NodeAddress`, () => {
|
||||||
const e = nodeAddress(["foo"]);
|
const e = NodeAddress.fromParts(["foo"]);
|
||||||
// $ExpectFlowError
|
// $ExpectFlowError
|
||||||
expect(() => f.call(new Graph(), e)).toThrow("got NodeAddress");
|
expect(() => f.call(new Graph(), e)).toThrow("got NodeAddress");
|
||||||
});
|
});
|
||||||
@ -177,9 +150,9 @@ describe("core/graph", () => {
|
|||||||
|
|
||||||
describe("addEdge edge validation", () => {
|
describe("addEdge edge validation", () => {
|
||||||
describe("throws on absent", () => {
|
describe("throws on absent", () => {
|
||||||
const src = nodeAddress(["src"]);
|
const src = NodeAddress.fromParts(["src"]);
|
||||||
const dst = nodeAddress(["dst"]);
|
const dst = NodeAddress.fromParts(["dst"]);
|
||||||
const address = edgeAddress(["hi"]);
|
const address = EdgeAddress.fromParts(["hi"]);
|
||||||
it("src", () => {
|
it("src", () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
new Graph().addNode(dst).addEdge({src, dst, address})
|
new Graph().addNode(dst).addEdge({src, dst, address})
|
||||||
@ -193,8 +166,8 @@ describe("core/graph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("throws on edge with", () => {
|
describe("throws on edge with", () => {
|
||||||
const n = nodeAddress(["foo"]);
|
const n = NodeAddress.fromParts(["foo"]);
|
||||||
const e = edgeAddress(["bar"]);
|
const e = EdgeAddress.fromParts(["bar"]);
|
||||||
const x = "foomlio";
|
const x = "foomlio";
|
||||||
const badEdges = [
|
const badEdges = [
|
||||||
{
|
{
|
||||||
@ -240,9 +213,9 @@ describe("core/graph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("on a graph", () => {
|
describe("on a graph", () => {
|
||||||
const src = nodeAddress(["foo"]);
|
const src = NodeAddress.fromParts(["foo"]);
|
||||||
const dst = nodeAddress(["bar"]);
|
const dst = NodeAddress.fromParts(["bar"]);
|
||||||
const address = edgeAddress(["yay"]);
|
const address = EdgeAddress.fromParts(["yay"]);
|
||||||
|
|
||||||
describe("that has no edges or nodes", () => {
|
describe("that has no edges or nodes", () => {
|
||||||
it("`hasEdge` is false for some address", () => {
|
it("`hasEdge` is false for some address", () => {
|
||||||
@ -298,8 +271,8 @@ describe("core/graph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("with multiple loop edges", () => {
|
describe("with multiple loop edges", () => {
|
||||||
const e1 = edgeAddress(["e1"]);
|
const e1 = EdgeAddress.fromParts(["e1"]);
|
||||||
const e2 = edgeAddress(["e2"]);
|
const e2 = EdgeAddress.fromParts(["e2"]);
|
||||||
const edge1 = {src, dst: src, address: e1};
|
const edge1 = {src, dst: src, address: e1};
|
||||||
const edge2 = {src, dst: src, address: e2};
|
const edge2 = {src, dst: src, address: e2};
|
||||||
const quiver = () =>
|
const quiver = () =>
|
||||||
@ -325,9 +298,9 @@ describe("core/graph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("idempotency of", () => {
|
describe("idempotency of", () => {
|
||||||
const src = nodeAddress(["src"]);
|
const src = NodeAddress.fromParts(["src"]);
|
||||||
const dst = nodeAddress(["dst"]);
|
const dst = NodeAddress.fromParts(["dst"]);
|
||||||
const address = edgeAddress(["hi"]);
|
const address = EdgeAddress.fromParts(["hi"]);
|
||||||
it("`addEdge`", () => {
|
it("`addEdge`", () => {
|
||||||
const g = new Graph()
|
const g = new Graph()
|
||||||
.addNode(src)
|
.addNode(src)
|
||||||
@ -352,15 +325,15 @@ describe("core/graph", () => {
|
|||||||
describe("edgeToString", () => {
|
describe("edgeToString", () => {
|
||||||
it("works", () => {
|
it("works", () => {
|
||||||
const edge = {
|
const edge = {
|
||||||
address: Address.edgeAddress(["one", "two"]),
|
address: EdgeAddress.fromParts(["one", "two"]),
|
||||||
dst: Address.nodeAddress(["five", "six"]),
|
dst: NodeAddress.fromParts(["five", "six"]),
|
||||||
src: Address.nodeAddress(["three", "four"]),
|
src: NodeAddress.fromParts(["three", "four"]),
|
||||||
};
|
};
|
||||||
const expected =
|
const expected =
|
||||||
"{" +
|
"{" +
|
||||||
'address: edgeAddress(["one","two"]), ' +
|
'address: EdgeAddress["one","two"], ' +
|
||||||
'src: nodeAddress(["three","four"]), ' +
|
'src: NodeAddress["three","four"], ' +
|
||||||
'dst: nodeAddress(["five","six"])' +
|
'dst: NodeAddress["five","six"]' +
|
||||||
"}";
|
"}";
|
||||||
expect(edgeToString(edge)).toEqual(expected);
|
expect(edgeToString(edge)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user