1
0

only reinsert all sessions if necessary

The purpose of this is data safety. If there ever was a broken model
that corrupted data previously it would have ruined everything if it
coincided with a schema migration. Now this is much less likely.
This commit is contained in:
Adrian Wannenmacher 2026-02-28 18:23:48 +01:00
parent 53e3b2539a
commit b5ead20f0b
Signed by: tfld
GPG Key ID: 19D986ECB1E492D5
2 changed files with 49 additions and 37 deletions

View File

@ -142,13 +142,18 @@ export default class WbDb extends EventTarget {
target: { result: db, transaction: trans }, target: { result: db, transaction: trans },
} = event; } = event;
let reinsertAll = false;
if (old < 1 && now >= 1) if (old < 1 && now >= 1)
this.#version1(db, trans); this.#version1(db, trans);
if (old < 2 && now >= 2) if (old < 2 && now >= 2) {
this.#version2(db, trans); this.#version2(db, trans);
reinsertAll = true;
}
// update existing data to be visible in indexes // update existing data to be visible in indexes
SessionRepo.reinsertAll(trans); if (reinsertAll)
SessionRepo.reinsertAll(trans);
} }
/** Handle the `error` event from opening the DB. /** Handle the `error` event from opening the DB.

View File

@ -133,44 +133,51 @@ export default function() {
assert.true(second.failed, "second instance failed"); assert.true(second.failed, "second instance failed");
}); });
QUnit.test("sessions are reinserted after upgrade", async function(assert) { QUnit.test.each(
let first = WbDb.get(true, 1); "sessions are reinserted after upgrade",
await waitForChange(first); [{ before: 1, after: 2, reinsert: true }],
first async function(assert, input) {
.db let first = WbDb.get(true, input.before);
.transaction([WbDb.OS_SESSIONS], "readwrite") await waitForChange(first);
.objectStore(WbDb.OS_SESSIONS) first
.put({
goal: 3,
ourTeam: "",
theirTeam: "",
games: [],
currentGame: null,
});
first.db.close();
inst = WbDb.get(true, 2);
await waitForChange();
let sessions = (await new Promise(function (resolve) {
inst
.db .db
.transaction([WbDb.OS_SESSIONS], "readonly") .transaction([WbDb.OS_SESSIONS], "readwrite")
.objectStore(WbDb.OS_SESSIONS) .objectStore(WbDb.OS_SESSIONS)
.index(WbDb.IDX_SESSIONS_UPDATED) .put({
.getAll() goal: 3,
.onsuccess = resolve; ourTeam: "",
})).target.result; theirTeam: "",
assert.strictEqual(sessions.length, 1, "session found by update index"); games: [],
currentGame: null,
});
first.db.close();
// Note that the inserted session data is older than the `updated` field inst = WbDb.get(true, input.after);
// in the model class. Thus it being present in the index proves that await waitForChange();
// the session has indeed been parsed and reinserted. let sessions = (await new Promise(function (resolve) {
// inst
// Also note that the exact parsing and default value adding is already .db
// checked in the model tests, thus it would be a duplicate to test that .transaction([WbDb.OS_SESSIONS], "readonly")
// here too. .objectStore(WbDb.OS_SESSIONS)
}); .index(WbDb.IDX_SESSIONS_UPDATED)
.getAll()
.onsuccess = resolve;
})).target.result;
if (input.reinsert)
assert.strictEqual(sessions.length, 1, "session found via index");
else
assert.strictEqual(sessions.length, 0, "session not in index");
// Note that the inserted session data is older than the `updated` field
// in the model class. Thus it being present in the index proves that
// the session has indeed been parsed and reinserted.
//
// Also note that the exact parsing and default value adding is already
// checked in the model tests, thus it would be a duplicate to test that
// here too.
}
);
QUnit.test("schema version 1", async function(assert) { QUnit.test("schema version 1", async function(assert) {
inst = WbDb.get(true, 1); inst = WbDb.get(true, 1);