dataply 0.0.24-alpha.10 → 0.0.24-alpha.12
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/cjs/index.js +406 -206
- package/dist/types/utils/array.d.ts +7 -0
- package/package.json +3 -3
package/dist/cjs/index.js
CHANGED
|
@@ -126,39 +126,125 @@ var StringComparator = class extends ValueComparator {
|
|
|
126
126
|
var MVCCStrategy = class {
|
|
127
127
|
};
|
|
128
128
|
var LRUMap = class {
|
|
129
|
-
cache = /* @__PURE__ */ new Map();
|
|
130
129
|
capacity;
|
|
130
|
+
map;
|
|
131
|
+
head = null;
|
|
132
|
+
tail = null;
|
|
133
|
+
/**
|
|
134
|
+
* Creates an instance of LRUMap.
|
|
135
|
+
* @param capacity The maximum number of items the cache can hold.
|
|
136
|
+
*/
|
|
131
137
|
constructor(capacity) {
|
|
132
138
|
this.capacity = capacity;
|
|
139
|
+
this.map = /* @__PURE__ */ new Map();
|
|
133
140
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
143
|
+
* @param node The node to promote.
|
|
144
|
+
*/
|
|
145
|
+
promote(node) {
|
|
146
|
+
this.extract(node);
|
|
147
|
+
this.prepend(node);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Disconnects a node from the doubly linked list.
|
|
151
|
+
* @param node The node to extract.
|
|
152
|
+
*/
|
|
153
|
+
extract(node) {
|
|
154
|
+
if (node.prev) node.prev.next = node.next;
|
|
155
|
+
else this.head = node.next;
|
|
156
|
+
if (node.next) node.next.prev = node.prev;
|
|
157
|
+
else this.tail = node.prev;
|
|
158
|
+
node.prev = null;
|
|
159
|
+
node.next = null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Inserts a node at the head of the doubly linked list.
|
|
163
|
+
* @param node The node to prepend.
|
|
164
|
+
*/
|
|
165
|
+
prepend(node) {
|
|
166
|
+
node.next = this.head;
|
|
167
|
+
if (this.head) this.head.prev = node;
|
|
168
|
+
this.head = node;
|
|
169
|
+
if (!this.tail) this.tail = node;
|
|
140
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Stores or updates a value by key.
|
|
173
|
+
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
174
|
+
* @param key The key to store.
|
|
175
|
+
* @param value The value to store.
|
|
176
|
+
*/
|
|
141
177
|
set(key, value) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
178
|
+
const existing = this.map.get(key);
|
|
179
|
+
if (existing) {
|
|
180
|
+
existing.value = value;
|
|
181
|
+
this.promote(existing);
|
|
182
|
+
return;
|
|
147
183
|
}
|
|
148
|
-
|
|
149
|
-
|
|
184
|
+
const newNode = { key, value, prev: null, next: null };
|
|
185
|
+
this.map.set(key, newNode);
|
|
186
|
+
this.prepend(newNode);
|
|
187
|
+
if (this.map.size > this.capacity && this.tail) {
|
|
188
|
+
this.map.delete(this.tail.key);
|
|
189
|
+
this.extract(this.tail);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Retrieves a value by key.
|
|
194
|
+
* Accessing the item moves it to the "most recently used" position.
|
|
195
|
+
* @param key The key to look for.
|
|
196
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
197
|
+
*/
|
|
198
|
+
get(key) {
|
|
199
|
+
const node = this.map.get(key);
|
|
200
|
+
if (!node) return void 0;
|
|
201
|
+
this.promote(node);
|
|
202
|
+
return node.value;
|
|
150
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Checks if a key exists in the cache without changing its access order.
|
|
206
|
+
* @param key The key to check.
|
|
207
|
+
* @returns True if the key exists, false otherwise.
|
|
208
|
+
*/
|
|
151
209
|
has(key) {
|
|
152
|
-
return this.
|
|
210
|
+
return this.map.has(key);
|
|
153
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Removes a key and its associated value from the cache.
|
|
214
|
+
* @param key The key to remove.
|
|
215
|
+
* @returns True if the key was found and removed, false otherwise.
|
|
216
|
+
*/
|
|
154
217
|
delete(key) {
|
|
155
|
-
|
|
218
|
+
const node = this.map.get(key);
|
|
219
|
+
if (!node) return false;
|
|
220
|
+
this.extract(node);
|
|
221
|
+
this.map.delete(key);
|
|
222
|
+
return true;
|
|
156
223
|
}
|
|
157
|
-
|
|
158
|
-
|
|
224
|
+
/**
|
|
225
|
+
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
226
|
+
* @returns An iterable iterator of keys.
|
|
227
|
+
*/
|
|
228
|
+
*keys() {
|
|
229
|
+
let current = this.head;
|
|
230
|
+
while (current) {
|
|
231
|
+
yield current.key;
|
|
232
|
+
current = current.next;
|
|
233
|
+
}
|
|
159
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Returns the current number of items in the cache.
|
|
237
|
+
*/
|
|
160
238
|
get size() {
|
|
161
|
-
return this.
|
|
239
|
+
return this.map.size;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Clears all items from the cache.
|
|
243
|
+
*/
|
|
244
|
+
clear() {
|
|
245
|
+
this.map.clear();
|
|
246
|
+
this.head = null;
|
|
247
|
+
this.tail = null;
|
|
162
248
|
}
|
|
163
249
|
};
|
|
164
250
|
var MVCCTransaction = class {
|
|
@@ -1552,7 +1638,7 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1552
1638
|
searchConfigs = {
|
|
1553
1639
|
gt: {
|
|
1554
1640
|
asc: {
|
|
1555
|
-
start: (tx, v) => tx.
|
|
1641
|
+
start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
|
|
1556
1642
|
end: () => null,
|
|
1557
1643
|
direction: 1,
|
|
1558
1644
|
earlyTerminate: false
|
|
@@ -1650,7 +1736,7 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1650
1736
|
},
|
|
1651
1737
|
primaryGt: {
|
|
1652
1738
|
asc: {
|
|
1653
|
-
start: (tx, v) => tx.
|
|
1739
|
+
start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
|
|
1654
1740
|
end: () => null,
|
|
1655
1741
|
direction: 1,
|
|
1656
1742
|
earlyTerminate: false
|
|
@@ -1712,7 +1798,7 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1712
1798
|
earlyTerminate: true
|
|
1713
1799
|
},
|
|
1714
1800
|
desc: {
|
|
1715
|
-
start: (tx, v) => tx.
|
|
1801
|
+
start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
|
|
1716
1802
|
end: (tx, v) => tx.insertableEndNode(v[0], -1),
|
|
1717
1803
|
direction: -1,
|
|
1718
1804
|
earlyTerminate: true
|
|
@@ -1740,7 +1826,7 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1740
1826
|
earlyTerminate: false
|
|
1741
1827
|
},
|
|
1742
1828
|
desc: {
|
|
1743
|
-
start: (tx, v) => tx.
|
|
1829
|
+
start: (tx, v) => tx.insertableRightestNodeByPrimary(tx.highestPrimaryValue(v)),
|
|
1744
1830
|
end: (tx, v) => tx.insertableEndNode(tx.lowestPrimaryValue(v), -1),
|
|
1745
1831
|
direction: -1,
|
|
1746
1832
|
earlyTerminate: false
|
|
@@ -1897,30 +1983,62 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1897
1983
|
return JSON.parse(JSON.stringify(node));
|
|
1898
1984
|
}
|
|
1899
1985
|
/**
|
|
1900
|
-
*
|
|
1901
|
-
*
|
|
1902
|
-
*
|
|
1986
|
+
* Resolves the best start/end configuration by independently examining
|
|
1987
|
+
* all conditions. Selects the tightest lower bound for start and the
|
|
1988
|
+
* tightest upper bound for end (in asc; reversed for desc).
|
|
1989
|
+
*
|
|
1903
1990
|
* @param condition The condition to analyze.
|
|
1904
|
-
* @
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1991
|
+
* @param order The sort order ('asc' or 'desc').
|
|
1992
|
+
* @returns The resolved start/end keys, values, and traversal direction.
|
|
1993
|
+
*/
|
|
1994
|
+
resolveStartEndConfigs(condition, order) {
|
|
1995
|
+
const direction = order === "asc" ? 1 : -1;
|
|
1996
|
+
const startCandidates = order === "asc" ? _BPTreeTransaction._lowerBoundKeys : _BPTreeTransaction._upperBoundKeys;
|
|
1997
|
+
const endCandidates = order === "asc" ? _BPTreeTransaction._upperBoundKeys : _BPTreeTransaction._lowerBoundKeys;
|
|
1998
|
+
let startKey = null;
|
|
1999
|
+
let endKey = null;
|
|
2000
|
+
let startValues = [];
|
|
2001
|
+
let endValues = [];
|
|
2002
|
+
for (const key of startCandidates) {
|
|
2003
|
+
if (key in condition) {
|
|
2004
|
+
startKey = key;
|
|
2005
|
+
startValues = this.ensureValues(condition[key]);
|
|
2006
|
+
break;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
for (const key of endCandidates) {
|
|
2010
|
+
if (key in condition) {
|
|
2011
|
+
endKey = key;
|
|
2012
|
+
endValues = this.ensureValues(condition[key]);
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
return { startKey, endKey, startValues, endValues, direction };
|
|
2017
|
+
}
|
|
2018
|
+
// Lower bound providers, ordered by selectivity (tightest first)
|
|
2019
|
+
// Used for asc start / desc end
|
|
2020
|
+
static _lowerBoundKeys = [
|
|
2021
|
+
"primaryEqual",
|
|
2022
|
+
"equal",
|
|
2023
|
+
"primaryGt",
|
|
2024
|
+
"gt",
|
|
2025
|
+
"primaryGte",
|
|
2026
|
+
"gte",
|
|
2027
|
+
"primaryOr",
|
|
2028
|
+
"or"
|
|
2029
|
+
];
|
|
2030
|
+
// Upper bound providers, ordered by selectivity (tightest first)
|
|
2031
|
+
// Used for asc end / desc start
|
|
2032
|
+
static _upperBoundKeys = [
|
|
2033
|
+
"primaryEqual",
|
|
2034
|
+
"equal",
|
|
2035
|
+
"primaryLt",
|
|
2036
|
+
"lt",
|
|
2037
|
+
"primaryLte",
|
|
2038
|
+
"lte",
|
|
2039
|
+
"primaryOr",
|
|
2040
|
+
"or"
|
|
2041
|
+
];
|
|
1924
2042
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
1925
2043
|
this.rootTx = rootTx === null ? this : rootTx;
|
|
1926
2044
|
this.mvccRoot = mvccRoot;
|
|
@@ -2226,13 +2344,10 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2226
2344
|
}
|
|
2227
2345
|
return node;
|
|
2228
2346
|
}
|
|
2229
|
-
*getPairsGenerator(
|
|
2347
|
+
*getPairsGenerator(startNode, endNode, direction) {
|
|
2230
2348
|
let node = startNode;
|
|
2231
|
-
|
|
2232
|
-
let hasMatched = false;
|
|
2233
|
-
while (!done) {
|
|
2349
|
+
while (true) {
|
|
2234
2350
|
if (endNode && node.id === endNode.id) {
|
|
2235
|
-
done = true;
|
|
2236
2351
|
break;
|
|
2237
2352
|
}
|
|
2238
2353
|
const len = node.values.length;
|
|
@@ -2240,14 +2355,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2240
2355
|
for (let i = 0; i < len; i++) {
|
|
2241
2356
|
const nValue = node.values[i];
|
|
2242
2357
|
const keys = node.keys[i];
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
for (let j = 0; j < keys.length; j++) {
|
|
2246
|
-
yield [keys[j], nValue];
|
|
2247
|
-
}
|
|
2248
|
-
} else if (earlyTerminate && hasMatched) {
|
|
2249
|
-
done = true;
|
|
2250
|
-
break;
|
|
2358
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
2359
|
+
yield [keys[j], nValue];
|
|
2251
2360
|
}
|
|
2252
2361
|
}
|
|
2253
2362
|
} else {
|
|
@@ -2255,30 +2364,17 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2255
2364
|
while (i--) {
|
|
2256
2365
|
const nValue = node.values[i];
|
|
2257
2366
|
const keys = node.keys[i];
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
while (j--) {
|
|
2262
|
-
yield [keys[j], nValue];
|
|
2263
|
-
}
|
|
2264
|
-
} else if (earlyTerminate && hasMatched) {
|
|
2265
|
-
done = true;
|
|
2266
|
-
break;
|
|
2367
|
+
let j = keys.length;
|
|
2368
|
+
while (j--) {
|
|
2369
|
+
yield [keys[j], nValue];
|
|
2267
2370
|
}
|
|
2268
2371
|
}
|
|
2269
2372
|
}
|
|
2270
|
-
if (done) break;
|
|
2271
2373
|
if (direction === 1) {
|
|
2272
|
-
if (!node.next)
|
|
2273
|
-
done = true;
|
|
2274
|
-
break;
|
|
2275
|
-
}
|
|
2374
|
+
if (!node.next) break;
|
|
2276
2375
|
node = this.getNode(node.next);
|
|
2277
2376
|
} else {
|
|
2278
|
-
if (!node.prev)
|
|
2279
|
-
done = true;
|
|
2280
|
-
break;
|
|
2281
|
-
}
|
|
2377
|
+
if (!node.prev) break;
|
|
2282
2378
|
node = this.getNode(node.prev);
|
|
2283
2379
|
}
|
|
2284
2380
|
}
|
|
@@ -2367,49 +2463,36 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2367
2463
|
}
|
|
2368
2464
|
*whereStream(condition, options) {
|
|
2369
2465
|
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2370
|
-
const
|
|
2371
|
-
if (
|
|
2372
|
-
const
|
|
2373
|
-
const
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
if (
|
|
2383
|
-
|
|
2466
|
+
const conditionKeys = Object.keys(condition);
|
|
2467
|
+
if (conditionKeys.length === 0) return;
|
|
2468
|
+
const resolved = this.resolveStartEndConfigs(condition, order);
|
|
2469
|
+
const direction = resolved.direction;
|
|
2470
|
+
let startNode;
|
|
2471
|
+
if (resolved.startKey) {
|
|
2472
|
+
const startConfig = this.searchConfigs[resolved.startKey][order];
|
|
2473
|
+
startNode = startConfig.start(this, resolved.startValues);
|
|
2474
|
+
} else {
|
|
2475
|
+
startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
|
|
2476
|
+
}
|
|
2477
|
+
let endNode = null;
|
|
2478
|
+
if (resolved.endKey) {
|
|
2479
|
+
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
2480
|
+
endNode = endConfig.end(this, resolved.endValues);
|
|
2384
2481
|
}
|
|
2385
2482
|
if (!startNode) return;
|
|
2386
|
-
const comparator = this.verifierMap[driverKey];
|
|
2387
2483
|
const generator = this.getPairsGenerator(
|
|
2388
|
-
value,
|
|
2389
2484
|
startNode,
|
|
2390
2485
|
endNode,
|
|
2391
|
-
|
|
2392
|
-
direction,
|
|
2393
|
-
earlyTerminate
|
|
2486
|
+
direction
|
|
2394
2487
|
);
|
|
2395
2488
|
let count = 0;
|
|
2396
2489
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2397
2490
|
for (const pair of generator) {
|
|
2398
|
-
const [k,
|
|
2491
|
+
const [k, v] = pair;
|
|
2399
2492
|
if (intersection && !intersection.has(k)) {
|
|
2400
2493
|
continue;
|
|
2401
2494
|
}
|
|
2402
|
-
|
|
2403
|
-
for (const key in condition) {
|
|
2404
|
-
if (key === driverKey) continue;
|
|
2405
|
-
const verify = this.verifierMap[key];
|
|
2406
|
-
const condValue = condition[key];
|
|
2407
|
-
if (!verify(v2, condValue)) {
|
|
2408
|
-
isMatch = false;
|
|
2409
|
-
break;
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
if (isMatch) {
|
|
2495
|
+
if (this.verify(v, condition)) {
|
|
2413
2496
|
yield pair;
|
|
2414
2497
|
count++;
|
|
2415
2498
|
if (limit !== void 0 && count >= limit) {
|
|
@@ -3354,22 +3437,19 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3354
3437
|
}
|
|
3355
3438
|
return node;
|
|
3356
3439
|
}
|
|
3357
|
-
async *getPairsGenerator(
|
|
3440
|
+
async *getPairsGenerator(startNode, endNode, direction) {
|
|
3358
3441
|
let node = startNode;
|
|
3359
|
-
let done = false;
|
|
3360
|
-
let hasMatched = false;
|
|
3361
3442
|
let nextNodePromise = null;
|
|
3362
|
-
while (
|
|
3443
|
+
while (true) {
|
|
3363
3444
|
if (endNode && node.id === endNode.id) {
|
|
3364
|
-
done = true;
|
|
3365
3445
|
break;
|
|
3366
3446
|
}
|
|
3367
3447
|
if (direction === 1) {
|
|
3368
|
-
if (node.next
|
|
3448
|
+
if (node.next) {
|
|
3369
3449
|
nextNodePromise = this.getNode(node.next);
|
|
3370
3450
|
}
|
|
3371
3451
|
} else {
|
|
3372
|
-
if (node.prev
|
|
3452
|
+
if (node.prev) {
|
|
3373
3453
|
nextNodePromise = this.getNode(node.prev);
|
|
3374
3454
|
}
|
|
3375
3455
|
}
|
|
@@ -3378,14 +3458,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3378
3458
|
for (let i = 0; i < len; i++) {
|
|
3379
3459
|
const nValue = node.values[i];
|
|
3380
3460
|
const keys = node.keys[i];
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
for (let j = 0; j < keys.length; j++) {
|
|
3384
|
-
yield [keys[j], nValue];
|
|
3385
|
-
}
|
|
3386
|
-
} else if (earlyTerminate && hasMatched) {
|
|
3387
|
-
done = true;
|
|
3388
|
-
break;
|
|
3461
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
3462
|
+
yield [keys[j], nValue];
|
|
3389
3463
|
}
|
|
3390
3464
|
}
|
|
3391
3465
|
} else {
|
|
@@ -3393,27 +3467,17 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3393
3467
|
while (i--) {
|
|
3394
3468
|
const nValue = node.values[i];
|
|
3395
3469
|
const keys = node.keys[i];
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
while (j--) {
|
|
3400
|
-
yield [keys[j], nValue];
|
|
3401
|
-
}
|
|
3402
|
-
} else if (earlyTerminate && hasMatched) {
|
|
3403
|
-
done = true;
|
|
3404
|
-
break;
|
|
3470
|
+
let j = keys.length;
|
|
3471
|
+
while (j--) {
|
|
3472
|
+
yield [keys[j], nValue];
|
|
3405
3473
|
}
|
|
3406
3474
|
}
|
|
3407
3475
|
}
|
|
3408
|
-
if (done) {
|
|
3409
|
-
if (nextNodePromise) await nextNodePromise;
|
|
3410
|
-
break;
|
|
3411
|
-
}
|
|
3412
3476
|
if (nextNodePromise) {
|
|
3413
3477
|
node = await nextNodePromise;
|
|
3414
3478
|
nextNodePromise = null;
|
|
3415
3479
|
} else {
|
|
3416
|
-
|
|
3480
|
+
break;
|
|
3417
3481
|
}
|
|
3418
3482
|
}
|
|
3419
3483
|
}
|
|
@@ -3501,49 +3565,36 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3501
3565
|
}
|
|
3502
3566
|
async *whereStream(condition, options) {
|
|
3503
3567
|
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
3504
|
-
const
|
|
3505
|
-
if (
|
|
3506
|
-
const
|
|
3507
|
-
const
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
if (
|
|
3517
|
-
|
|
3568
|
+
const conditionKeys = Object.keys(condition);
|
|
3569
|
+
if (conditionKeys.length === 0) return;
|
|
3570
|
+
const resolved = this.resolveStartEndConfigs(condition, order);
|
|
3571
|
+
const direction = resolved.direction;
|
|
3572
|
+
let startNode;
|
|
3573
|
+
if (resolved.startKey) {
|
|
3574
|
+
const startConfig = this.searchConfigs[resolved.startKey][order];
|
|
3575
|
+
startNode = await startConfig.start(this, resolved.startValues);
|
|
3576
|
+
} else {
|
|
3577
|
+
startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
|
|
3578
|
+
}
|
|
3579
|
+
let endNode = null;
|
|
3580
|
+
if (resolved.endKey) {
|
|
3581
|
+
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
3582
|
+
endNode = await endConfig.end(this, resolved.endValues);
|
|
3518
3583
|
}
|
|
3519
3584
|
if (!startNode) return;
|
|
3520
|
-
const comparator = this.verifierMap[driverKey];
|
|
3521
3585
|
const generator = this.getPairsGenerator(
|
|
3522
|
-
value,
|
|
3523
3586
|
startNode,
|
|
3524
3587
|
endNode,
|
|
3525
|
-
|
|
3526
|
-
direction,
|
|
3527
|
-
earlyTerminate
|
|
3588
|
+
direction
|
|
3528
3589
|
);
|
|
3529
3590
|
let count = 0;
|
|
3530
3591
|
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3531
3592
|
for await (const pair of generator) {
|
|
3532
|
-
const [k,
|
|
3593
|
+
const [k, v] = pair;
|
|
3533
3594
|
if (intersection && !intersection.has(k)) {
|
|
3534
3595
|
continue;
|
|
3535
3596
|
}
|
|
3536
|
-
|
|
3537
|
-
for (const key in condition) {
|
|
3538
|
-
if (key === driverKey) continue;
|
|
3539
|
-
const verify = this.verifierMap[key];
|
|
3540
|
-
const condValue = condition[key];
|
|
3541
|
-
if (!verify(v2, condValue)) {
|
|
3542
|
-
isMatch = false;
|
|
3543
|
-
break;
|
|
3544
|
-
}
|
|
3545
|
-
}
|
|
3546
|
-
if (isMatch) {
|
|
3597
|
+
if (this.verify(v, condition)) {
|
|
3547
3598
|
yield pair;
|
|
3548
3599
|
count++;
|
|
3549
3600
|
if (limit !== void 0 && count >= limit) {
|
|
@@ -4844,39 +4895,125 @@ var InvertedWeakMap = class {
|
|
|
4844
4895
|
var MVCCStrategy2 = class {
|
|
4845
4896
|
};
|
|
4846
4897
|
var LRUMap3 = class {
|
|
4847
|
-
cache = /* @__PURE__ */ new Map();
|
|
4848
4898
|
capacity;
|
|
4899
|
+
map;
|
|
4900
|
+
head = null;
|
|
4901
|
+
tail = null;
|
|
4902
|
+
/**
|
|
4903
|
+
* Creates an instance of LRUMap.
|
|
4904
|
+
* @param capacity The maximum number of items the cache can hold.
|
|
4905
|
+
*/
|
|
4849
4906
|
constructor(capacity) {
|
|
4850
4907
|
this.capacity = capacity;
|
|
4908
|
+
this.map = /* @__PURE__ */ new Map();
|
|
4851
4909
|
}
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4910
|
+
/**
|
|
4911
|
+
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
4912
|
+
* @param node The node to promote.
|
|
4913
|
+
*/
|
|
4914
|
+
promote(node) {
|
|
4915
|
+
this.extract(node);
|
|
4916
|
+
this.prepend(node);
|
|
4858
4917
|
}
|
|
4918
|
+
/**
|
|
4919
|
+
* Disconnects a node from the doubly linked list.
|
|
4920
|
+
* @param node The node to extract.
|
|
4921
|
+
*/
|
|
4922
|
+
extract(node) {
|
|
4923
|
+
if (node.prev) node.prev.next = node.next;
|
|
4924
|
+
else this.head = node.next;
|
|
4925
|
+
if (node.next) node.next.prev = node.prev;
|
|
4926
|
+
else this.tail = node.prev;
|
|
4927
|
+
node.prev = null;
|
|
4928
|
+
node.next = null;
|
|
4929
|
+
}
|
|
4930
|
+
/**
|
|
4931
|
+
* Inserts a node at the head of the doubly linked list.
|
|
4932
|
+
* @param node The node to prepend.
|
|
4933
|
+
*/
|
|
4934
|
+
prepend(node) {
|
|
4935
|
+
node.next = this.head;
|
|
4936
|
+
if (this.head) this.head.prev = node;
|
|
4937
|
+
this.head = node;
|
|
4938
|
+
if (!this.tail) this.tail = node;
|
|
4939
|
+
}
|
|
4940
|
+
/**
|
|
4941
|
+
* Stores or updates a value by key.
|
|
4942
|
+
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
4943
|
+
* @param key The key to store.
|
|
4944
|
+
* @param value The value to store.
|
|
4945
|
+
*/
|
|
4859
4946
|
set(key, value) {
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4947
|
+
const existing = this.map.get(key);
|
|
4948
|
+
if (existing) {
|
|
4949
|
+
existing.value = value;
|
|
4950
|
+
this.promote(existing);
|
|
4951
|
+
return;
|
|
4865
4952
|
}
|
|
4866
|
-
|
|
4867
|
-
|
|
4953
|
+
const newNode = { key, value, prev: null, next: null };
|
|
4954
|
+
this.map.set(key, newNode);
|
|
4955
|
+
this.prepend(newNode);
|
|
4956
|
+
if (this.map.size > this.capacity && this.tail) {
|
|
4957
|
+
this.map.delete(this.tail.key);
|
|
4958
|
+
this.extract(this.tail);
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4961
|
+
/**
|
|
4962
|
+
* Retrieves a value by key.
|
|
4963
|
+
* Accessing the item moves it to the "most recently used" position.
|
|
4964
|
+
* @param key The key to look for.
|
|
4965
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
4966
|
+
*/
|
|
4967
|
+
get(key) {
|
|
4968
|
+
const node = this.map.get(key);
|
|
4969
|
+
if (!node) return void 0;
|
|
4970
|
+
this.promote(node);
|
|
4971
|
+
return node.value;
|
|
4868
4972
|
}
|
|
4973
|
+
/**
|
|
4974
|
+
* Checks if a key exists in the cache without changing its access order.
|
|
4975
|
+
* @param key The key to check.
|
|
4976
|
+
* @returns True if the key exists, false otherwise.
|
|
4977
|
+
*/
|
|
4869
4978
|
has(key) {
|
|
4870
|
-
return this.
|
|
4979
|
+
return this.map.has(key);
|
|
4871
4980
|
}
|
|
4981
|
+
/**
|
|
4982
|
+
* Removes a key and its associated value from the cache.
|
|
4983
|
+
* @param key The key to remove.
|
|
4984
|
+
* @returns True if the key was found and removed, false otherwise.
|
|
4985
|
+
*/
|
|
4872
4986
|
delete(key) {
|
|
4873
|
-
|
|
4987
|
+
const node = this.map.get(key);
|
|
4988
|
+
if (!node) return false;
|
|
4989
|
+
this.extract(node);
|
|
4990
|
+
this.map.delete(key);
|
|
4991
|
+
return true;
|
|
4874
4992
|
}
|
|
4875
|
-
|
|
4876
|
-
|
|
4993
|
+
/**
|
|
4994
|
+
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
4995
|
+
* @returns An iterable iterator of keys.
|
|
4996
|
+
*/
|
|
4997
|
+
*keys() {
|
|
4998
|
+
let current = this.head;
|
|
4999
|
+
while (current) {
|
|
5000
|
+
yield current.key;
|
|
5001
|
+
current = current.next;
|
|
5002
|
+
}
|
|
4877
5003
|
}
|
|
5004
|
+
/**
|
|
5005
|
+
* Returns the current number of items in the cache.
|
|
5006
|
+
*/
|
|
4878
5007
|
get size() {
|
|
4879
|
-
return this.
|
|
5008
|
+
return this.map.size;
|
|
5009
|
+
}
|
|
5010
|
+
/**
|
|
5011
|
+
* Clears all items from the cache.
|
|
5012
|
+
*/
|
|
5013
|
+
clear() {
|
|
5014
|
+
this.map.clear();
|
|
5015
|
+
this.head = null;
|
|
5016
|
+
this.tail = null;
|
|
4880
5017
|
}
|
|
4881
5018
|
};
|
|
4882
5019
|
var MVCCTransaction2 = class {
|
|
@@ -6333,21 +6470,68 @@ function crc32(buf) {
|
|
|
6333
6470
|
}
|
|
6334
6471
|
|
|
6335
6472
|
// src/utils/array.ts
|
|
6336
|
-
function
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6473
|
+
function calcThreshold(sortedGaps, n) {
|
|
6474
|
+
const gLen = sortedGaps.length;
|
|
6475
|
+
if (gLen === 0) return 0;
|
|
6476
|
+
const median = sortedGaps[Math.floor(gLen * 0.5)];
|
|
6477
|
+
const q1 = sortedGaps[Math.floor(gLen * 0.25)];
|
|
6478
|
+
const q3 = sortedGaps[Math.floor(gLen * 0.75)];
|
|
6479
|
+
const iqr = q3 - q1;
|
|
6480
|
+
const logN = Math.max(1, Math.log10(n));
|
|
6481
|
+
if (iqr > 0) {
|
|
6482
|
+
const threshold2 = q3 + iqr * 1.5 * logN;
|
|
6483
|
+
const minJump = Math.max(median * 5, 20);
|
|
6484
|
+
return Math.max(threshold2, minJump);
|
|
6485
|
+
}
|
|
6486
|
+
const baseGap = median > 0 ? median : 1;
|
|
6487
|
+
const p90 = sortedGaps[Math.floor(gLen * 0.9)];
|
|
6488
|
+
if (p90 > baseGap) {
|
|
6489
|
+
const threshold2 = baseGap + (p90 - baseGap) * 0.5 * logN;
|
|
6490
|
+
return Math.max(threshold2, baseGap * 5, 20);
|
|
6491
|
+
}
|
|
6492
|
+
let mean = 0;
|
|
6493
|
+
for (let i = 0; i < gLen; i++) mean += sortedGaps[i];
|
|
6494
|
+
mean /= gLen;
|
|
6495
|
+
let variance = 0;
|
|
6496
|
+
for (let i = 0; i < gLen; i++) {
|
|
6497
|
+
const d = sortedGaps[i] - mean;
|
|
6498
|
+
variance += d * d;
|
|
6499
|
+
}
|
|
6500
|
+
const stddev = Math.sqrt(variance / gLen);
|
|
6501
|
+
if (stddev === 0) {
|
|
6502
|
+
return baseGap * 2;
|
|
6503
|
+
}
|
|
6504
|
+
const threshold = mean + stddev * logN;
|
|
6505
|
+
return Math.max(threshold, baseGap * 5, 20);
|
|
6506
|
+
}
|
|
6507
|
+
function clusterNumbers(numbers, gapMultiplier) {
|
|
6508
|
+
const n = numbers.length;
|
|
6509
|
+
if (n === 0) return [];
|
|
6510
|
+
if (n === 1) return [new Float64Array([numbers[0]])];
|
|
6511
|
+
const sorted = (numbers instanceof Float64Array ? numbers.slice() : Float64Array.from(numbers)).sort();
|
|
6512
|
+
const gaps = new Float64Array(n - 1);
|
|
6513
|
+
for (let i = 0, len = n - 1; i < len; i++) {
|
|
6514
|
+
gaps[i] = sorted[i + 1] - sorted[i];
|
|
6515
|
+
}
|
|
6516
|
+
const sortedGaps = gaps.slice().sort();
|
|
6517
|
+
let threshold;
|
|
6518
|
+
if (gapMultiplier !== void 0) {
|
|
6519
|
+
const q3 = sortedGaps[Math.floor((n - 1) * 0.75)];
|
|
6520
|
+
const iqr = q3 - sortedGaps[Math.floor((n - 1) * 0.25)];
|
|
6521
|
+
threshold = q3 + iqr * gapMultiplier;
|
|
6522
|
+
} else {
|
|
6523
|
+
threshold = calcThreshold(sortedGaps, n);
|
|
6524
|
+
}
|
|
6525
|
+
const clusters = [];
|
|
6526
|
+
let clusterStart = 0;
|
|
6527
|
+
for (let i = 0, len = n - 1; i < len; i++) {
|
|
6528
|
+
if (gaps[i] > threshold) {
|
|
6529
|
+
clusters.push(sorted.subarray(clusterStart, i + 1));
|
|
6530
|
+
clusterStart = i + 1;
|
|
6347
6531
|
}
|
|
6348
|
-
i++;
|
|
6349
6532
|
}
|
|
6350
|
-
|
|
6533
|
+
clusters.push(sorted.subarray(clusterStart));
|
|
6534
|
+
return clusters;
|
|
6351
6535
|
}
|
|
6352
6536
|
|
|
6353
6537
|
// src/core/Row.ts
|
|
@@ -9311,14 +9495,30 @@ var RowTableEngine = class {
|
|
|
9311
9495
|
for (let i = 0, len = pks.length; i < len; i++) {
|
|
9312
9496
|
pkIndexMap.set(pks[i], i);
|
|
9313
9497
|
}
|
|
9314
|
-
const [minPk, maxPk] = getMinMaxValue(pks);
|
|
9315
9498
|
const pkRidPairs = new Array(pks.length).fill(null);
|
|
9316
9499
|
const btx = await this.getBPTreeTransaction(tx);
|
|
9317
|
-
const
|
|
9318
|
-
for
|
|
9319
|
-
const
|
|
9320
|
-
|
|
9321
|
-
|
|
9500
|
+
const clusters = clusterNumbers(pks);
|
|
9501
|
+
for (let i = 0, len = clusters.length; i < len; i++) {
|
|
9502
|
+
const cluster = clusters[i];
|
|
9503
|
+
const minPk = cluster[0];
|
|
9504
|
+
const maxPk = cluster[cluster.length - 1];
|
|
9505
|
+
if (minPk === maxPk) {
|
|
9506
|
+
const keys = await btx.keys({ equal: minPk });
|
|
9507
|
+
if (keys.size > 0) {
|
|
9508
|
+
const rid = keys.values().next().value;
|
|
9509
|
+
const index = pkIndexMap.get(minPk);
|
|
9510
|
+
if (index !== void 0) {
|
|
9511
|
+
pkRidPairs[index] = { pk: minPk, rid, index };
|
|
9512
|
+
}
|
|
9513
|
+
}
|
|
9514
|
+
continue;
|
|
9515
|
+
}
|
|
9516
|
+
const stream = btx.whereStream({ gte: minPk, lte: maxPk });
|
|
9517
|
+
for await (const [rid, pk] of stream) {
|
|
9518
|
+
const index = pkIndexMap.get(pk);
|
|
9519
|
+
if (index !== void 0) {
|
|
9520
|
+
pkRidPairs[index] = { pk, rid, index };
|
|
9521
|
+
}
|
|
9322
9522
|
}
|
|
9323
9523
|
}
|
|
9324
9524
|
return this.fetchRowsByRids(pkRidPairs, tx);
|
|
@@ -2,4 +2,11 @@ type SupportedNumberArray = number[] | Uint8Array | Uint16Array | Uint32Array |
|
|
|
2
2
|
export declare function getMinValue(array: SupportedNumberArray): number;
|
|
3
3
|
export declare function getMaxValue(array: SupportedNumberArray): number;
|
|
4
4
|
export declare function getMinMaxValue(array: SupportedNumberArray): [number, number];
|
|
5
|
+
/**
|
|
6
|
+
* Sorts the input array and splits it into clusters based on the gaps between consecutive elements.
|
|
7
|
+
* @param numbers Array of numbers to cluster
|
|
8
|
+
* @param gapMultiplier Multiplier for the gap threshold (default is calculated automatically)
|
|
9
|
+
* @returns Array of clusters
|
|
10
|
+
*/
|
|
11
|
+
export declare function clusterNumbers(numbers: number[] | Float64Array, gapMultiplier?: number): Float64Array[];
|
|
5
12
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dataply",
|
|
3
|
-
"version": "0.0.24-alpha.
|
|
3
|
+
"version": "0.0.24-alpha.12",
|
|
4
4
|
"description": "A lightweight storage engine for Node.js with support for MVCC, WAL.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "izure <admin@izure.org>",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"cache-entanglement": "^1.7.1",
|
|
49
49
|
"hookall": "^2.2.0",
|
|
50
|
-
"mvcc-api": "^1.3.
|
|
50
|
+
"mvcc-api": "^1.3.5",
|
|
51
51
|
"ryoiki": "^1.2.0",
|
|
52
|
-
"serializable-bptree": "^8.3.
|
|
52
|
+
"serializable-bptree": "^8.3.4"
|
|
53
53
|
}
|
|
54
54
|
}
|