diff --git a/libs/shared/database/README.md b/libs/shared/database/README.md index 11baaffb9..d9fe92911 100644 --- a/libs/shared/database/README.md +++ b/libs/shared/database/README.md @@ -66,7 +66,8 @@ The #1580 index-ordering fix is included in 0.24 through PR #1550. `src/lib/connection-upgrades.spec.ts` exercises `initDatabase()` with real SQLite under the Electron runtime, using fresh-install schema snapshots from tags 0.19–0.23 and a fresh current database. The `epg_channel_id` column is absent -in 0.19, present from 0.20, and indexed from 0.23. Each case checks preserved user +in 0.19, present from 0.20, and indexed from 0.23. Each case checks current Drizzle +tables, columns/types, and named indexes/uniqueness, as well as preserved user rows, foreign keys, database integrity, index availability, and repeated startup; an existing EPG index must keep its definition and root page. Snapshots live in `src/lib/testing/fixtures/` and are independent of the current schema, so moving diff --git a/libs/shared/database/src/lib/testing/connection-upgrade.ts b/libs/shared/database/src/lib/testing/connection-upgrade.ts index 901ada471..94cdaa19a 100644 --- a/libs/shared/database/src/lib/testing/connection-upgrade.ts +++ b/libs/shared/database/src/lib/testing/connection-upgrade.ts @@ -1,7 +1,9 @@ import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import Database from 'better-sqlite3'; +import { getTableConfig } from 'drizzle-orm/sqlite-core'; import { closeDatabase, getDatabasePath, initDatabase } from '../connection'; +import * as currentSchema from '../schema'; const tables = [ 'playlists', @@ -54,6 +56,38 @@ function epgIndex(sqlite: Database.Database) { .get(); } +function verifyCurrentSchema(sqlite: Database.Database) { + for (const table of Object.values(currentSchema)) { + const { name, columns, indexes } = getTableConfig(table); + const actualColumns = sqlite.pragma(`table_info(${name})`) as { + name: string; + type: string; + }[]; + assert(actualColumns.length > 0, `Missing current table: ${name}`); + for (const column of columns) { + const actual = actualColumns.find( + (item) => item.name === column.name + ); + assert(actual, `Missing current column: ${name}.${column.name}`); + assert.equal( + actual.type.toLowerCase(), + column.getSQLType().toLowerCase() + ); + } + const actualIndexes = sqlite.pragma(`index_list(${name})`) as { + name: string; + unique: number; + }[]; + for (const { config } of indexes) { + const actual = actualIndexes.find( + (item) => item.name === config.name + ); + assert(actual, `Missing current index: ${config.name}`); + assert.equal(actual.unique, Number(config.unique), config.name); + } + } +} + async function main() { const fixture = process.argv[2]; assert( @@ -83,6 +117,7 @@ async function main() { await initDatabase(); const sqlite = new Database(databasePath, { readonly: true }); try { + verifyCurrentSchema(sqlite); for (const { query, rows } of before) { assert.deepEqual(sqlite.prepare(query).all(), rows, query); }