@osmix/core 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +86 -69
- package/dist/contracts.d.ts +26 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +1 -0
- package/dist/contracts.js.map +1 -0
- package/dist/entities.d.ts +1 -1
- package/dist/entities.d.ts.map +1 -1
- package/dist/entities.js +2 -7
- package/dist/entities.js.map +1 -1
- package/dist/ids.d.ts +2 -0
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +23 -15
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/mocks.d.ts.map +1 -1
- package/dist/mocks.js.map +1 -1
- package/dist/nodes.d.ts +9 -3
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +6 -13
- package/dist/nodes.js.map +1 -1
- package/dist/osm.d.ts +1 -1
- package/dist/osm.d.ts.map +1 -1
- package/dist/osm.js +1 -4
- package/dist/osm.js.map +1 -1
- package/dist/relations.d.ts +3 -2
- package/dist/relations.d.ts.map +1 -1
- package/dist/relations.js +15 -9
- package/dist/relations.js.map +1 -1
- package/dist/stringtable.d.ts.map +1 -1
- package/dist/stringtable.js +4 -13
- package/dist/stringtable.js.map +1 -1
- package/dist/tags.d.ts +1 -1
- package/dist/tags.d.ts.map +1 -1
- package/dist/tags.js.map +1 -1
- package/dist/typed-arrays.d.ts +1 -1
- package/dist/typed-arrays.d.ts.map +1 -1
- package/dist/typed-arrays.js.map +1 -1
- package/dist/ways.d.ts +2 -1
- package/dist/ways.d.ts.map +1 -1
- package/dist/ways.js +18 -18
- package/dist/ways.js.map +1 -1
- package/package.json +46 -31
- package/src/contracts.ts +28 -0
- package/src/entities.ts +179 -194
- package/src/ids.ts +228 -235
- package/src/index.ts +12 -9
- package/src/mocks.ts +114 -113
- package/src/nodes.ts +364 -397
- package/src/osm.ts +196 -207
- package/src/relations.ts +530 -558
- package/src/stringtable.ts +174 -183
- package/src/tags.ts +263 -271
- package/src/typed-arrays.ts +184 -194
- package/src/types/geoflatbush.d.ts +28 -33
- package/src/types/geokdbush.d.ts +28 -33
- package/src/types/kdbush.d.ts +34 -34
- package/src/ways.ts +381 -405
- package/test/ids.bench.ts +29 -0
- package/test/ids.test.ts +84 -0
- package/test/memory.test.ts +29 -30
- package/test/relations.bench.ts +27 -0
- package/test/relations.test.ts +101 -0
- package/test/tags-search.test.ts +76 -56
- package/test/typed-arrays.test.ts +100 -99
- package/tsconfig.build.json +6 -3
- package/tsconfig.json +7 -7
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { bench, describe } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Ids } from "../src/ids";
|
|
4
|
+
import { Osm } from "../src/osm";
|
|
5
|
+
|
|
6
|
+
const values = Array.from({ length: 20_000 }, (_, index) => (index * 7919) % 100_000);
|
|
7
|
+
|
|
8
|
+
function buildIds() {
|
|
9
|
+
const ids = new Ids();
|
|
10
|
+
for (const value of values) ids.add(value);
|
|
11
|
+
ids.buildIndex();
|
|
12
|
+
return ids;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const osm = new Osm();
|
|
16
|
+
for (const value of values) osm.nodes.addNode({ id: value, lon: value, lat: value });
|
|
17
|
+
osm.buildIndexes();
|
|
18
|
+
|
|
19
|
+
describe("sorted ID iteration", () => {
|
|
20
|
+
bench("build shuffled sorted index", () => {
|
|
21
|
+
buildIds();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
bench("iterate all sorted entities", () => {
|
|
25
|
+
let checksum = 0;
|
|
26
|
+
for (const node of osm.nodes.sorted()) checksum += node.id + node.lon;
|
|
27
|
+
if (checksum === 0) throw Error("Unexpected empty benchmark");
|
|
28
|
+
});
|
|
29
|
+
});
|
package/test/ids.test.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Ids } from "../src/ids";
|
|
4
|
+
import { Osm } from "../src/osm";
|
|
5
|
+
|
|
6
|
+
function buildIds(values: number[]) {
|
|
7
|
+
const ids = new Ids();
|
|
8
|
+
for (const value of values) ids.add(value);
|
|
9
|
+
ids.buildIndex();
|
|
10
|
+
return ids;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe("Ids sorted entries", () => {
|
|
14
|
+
it.each([
|
|
15
|
+
{ name: "empty", values: [], entries: [] },
|
|
16
|
+
{
|
|
17
|
+
name: "ascending",
|
|
18
|
+
values: [1, 2, 3],
|
|
19
|
+
entries: [
|
|
20
|
+
[1, 0],
|
|
21
|
+
[2, 1],
|
|
22
|
+
[3, 2],
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "reverse",
|
|
27
|
+
values: [3, 2, 1],
|
|
28
|
+
entries: [
|
|
29
|
+
[1, 2],
|
|
30
|
+
[2, 1],
|
|
31
|
+
[3, 0],
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "sparse",
|
|
36
|
+
values: [100, 2, 50],
|
|
37
|
+
entries: [
|
|
38
|
+
[2, 1],
|
|
39
|
+
[50, 2],
|
|
40
|
+
[100, 0],
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "duplicates",
|
|
45
|
+
values: [5, 2, 5, 2],
|
|
46
|
+
entries: [
|
|
47
|
+
[2, 1],
|
|
48
|
+
[2, 3],
|
|
49
|
+
[5, 0],
|
|
50
|
+
[5, 2],
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
])("preserves sorted ID and original-position order for $name IDs", ({ values, entries }) => {
|
|
54
|
+
expect(Array.from(buildIds(values).sortedEntries())).toEqual(entries);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("preserves sorted entries through transfer reconstruction", () => {
|
|
58
|
+
const source = buildIds([9, 3, 9, 1]);
|
|
59
|
+
const reconstructed = new Ids(source.transferables());
|
|
60
|
+
|
|
61
|
+
expect(Array.from(reconstructed.sortedEntries())).toEqual([
|
|
62
|
+
[1, 3],
|
|
63
|
+
[3, 1],
|
|
64
|
+
[9, 0],
|
|
65
|
+
[9, 2],
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("streams sorted entities without looking up each ID again", () => {
|
|
70
|
+
const osm = new Osm();
|
|
71
|
+
osm.nodes.addNode({ id: 2, lon: 20, lat: 20 });
|
|
72
|
+
osm.nodes.addNode({ id: 1, lon: 10, lat: 10 });
|
|
73
|
+
osm.nodes.addNode({ id: 1, lon: 11, lat: 11 });
|
|
74
|
+
osm.buildIndexes();
|
|
75
|
+
const getIndexFromId = vi.spyOn(osm.nodes.ids, "getIndexFromId");
|
|
76
|
+
|
|
77
|
+
expect([...osm.nodes.sorted()].map((node) => [node.id, node.lon])).toEqual([
|
|
78
|
+
[1, 10],
|
|
79
|
+
[1, 11],
|
|
80
|
+
[2, 20],
|
|
81
|
+
]);
|
|
82
|
+
expect(getIndexFromId).not.toHaveBeenCalled();
|
|
83
|
+
});
|
|
84
|
+
});
|
package/test/memory.test.ts
CHANGED
|
@@ -1,38 +1,37 @@
|
|
|
1
|
-
import { describe, expect, it } from "
|
|
2
|
-
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Nodes, Relations, Ways } from "../src";
|
|
3
4
|
|
|
4
5
|
export function getOsmCoreMemoryRequirements(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
nodeCount: number,
|
|
7
|
+
wayCount: number,
|
|
8
|
+
relationCount: number,
|
|
8
9
|
) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const nodesBytes = Nodes.getBytesRequired(nodeCount);
|
|
11
|
+
const waysBytes = Ways.getBytesRequired(wayCount);
|
|
12
|
+
const relationsBytes = Relations.getBytesRequired(relationCount);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
return {
|
|
15
|
+
nodes: nodesBytes,
|
|
16
|
+
ways: waysBytes,
|
|
17
|
+
relations: relationsBytes,
|
|
18
|
+
total: nodesBytes + waysBytes + relationsBytes,
|
|
19
|
+
};
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
describe("Memory Requirements", () => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
})
|
|
23
|
+
it("computes memory requirements for small datasets", () => {
|
|
24
|
+
const breakdown = getOsmCoreMemoryRequirements(10, 2, 1);
|
|
25
|
+
expect(breakdown.nodes).toBeGreaterThan(0);
|
|
26
|
+
expect(breakdown.ways).toBeGreaterThan(0);
|
|
27
|
+
expect(breakdown.relations).toBeGreaterThan(0);
|
|
28
|
+
expect(breakdown.total).toBe(breakdown.nodes + breakdown.ways + breakdown.relations);
|
|
29
|
+
});
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
})
|
|
31
|
+
it("computes memory requirements for large datasets", () => {
|
|
32
|
+
const breakdown = getOsmCoreMemoryRequirements(70000, 20000, 0);
|
|
33
|
+
expect(breakdown.nodes).toBeGreaterThan(0);
|
|
34
|
+
expect(breakdown.ways).toBeGreaterThan(0);
|
|
35
|
+
expect(breakdown.total).toBe(breakdown.nodes + breakdown.ways);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { bench, describe } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Osm } from "../src/osm";
|
|
4
|
+
|
|
5
|
+
function createManyMemberRelations() {
|
|
6
|
+
const osm = new Osm({ id: "relations-benchmark" });
|
|
7
|
+
for (let relationId = 0; relationId < 100; relationId++) {
|
|
8
|
+
osm.relations.addRelation({
|
|
9
|
+
id: relationId,
|
|
10
|
+
members: Array.from({ length: 100 }, (_, index) => ({
|
|
11
|
+
type: "way" as const,
|
|
12
|
+
ref: relationId * 100 + index,
|
|
13
|
+
role: "",
|
|
14
|
+
})),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return osm;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const osm = createManyMemberRelations();
|
|
21
|
+
osm.relations.getWayMemberIds();
|
|
22
|
+
|
|
23
|
+
describe("relation way membership cache", () => {
|
|
24
|
+
bench("1000 repeated cached lookups", () => {
|
|
25
|
+
for (let i = 0; i < 1000; i++) osm.relations.getWayMemberIds();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Osm, type Osm as OsmType } from "../src/osm";
|
|
4
|
+
|
|
5
|
+
function createOsmWithRelations(): OsmType {
|
|
6
|
+
const osm = new Osm({ id: "relations" });
|
|
7
|
+
osm.nodes.addNode({ id: 1, lon: -120, lat: 46 });
|
|
8
|
+
osm.nodes.addNode({ id: 2, lon: -120.01, lat: 46.01 });
|
|
9
|
+
osm.nodes.addNode({ id: 3, lon: -120.02, lat: 46.02 });
|
|
10
|
+
osm.ways.addWay({ id: 10, refs: [1, 2], tags: { highway: "primary" } });
|
|
11
|
+
osm.ways.addWay({ id: 20, refs: [2, 3], tags: { highway: "secondary" } });
|
|
12
|
+
osm.relations.addRelation({
|
|
13
|
+
id: 100,
|
|
14
|
+
members: [
|
|
15
|
+
{ type: "way", ref: 10, role: "outer" },
|
|
16
|
+
{ type: "node", ref: 1, role: "label" },
|
|
17
|
+
{ type: "way", ref: 10, role: "outer" },
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
osm.relations.addRelation({
|
|
21
|
+
id: 200,
|
|
22
|
+
members: [
|
|
23
|
+
{ type: "way", ref: 20, role: "outer" },
|
|
24
|
+
{ type: "relation", ref: 100, role: "child" },
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
osm.buildIndexes();
|
|
28
|
+
return osm;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("relation way membership cache", () => {
|
|
32
|
+
it("returns an empty cached set for empty relations", () => {
|
|
33
|
+
const osm = new Osm();
|
|
34
|
+
|
|
35
|
+
const first = osm.relations.getWayMemberIds();
|
|
36
|
+
const second = osm.relations.getWayMemberIds();
|
|
37
|
+
|
|
38
|
+
expect(first).toBe(second);
|
|
39
|
+
expect(first).toEqual(new Set());
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("collects unique direct and nested way members", () => {
|
|
43
|
+
const wayIds = createOsmWithRelations().relations.getWayMemberIds();
|
|
44
|
+
|
|
45
|
+
expect(wayIds).toEqual(new Set([10, 20]));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("does not traverse relations again while the cache is warm", () => {
|
|
49
|
+
const osm = createOsmWithRelations();
|
|
50
|
+
const getByIndex = vi.spyOn(osm.relations, "getByIndex");
|
|
51
|
+
|
|
52
|
+
const first = osm.relations.getWayMemberIds();
|
|
53
|
+
const callsAfterFirstLookup = getByIndex.mock.calls.length;
|
|
54
|
+
const second = osm.relations.getWayMemberIds();
|
|
55
|
+
|
|
56
|
+
expect(second).toBe(first);
|
|
57
|
+
expect(callsAfterFirstLookup).toBeGreaterThan(0);
|
|
58
|
+
expect(getByIndex).toHaveBeenCalledTimes(callsAfterFirstLookup);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("invalidates the cache when a relation is added", () => {
|
|
62
|
+
const osm = new Osm();
|
|
63
|
+
osm.relations.addRelation({ id: 1, members: [{ type: "way", ref: 10, role: "" }] });
|
|
64
|
+
const first = osm.relations.getWayMemberIds();
|
|
65
|
+
|
|
66
|
+
osm.relations.addRelation({ id: 2, members: [{ type: "way", ref: 20, role: "" }] });
|
|
67
|
+
const second = osm.relations.getWayMemberIds();
|
|
68
|
+
|
|
69
|
+
expect(second).not.toBe(first);
|
|
70
|
+
expect(second).toEqual(new Set([10, 20]));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("invalidates the cache when relations are added in bulk", () => {
|
|
74
|
+
const osm = new Osm();
|
|
75
|
+
osm.stringTable.add("");
|
|
76
|
+
osm.relations.addRelation({ id: 1, members: [{ type: "way", ref: 10, role: "" }] });
|
|
77
|
+
osm.relations.getWayMemberIds();
|
|
78
|
+
|
|
79
|
+
osm.relations.addRelations(
|
|
80
|
+
[{ id: 2, keys: [], vals: [], memids: [20], roles_sid: [0], types: [1] }],
|
|
81
|
+
new Uint32Array([0]),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(osm.relations.getWayMemberIds()).toEqual(new Set([10, 20]));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("starts with an empty cache after transfer and reconstruction", () => {
|
|
88
|
+
const source = createOsmWithRelations();
|
|
89
|
+
const reconstructed = new Osm(source);
|
|
90
|
+
const getByIndex = vi.spyOn(reconstructed.relations, "getByIndex");
|
|
91
|
+
|
|
92
|
+
const first = reconstructed.relations.getWayMemberIds();
|
|
93
|
+
const callsAfterFirstLookup = getByIndex.mock.calls.length;
|
|
94
|
+
const second = reconstructed.relations.getWayMemberIds();
|
|
95
|
+
|
|
96
|
+
expect(first).toEqual(new Set([10, 20]));
|
|
97
|
+
expect(second).toBe(first);
|
|
98
|
+
expect(callsAfterFirstLookup).toBeGreaterThan(0);
|
|
99
|
+
expect(getByIndex).toHaveBeenCalledTimes(callsAfterFirstLookup);
|
|
100
|
+
});
|
|
101
|
+
});
|
package/test/tags-search.test.ts
CHANGED
|
@@ -1,60 +1,80 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import type { OsmNode, OsmWay } from "@osmix/types";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { Nodes } from "../src/nodes";
|
|
5
|
+
import StringTable from "../src/stringtable";
|
|
6
|
+
import { Ways } from "../src/ways";
|
|
6
7
|
|
|
7
8
|
describe("Tags.search on Nodes", () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
9
|
+
it("returns null for an unknown ID in an empty collection", () => {
|
|
10
|
+
const nodes = new Nodes(new StringTable());
|
|
11
|
+
nodes.buildIndex();
|
|
12
|
+
|
|
13
|
+
expect(nodes.getNodeLonLat({ id: 999 })).toBeNull();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("finds by key and key+value", () => {
|
|
17
|
+
const st = new StringTable();
|
|
18
|
+
const nodes = new Nodes(st);
|
|
19
|
+
const node1: OsmNode = { id: 1, lon: -1, lat: 1, tags: { curb: "yes" } };
|
|
20
|
+
const node2: OsmNode = { id: 2, lon: -2, lat: 2, tags: { curb: "no" } };
|
|
21
|
+
const node3: OsmNode = { id: 3, lon: -3, lat: 3 };
|
|
22
|
+
nodes.addNode(node1);
|
|
23
|
+
nodes.addNode(node2);
|
|
24
|
+
nodes.addNode(node3);
|
|
25
|
+
nodes.buildIndex();
|
|
26
|
+
|
|
27
|
+
expect(nodes.getNodeLonLat({ id: 999 })).toBeNull();
|
|
28
|
+
|
|
29
|
+
const allCurb = nodes.search("curb");
|
|
30
|
+
expect(allCurb).toEqual([node1, node2]);
|
|
31
|
+
const curbYes = nodes.search("curb", "yes");
|
|
32
|
+
expect(curbYes).toEqual([node1]);
|
|
33
|
+
const curbNo = nodes.search("curb", "no");
|
|
34
|
+
expect(curbNo).toEqual([node2]);
|
|
35
|
+
const none = nodes.search("highway");
|
|
36
|
+
expect(none).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
29
39
|
|
|
30
40
|
describe("Tags.search on Ways", () => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
41
|
+
it("rejects block-local tag indexes missing from the string table map", () => {
|
|
42
|
+
const st = new StringTable();
|
|
43
|
+
const nodes = new Nodes(st);
|
|
44
|
+
const ways = new Ways(st, nodes);
|
|
45
|
+
|
|
46
|
+
expect(() =>
|
|
47
|
+
ways.addWays([{ id: 1, keys: [9], vals: [0], refs: [1] }], new Uint32Array()),
|
|
48
|
+
).toThrow("Tag key not found");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("finds by key and key+value", () => {
|
|
52
|
+
const st = new StringTable();
|
|
53
|
+
const nodes = new Nodes(st);
|
|
54
|
+
const ways = new Ways(st, nodes);
|
|
55
|
+
const way1: OsmWay = {
|
|
56
|
+
id: 10,
|
|
57
|
+
refs: [1, 2],
|
|
58
|
+
tags: { highway: "residential" },
|
|
59
|
+
};
|
|
60
|
+
const way2: OsmWay = { id: 11, refs: [2, 3], tags: { area: "yes" } };
|
|
61
|
+
const way3: OsmWay = {
|
|
62
|
+
id: 12,
|
|
63
|
+
refs: [3, 4],
|
|
64
|
+
tags: { highway: "primary", area: "no" },
|
|
65
|
+
};
|
|
66
|
+
ways.addWay(way1);
|
|
67
|
+
ways.addWay(way2);
|
|
68
|
+
ways.addWay(way3);
|
|
69
|
+
ways.buildIndex();
|
|
70
|
+
|
|
71
|
+
const allHighway = ways.search("highway");
|
|
72
|
+
expect(allHighway).toEqual([way1, way3]);
|
|
73
|
+
const areaYes = ways.search("area", "yes");
|
|
74
|
+
expect(areaYes).toEqual([way2]);
|
|
75
|
+
const areaAll = ways.search("area");
|
|
76
|
+
expect(areaAll).toEqual([way2, way3]);
|
|
77
|
+
const areaNo = ways.search("area", "no");
|
|
78
|
+
expect(areaNo).toEqual([way3]);
|
|
79
|
+
});
|
|
80
|
+
});
|