@moyodb/sdk 1.4.0 → 1.5.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/README.md +2 -2
- package/dist/assets/browser-worker-p7uX85l-.js +4 -0
- package/dist/assets/browser-worker-p7uX85l-.js.map +1 -0
- package/dist/assets/shared-worker-BALTqEUe.js +2 -0
- package/dist/assets/shared-worker-BALTqEUe.js.map +1 -0
- package/dist/chunks/{indexing-B0duqlUs.js → indexing-DdpU69Fd.js} +302 -69
- package/dist/chunks/{indexing-B0duqlUs.js.map → indexing-DdpU69Fd.js.map} +1 -1
- package/dist/codec.d.ts.map +1 -1
- package/dist/compression.d.ts.map +1 -1
- package/dist/engine/README.md +2 -2
- package/dist/engine/moyodb_engine.d.ts +2 -2
- package/dist/engine/moyodb_engine.js +22 -22
- package/dist/engine/moyodb_engine_bg.wasm +0 -0
- package/dist/engine/moyodb_engine_bg.wasm.d.ts +2 -2
- package/dist/engine/package.json +1 -1
- package/dist/engine/snippets/{moyodb-engine-1d53039816cbc2f7 → moyodb-engine-1f8134232168280b}/js/opfs_shim.js +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/indexing.d.ts +7 -0
- package/dist/indexing.d.ts.map +1 -1
- package/dist/moyodb-sdk.js +1329 -931
- package/dist/moyodb-sdk.js.map +1 -1
- package/dist/node-engine.js +382 -47
- package/dist/node-engine.js.map +1 -1
- package/dist/node.js +332 -44
- package/dist/node.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/subscriptions.d.ts.map +1 -1
- package/dist/worker-client.d.ts.map +1 -1
- package/dist/worker-server.d.ts.map +1 -1
- package/dist/worker.d.ts +10 -3
- package/dist/worker.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/assets/browser-worker-Bj2ErRvC.js +0 -4
- package/dist/assets/browser-worker-Bj2ErRvC.js.map +0 -1
- package/dist/assets/shared-worker-CMeTcusa.js +0 -2
- package/dist/assets/shared-worker-CMeTcusa.js.map +0 -1
package/dist/node-engine.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bt as unpackPackedBinaryList, Ct as isWorkerCommand, Dt as isWorkerProtocolRequestBatchMessage, Gt as clampTimerDelayMs, Ht as unpackPackedOptionalValues, It as prepareWorkerResponsePayload, L as utf8Encode, Lt as serializeWorkerError, Mt as packedBinaryListBytes, Nt as packedOptionalValues, Ot as isWorkerProtocolRequestMessage, Pt as packedScanRows, Rt as unpackPackedBatchOpKeys, S as normalizeIndexDefinitions, St as isAutocommitCommand, Ut as unpackPackedScanRows, Vt as unpackPackedBinaryPairKeys, Wt as workerProtocolError, _t as WORKER_PROTOCOL_RESPONSE_BATCH, a as cloneNormalizedIndexDefinitions, c as decodeIndexEntryKey, d as encodeIndexEntryKey, f as encodeIndexMetadataKey, g as findIndexDefinition, gt as WORKER_PROTOCOL_RESPONSE, h as extractLogicalIndexKeyFromDocument, i as assertValidScanRange, jt as packedBatchOpsBytes, l as decodeIndexMetadataValue, m as extractLogicalIndexKey, o as compareNormalizedIndexDefinitions, p as encodeIndexMetadataValue, pt as WORKER_PROTOCOL_READY, qt as isRecord, s as createIndexKeyExtractor, t as INDEX_METADATA_STORE, u as decodeIndexedDocument, v as indexKeyExactRange, vt as captureWorkerPayload, w as toPublicIndexDefinitions, wt as isWorkerProtocolEnvelope, x as isInternalStoreName, y as indexRangeToPhysicalRange, yt as decodeWorkerCommandPayload, zt as unpackPackedBatchOps } from "./chunks/indexing-DdpU69Fd.js";
|
|
2
2
|
//#region src/worker-server.ts
|
|
3
3
|
/** The first argument identifies the transaction lane. */
|
|
4
4
|
var TRANSACTION_COMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -128,10 +128,20 @@ var ResponseQueue = class {
|
|
|
128
128
|
constructor(scope) {
|
|
129
129
|
this.scope = scope;
|
|
130
130
|
}
|
|
131
|
-
enqueue
|
|
131
|
+
enqueue(response, transfer = [], flushNow = false) {
|
|
132
132
|
if (this.closed) return;
|
|
133
|
-
const
|
|
134
|
-
if (this.queued.length > 0 && this.queuedBytes +
|
|
133
|
+
const byteLength = payloadBytes(response);
|
|
134
|
+
if (this.queued.length > 0 && this.queuedBytes + byteLength > 1048576) this.flush();
|
|
135
|
+
if (flushNow || this.queued.length + 1 >= 128 || this.queuedBytes + byteLength >= 1048576) {
|
|
136
|
+
this.queued.push({
|
|
137
|
+
response,
|
|
138
|
+
transfer
|
|
139
|
+
});
|
|
140
|
+
this.queuedBytes += byteLength;
|
|
141
|
+
this.flush();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const captured = snapshotQueuedPayload(response, transfer);
|
|
135
145
|
this.queued.push({
|
|
136
146
|
response: captured.value,
|
|
137
147
|
transfer: captured.transfer
|
|
@@ -148,8 +158,7 @@ var ResponseQueue = class {
|
|
|
148
158
|
this.flushChannel.port2.postMessage(null);
|
|
149
159
|
});
|
|
150
160
|
}
|
|
151
|
-
|
|
152
|
-
};
|
|
161
|
+
}
|
|
153
162
|
close() {
|
|
154
163
|
this.closed = true;
|
|
155
164
|
this.queued = [];
|
|
@@ -190,9 +199,8 @@ function exposeWorkerApi(api, scope = self) {
|
|
|
190
199
|
if (isWorkerProtocolRequestBatchMessage(event.data)) {
|
|
191
200
|
let remaining = event.data.requests.length;
|
|
192
201
|
const respond = (response, transfer) => {
|
|
193
|
-
responses.enqueue(response, transfer);
|
|
194
202
|
remaining -= 1;
|
|
195
|
-
|
|
203
|
+
responses.enqueue(response, transfer, remaining === 0);
|
|
196
204
|
};
|
|
197
205
|
for (const request of event.data.requests) dispatchWorkerRequest(scope, api, scheduler, request, respond);
|
|
198
206
|
return;
|
|
@@ -316,6 +324,203 @@ function postWorkerResponse(scope, response, transfer = []) {
|
|
|
316
324
|
} catch {}
|
|
317
325
|
scope.postMessage(response);
|
|
318
326
|
}
|
|
327
|
+
var STANDARD_VIEW_CONSTRUCTORS = /* @__PURE__ */ new Set([
|
|
328
|
+
DataView,
|
|
329
|
+
Uint8Array,
|
|
330
|
+
Uint8ClampedArray,
|
|
331
|
+
Uint16Array,
|
|
332
|
+
Uint32Array,
|
|
333
|
+
Int8Array,
|
|
334
|
+
Int16Array,
|
|
335
|
+
Int32Array,
|
|
336
|
+
Float32Array,
|
|
337
|
+
Float64Array,
|
|
338
|
+
BigInt64Array,
|
|
339
|
+
BigUint64Array
|
|
340
|
+
]);
|
|
341
|
+
/**
|
|
342
|
+
* Freeze a queued payload so the later postMessage is its only structured clone.
|
|
343
|
+
* Listed buffers move now. Other ArrayBuffers are copied. SharedArrayBuffers stay shared.
|
|
344
|
+
*/
|
|
345
|
+
function snapshotQueuedPayload(value, transfer) {
|
|
346
|
+
const moving = /* @__PURE__ */ new Set();
|
|
347
|
+
for (const item of transfer) {
|
|
348
|
+
if (!(item instanceof ArrayBuffer) || isResizableBuffer(item)) return captureWorkerPayload(value, transfer);
|
|
349
|
+
moving.add(item);
|
|
350
|
+
}
|
|
351
|
+
const geometries = /* @__PURE__ */ new Map();
|
|
352
|
+
if (!isPlainPayload(value, geometries, /* @__PURE__ */ new WeakSet())) return captureWorkerPayload(value, transfer);
|
|
353
|
+
const relocated = /* @__PURE__ */ new Map();
|
|
354
|
+
for (const buffer of moving) relocated.set(buffer, moveArrayBuffer(buffer));
|
|
355
|
+
const owned = [];
|
|
356
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
357
|
+
const cloneValue = (item) => {
|
|
358
|
+
if (item === null || typeof item !== "object") return item;
|
|
359
|
+
const existing = seen.get(item);
|
|
360
|
+
if (existing !== void 0) return existing;
|
|
361
|
+
if (typeof SharedArrayBuffer !== "undefined" && item instanceof SharedArrayBuffer) {
|
|
362
|
+
seen.set(item, item);
|
|
363
|
+
return item;
|
|
364
|
+
}
|
|
365
|
+
if (item instanceof ArrayBuffer) {
|
|
366
|
+
const next = relocated.get(item) ?? item.slice(0);
|
|
367
|
+
seen.set(item, next);
|
|
368
|
+
owned.push(next);
|
|
369
|
+
return next;
|
|
370
|
+
}
|
|
371
|
+
if (ArrayBuffer.isView(item)) {
|
|
372
|
+
const geometry = geometries.get(item);
|
|
373
|
+
if (!geometry) throw workerProtocolError("WorkerProtocolError", "worker payload could not be queued");
|
|
374
|
+
const buffer = item.buffer;
|
|
375
|
+
const out = retargetView(item, typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer ? buffer : cloneValue(buffer), geometry);
|
|
376
|
+
seen.set(item, out);
|
|
377
|
+
return out;
|
|
378
|
+
}
|
|
379
|
+
if (Array.isArray(item)) {
|
|
380
|
+
const out = new Array(item.length);
|
|
381
|
+
seen.set(item, out);
|
|
382
|
+
for (let index = 0; index < item.length; index += 1) if (index in item) out[index] = cloneValue(item[index]);
|
|
383
|
+
return out;
|
|
384
|
+
}
|
|
385
|
+
const out = Object.getPrototypeOf(item) === null ? Object.create(null) : {};
|
|
386
|
+
seen.set(item, out);
|
|
387
|
+
const record = item;
|
|
388
|
+
for (const key in record) if (Object.prototype.hasOwnProperty.call(record, key)) out[key] = cloneValue(record[key]);
|
|
389
|
+
return out;
|
|
390
|
+
};
|
|
391
|
+
const cloned = cloneValue(value);
|
|
392
|
+
return {
|
|
393
|
+
value: cloned,
|
|
394
|
+
transfer: owned,
|
|
395
|
+
byteLength: payloadBytes(cloned)
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
function payloadBytes(value) {
|
|
399
|
+
let byteLength = 0;
|
|
400
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
401
|
+
const visit = (item) => {
|
|
402
|
+
if (!Number.isFinite(byteLength)) return;
|
|
403
|
+
if (typeof item === "string") {
|
|
404
|
+
byteLength += 8 + item.length * 2;
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (item === null || typeof item !== "object") {
|
|
408
|
+
byteLength += 8;
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (seen.has(item)) return;
|
|
412
|
+
seen.add(item);
|
|
413
|
+
byteLength += 8;
|
|
414
|
+
if (item instanceof ArrayBuffer) byteLength += item.byteLength;
|
|
415
|
+
else if (typeof SharedArrayBuffer !== "undefined" && item instanceof SharedArrayBuffer) byteLength += item.byteLength;
|
|
416
|
+
else if (ArrayBuffer.isView(item)) visit(item.buffer);
|
|
417
|
+
else if (Array.isArray(item)) {
|
|
418
|
+
if (Object.getPrototypeOf(item) !== Array.prototype || hasExtraKeys(item)) {
|
|
419
|
+
byteLength = Number.POSITIVE_INFINITY;
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
for (let index = 0; index < item.length; index += 1) {
|
|
423
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, String(index));
|
|
424
|
+
if (descriptor && !("value" in descriptor)) {
|
|
425
|
+
byteLength = Number.POSITIVE_INFINITY;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
visit(descriptor?.value);
|
|
429
|
+
}
|
|
430
|
+
} else if (item instanceof Map) for (const [key, child] of item) {
|
|
431
|
+
visit(key);
|
|
432
|
+
visit(child);
|
|
433
|
+
}
|
|
434
|
+
else if (item instanceof Set) for (const child of item) visit(child);
|
|
435
|
+
else {
|
|
436
|
+
const record = item;
|
|
437
|
+
for (const key in record) if (Object.prototype.hasOwnProperty.call(record, key)) {
|
|
438
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
439
|
+
if (key === "__proto__" || !descriptor || !("value" in descriptor)) {
|
|
440
|
+
byteLength = Number.POSITIVE_INFINITY;
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
byteLength += 8 + key.length * 2;
|
|
444
|
+
visit(descriptor.value);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
visit(value);
|
|
449
|
+
return byteLength;
|
|
450
|
+
}
|
|
451
|
+
function isPlainPayload(value, geometries, seen) {
|
|
452
|
+
if (typeof value === "function" || typeof value === "symbol") return false;
|
|
453
|
+
if (value === null || typeof value !== "object") return true;
|
|
454
|
+
if (seen.has(value)) return true;
|
|
455
|
+
seen.add(value);
|
|
456
|
+
if (typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer) return !isResizableBuffer(value);
|
|
457
|
+
if (value instanceof ArrayBuffer) return !isResizableBuffer(value);
|
|
458
|
+
if (ArrayBuffer.isView(value)) {
|
|
459
|
+
if (!isStandardView(value)) return false;
|
|
460
|
+
const buffer = value.buffer;
|
|
461
|
+
if (typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer) {
|
|
462
|
+
if (isResizableBuffer(buffer)) return false;
|
|
463
|
+
geometries.set(value, viewGeometry(value));
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
if (!(buffer instanceof ArrayBuffer) || isResizableBuffer(buffer)) return false;
|
|
467
|
+
geometries.set(value, viewGeometry(value));
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
if (value instanceof Map || value instanceof Set || value instanceof Date || value instanceof RegExp) return false;
|
|
471
|
+
if (Array.isArray(value)) {
|
|
472
|
+
if (hasExtraKeys(value) || hasEnumerableSymbols(value)) return false;
|
|
473
|
+
for (const child of value) if (!isPlainPayload(child, geometries, seen)) return false;
|
|
474
|
+
return true;
|
|
475
|
+
}
|
|
476
|
+
const proto = Object.getPrototypeOf(value);
|
|
477
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
478
|
+
if (hasEnumerableSymbols(value)) return false;
|
|
479
|
+
const record = value;
|
|
480
|
+
for (const key in record) if (Object.prototype.hasOwnProperty.call(record, key) && !isPlainPayload(record[key], geometries, seen)) return false;
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
function hasExtraKeys(value) {
|
|
484
|
+
const record = value;
|
|
485
|
+
for (const key in record) {
|
|
486
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
|
|
487
|
+
const index = Number(key);
|
|
488
|
+
if (!Number.isInteger(index) || index < 0 || index >= value.length || String(index) !== key) return true;
|
|
489
|
+
}
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
function hasEnumerableSymbols(value) {
|
|
493
|
+
for (const symbol of Object.getOwnPropertySymbols(value)) if (Object.prototype.propertyIsEnumerable.call(value, symbol)) return true;
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
function isStandardView(view) {
|
|
497
|
+
return STANDARD_VIEW_CONSTRUCTORS.has(view.constructor);
|
|
498
|
+
}
|
|
499
|
+
function viewGeometry(view) {
|
|
500
|
+
if (view instanceof DataView) return {
|
|
501
|
+
offset: view.byteOffset,
|
|
502
|
+
length: view.byteLength,
|
|
503
|
+
dataView: true
|
|
504
|
+
};
|
|
505
|
+
return {
|
|
506
|
+
offset: view.byteOffset,
|
|
507
|
+
length: view.length,
|
|
508
|
+
dataView: false
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function retargetView(view, buffer, geometry) {
|
|
512
|
+
if (geometry.dataView) return new DataView(buffer, geometry.offset, geometry.length);
|
|
513
|
+
const Typed = view.constructor;
|
|
514
|
+
return new Typed(buffer, geometry.offset, geometry.length);
|
|
515
|
+
}
|
|
516
|
+
function moveArrayBuffer(buffer) {
|
|
517
|
+
const movable = buffer;
|
|
518
|
+
if (typeof movable.transfer === "function") return movable.transfer();
|
|
519
|
+
return structuredClone(buffer, { transfer: [buffer] });
|
|
520
|
+
}
|
|
521
|
+
function isResizableBuffer(buffer) {
|
|
522
|
+
return buffer.resizable === true;
|
|
523
|
+
}
|
|
319
524
|
//#endregion
|
|
320
525
|
//#region src/snappy.ts
|
|
321
526
|
var BLOCK_SIZE = 65536;
|
|
@@ -543,6 +748,25 @@ function writeEnvelope(out, offset, magic, kindTag, rawLength, payload) {
|
|
|
543
748
|
view.setUint32(10, rawLength, true);
|
|
544
749
|
view.setUint32(14, checksum, true);
|
|
545
750
|
}
|
|
751
|
+
function writeEnvelopeHeader(out, magic, kindTag, rawLength, payload) {
|
|
752
|
+
const checksum = crc32(payload);
|
|
753
|
+
out.set(magic);
|
|
754
|
+
out[8] = ENVELOPE_VERSION;
|
|
755
|
+
out[9] = kindTag;
|
|
756
|
+
const view = new DataView(out.buffer, out.byteOffset, ENVELOPE_HEADER_SIZE);
|
|
757
|
+
view.setUint32(10, rawLength, true);
|
|
758
|
+
view.setUint32(14, checksum, true);
|
|
759
|
+
}
|
|
760
|
+
function envelopeFromChunks(magic, kindTag, rawLength, chunks, totalBytes) {
|
|
761
|
+
const out = new Uint8Array(ENVELOPE_HEADER_SIZE + totalBytes);
|
|
762
|
+
let offset = ENVELOPE_HEADER_SIZE;
|
|
763
|
+
for (const chunk of chunks) {
|
|
764
|
+
out.set(chunk, offset);
|
|
765
|
+
offset += chunk.byteLength;
|
|
766
|
+
}
|
|
767
|
+
writeEnvelopeHeader(out, magic, kindTag, rawLength, out.subarray(ENVELOPE_HEADER_SIZE));
|
|
768
|
+
return out;
|
|
769
|
+
}
|
|
546
770
|
function compressionIsProfitable(rawLength, compressedLength) {
|
|
547
771
|
return (compressedLength + ENVELOPE_HEADER_SIZE) * 100 <= rawLength * 90;
|
|
548
772
|
}
|
|
@@ -555,10 +779,6 @@ function snappyPreflightIsProfitable(value) {
|
|
|
555
779
|
}
|
|
556
780
|
return compressionIsProfitable(STORE_VALUE_COMPRESSION_PREFLIGHT_WINDOW_BYTES * 3, compressedLength);
|
|
557
781
|
}
|
|
558
|
-
function buildStoreRecord(input, compressed, compression) {
|
|
559
|
-
if (!compressionIsProfitable(input.byteLength, compressed.byteLength)) return buildEnvelope(STORE_RECORD_MAGIC, COMPRESSION_TAG_NONE, input.byteLength, input);
|
|
560
|
-
return buildEnvelope(STORE_RECORD_MAGIC, compressionTag(compression), input.byteLength, compressed);
|
|
561
|
-
}
|
|
562
782
|
function validateStoreValueLength(value) {
|
|
563
783
|
if (value.byteLength > MAX_DECOMPRESSED_STORE_VALUE_BYTES) throw namedError("ValueTooLargeError", `value has ${value.byteLength} bytes, exceeding the ${MAX_DECOMPRESSED_STORE_VALUE_BYTES} byte limit`);
|
|
564
784
|
}
|
|
@@ -623,19 +843,41 @@ function readEnvelopeHeader(magic, bytes, strict = true) {
|
|
|
623
843
|
payloadChecksum: view.getUint32(14, true)
|
|
624
844
|
};
|
|
625
845
|
}
|
|
626
|
-
async function
|
|
846
|
+
async function collectCompressed(input, kind, stopAtBytes) {
|
|
627
847
|
ensureCompressionRuntime();
|
|
628
848
|
let stream;
|
|
629
849
|
try {
|
|
630
|
-
stream = byteStream(
|
|
850
|
+
stream = byteStream(input).pipeThrough(new CompressionStream(kind));
|
|
631
851
|
} catch {
|
|
632
852
|
throw compressionRuntimeUnavailable();
|
|
633
853
|
}
|
|
854
|
+
const reader = stream.getReader();
|
|
855
|
+
const chunks = [];
|
|
856
|
+
let totalBytes = 0;
|
|
857
|
+
let stopped = false;
|
|
634
858
|
try {
|
|
635
|
-
|
|
859
|
+
for (let next = await reader.read(); !next.done; next = await reader.read()) {
|
|
860
|
+
const part = next.value;
|
|
861
|
+
totalBytes += part.byteLength;
|
|
862
|
+
if (stopAtBytes !== void 0 && totalBytes >= stopAtBytes) {
|
|
863
|
+
stopped = true;
|
|
864
|
+
await reader.cancel("compressed output is not smaller than the raw payload");
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
chunks.push(part);
|
|
868
|
+
}
|
|
636
869
|
} catch (error) {
|
|
637
|
-
throw namedError("InternalError", `failed to compress bytes with ${kind}: ${String(error)}`);
|
|
870
|
+
if (!stopped) throw namedError("InternalError", `failed to compress bytes with ${kind}: ${String(error)}`);
|
|
871
|
+
} finally {
|
|
872
|
+
try {
|
|
873
|
+
reader.releaseLock();
|
|
874
|
+
} catch {}
|
|
638
875
|
}
|
|
876
|
+
if (stopped || stopAtBytes !== void 0 && totalBytes >= stopAtBytes) return null;
|
|
877
|
+
return {
|
|
878
|
+
chunks,
|
|
879
|
+
totalBytes
|
|
880
|
+
};
|
|
639
881
|
}
|
|
640
882
|
async function decompressBytes(data, kind, label, maxOutputBytes) {
|
|
641
883
|
if (kind === "snappy") return decodeSnappy(data, maxOutputBytes ?? MAX_DECOMPRESSED_STORE_VALUE_BYTES, maxOutputBytes);
|
|
@@ -689,6 +931,7 @@ function compressionFromStoreFlags(flags) {
|
|
|
689
931
|
}
|
|
690
932
|
}
|
|
691
933
|
async function encodeStoreValueRecord(value, compression) {
|
|
934
|
+
validateStoreValueLength(value);
|
|
692
935
|
if (compression === false) return value;
|
|
693
936
|
if (compression === "snappy") {
|
|
694
937
|
const record = prepareFastStoreValueRecord(value, compression);
|
|
@@ -696,10 +939,16 @@ async function encodeStoreValueRecord(value, compression) {
|
|
|
696
939
|
writePreparedStoreValueRecord(record, output, 0);
|
|
697
940
|
return output;
|
|
698
941
|
}
|
|
699
|
-
validateStoreValueLength(value);
|
|
700
942
|
if (value.byteLength < 1024) return buildEnvelope(STORE_RECORD_MAGIC, COMPRESSION_TAG_NONE, value.byteLength, value);
|
|
701
|
-
const
|
|
702
|
-
|
|
943
|
+
const stored = new Uint8Array(ENVELOPE_HEADER_SIZE + value.byteLength);
|
|
944
|
+
const payload = stored.subarray(ENVELOPE_HEADER_SIZE);
|
|
945
|
+
payload.set(value);
|
|
946
|
+
const compressed = await collectCompressed(payload, compression, payload.byteLength);
|
|
947
|
+
if (compressed === null || !compressionIsProfitable(payload.byteLength, compressed.totalBytes)) {
|
|
948
|
+
writeEnvelopeHeader(stored, STORE_RECORD_MAGIC, COMPRESSION_TAG_NONE, payload.byteLength, payload);
|
|
949
|
+
return stored;
|
|
950
|
+
}
|
|
951
|
+
return envelopeFromChunks(STORE_RECORD_MAGIC, compressionTag(compression), payload.byteLength, compressed.chunks, compressed.totalBytes);
|
|
703
952
|
}
|
|
704
953
|
async function decodeStoreValueRecord(value, options) {
|
|
705
954
|
const header = readEnvelopeHeader(STORE_RECORD_MAGIC, value, options.strict);
|
|
@@ -735,9 +984,11 @@ async function decodeStoreValueRecord(value, options) {
|
|
|
735
984
|
async function wrapSnapshotWithCompression(snapshot, compression) {
|
|
736
985
|
if (compression === false) return snapshot;
|
|
737
986
|
if (!["gzip", "deflate"].includes(compression)) throw namedError("InternalError", `unsupported snapshot compression kind: ${String(compression)}`);
|
|
987
|
+
if (snapshot.byteLength > MAX_DECOMPRESSED_SNAPSHOT_BYTES) throw namedError("SerializationError", `snapshot has ${snapshot.byteLength} bytes, exceeding the ${MAX_DECOMPRESSED_SNAPSHOT_BYTES} byte limit`);
|
|
738
988
|
const input = copyBytes(snapshot);
|
|
739
|
-
const compressed = await
|
|
740
|
-
|
|
989
|
+
const compressed = await collectCompressed(input, compression);
|
|
990
|
+
if (compressed === null) throw namedError("InternalError", `failed to compress bytes with ${compression}`);
|
|
991
|
+
return envelopeFromChunks(SNAPSHOT_EXPORT_MAGIC, compressionTag(compression), input.byteLength, compressed.chunks, compressed.totalBytes);
|
|
741
992
|
}
|
|
742
993
|
async function unwrapSnapshotCompression(snapshot) {
|
|
743
994
|
const header = readEnvelopeHeader(SNAPSHOT_EXPORT_MAGIC, snapshot);
|
|
@@ -773,6 +1024,7 @@ function toWasmPutOptions(options) {
|
|
|
773
1024
|
};
|
|
774
1025
|
}
|
|
775
1026
|
function toWasmRange(range) {
|
|
1027
|
+
assertValidScanRange(range);
|
|
776
1028
|
const normalized = {};
|
|
777
1029
|
if (range.gt !== void 0) normalized.gt = range.gt;
|
|
778
1030
|
if (range.gte !== void 0) normalized.gte = range.gte;
|
|
@@ -788,6 +1040,7 @@ var MAX_ENGINE_KEY_BYTES = 1024;
|
|
|
788
1040
|
var MAX_PACKED_BYTES = 4294967295;
|
|
789
1041
|
var INDEX_PUT_BATCH_ROWS = 64;
|
|
790
1042
|
var INDEX_PUT_BATCH_BYTES = 4194304;
|
|
1043
|
+
var MAX_PLAIN_STORE_VALUE_BYTES = 8388608;
|
|
791
1044
|
var INDEX_SCAN_PAGE_ROWS = 256;
|
|
792
1045
|
var INDEX_SCAN_PAGE_BYTES = 8389662;
|
|
793
1046
|
var INDEX_SCAN_RAW_CHUNK_ROWS = 512;
|
|
@@ -933,6 +1186,29 @@ function rangesEqual(left, right) {
|
|
|
933
1186
|
}
|
|
934
1187
|
return left.reverse === right.reverse && left.limit === right.limit;
|
|
935
1188
|
}
|
|
1189
|
+
function sameBound(cached, next) {
|
|
1190
|
+
if (cached === void 0 || next === void 0) return cached === next;
|
|
1191
|
+
return bytesEqual(cached, next);
|
|
1192
|
+
}
|
|
1193
|
+
function copyBound(value) {
|
|
1194
|
+
return value === void 0 ? void 0 : value.slice();
|
|
1195
|
+
}
|
|
1196
|
+
function compoundEntryKeyLength(logicalKey, primaryKey) {
|
|
1197
|
+
return escapedPartLength(logicalKey) + escapedPartLength(primaryKey);
|
|
1198
|
+
}
|
|
1199
|
+
function escapedPartLength(part) {
|
|
1200
|
+
let length = 2;
|
|
1201
|
+
for (let index = 0; index < part.length; index += 1) length += part[index] === 0 ? 2 : 1;
|
|
1202
|
+
return length;
|
|
1203
|
+
}
|
|
1204
|
+
function limitPlainStoreValue(value) {
|
|
1205
|
+
if (value.byteLength > MAX_PLAIN_STORE_VALUE_BYTES) {
|
|
1206
|
+
const error = /* @__PURE__ */ new Error(`stored value has ${value.byteLength} bytes, exceeding the ${MAX_PLAIN_STORE_VALUE_BYTES} byte limit`);
|
|
1207
|
+
error.name = "ValueTooLargeError";
|
|
1208
|
+
throw error;
|
|
1209
|
+
}
|
|
1210
|
+
return value;
|
|
1211
|
+
}
|
|
936
1212
|
function normalizeWasmBytes(value) {
|
|
937
1213
|
if (value instanceof Uint8Array) return value.byteOffset === 0 && value.byteLength === value.buffer.byteLength ? value : value.slice();
|
|
938
1214
|
return new Uint8Array(value);
|
|
@@ -1090,6 +1366,9 @@ var DbWorker = class {
|
|
|
1090
1366
|
*/
|
|
1091
1367
|
txIndexSchemas = /* @__PURE__ */ new Map();
|
|
1092
1368
|
indexesBySchema = /* @__PURE__ */ new WeakMap();
|
|
1369
|
+
/** Readonly scans reuse a resolved index; readwrite scans recheck so TTL staging still runs. */
|
|
1370
|
+
readonlyIndexCache = /* @__PURE__ */ new Map();
|
|
1371
|
+
indexBoundCache = null;
|
|
1093
1372
|
txEnsuredRawStores = /* @__PURE__ */ new Map();
|
|
1094
1373
|
txIndexSchemaChanged = /* @__PURE__ */ new Set();
|
|
1095
1374
|
txStoreCompression = /* @__PURE__ */ new Map();
|
|
@@ -1328,9 +1607,14 @@ var DbWorker = class {
|
|
|
1328
1607
|
return Promise.resolve(this.withEngine((engine) => engine.has(toWasmU64(txId), store, key)));
|
|
1329
1608
|
}
|
|
1330
1609
|
async put(txId, store, key, value, options = {}) {
|
|
1331
|
-
|
|
1610
|
+
await this.putEntry(txId, store, key, value, options);
|
|
1611
|
+
}
|
|
1612
|
+
async putEntry(txId, store, key, value, options, knownDefs, knownCompression) {
|
|
1613
|
+
const defs = knownDefs ?? this.indexesForStoreInTx(txId, store);
|
|
1614
|
+
const compression = knownCompression ?? this.storeCompressionForTx(txId, store);
|
|
1332
1615
|
if (defs.length === 0) {
|
|
1333
|
-
const
|
|
1616
|
+
const preparedValue = this.prepareStoredValue(store, value, compression);
|
|
1617
|
+
const storedValue = preparedValue instanceof Uint8Array ? preparedValue : await preparedValue;
|
|
1334
1618
|
const baselineExists = this.withEngine((engine) => engine.put(toWasmU64(txId), store, key, storedValue, toWasmPutOptions(options)));
|
|
1335
1619
|
this.recordPutChange(txId, store, key, baselineExists);
|
|
1336
1620
|
return;
|
|
@@ -1522,7 +1806,7 @@ var DbWorker = class {
|
|
|
1522
1806
|
if (rows !== null) {
|
|
1523
1807
|
bytes = 4;
|
|
1524
1808
|
for (const row of rows) {
|
|
1525
|
-
row.value = await
|
|
1809
|
+
row.value = await decodeStoreValueRecord(row.value, { strict: true });
|
|
1526
1810
|
bytes += 8 + row.key.byteLength + row.value.byteLength;
|
|
1527
1811
|
if (bytes > request.maxBytes) throw remoteError("ValueTooLargeError", "decoded scan page exceeds maxBytes");
|
|
1528
1812
|
}
|
|
@@ -1560,12 +1844,15 @@ var DbWorker = class {
|
|
|
1560
1844
|
return page.rows.length === 0 ? null : page.rows[0].value;
|
|
1561
1845
|
}
|
|
1562
1846
|
async scanByIndex(txId, store, indexName, range = {}) {
|
|
1847
|
+
assertValidScanRange(range);
|
|
1563
1848
|
const def = this.resolveIndexDefinition(txId, store, indexName);
|
|
1564
1849
|
const rows = [];
|
|
1565
1850
|
let remaining = range.limit ?? Number.POSITIVE_INFINITY;
|
|
1851
|
+
if (remaining <= 0) return rows;
|
|
1852
|
+
const physical = this.physicalIndexRange(txId, def, range);
|
|
1566
1853
|
let cursor = null;
|
|
1567
1854
|
while (remaining > 0) {
|
|
1568
|
-
const page = await this.loadVisibleIndexPage(txId, def, range, cursor, Math.min(remaining, INDEX_SCAN_PAGE_ROWS));
|
|
1855
|
+
const page = await this.loadVisibleIndexPage(txId, def, range, cursor, Math.min(remaining, INDEX_SCAN_PAGE_ROWS), INDEX_SCAN_PAGE_BYTES, physical);
|
|
1569
1856
|
rows.push(...page.rows);
|
|
1570
1857
|
remaining -= page.rows.length;
|
|
1571
1858
|
if (page.cursor === null) break;
|
|
@@ -1577,7 +1864,7 @@ var DbWorker = class {
|
|
|
1577
1864
|
if (!Number.isSafeInteger(limit) || limit <= 0) throw remoteError("InvalidRangeError", "index scan page limit must be a positive integer");
|
|
1578
1865
|
if (!Number.isSafeInteger(maxBytes) || maxBytes < 4 || maxBytes > MAX_PACKED_BYTES) throw remoteError("InvalidRangeError", "index scan page maxBytes must be a u32 integer of at least 4");
|
|
1579
1866
|
const def = this.resolveIndexDefinition(txId, store, indexName);
|
|
1580
|
-
return this.loadVisibleIndexPage(txId, def, range, cursor, limit, maxBytes);
|
|
1867
|
+
return this.loadVisibleIndexPage(txId, def, range, cursor, limit, maxBytes, this.physicalIndexRange(txId, def, range));
|
|
1581
1868
|
}
|
|
1582
1869
|
getIndexes(txId) {
|
|
1583
1870
|
return Promise.resolve(toPublicIndexDefinitions(txId === void 0 ? this.loadCommittedIndexSchema() : this.indexSchemaForTx(txId)));
|
|
@@ -1927,9 +2214,11 @@ var DbWorker = class {
|
|
|
1927
2214
|
this.txChanges.delete(txId);
|
|
1928
2215
|
this.txModes.delete(txId);
|
|
1929
2216
|
this.txIndexSchemas.delete(txId);
|
|
2217
|
+
this.readonlyIndexCache.delete(txId);
|
|
1930
2218
|
this.txEnsuredRawStores.delete(txId);
|
|
1931
2219
|
this.txIndexSchemaChanged.delete(txId);
|
|
1932
2220
|
this.txStoreCompression.delete(txId);
|
|
2221
|
+
if (this.indexBoundCache?.txId === txId) this.indexBoundCache = null;
|
|
1933
2222
|
}
|
|
1934
2223
|
getOrCreateTrackedTxn(txId) {
|
|
1935
2224
|
return getOrInsert(this.txChanges, txId, () => /* @__PURE__ */ new Map());
|
|
@@ -2217,22 +2506,20 @@ var DbWorker = class {
|
|
|
2217
2506
|
} : op);
|
|
2218
2507
|
return storedOps;
|
|
2219
2508
|
}
|
|
2220
|
-
|
|
2221
|
-
if (isInternalStoreName(store)) return value;
|
|
2222
|
-
return encodeStoreValueRecord(value, this.storeCompressionForTx(txId, store));
|
|
2223
|
-
}
|
|
2224
|
-
async decodeStoreValue(txId, store, value) {
|
|
2509
|
+
prepareStoredValue(store, value, compression) {
|
|
2225
2510
|
if (isInternalStoreName(store)) return value;
|
|
2226
|
-
if (
|
|
2227
|
-
return
|
|
2511
|
+
if (compression === false) return limitPlainStoreValue(value);
|
|
2512
|
+
return encodeStoreValueRecord(value, compression);
|
|
2228
2513
|
}
|
|
2229
2514
|
async decodeStoreValueForFeed(store, value) {
|
|
2230
2515
|
if (isInternalStoreName(store)) return value;
|
|
2231
2516
|
return decodeStoreValueRecord(value, { strict: (this.loadCommittedStoreCompression().get(store) ?? false) !== false });
|
|
2232
2517
|
}
|
|
2233
|
-
async readStoreValue(txId, store, key) {
|
|
2518
|
+
async readStoreValue(txId, store, key, knownCompression) {
|
|
2234
2519
|
const value = this.readRawValue(txId, store, key);
|
|
2235
|
-
|
|
2520
|
+
if (value === null || isInternalStoreName(store)) return value;
|
|
2521
|
+
if ((knownCompression ?? this.storeCompressionForTx(txId, store)) === false) return value;
|
|
2522
|
+
return await decodeStoreValueRecord(value, { strict: true });
|
|
2236
2523
|
}
|
|
2237
2524
|
async readStoreScan(txId, store, range) {
|
|
2238
2525
|
const rows = this.readRawScan(txId, store, range);
|
|
@@ -2242,7 +2529,7 @@ var DbWorker = class {
|
|
|
2242
2529
|
for (let index = 0; index < rows.length; index += 1) rows[index].value = values[index];
|
|
2243
2530
|
return rows;
|
|
2244
2531
|
}
|
|
2245
|
-
async decodeStoreValues(
|
|
2532
|
+
async decodeStoreValues(_txId, _store, values) {
|
|
2246
2533
|
const state = {
|
|
2247
2534
|
next: 0,
|
|
2248
2535
|
failed: false,
|
|
@@ -2254,7 +2541,7 @@ var DbWorker = class {
|
|
|
2254
2541
|
const value = values[index];
|
|
2255
2542
|
if (value === null) continue;
|
|
2256
2543
|
try {
|
|
2257
|
-
values[index] = await
|
|
2544
|
+
values[index] = await decodeStoreValueRecord(value, { strict: true });
|
|
2258
2545
|
} catch (error) {
|
|
2259
2546
|
if (!state.failed) {
|
|
2260
2547
|
state.failed = true;
|
|
@@ -2282,11 +2569,42 @@ var DbWorker = class {
|
|
|
2282
2569
|
return byStore.get(store) ?? [];
|
|
2283
2570
|
}
|
|
2284
2571
|
resolveIndexDefinition(txId, store, indexName) {
|
|
2572
|
+
if (this.txModes.get(txId) === "readonly") {
|
|
2573
|
+
const byStore = this.readonlyIndexCache.get(txId)?.get(store);
|
|
2574
|
+
if (byStore) {
|
|
2575
|
+
const cached = byStore.get(indexName);
|
|
2576
|
+
if (cached) return cached;
|
|
2577
|
+
const def = findIndexDefinition(this.indexesForStoreInTx(txId, store), store, indexName);
|
|
2578
|
+
if (!def) throw remoteError("IndexNotFoundError", `index not found: ${store}.${indexName}`);
|
|
2579
|
+
byStore.set(indexName, def);
|
|
2580
|
+
return def;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2285
2583
|
if (!this.rawStoreExistsInTx(txId, store)) throw remoteError("StoreNotFoundError", `store not found: ${store}`);
|
|
2286
2584
|
const def = findIndexDefinition(this.indexesForStoreInTx(txId, store), store, indexName);
|
|
2287
2585
|
if (!def) throw remoteError("IndexNotFoundError", `index not found: ${store}.${indexName}`);
|
|
2586
|
+
if (this.txModes.get(txId) === "readonly") getOrInsert(getOrInsert(this.readonlyIndexCache, txId, () => /* @__PURE__ */ new Map()), store, () => /* @__PURE__ */ new Map()).set(indexName, def);
|
|
2288
2587
|
return def;
|
|
2289
2588
|
}
|
|
2589
|
+
physicalIndexRange(txId, def, range) {
|
|
2590
|
+
assertValidScanRange(range);
|
|
2591
|
+
const reverse = range.reverse === true;
|
|
2592
|
+
const cached = this.indexBoundCache;
|
|
2593
|
+
if (cached !== null && cached.txId === txId && cached.def === def && cached.reverse === reverse && sameBound(cached.gt, range.gt) && sameBound(cached.gte, range.gte) && sameBound(cached.lt, range.lt) && sameBound(cached.lte, range.lte)) return cached.physical;
|
|
2594
|
+
const { limit: _ignored, ...withoutLimit } = range;
|
|
2595
|
+
const physical = indexRangeToPhysicalRange(withoutLimit);
|
|
2596
|
+
this.indexBoundCache = {
|
|
2597
|
+
txId,
|
|
2598
|
+
def,
|
|
2599
|
+
reverse,
|
|
2600
|
+
gt: copyBound(range.gt),
|
|
2601
|
+
gte: copyBound(range.gte),
|
|
2602
|
+
lt: copyBound(range.lt),
|
|
2603
|
+
lte: copyBound(range.lte),
|
|
2604
|
+
physical
|
|
2605
|
+
};
|
|
2606
|
+
return physical;
|
|
2607
|
+
}
|
|
2290
2608
|
indexSchemaForTx(txId) {
|
|
2291
2609
|
const override = this.txIndexSchemas.get(txId);
|
|
2292
2610
|
if (override) return override;
|
|
@@ -2466,7 +2784,10 @@ var DbWorker = class {
|
|
|
2466
2784
|
if (physicalKey.byteLength > MAX_ENGINE_KEY_BYTES) throw remoteError("KeyTooLargeError", `index key too large for ${def.store}.${def.name}`);
|
|
2467
2785
|
return physicalKey;
|
|
2468
2786
|
}
|
|
2469
|
-
|
|
2787
|
+
assertIndexEntryKeySize(def, logicalKey, primaryKey) {
|
|
2788
|
+
if (compoundEntryKeyLength(logicalKey, primaryKey) > MAX_ENGINE_KEY_BYTES) throw remoteError("KeyTooLargeError", `index key too large for ${def.store}.${def.name}`);
|
|
2789
|
+
}
|
|
2790
|
+
async assertUniqueIndexAvailability(txId, def, logicalKey, primaryKey, knownCompression) {
|
|
2470
2791
|
if (!def.unique) return;
|
|
2471
2792
|
const physical = indexKeyExactRange(logicalKey);
|
|
2472
2793
|
let cursor = null;
|
|
@@ -2491,7 +2812,7 @@ var DbWorker = class {
|
|
|
2491
2812
|
continue;
|
|
2492
2813
|
}
|
|
2493
2814
|
if (state === "trusted") throw remoteError("UniqueIndexConstraintError", `unique index constraint violation on ${def.store}.${def.name}`);
|
|
2494
|
-
const value = await this.readStoreValue(txId, def.store, decoded.primaryKey);
|
|
2815
|
+
const value = await this.readStoreValue(txId, def.store, decoded.primaryKey, knownCompression);
|
|
2495
2816
|
if (value === null) {
|
|
2496
2817
|
this.cleanupStaleIndexRow(txId, def, row.key);
|
|
2497
2818
|
continue;
|
|
@@ -2512,10 +2833,11 @@ var DbWorker = class {
|
|
|
2512
2833
|
* chunks prevent stale entries from forcing the whole range into memory.
|
|
2513
2834
|
* The output limit counts only live rows.
|
|
2514
2835
|
*/
|
|
2515
|
-
async loadVisibleIndexPage(txId, def, range, cursor, limit, maxBytes = INDEX_SCAN_PAGE_BYTES) {
|
|
2836
|
+
async loadVisibleIndexPage(txId, def, range, cursor, limit, maxBytes = INDEX_SCAN_PAGE_BYTES, physicalRange) {
|
|
2516
2837
|
const { limit: _ignored, ...withoutLimit } = range;
|
|
2517
|
-
const physical = indexRangeToPhysicalRange(withoutLimit);
|
|
2838
|
+
const physical = physicalRange ?? indexRangeToPhysicalRange(withoutLimit);
|
|
2518
2839
|
const reverse = physical.reverse === true;
|
|
2840
|
+
const compression = this.storeCompressionForTx(txId, def.store);
|
|
2519
2841
|
let resumeAfter = cursor;
|
|
2520
2842
|
const visible = [];
|
|
2521
2843
|
let outputBytes = 4;
|
|
@@ -2554,9 +2876,10 @@ var DbWorker = class {
|
|
|
2554
2876
|
batchStart = index;
|
|
2555
2877
|
batch = this.readIndexPrimaryValues(txId, def, rawRows, index, Math.min(rawRows.length, index + limit - visible.length), maxBytes - outputBytes);
|
|
2556
2878
|
batchEnd = index + (batch?.entries.length ?? 1);
|
|
2879
|
+
if (batch && compression !== false) this.stabilizeWasmValues(batch.values);
|
|
2557
2880
|
}
|
|
2558
2881
|
const row = rawRows[index];
|
|
2559
|
-
const resolved = batch ? await this.resolveVisibleIndexedValue(txId, def, row.key, batch.entries[index - batchStart], batch.values[index - batchStart], batch.trusted[index - batchStart]) : await this.
|
|
2882
|
+
const resolved = batch ? await this.resolveVisibleIndexedValue(txId, def, row.key, batch.entries[index - batchStart], batch.values[index - batchStart], batch.trusted[index - batchStart], compression, true) : await this.visibleIndexedRow(txId, def, row.key, compression);
|
|
2560
2883
|
if (batch !== null) batch.values[index - batchStart] = null;
|
|
2561
2884
|
if (!resolved) {
|
|
2562
2885
|
resumeAfter = row.key;
|
|
@@ -2576,7 +2899,7 @@ var DbWorker = class {
|
|
|
2576
2899
|
resumeAfter = row.key;
|
|
2577
2900
|
if (visible.length >= limit) return {
|
|
2578
2901
|
rows: visible,
|
|
2579
|
-
cursor: row.key
|
|
2902
|
+
cursor: row.key
|
|
2580
2903
|
};
|
|
2581
2904
|
}
|
|
2582
2905
|
if (rawRows.length < chunkLimit) return {
|
|
@@ -2649,7 +2972,13 @@ var DbWorker = class {
|
|
|
2649
2972
|
trusted
|
|
2650
2973
|
};
|
|
2651
2974
|
}
|
|
2652
|
-
|
|
2975
|
+
stabilizeWasmValues(values) {
|
|
2976
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
2977
|
+
const value = values[index];
|
|
2978
|
+
if (value !== null) values[index] = normalizeWasmBytes(value);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
visibleIndexedRow(txId, def, physicalKey, compression) {
|
|
2653
2982
|
const decoded = decodeIndexEntryKey(physicalKey);
|
|
2654
2983
|
const state = this.inspectIndexedValue(txId, def, physicalKey, decoded.primaryKey);
|
|
2655
2984
|
if (state === "missing") {
|
|
@@ -2657,14 +2986,18 @@ var DbWorker = class {
|
|
|
2657
2986
|
return null;
|
|
2658
2987
|
}
|
|
2659
2988
|
const value = this.readRawValue(txId, def.store, decoded.primaryKey);
|
|
2660
|
-
return this.resolveVisibleIndexedValue(txId, def, physicalKey, decoded, value, state === "trusted");
|
|
2989
|
+
return this.resolveVisibleIndexedValue(txId, def, physicalKey, decoded, value, state === "trusted", compression, true);
|
|
2661
2990
|
}
|
|
2662
|
-
|
|
2991
|
+
resolveVisibleIndexedValue(txId, def, physicalKey, decoded, rawValue, trusted = false, compression, stable) {
|
|
2663
2992
|
if (rawValue === null) {
|
|
2664
2993
|
this.cleanupStaleIndexRow(txId, def, physicalKey);
|
|
2665
2994
|
return null;
|
|
2666
2995
|
}
|
|
2667
|
-
const
|
|
2996
|
+
const bytes = stable ? rawValue : normalizeWasmBytes(rawValue);
|
|
2997
|
+
if (compression === false) return this.finishVisibleIndexedValue(txId, def, physicalKey, decoded, bytes, trusted);
|
|
2998
|
+
return decodeStoreValueRecord(bytes, { strict: true }).then((value) => this.finishVisibleIndexedValue(txId, def, physicalKey, decoded, value, trusted));
|
|
2999
|
+
}
|
|
3000
|
+
finishVisibleIndexedValue(txId, def, physicalKey, decoded, value, trusted) {
|
|
2668
3001
|
if (!trusted) {
|
|
2669
3002
|
const currentLogicalKey = extractLogicalIndexKey(def, value);
|
|
2670
3003
|
if (currentLogicalKey === null || !bytesEqual(currentLogicalKey, decoded.logicalKey)) {
|
|
@@ -2718,6 +3051,8 @@ var DbWorker = class {
|
|
|
2718
3051
|
this.txChanges.clear();
|
|
2719
3052
|
this.txModes.clear();
|
|
2720
3053
|
this.txIndexSchemas.clear();
|
|
3054
|
+
this.readonlyIndexCache.clear();
|
|
3055
|
+
this.indexBoundCache = null;
|
|
2721
3056
|
this.txEnsuredRawStores.clear();
|
|
2722
3057
|
this.txIndexSchemaChanged.clear();
|
|
2723
3058
|
this.txStoreCompression.clear();
|