From 188fbbaf545f766c6012d5daaafd879b7dad862f Mon Sep 17 00:00:00 2001 From: David Fahlander Date: Mon, 5 Feb 2024 09:49:07 +0100 Subject: [PATCH] Fix issue with BigInt64Array (#1892) Resolves issue #1890 --- src/functions/utils.ts | 2 +- test/tests-misc.js | 72 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/functions/utils.ts b/src/functions/utils.ts index c9a672094..16464556a 100644 --- a/src/functions/utils.ts +++ b/src/functions/utils.ts @@ -187,7 +187,7 @@ export function flatten (a: (T | T[])[]) : T[] { //https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm const intrinsicTypeNames = - "Boolean,String,Date,RegExp,Blob,File,FileList,FileSystemFileHandle,ArrayBuffer,DataView,Uint8ClampedArray,ImageBitmap,ImageData,Map,Set,CryptoKey" + "BigInt64Array,Array,Boolean,String,Date,RegExp,Blob,File,FileList,FileSystemFileHandle,FileSystemDirectoryHandle,ArrayBuffer,DataView,Uint8ClampedArray,ImageBitmap,ImageData,Map,Set,CryptoKey" .split(',').concat( flatten([8,16,32,64].map(num=>["Int","Uint","Float"].map(t=>t+num+"Array"))) ).filter(t=>_global[t]); diff --git a/test/tests-misc.js b/test/tests-misc.js index 120b03346..c19b6982f 100644 --- a/test/tests-misc.js +++ b/test/tests-misc.js @@ -421,3 +421,75 @@ promisedTest("Issue #1333 - uniqueKeys on virtual index should produce unique re const result = await db.metrics.orderBy("name").uniqueKeys(); ok(result.length === 2, `Unexpected array length ${result.length} from uniqueKeys on virtual index, expected 2. Got ${result.join(',')}`); }); + +/** Reproduce customer issue where ReadonlyError was thrown when using liveQuery. + */ +promisedTest("Issue - ReadonlyError thrown in liveQuery despite user did not do write transactions", async () => { + // Encapsulating the code in a string to avoid transpilation. We need native await here to trigger bug. + ok(!Promise.PSD, "Must not be within async context when starting"); + ok(db.isOpen(), "DB must be open when starting"); + await new Promise(resolve => setTimeout(resolve, 10)); + const F = new Function('ok', 'equal', 'Dexie', 'db', 'liveQuery', ` + ok(true, "Got here"); + return (async ()=>{ + equal(Dexie.Promise.PSD.id, 'global', "PSD is the global PSD"); + const observable = liveQuery(async () => { + console.debug("liveQuery executing"); + const result = await db.metrics.toArray(); + //await 3; + async function foo() { + console.log("qm PSD.id = " + Dexie.Promise.PSD?.id); + await db.metrics.toArray(); + console.log("qm PSD.id = " + Dexie.Promise.PSD?.id); + } + foo(); // Be naughty and spawn promises that we don't await. + // Verify that we handle this situation and escape from zone echoing before + // we return the result. + return result; + }); + + equal(Dexie.Promise.PSD.id, 'global', "PSD is the global PSD"); + ok(true, "Now awaiting promise subscribing to liveQuery observable"); + console.log("before await in global"); + await new Promise(resolve => { + const o = observable.subscribe(val => { + o.unsubscribe(); + console.log("PSD.id = " + Dexie.Promise.PSD?.id); + resolve(val); + }); + }); + console.log("after await in global"); + console.log("Got result from observable"); + equal(Dexie.Promise.PSD.id, "global", "PSD is still the global PSD"); + await db.transaction('rw', db.metrics, () => {}); // Fails if we're in a liveQuery zone + })(); + `); + return F(ok, equal, Dexie, db, liveQuery).catch(err => ok(false, 'final catch: '+err)); +}); + + +promisedTest("Issue #1890 - BigInt64Array getting corrupted after an update", async () => { + if (typeof BigInt64Array === 'undefined') { + ok(true, "BigInt64Array not supported in browser"); + return; + } + if (typeof Dexie.Observable?.version === 'string') { + ok(true, "Skipping this test - Dexie.Observable bails out from BigInts"); + return; + } + + await db.foo.put({ + id: 1, + updated: Date.now(), + cols: [{ + values: new BigInt64Array([1n, 2n]) + }] + }); + let val = await db.foo.get(1); + ok(val.cols[0].values instanceof BigInt64Array, "cols[0].values is a BigInt64Array"); + await db.foo.update(1, { + updated: Date.now() + }); + val = await db.foo.get(1); + ok(val.cols[0].values instanceof BigInt64Array, "cols[0].values is still a BigInt64Array after update"); +});