@minnowdb/core 0.6.9 → 0.7.1
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/block-format/block.js +254 -325
- package/dist/block-format/checksum.js +30 -52
- package/dist/block-format/codecs.js +112 -125
- package/dist/block-format/column.js +187 -205
- package/dist/block-format/index.js +5 -1
- package/dist/block-format/physical.js +371 -387
- package/dist/block-format/types.js +4 -1
- package/dist/block-format/unicode.js +30 -39
- package/dist/date-value.d.ts +5 -0
- package/dist/date-value.js +71 -41
- package/dist/engine/artifact-cache.js +106 -116
- package/dist/engine/batch.js +36 -44
- package/dist/engine/buffered-writer.js +156 -158
- package/dist/engine/byte-estimates.js +20 -22
- package/dist/engine/cache-limits.js +24 -25
- package/dist/engine/cancellation.js +5 -3
- package/dist/engine/catalog.js +64 -73
- package/dist/engine/client.js +715 -780
- package/dist/engine/database.js +15952 -18465
- package/dist/engine/defaults.js +104 -111
- package/dist/engine/errors.js +113 -128
- package/dist/engine/fts.js +233 -280
- package/dist/engine/group-index.js +287 -321
- package/dist/engine/index.js +23 -12
- package/dist/engine/join-index.js +177 -186
- package/dist/engine/keyed-live.js +168 -173
- package/dist/engine/live-api.js +0 -1
- package/dist/engine/live-equal.js +32 -37
- package/dist/engine/live.js +603 -647
- package/dist/engine/memory.js +109 -111
- package/dist/engine/optimizer.d.ts +19 -1
- package/dist/engine/optimizer.js +2642 -2515
- package/dist/engine/point-read.d.ts +4 -2
- package/dist/engine/point-read.js +121 -171
- package/dist/engine/query-api.js +12 -3
- package/dist/engine/query-cache.js +61 -69
- package/dist/engine/query.d.ts +45 -0
- package/dist/engine/query.js +8506 -9375
- package/dist/engine/result-wire.js +221 -252
- package/dist/engine/schema-wire.js +97 -112
- package/dist/engine/schema.js +1099 -1254
- package/dist/engine/sort-keys.js +315 -389
- package/dist/engine/sql-domains.d.ts +7 -1
- package/dist/engine/sql-domains.js +648 -734
- package/dist/engine/sql-driver.js +0 -1
- package/dist/engine/sql-functions.d.ts +11 -0
- package/dist/engine/sql-functions.js +1092 -0
- package/dist/engine/sql-json.js +199 -218
- package/dist/engine/sql-semantics.d.ts +25 -4
- package/dist/engine/sql-semantics.js +579 -513
- package/dist/engine/typed-live.js +271 -293
- package/dist/engine/vector.d.ts +7 -1
- package/dist/engine/vector.js +4513 -4580
- package/dist/engine/worker-host.d.ts +8 -63
- package/dist/engine/worker-host.js +28 -1130
- package/dist/engine/worker-indexeddb.d.ts +1 -0
- package/dist/engine/worker-indexeddb.js +3 -0
- package/dist/engine/worker-memory.d.ts +1 -0
- package/dist/engine/worker-memory.js +3 -0
- package/dist/engine/worker-opfs.d.ts +1 -0
- package/dist/engine/worker-opfs.js +3 -0
- package/dist/engine/worker-server.d.ts +93 -0
- package/dist/engine/worker-server.js +999 -0
- package/dist/engine/worker-store-indexeddb.d.ts +2 -0
- package/dist/engine/worker-store-indexeddb.js +11 -0
- package/dist/engine/worker-store-memory.d.ts +2 -0
- package/dist/engine/worker-store-memory.js +6 -0
- package/dist/engine/worker-store-opfs.d.ts +2 -0
- package/dist/engine/worker-store-opfs.js +9 -0
- package/dist/engine/worker.js +0 -12
- package/dist/engine/write-block-planner.js +93 -100
- package/dist/plan/index.js +15 -16
- package/dist/plan/model.d.ts +9 -1
- package/dist/plan/model.js +20 -27
- package/dist/storage/index.js +0 -12
- package/dist/storage/indexeddb.js +11776 -13171
- package/dist/storage/memory.js +1198 -1241
- package/dist/storage/opfs/files.js +238 -295
- package/dist/storage/opfs/index.js +9 -3
- package/dist/storage/opfs/leader.js +4386 -4856
- package/dist/storage/opfs/rpc.js +223 -259
- package/dist/storage/opfs/snapshot-ledger.js +219 -260
- package/dist/storage/opfs/store.js +884 -1003
- package/dist/storage/persistence.js +59 -74
- package/dist/storage/snapshot-stream.js +788 -826
- package/dist/storage/snapshot.js +36 -37
- package/dist/storage/toolkit/extents.js +444 -520
- package/dist/storage/toolkit/index.js +28 -29
- package/dist/storage/toolkit/record-core.js +5792 -6377
- package/dist/storage/toolkit/sync-file.js +34 -42
- package/dist/storage/toolkit/wal.js +92 -127
- package/dist/storage/toolkit/wire.js +232 -256
- package/dist/storage/types.js +2952 -3228
- package/dist/testing/block-store-conformance.js +1556 -1629
- package/dist/testing/index.js +310 -291
- package/dist/testing/opfs-shim.js +280 -312
- package/dist/testing/simulator.js +496 -534
- package/dist/testing/sqllogictest.js +425 -365
- package/dist/transactions/index.js +1464 -1712
- package/dist/worker-protocol/index.js +70 -69
- package/package.json +20 -2
- package/postgres-feature-profile.json +15 -5
- package/sql-feature-matrix.json +252 -2
package/dist/engine/sort-keys.js
CHANGED
|
@@ -1,421 +1,347 @@
|
|
|
1
1
|
import { dateMilliseconds } from "../date-value.js";
|
|
2
2
|
import { compareSqlStrings, compareSqlValues } from "./sql-semantics.js";
|
|
3
|
-
/** Unwraps a datetime to the number the comparisons use; every other value passes through. */
|
|
4
3
|
function comparableSortValue(value) {
|
|
5
|
-
|
|
4
|
+
return value instanceof Date ? dateMilliseconds(value) : value;
|
|
6
5
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*/
|
|
18
|
-
export function buildSortKeyColumn(count, valueAt) {
|
|
19
|
-
const numbers = new Float64Array(count);
|
|
20
|
-
const nulls = new Uint8Array(count);
|
|
21
|
-
let kind;
|
|
22
|
-
let ranks;
|
|
23
|
-
for (let index = 0; index < count; index += 1) {
|
|
24
|
-
const value = comparableSortValue(valueAt(index));
|
|
25
|
-
if (value === null || value === undefined) {
|
|
26
|
-
nulls[index] = 1;
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (typeof value === "number" && kind !== "boolean" && kind !== "string") {
|
|
30
|
-
kind = "number";
|
|
31
|
-
numbers[index] = value;
|
|
32
|
-
}
|
|
33
|
-
else if (typeof value === "boolean" && kind !== "number" && kind !== "string") {
|
|
34
|
-
kind = "boolean";
|
|
35
|
-
numbers[index] = value ? 1 : 0;
|
|
36
|
-
}
|
|
37
|
-
else if (typeof value === "string" &&
|
|
38
|
-
// NUL-prefixed strings are the engine's lossless internal SQL-domain values
|
|
39
|
-
// (NUMERIC, ENUM, COLLATE, and friends). Their physical encoding is deliberately
|
|
40
|
-
// stable, not lexicographically ordered, so ranking the encoded strings would make
|
|
41
|
-
// ORDER BY disagree with the SQL comparator. Keep those terms on the generic path.
|
|
42
|
-
value.charCodeAt(0) !== 0 &&
|
|
43
|
-
kind !== "number" &&
|
|
44
|
-
kind !== "boolean") {
|
|
45
|
-
kind = "string";
|
|
46
|
-
ranks ??= new Map();
|
|
47
|
-
let rank = ranks.get(value);
|
|
48
|
-
if (rank === undefined) {
|
|
49
|
-
rank = ranks.size;
|
|
50
|
-
ranks.set(value, rank);
|
|
51
|
-
}
|
|
52
|
-
numbers[index] = rank;
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
return buildGenericSortKeyColumn(count, valueAt);
|
|
56
|
-
}
|
|
6
|
+
function buildSortKeyColumn(count, valueAt) {
|
|
7
|
+
const numbers = new Float64Array(count);
|
|
8
|
+
const nulls = new Uint8Array(count);
|
|
9
|
+
let kind;
|
|
10
|
+
let ranks;
|
|
11
|
+
for (let index = 0; index < count; index += 1) {
|
|
12
|
+
const value = comparableSortValue(valueAt(index));
|
|
13
|
+
if (value === null || value === void 0) {
|
|
14
|
+
nulls[index] = 1;
|
|
15
|
+
continue;
|
|
57
16
|
}
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
17
|
+
if (typeof value === "number" && kind !== "boolean" && kind !== "string") {
|
|
18
|
+
kind = "number";
|
|
19
|
+
numbers[index] = value;
|
|
20
|
+
} else if (typeof value === "boolean" && kind !== "number" && kind !== "string") {
|
|
21
|
+
kind = "boolean";
|
|
22
|
+
numbers[index] = value ? 1 : 0;
|
|
23
|
+
} else if (typeof value === "string" && value.charCodeAt(0) !== 0 && kind !== "number" && kind !== "boolean") {
|
|
24
|
+
kind = "string";
|
|
25
|
+
ranks ??= /* @__PURE__ */ new Map();
|
|
26
|
+
let rank = ranks.get(value);
|
|
27
|
+
if (rank === void 0) {
|
|
28
|
+
rank = ranks.size;
|
|
29
|
+
ranks.set(value, rank);
|
|
30
|
+
}
|
|
31
|
+
numbers[index] = rank;
|
|
32
|
+
} else {
|
|
33
|
+
return buildGenericSortKeyColumn(count, valueAt);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (ranks !== void 0) {
|
|
37
|
+
const distinct = [...ranks.keys()].sort(compareSqlStrings);
|
|
38
|
+
const sortedRank = new Float64Array(distinct.length);
|
|
39
|
+
for (let position = 0; position < distinct.length; position += 1) {
|
|
40
|
+
sortedRank[ranks.get(distinct[position] ?? "") ?? 0] = position;
|
|
70
41
|
}
|
|
71
|
-
return {
|
|
72
|
-
compare: (left, right) => {
|
|
73
|
-
const leftNull = nulls[left] === 1;
|
|
74
|
-
const rightNull = nulls[right] === 1;
|
|
75
|
-
if (leftNull || rightNull)
|
|
76
|
-
return leftNull && rightNull ? 0 : leftNull ? -1 : 1;
|
|
77
|
-
const leftValue = numbers[left] ?? 0;
|
|
78
|
-
const rightValue = numbers[right] ?? 0;
|
|
79
|
-
if (leftValue === rightValue)
|
|
80
|
-
return 0;
|
|
81
|
-
// NaN sorts last, as compareSqlValues has it. The typed path has to say so outright,
|
|
82
|
-
// because a NaN comparison is false whichever way round it is asked.
|
|
83
|
-
if (Number.isNaN(leftValue))
|
|
84
|
-
return Number.isNaN(rightValue) ? 0 : 1;
|
|
85
|
-
if (Number.isNaN(rightValue))
|
|
86
|
-
return -1;
|
|
87
|
-
return leftValue < rightValue ? -1 : 1;
|
|
88
|
-
},
|
|
89
|
-
isNull: (index) => nulls[index] === 1,
|
|
90
|
-
numbers,
|
|
91
|
-
nulls,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
function buildGenericSortKeyColumn(count, valueAt) {
|
|
95
|
-
const values = new Array(count);
|
|
96
42
|
for (let index = 0; index < count; index += 1) {
|
|
97
|
-
|
|
43
|
+
if (nulls[index] === 0)
|
|
44
|
+
numbers[index] = sortedRank[numbers[index] ?? 0] ?? 0;
|
|
98
45
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
compare: (left, right) => {
|
|
49
|
+
const leftNull = nulls[left] === 1;
|
|
50
|
+
const rightNull = nulls[right] === 1;
|
|
51
|
+
if (leftNull || rightNull)
|
|
52
|
+
return leftNull && rightNull ? 0 : leftNull ? -1 : 1;
|
|
53
|
+
const leftValue = numbers[left] ?? 0;
|
|
54
|
+
const rightValue = numbers[right] ?? 0;
|
|
55
|
+
if (leftValue === rightValue)
|
|
56
|
+
return 0;
|
|
57
|
+
if (Number.isNaN(leftValue))
|
|
58
|
+
return Number.isNaN(rightValue) ? 0 : 1;
|
|
59
|
+
if (Number.isNaN(rightValue))
|
|
60
|
+
return -1;
|
|
61
|
+
return leftValue < rightValue ? -1 : 1;
|
|
62
|
+
},
|
|
63
|
+
isNull: (index) => nulls[index] === 1,
|
|
64
|
+
numbers,
|
|
65
|
+
nulls
|
|
66
|
+
};
|
|
108
67
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
68
|
+
function buildGenericSortKeyColumn(count, valueAt) {
|
|
69
|
+
const values = new Array(count);
|
|
70
|
+
for (let index = 0; index < count; index += 1) {
|
|
71
|
+
values[index] = comparableSortValue(valueAt(index));
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
compare: (left, right) => compareSqlValues(values[left], values[right]),
|
|
75
|
+
isNull: (index) => {
|
|
76
|
+
const value = values[index];
|
|
77
|
+
return value === null || value === void 0;
|
|
78
|
+
},
|
|
79
|
+
numbers: void 0,
|
|
80
|
+
nulls: void 0
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function sortKeyIndexes(count, terms) {
|
|
84
|
+
if (count > 4294967295)
|
|
85
|
+
throw new RangeError("Too many rows to order");
|
|
86
|
+
const indexes = new Uint32Array(count);
|
|
87
|
+
for (let index = 0; index < count; index += 1)
|
|
88
|
+
indexes[index] = index;
|
|
89
|
+
if (count < 2 || terms.length === 0)
|
|
131
90
|
return indexes;
|
|
91
|
+
const sorter = new KeySorter(count, terms);
|
|
92
|
+
sorter.sortRange(indexes, 0, count, 0);
|
|
93
|
+
return indexes;
|
|
132
94
|
}
|
|
133
|
-
/** Ranges at least this long radix-sort; shorter ones merge, where the constant factor wins. */
|
|
134
95
|
const RADIX_MIN_ROWS = 2048;
|
|
135
96
|
const RADIX_DIGIT_BITS = 11;
|
|
136
97
|
const RADIX_BUCKETS = 1 << RADIX_DIGIT_BITS;
|
|
137
|
-
/** Ranges at most this long insertion-sort, which is what a merge bottoms out in anyway. */
|
|
138
98
|
const INSERTION_MAX_ROWS = 16;
|
|
139
|
-
const UINT32_MAX =
|
|
99
|
+
const UINT32_MAX = 4294967295;
|
|
140
100
|
const LITTLE_ENDIAN = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
|
|
141
101
|
const HI = LITTLE_ENDIAN ? 1 : 0;
|
|
142
102
|
const LO = 1 - HI;
|
|
143
103
|
class KeySorter {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
this.sortRange(indexes, runStart, index, term + 1);
|
|
174
|
-
runStart = index;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
this.#sortEncoded(indexes, start, end, encoded, term);
|
|
180
|
-
if (term + 1 < this.#terms.length) {
|
|
181
|
-
let runStart = start;
|
|
182
|
-
let previous = indexes[start] ?? 0;
|
|
183
|
-
for (let index = start + 1; index <= end; index += 1) {
|
|
184
|
-
const current = indexes[index] ?? 0;
|
|
185
|
-
if (index < end &&
|
|
186
|
-
encoded[current * 2 + HI] === encoded[previous * 2 + HI] &&
|
|
187
|
-
encoded[current * 2 + LO] === encoded[previous * 2 + LO]) {
|
|
188
|
-
previous = current;
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
if (index - runStart > 1)
|
|
192
|
-
this.sortRange(indexes, runStart, index, term + 1);
|
|
193
|
-
runStart = index;
|
|
194
|
-
previous = current;
|
|
195
|
-
}
|
|
104
|
+
#count;
|
|
105
|
+
#terms;
|
|
106
|
+
#scratch;
|
|
107
|
+
#encoded;
|
|
108
|
+
#comparators;
|
|
109
|
+
#counts;
|
|
110
|
+
constructor(count, terms) {
|
|
111
|
+
this.#count = count;
|
|
112
|
+
this.#terms = terms;
|
|
113
|
+
this.#scratch = new Uint32Array(count);
|
|
114
|
+
this.#encoded = new Array(terms.length);
|
|
115
|
+
this.#comparators = new Array(terms.length);
|
|
116
|
+
}
|
|
117
|
+
sortRange(indexes, start, end, term) {
|
|
118
|
+
const spec = this.#terms[term];
|
|
119
|
+
if (spec === void 0 || end - start < 2)
|
|
120
|
+
return;
|
|
121
|
+
const encoded = this.#encodedKeys(term);
|
|
122
|
+
if (encoded === void 0) {
|
|
123
|
+
const compare = this.#comparator(term);
|
|
124
|
+
this.#mergeSort(indexes, start, end, compare);
|
|
125
|
+
if (term + 1 < this.#terms.length) {
|
|
126
|
+
let runStart = start;
|
|
127
|
+
for (let index = start + 1; index <= end; index += 1) {
|
|
128
|
+
if (index < end && compare(indexes[index - 1] ?? 0, indexes[index] ?? 0) === 0)
|
|
129
|
+
continue;
|
|
130
|
+
if (index - runStart > 1)
|
|
131
|
+
this.sortRange(indexes, runStart, index, term + 1);
|
|
132
|
+
runStart = index;
|
|
196
133
|
}
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
197
136
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
let orLo = 0;
|
|
208
|
-
let andLo = UINT32_MAX;
|
|
209
|
-
let orHi = 0;
|
|
210
|
-
let andHi = UINT32_MAX;
|
|
211
|
-
let ordered = true;
|
|
212
|
-
let previousLo = 0;
|
|
213
|
-
let previousHi = 0;
|
|
214
|
-
for (let index = start; index < end; index += 1) {
|
|
215
|
-
const row = (indexes[index] ?? 0) * 2;
|
|
216
|
-
const lo = encoded[row + LO] ?? 0;
|
|
217
|
-
const hi = encoded[row + HI] ?? 0;
|
|
218
|
-
orLo |= lo;
|
|
219
|
-
andLo &= lo;
|
|
220
|
-
orHi |= hi;
|
|
221
|
-
andHi &= hi;
|
|
222
|
-
if (ordered && index > start && (hi < previousHi || (hi === previousHi && lo < previousLo))) {
|
|
223
|
-
ordered = false;
|
|
224
|
-
}
|
|
225
|
-
previousLo = lo;
|
|
226
|
-
previousHi = hi;
|
|
137
|
+
this.#sortEncoded(indexes, start, end, encoded, term);
|
|
138
|
+
if (term + 1 < this.#terms.length) {
|
|
139
|
+
let runStart = start;
|
|
140
|
+
let previous = indexes[start] ?? 0;
|
|
141
|
+
for (let index = start + 1; index <= end; index += 1) {
|
|
142
|
+
const current = indexes[index] ?? 0;
|
|
143
|
+
if (index < end && encoded[current * 2 + HI] === encoded[previous * 2 + HI] && encoded[current * 2 + LO] === encoded[previous * 2 + LO]) {
|
|
144
|
+
previous = current;
|
|
145
|
+
continue;
|
|
227
146
|
}
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
147
|
+
if (index - runStart > 1)
|
|
148
|
+
this.sortRange(indexes, runStart, index, term + 1);
|
|
149
|
+
runStart = index;
|
|
150
|
+
previous = current;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
#sortEncoded(indexes, start, end, encoded, term) {
|
|
155
|
+
const length = end - start;
|
|
156
|
+
if (length < RADIX_MIN_ROWS) {
|
|
157
|
+
this.#mergeSort(indexes, start, end, this.#comparator(term));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
let orLo = 0;
|
|
161
|
+
let andLo = UINT32_MAX;
|
|
162
|
+
let orHi = 0;
|
|
163
|
+
let andHi = UINT32_MAX;
|
|
164
|
+
let ordered = true;
|
|
165
|
+
let previousLo = 0;
|
|
166
|
+
let previousHi = 0;
|
|
167
|
+
for (let index = start; index < end; index += 1) {
|
|
168
|
+
const row = (indexes[index] ?? 0) * 2;
|
|
169
|
+
const lo = encoded[row + LO] ?? 0;
|
|
170
|
+
const hi = encoded[row + HI] ?? 0;
|
|
171
|
+
orLo |= lo;
|
|
172
|
+
andLo &= lo;
|
|
173
|
+
orHi |= hi;
|
|
174
|
+
andHi &= hi;
|
|
175
|
+
if (ordered && index > start && (hi < previousHi || hi === previousHi && lo < previousLo)) {
|
|
176
|
+
ordered = false;
|
|
177
|
+
}
|
|
178
|
+
previousLo = lo;
|
|
179
|
+
previousHi = hi;
|
|
180
|
+
}
|
|
181
|
+
if (ordered)
|
|
182
|
+
return;
|
|
183
|
+
const varying = [(orLo ^ andLo) >>> 0, (orHi ^ andHi) >>> 0];
|
|
184
|
+
const counts = this.#counts ??= new Uint32Array(RADIX_BUCKETS);
|
|
185
|
+
let source = indexes;
|
|
186
|
+
let target = this.#scratch;
|
|
187
|
+
for (let pass = 0; pass < 6; pass += 1) {
|
|
188
|
+
const word = pass < 3 ? LO : HI;
|
|
189
|
+
const shift = pass % 3 * RADIX_DIGIT_BITS;
|
|
190
|
+
const mask = pass % 3 === 2 ? (1 << 32 - 2 * RADIX_DIGIT_BITS) - 1 : RADIX_BUCKETS - 1;
|
|
191
|
+
if (((varying[pass < 3 ? 0 : 1] ?? 0) & mask << shift) === 0)
|
|
192
|
+
continue;
|
|
193
|
+
counts.fill(0);
|
|
194
|
+
for (let index = start; index < end; index += 1) {
|
|
195
|
+
const digit = (encoded[(source[index] ?? 0) * 2 + word] ?? 0) >>> shift & mask;
|
|
196
|
+
counts[digit] = (counts[digit] ?? 0) + 1;
|
|
197
|
+
}
|
|
198
|
+
let offset = start;
|
|
199
|
+
for (let digit = 0; digit <= mask; digit += 1) {
|
|
200
|
+
const bucket = counts[digit] ?? 0;
|
|
201
|
+
counts[digit] = offset;
|
|
202
|
+
offset += bucket;
|
|
203
|
+
}
|
|
204
|
+
for (let index = start; index < end; index += 1) {
|
|
205
|
+
const row = source[index] ?? 0;
|
|
206
|
+
const digit = (encoded[row * 2 + word] ?? 0) >>> shift & mask;
|
|
207
|
+
const slot = counts[digit] ?? 0;
|
|
208
|
+
target[slot] = row;
|
|
209
|
+
counts[digit] = slot + 1;
|
|
210
|
+
}
|
|
211
|
+
const held = source;
|
|
212
|
+
source = target;
|
|
213
|
+
target = held;
|
|
214
|
+
}
|
|
215
|
+
if (source !== indexes)
|
|
216
|
+
indexes.set(source.subarray(start, end), start);
|
|
217
|
+
}
|
|
218
|
+
#mergeSort(indexes, start, end, compare) {
|
|
219
|
+
const length = end - start;
|
|
220
|
+
for (let blockStart = start; blockStart < end; blockStart += INSERTION_MAX_ROWS) {
|
|
221
|
+
const blockEnd = Math.min(blockStart + INSERTION_MAX_ROWS, end);
|
|
222
|
+
for (let index = blockStart + 1; index < blockEnd; index += 1) {
|
|
223
|
+
const row = indexes[index] ?? 0;
|
|
224
|
+
let position = index;
|
|
225
|
+
while (position > blockStart && compare(indexes[position - 1] ?? 0, row) > 0) {
|
|
226
|
+
indexes[position] = indexes[position - 1] ?? 0;
|
|
227
|
+
position -= 1;
|
|
261
228
|
}
|
|
262
|
-
|
|
263
|
-
|
|
229
|
+
indexes[position] = row;
|
|
230
|
+
}
|
|
264
231
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
while (position > blockStart && compare(indexes[position - 1] ?? 0, row) > 0) {
|
|
278
|
-
indexes[position] = indexes[position - 1] ?? 0;
|
|
279
|
-
position -= 1;
|
|
280
|
-
}
|
|
281
|
-
indexes[position] = row;
|
|
282
|
-
}
|
|
232
|
+
if (length <= INSERTION_MAX_ROWS)
|
|
233
|
+
return;
|
|
234
|
+
const scratch = this.#scratch;
|
|
235
|
+
let source = indexes;
|
|
236
|
+
let target = scratch;
|
|
237
|
+
for (let width = INSERTION_MAX_ROWS; width < length; width *= 2) {
|
|
238
|
+
for (let left = start; left < end; left += width * 2) {
|
|
239
|
+
const middle = Math.min(left + width, end);
|
|
240
|
+
const right = Math.min(left + width * 2, end);
|
|
241
|
+
if (middle >= right || compare(source[middle - 1] ?? 0, source[middle] ?? 0) <= 0) {
|
|
242
|
+
target.set(source.subarray(left, right), left);
|
|
243
|
+
continue;
|
|
283
244
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
target.set(source.subarray(left, right), left);
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
let leftIndex = left;
|
|
298
|
-
let rightIndex = middle;
|
|
299
|
-
for (let output = left; output < right; output += 1) {
|
|
300
|
-
if (rightIndex >= right ||
|
|
301
|
-
(leftIndex < middle && compare(source[leftIndex] ?? 0, source[rightIndex] ?? 0) <= 0)) {
|
|
302
|
-
target[output] = source[leftIndex] ?? 0;
|
|
303
|
-
leftIndex += 1;
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
target[output] = source[rightIndex] ?? 0;
|
|
307
|
-
rightIndex += 1;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
const held = source;
|
|
312
|
-
source = target;
|
|
313
|
-
target = held;
|
|
245
|
+
let leftIndex = left;
|
|
246
|
+
let rightIndex = middle;
|
|
247
|
+
for (let output = left; output < right; output += 1) {
|
|
248
|
+
if (rightIndex >= right || leftIndex < middle && compare(source[leftIndex] ?? 0, source[rightIndex] ?? 0) <= 0) {
|
|
249
|
+
target[output] = source[leftIndex] ?? 0;
|
|
250
|
+
leftIndex += 1;
|
|
251
|
+
} else {
|
|
252
|
+
target[output] = source[rightIndex] ?? 0;
|
|
253
|
+
rightIndex += 1;
|
|
254
|
+
}
|
|
314
255
|
}
|
|
315
|
-
|
|
316
|
-
|
|
256
|
+
}
|
|
257
|
+
const held = source;
|
|
258
|
+
source = target;
|
|
259
|
+
target = held;
|
|
317
260
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
const value = numbers[index] ?? 0;
|
|
362
|
-
if (value !== value) {
|
|
363
|
-
words[lo] = flip;
|
|
364
|
-
words[hi] = (0xfff80000 ^ flip) >>> 0;
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
// Adding +0 turns -0 into +0 and leaves every other value alone.
|
|
368
|
-
floats[index] = value + 0;
|
|
369
|
-
const rawHi = words[hi] ?? 0;
|
|
370
|
-
if ((rawHi & 0x80000000) !== 0) {
|
|
371
|
-
words[lo] = (~(words[lo] ?? 0) ^ flip) >>> 0;
|
|
372
|
-
words[hi] = (~rawHi ^ flip) >>> 0;
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
words[lo] = ((words[lo] ?? 0) ^ flip) >>> 0;
|
|
376
|
-
words[hi] = ((rawHi | 0x80000000) ^ flip) >>> 0;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
261
|
+
if (source !== indexes)
|
|
262
|
+
indexes.set(source.subarray(start, end), start);
|
|
263
|
+
}
|
|
264
|
+
#encodedKeys(term) {
|
|
265
|
+
const cached = this.#encoded[term];
|
|
266
|
+
if (cached !== void 0)
|
|
267
|
+
return cached;
|
|
268
|
+
const spec = this.#terms[term];
|
|
269
|
+
const numbers = spec?.column.numbers;
|
|
270
|
+
const nulls = spec?.column.nulls;
|
|
271
|
+
if (spec === void 0 || numbers === void 0 || nulls === void 0)
|
|
272
|
+
return void 0;
|
|
273
|
+
const count = this.#count;
|
|
274
|
+
const buffer = new ArrayBuffer(count * 8);
|
|
275
|
+
const floats = new Float64Array(buffer);
|
|
276
|
+
const words = new Uint32Array(buffer);
|
|
277
|
+
const nullsFirst = (spec.nulls ?? (spec.descending ? "first" : "last")) === "first";
|
|
278
|
+
const flip = spec.descending ? UINT32_MAX : 0;
|
|
279
|
+
const nullHi = spec.descending ? nullsFirst ? 524286 : UINT32_MAX : nullsFirst ? 0 : 4294443009;
|
|
280
|
+
const nullLo = spec.descending ? UINT32_MAX : 0;
|
|
281
|
+
for (let index = 0; index < count; index += 1) {
|
|
282
|
+
const lo = index * 2 + LO;
|
|
283
|
+
const hi = index * 2 + HI;
|
|
284
|
+
if (nulls[index] === 1) {
|
|
285
|
+
words[lo] = nullLo;
|
|
286
|
+
words[hi] = nullHi;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const value = numbers[index] ?? 0;
|
|
290
|
+
if (value !== value) {
|
|
291
|
+
words[lo] = flip;
|
|
292
|
+
words[hi] = (4294443008 ^ flip) >>> 0;
|
|
293
|
+
} else {
|
|
294
|
+
floats[index] = value + 0;
|
|
295
|
+
const rawHi = words[hi] ?? 0;
|
|
296
|
+
if ((rawHi & 2147483648) !== 0) {
|
|
297
|
+
words[lo] = (~(words[lo] ?? 0) ^ flip) >>> 0;
|
|
298
|
+
words[hi] = (~rawHi ^ flip) >>> 0;
|
|
299
|
+
} else {
|
|
300
|
+
words[lo] = ((words[lo] ?? 0) ^ flip) >>> 0;
|
|
301
|
+
words[hi] = ((rawHi | 2147483648) ^ flip) >>> 0;
|
|
379
302
|
}
|
|
380
|
-
|
|
381
|
-
return words;
|
|
303
|
+
}
|
|
382
304
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
const comparison = column.compare(left, right);
|
|
415
|
-
return descending ? -comparison : comparison;
|
|
416
|
-
};
|
|
305
|
+
this.#encoded[term] = words;
|
|
306
|
+
return words;
|
|
307
|
+
}
|
|
308
|
+
#comparator(term) {
|
|
309
|
+
const cached = this.#comparators[term];
|
|
310
|
+
if (cached !== void 0)
|
|
311
|
+
return cached;
|
|
312
|
+
const spec = this.#terms[term];
|
|
313
|
+
if (spec === void 0)
|
|
314
|
+
throw new Error("Order term is missing");
|
|
315
|
+
const encoded = this.#encodedKeys(term);
|
|
316
|
+
let compare;
|
|
317
|
+
if (encoded !== void 0) {
|
|
318
|
+
compare = (left, right) => {
|
|
319
|
+
const leftHi = encoded[left * 2 + HI] ?? 0;
|
|
320
|
+
const rightHi = encoded[right * 2 + HI] ?? 0;
|
|
321
|
+
if (leftHi !== rightHi)
|
|
322
|
+
return leftHi < rightHi ? -1 : 1;
|
|
323
|
+
const leftLo = encoded[left * 2 + LO] ?? 0;
|
|
324
|
+
const rightLo = encoded[right * 2 + LO] ?? 0;
|
|
325
|
+
return leftLo === rightLo ? 0 : leftLo < rightLo ? -1 : 1;
|
|
326
|
+
};
|
|
327
|
+
} else {
|
|
328
|
+
const { column, descending } = spec;
|
|
329
|
+
const nulls = spec.nulls ?? (spec.descending ? "first" : "last");
|
|
330
|
+
compare = (left, right) => {
|
|
331
|
+
const leftNull = column.isNull(left);
|
|
332
|
+
const rightNull = column.isNull(right);
|
|
333
|
+
if (leftNull || rightNull) {
|
|
334
|
+
return leftNull && rightNull ? 0 : (leftNull ? -1 : 1) * (nulls === "first" ? 1 : -1);
|
|
417
335
|
}
|
|
418
|
-
|
|
419
|
-
return
|
|
336
|
+
const comparison = column.compare(left, right);
|
|
337
|
+
return descending ? -comparison : comparison;
|
|
338
|
+
};
|
|
420
339
|
}
|
|
340
|
+
this.#comparators[term] = compare;
|
|
341
|
+
return compare;
|
|
342
|
+
}
|
|
421
343
|
}
|
|
344
|
+
export {
|
|
345
|
+
buildSortKeyColumn,
|
|
346
|
+
sortKeyIndexes
|
|
347
|
+
};
|