mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 21:46:49 +00:00
0a4c6fbace
db/database.ts opened the connection as a side effect of being imported, so the moment anything reached it the database was open. index.ts had to defer loading the app until a first-boot restore was done, and nothing in the container decided when the connection opened or closed. The module now opens the connection on first use and opens nothing at import. A connection closed on purpose (a restore, the shutdown) stays closed until it is reopened, as before. The new DatabaseLifecycle provider owns the decisions: buildApp() opens through it, which also binds the ORM to later swaps (the hook attachOrm used to register) and runs the schema bootstrap in the same order as before, and the shutdown closes through it. Its file property is the one resolved database path. The module keeps every export, so the test suites that replace it with vi.mock keep working; buildDbMock gains the new openDb.
81 lines
3.0 KiB
TypeScript
81 lines
3.0 KiB
TypeScript
/**
|
|
* db/database.ts opens the connection on first use, not at import.
|
|
*
|
|
* It used to call initDb() at module load, so importing anything that reached
|
|
* it opened the database: index.ts had to defer loading the app until a
|
|
* first-boot restore had put the backup's file in place. The connection is now
|
|
* opened by its first reader (the ORM's first connect inside buildApp(), driven
|
|
* by DatabaseLifecycle), and a connection closed on purpose for a restore stays
|
|
* closed until it is reopened.
|
|
*
|
|
* The cases share the module's one connection and run in order.
|
|
*/
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
|
|
const opened = vi.hoisted(() => ({ count: 0 }));
|
|
|
|
vi.mock('../../../src/db/connection', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('../../../src/db/connection')>();
|
|
return {
|
|
...actual,
|
|
openDatabase: (...args: Parameters<typeof actual.openDatabase>) => {
|
|
opened.count++;
|
|
return actual.openDatabase(...args);
|
|
},
|
|
};
|
|
});
|
|
|
|
import { closeDb, db, getRawConnection, openDb, registerReinitializeHook, reinitialize } from '../../../src/db/database';
|
|
|
|
describe('db/database.ts connection lifecycle', () => {
|
|
it('DBOPEN-001: importing the module opens nothing', () => {
|
|
expect(opened.count).toBe(0);
|
|
});
|
|
|
|
it('DBOPEN-002: the first reader opens it once, with the pragmas applied', () => {
|
|
const handle = getRawConnection();
|
|
expect(getRawConnection()).toBe(handle);
|
|
expect(opened.count).toBe(1);
|
|
expect(handle.pragma('foreign_keys', { simple: true })).toBe(1);
|
|
expect(handle.pragma('busy_timeout', { simple: true })).toBe(5000);
|
|
// The Proxy reads through to the same handle.
|
|
expect(db.open).toBe(true);
|
|
});
|
|
|
|
it('DBOPEN-003: a connection closed on purpose stays closed instead of quietly reopening', () => {
|
|
const log = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
try {
|
|
closeDb();
|
|
} finally {
|
|
log.mockRestore();
|
|
}
|
|
expect(() => getRawConnection()).toThrow('Database connection is not available (restore in progress?)');
|
|
expect(() => db.prepare('SELECT 1')).toThrow('Database connection is not available (restore in progress?)');
|
|
expect(opened.count).toBe(1);
|
|
});
|
|
|
|
it('DBOPEN-004: openDb() reopens it, and opening an open connection is a no-op', () => {
|
|
openDb();
|
|
openDb();
|
|
expect(opened.count).toBe(2);
|
|
expect(getRawConnection().open).toBe(true);
|
|
});
|
|
|
|
it('DBOPEN-005: reinitialize() swaps in a fresh handle and then runs the registered hook', async () => {
|
|
const before = getRawConnection();
|
|
const seen: boolean[] = [];
|
|
registerReinitializeHook(async () => {
|
|
seen.push(getRawConnection() !== before && getRawConnection().open);
|
|
});
|
|
const log = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
try {
|
|
await reinitialize();
|
|
} finally {
|
|
log.mockRestore();
|
|
}
|
|
expect(before.open).toBe(false);
|
|
expect(seen).toEqual([true]);
|
|
expect(opened.count).toBe(3);
|
|
});
|
|
});
|