import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import Database from 'better-sqlite3'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; import { runMigrations } from './migrate.js'; describe('migrate: notes tables', () => { let tmpRoot: string; let db: Database.Database; beforeEach(() => { tmpRoot = mkdtempSync(join(tmpdir(), 'migrate-notes-test-')); db = new Database(join(tmpRoot, 'test.db')); }); afterEach(() => { db.close(); rmSync(tmpRoot, { recursive: true, force: true }); }); it('creates note_index, note_subscriptions, pending_reindex, note_index_fts', () => { runMigrations(db); const tables = db // FTS5 virtual tables appear as type='table' in sqlite_master, not 'virtual'. .prepare("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name") .all() .map((r: any) => r.name); expect(tables).toContain('note_index'); expect(tables).toContain('note_subscriptions'); expect(tables).toContain('pending_reindex'); expect(tables).toContain('note_index_fts'); }); it('note_index_fts is kept in sync via triggers on note_index insert', () => { runMigrations(db); db.prepare(`INSERT INTO users (id, email) VALUES ('u1','u1@x.com')`).run(); db.prepare(` INSERT INTO note_index (owner_id, folder, file_name, title, visibility, tags_json, content_size, content_hash, updated_at, body) VALUES ('u1','cve','foo.md','CVE foo','public','["cve"]',100,'h',1,'this is the body') `).run(); const row: any = db.prepare(`SELECT title, tags, body FROM note_index_fts WHERE owner_id='u1'`).get(); expect(row.title).toBe('CVE foo'); expect(row.tags).toBe('["cve"]'); expect(row.body).toBe('this is the body'); }); it('CASCADE deletes note_index rows when user is deleted', () => { runMigrations(db); db.prepare(`INSERT INTO users (id, email) VALUES ('u1','u1@x.com')`).run(); db.prepare(` INSERT INTO note_index (owner_id, folder, file_name, visibility, updated_at, content_size, content_hash, body) VALUES ('u1','f','x.md','private',1,0,'h','') `).run(); db.prepare(`DELETE FROM users WHERE id='u1'`).run(); const count: any = db.prepare(`SELECT COUNT(*) c FROM note_index WHERE owner_id='u1'`).get(); expect(count.c).toBe(0); }); });