diff --git a/data/db.js b/data/db.js index 62b4820..ec8266b 100644 --- a/data/db.js +++ b/data/db.js @@ -1,5 +1,7 @@ "use strict"; +import SessionRepo from "/data/session_repo.js"; + /** A wrapper around an IndexedDB. * * This wrapper handles the following tasks: @@ -19,10 +21,12 @@ export default class WbDb extends EventTarget { /** The name of the test `IDBDatabase`. */ static get DB_NAME_TEST() { return "test-watterblock"; } /** The currently correct DB version. */ - static get DB_VERSION() { return 1; } + static get DB_VERSION() { return 2; } /** The name of the `IDBObjectStore` for `Session`s. */ static get OS_SESSIONS() { return "sessions"; } + /** The name of the `IDBIndex` for the `Session` update time. */ + static get IDX_SESSIONS_UPDATED() { return "sessions-updated"; } /** Whether the WbDb constructor may be called. */ static #mayConstruct = false; @@ -140,6 +144,11 @@ export default class WbDb extends EventTarget { if (old < 1 && now >= 1) this.#version1(db, trans); + if (old < 2 && now >= 2) + this.#version2(db, trans); + + // update existing data to be visible in indexes + SessionRepo.reinsertAll(trans); } /** Handle the `error` event from opening the DB. @@ -172,4 +181,14 @@ export default class WbDb extends EventTarget { autoIncrement: true, }); } + + /** Do the migration for db version 2. + * @param {IDBDatabase} db The db to upgrade. + * @param {IDBTransaction} trans The db transaction. + */ + #version2(db, trans) { + trans + .objectStore(WbDb.OS_SESSIONS) + .createIndex(WbDb.IDX_SESSIONS_UPDATED, "updated"); + } } diff --git a/data/db.test.js b/data/db.test.js index 672cc89..8fb8d06 100644 --- a/data/db.test.js +++ b/data/db.test.js @@ -133,6 +133,45 @@ export default function() { assert.true(second.failed, "second instance failed"); }); + QUnit.test("sessions are reinserted after upgrade", async function(assert) { + let first = WbDb.get(true, 1); + await waitForChange(first); + first + .db + .transaction([WbDb.OS_SESSIONS], "readwrite") + .objectStore(WbDb.OS_SESSIONS) + .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 + .transaction([WbDb.OS_SESSIONS], "readonly") + .objectStore(WbDb.OS_SESSIONS) + .index(WbDb.IDX_SESSIONS_UPDATED) + .getAll() + .onsuccess = resolve; + })).target.result; + assert.strictEqual(sessions.length, 1, "session found by update 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) { inst = WbDb.get(true, 1); await waitForChange(); @@ -149,5 +188,32 @@ export default function() { assert.true(sessions.autoIncrement, "sessions autoIncrement"); assert.strictEqual(sessions.indexNames.length, 0, "sessions no indexes"); }); + + QUnit.test("schema version 2", async function(assert) { + inst = WbDb.get(true, 2); + await waitForChange(); + assert.true(inst.open, "db is opened"); + assert.strictEqual(inst.db.version, 2, "db is version 2"); + + let osn = inst.db.objectStoreNames; + assert.strictEqual(osn.length, 1, "correct number of object stores"); + assert.true(osn.contains(WbDb.OS_SESSIONS), "contains sessions"); + + let trans = inst.db.transaction(osn); + + let sessions = trans.objectStore(WbDb.OS_SESSIONS); + assert.strictEqual(sessions.keyPath, "id", "sessions keyPath"); + assert.true(sessions.autoIncrement, "sessions autoIncrement"); + assert.strictEqual(sessions.indexNames.length, 1, "sessions one index"); + + assert.true( + sessions.indexNames.contains(WbDb.IDX_SESSIONS_UPDATED), + "sessions contains session updated"); + let sessionsUpdated = sessions.index(WbDb.IDX_SESSIONS_UPDATED); + assert.strictEqual( + sessionsUpdated.keyPath, "updated", "sessionsUpdated keyPath"); + assert.false(sessionsUpdated.unique, "sessionsUpdated unique"); + assert.false(sessionsUpdated.multiEntry, "sessionsUpdated multiEntry"); + }); }); }