diff --git a/web/database/queries/db-queries.js b/web/database/queries/db-queries.js --- a/web/database/queries/db-queries.js +++ b/web/database/queries/db-queries.js @@ -2,6 +2,8 @@ import type { SqliteDatabase } from 'sql.js'; +import { migrations } from '../utils/migrations.js'; + function getSQLiteDBVersion(db: SqliteDatabase): number { const versionData = db.exec('PRAGMA user_version;'); if (!versionData.length || !versionData[0].values.length) { @@ -16,6 +18,10 @@ return dbVersion; } +function setSQLiteDBVersion(db: SqliteDatabase, version: number) { + db.exec(`PRAGMA user_version=${version};`); +} + function setupSQLiteDB(db: SqliteDatabase) { db.exec(` CREATE TABLE IF NOT EXISTS drafts ( @@ -33,6 +39,31 @@ item TEXT NOT NULL ); `); + const migrationKeys = migrations.size ? migrations.keys() : [0]; + const newDatabaseVersion = Math.max(...migrationKeys); + setSQLiteDBVersion(db, newDatabaseVersion); +} + +function migrate(sqliteDb: SqliteDatabase): boolean { + const dbVersion = getSQLiteDBVersion(sqliteDb); + console.info(`Db version: ${dbVersion}`); + + for (const [idx, migration] of migrations.entries()) { + if (idx <= dbVersion) { + continue; + } + + try { + migration(sqliteDb); + console.log(`migration ${idx} succeeded.`); + setSQLiteDBVersion(sqliteDb, idx); + } catch (e) { + console.error(`migration ${idx} failed.`); + console.error(e); + return false; + } + } + return true; } -export { getSQLiteDBVersion, setupSQLiteDB }; +export { getSQLiteDBVersion, setupSQLiteDB, setSQLiteDBVersion, migrate }; diff --git a/web/database/sql-js.test.js b/web/database/sql-js.test.js --- a/web/database/sql-js.test.js +++ b/web/database/sql-js.test.js @@ -2,7 +2,10 @@ import initSqlJs from 'sql.js'; -import { getSQLiteDBVersion } from './queries/db-queries.js'; +import { + getSQLiteDBVersion, + setSQLiteDBVersion, +} from './queries/db-queries.js'; describe('sql.js', () => { it('should construct a Database', async () => { @@ -16,4 +19,11 @@ const db = new SQL.Database(); expect(getSQLiteDBVersion(db)).toBe(0); }); + + it('should update database version', async () => { + const SQL = await initSqlJs(); + const db = new SQL.Database(); + setSQLiteDBVersion(db, 10); + expect(getSQLiteDBVersion(db)).toBe(10); + }); }); diff --git a/web/database/utils/migrations.js b/web/database/utils/migrations.js new file mode 100644 --- /dev/null +++ b/web/database/utils/migrations.js @@ -0,0 +1,8 @@ +// @flow + +import type { SqliteDatabase } from 'sql.js'; + +const migrations: $ReadOnlyMap void> = + new Map([]); + +export { migrations }; diff --git a/web/database/worker/db-worker.js b/web/database/worker/db-worker.js --- a/web/database/worker/db-worker.js +++ b/web/database/worker/db-worker.js @@ -18,7 +18,7 @@ type WorkerRequestProxyMessage, workerWriteRequests, } from '../../types/worker-types.js'; -import { getSQLiteDBVersion, setupSQLiteDB } from '../queries/db-queries.js'; +import { migrate, setupSQLiteDB } from '../queries/db-queries.js'; import { getAllDrafts, moveDraft, @@ -91,14 +91,12 @@ console.info( 'Database exists and is properly encrypted, using persisted data', ); + migrate(sqliteDb); } else { sqliteDb = new SQL.Database(); setupSQLiteDB(sqliteDb); console.info('Creating fresh database'); } - - const dbVersion = getSQLiteDBVersion(sqliteDb); - console.info(`Db version: ${dbVersion}`); } function processDraftStoreOperations(