@peerbit/indexer-tests 3.0.4 → 3.0.6
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/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/tests.d.ts.map +1 -1
- package/dist/src/tests.js +207 -62
- package/dist/src/tests.js.map +1 -1
- package/dist/src/tie-parity.d.ts +3 -0
- package/dist/src/tie-parity.d.ts.map +1 -0
- package/dist/src/tie-parity.js +214 -0
- package/dist/src/tie-parity.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/tests.ts +267 -68
- package/src/tie-parity.ts +138 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { field, variant } from "@dao-xyz/borsh";
|
|
2
|
+
import {
|
|
3
|
+
type Indices,
|
|
4
|
+
Sort,
|
|
5
|
+
SortDirection,
|
|
6
|
+
getIdProperty,
|
|
7
|
+
id,
|
|
8
|
+
} from "@peerbit/indexer-interface";
|
|
9
|
+
import { expect } from "chai";
|
|
10
|
+
|
|
11
|
+
// Cross-backend SORT TIE-BREAK parity: @peerbit/indexer-simple (HashmapIndex) and
|
|
12
|
+
// @peerbit/indexer-sqlite3 must break ties on equal sort keys IDENTICALLY, in the
|
|
13
|
+
// document primary-key id's natural typed order:
|
|
14
|
+
// - string ids -> UTF-8 byte order (sqlite TEXT / BINARY collation)
|
|
15
|
+
// - integer ids -> NUMERIC order (sqlite INTEGER: 2 < 10, not "10" < "2")
|
|
16
|
+
// - Uint8Array ids -> raw-byte memcmp (sqlite BLOB: 0x00 < 0xff, not base64)
|
|
17
|
+
// and REVERSE that id order when the (single) sort field is DESC.
|
|
18
|
+
//
|
|
19
|
+
// Every document shares sortKey=1 so the whole result set is one tie group, which
|
|
20
|
+
// forces the id tie-break for every row. Simple historically ordered ties by
|
|
21
|
+
// INSERTION order (direction-independent), matching neither sqlite nor a stable
|
|
22
|
+
// content order; this suite locks simple == sqlite.
|
|
23
|
+
|
|
24
|
+
@variant("tie_str")
|
|
25
|
+
class StringIdDoc {
|
|
26
|
+
@id({ type: "string" })
|
|
27
|
+
id: string;
|
|
28
|
+
|
|
29
|
+
@field({ type: "u32" })
|
|
30
|
+
sortKey: number;
|
|
31
|
+
|
|
32
|
+
constructor(id: string) {
|
|
33
|
+
this.id = id;
|
|
34
|
+
this.sortKey = 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@variant("tie_bigint")
|
|
39
|
+
class BigIntIdDoc {
|
|
40
|
+
@id({ type: "u64" })
|
|
41
|
+
id: bigint;
|
|
42
|
+
|
|
43
|
+
@field({ type: "u32" })
|
|
44
|
+
sortKey: number;
|
|
45
|
+
|
|
46
|
+
constructor(id: bigint) {
|
|
47
|
+
this.id = id;
|
|
48
|
+
this.sortKey = 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@variant("tie_bytes")
|
|
53
|
+
class BytesIdDoc {
|
|
54
|
+
@id({ type: Uint8Array })
|
|
55
|
+
id: Uint8Array;
|
|
56
|
+
|
|
57
|
+
@field({ type: "u32" })
|
|
58
|
+
sortKey: number;
|
|
59
|
+
|
|
60
|
+
constructor(id: Uint8Array) {
|
|
61
|
+
this.id = id;
|
|
62
|
+
this.sortKey = 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const fmt = (value: string | number | bigint | Uint8Array): string =>
|
|
67
|
+
value instanceof Uint8Array
|
|
68
|
+
? Array.from(value)
|
|
69
|
+
.map((x) => x.toString(16).padStart(2, "0"))
|
|
70
|
+
.join("")
|
|
71
|
+
: String(value);
|
|
72
|
+
|
|
73
|
+
export const tieParityTests = (
|
|
74
|
+
createIndicies: (directory?: string) => Indices | Promise<Indices>,
|
|
75
|
+
) => {
|
|
76
|
+
return describe("sort tie-break parity", () => {
|
|
77
|
+
let indices: Indices | undefined;
|
|
78
|
+
|
|
79
|
+
afterEach(async () => {
|
|
80
|
+
await indices?.stop?.();
|
|
81
|
+
await indices?.drop?.();
|
|
82
|
+
indices = undefined;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const collect = async (schema: any, docs: any[]) => {
|
|
86
|
+
indices = await createIndicies();
|
|
87
|
+
await indices.start();
|
|
88
|
+
const store = await indices.init({
|
|
89
|
+
schema,
|
|
90
|
+
indexBy: getIdProperty(schema) || ["id"],
|
|
91
|
+
});
|
|
92
|
+
for (const doc of docs) {
|
|
93
|
+
await store.put(doc);
|
|
94
|
+
}
|
|
95
|
+
const order = async (direction: SortDirection) => {
|
|
96
|
+
const results = await store
|
|
97
|
+
.iterate({
|
|
98
|
+
query: [],
|
|
99
|
+
sort: [new Sort({ key: "sortKey", direction })],
|
|
100
|
+
})
|
|
101
|
+
.all();
|
|
102
|
+
return results.map((r) => fmt(r.value.id));
|
|
103
|
+
};
|
|
104
|
+
const asc = await order(SortDirection.ASC);
|
|
105
|
+
const desc = await order(SortDirection.DESC);
|
|
106
|
+
await store.stop?.();
|
|
107
|
+
await indices.stop?.();
|
|
108
|
+
await indices.drop?.();
|
|
109
|
+
indices = undefined;
|
|
110
|
+
return { asc, desc };
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
it("orders string-id ties by UTF-8 bytes, both directions", async () => {
|
|
114
|
+
const docs = ["c", "a", "b", "aa", "A", "Z"].map((s) => new StringIdDoc(s));
|
|
115
|
+
const { asc, desc } = await collect(StringIdDoc, docs);
|
|
116
|
+
// UTF-8 byte order: uppercase (A, Z) before lowercase (a, aa, b, c).
|
|
117
|
+
expect(asc).to.deep.equal(["A", "Z", "a", "aa", "b", "c"]);
|
|
118
|
+
expect(desc).to.deep.equal(["c", "b", "aa", "a", "Z", "A"]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("orders bigint-id ties numerically, both directions", async () => {
|
|
122
|
+
const docs = [10n, 2n, 21n, 9n, 100n, 300n].map((n) => new BigIntIdDoc(n));
|
|
123
|
+
const { asc, desc } = await collect(BigIntIdDoc, docs);
|
|
124
|
+
expect(asc).to.deep.equal(["2", "9", "10", "21", "100", "300"]);
|
|
125
|
+
expect(desc).to.deep.equal(["300", "100", "21", "10", "9", "2"]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("orders Uint8Array-id ties by raw bytes, both directions", async () => {
|
|
129
|
+
const docs = [[0xff], [0x00], [0x0a], [0x3e], [0xf8], [0xfb]].map(
|
|
130
|
+
(b) => new BytesIdDoc(new Uint8Array(b)),
|
|
131
|
+
);
|
|
132
|
+
const { asc, desc } = await collect(BytesIdDoc, docs);
|
|
133
|
+
// Raw-byte memcmp: 0x00 < 0x0a < 0x3e < 0xf8 < 0xfb < 0xff.
|
|
134
|
+
expect(asc).to.deep.equal(["00", "0a", "3e", "f8", "fb", "ff"]);
|
|
135
|
+
expect(desc).to.deep.equal(["ff", "fb", "f8", "3e", "0a", "00"]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
};
|