Replace all db.run(sql, [params]) calls with db.prepare(sql).run(...params) across all source modules and test files. Also remove the node-sqlite3-wasm import from tests/db.test.ts and update the type annotation accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
152 lines
5.1 KiB
TypeScript
152 lines
5.1 KiB
TypeScript
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
import type Database from 'better-sqlite3';
|
|
import { initDb, closeDb } from '../src/db/index';
|
|
|
|
let db: InstanceType<typeof Database>;
|
|
|
|
beforeAll(() => {
|
|
db = initDb(':memory:');
|
|
});
|
|
|
|
afterAll(() => {
|
|
closeDb();
|
|
});
|
|
|
|
describe('Database initialization', () => {
|
|
it('should enable WAL or memory journal mode (WAL for file, memory for :memory:)', () => {
|
|
const result = db.prepare('PRAGMA journal_mode').get() as { journal_mode: string };
|
|
// :memory: databases use 'memory' journal mode, file DBs use 'wal'
|
|
expect(['wal', 'memory']).toContain(result.journal_mode);
|
|
});
|
|
|
|
it('should enable foreign keys', () => {
|
|
const result = db.prepare('PRAGMA foreign_keys').get() as { foreign_keys: number };
|
|
expect(result.foreign_keys).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('Table creation', () => {
|
|
const expectedTables = [
|
|
'users',
|
|
'mqtt_brokers',
|
|
'mqtt_topics',
|
|
'pg_sources',
|
|
'pg_queries',
|
|
'datapoints',
|
|
'layouts',
|
|
'layout_elements',
|
|
'displays',
|
|
];
|
|
|
|
it('should create all 9 tables', () => {
|
|
const tables = db
|
|
.prepare(`SELECT name FROM sqlite_master WHERE type='table' ORDER BY name`)
|
|
.all() as Array<{ name: string }>;
|
|
const tableNames = tables.map((t) => t.name);
|
|
|
|
for (const expected of expectedTables) {
|
|
expect(tableNames).toContain(expected);
|
|
}
|
|
expect(tableNames.filter((n) => !n.startsWith('sqlite_')).length).toBe(9);
|
|
});
|
|
|
|
it('should create users table with correct columns', () => {
|
|
const cols = db.prepare('PRAGMA table_info(users)').all() as Array<{ name: string }>;
|
|
const colNames = cols.map((c) => c.name);
|
|
expect(colNames).toContain('id');
|
|
expect(colNames).toContain('username');
|
|
expect(colNames).toContain('password_hash');
|
|
expect(colNames).toContain('created_at');
|
|
});
|
|
|
|
it('should create mqtt_brokers table with correct columns', () => {
|
|
const cols = db.prepare('PRAGMA table_info(mqtt_brokers)').all() as Array<{ name: string }>;
|
|
const colNames = cols.map((c) => c.name);
|
|
expect(colNames).toContain('id');
|
|
expect(colNames).toContain('name');
|
|
expect(colNames).toContain('host');
|
|
expect(colNames).toContain('port');
|
|
expect(colNames).toContain('use_tls');
|
|
expect(colNames).toContain('enabled');
|
|
expect(colNames).toContain('status');
|
|
});
|
|
|
|
it('should create datapoints table with source_type CHECK constraint columns', () => {
|
|
const cols = db.prepare('PRAGMA table_info(datapoints)').all() as Array<{ name: string }>;
|
|
const colNames = cols.map((c) => c.name);
|
|
expect(colNames).toContain('source_type');
|
|
expect(colNames).toContain('source_id');
|
|
expect(colNames).toContain('topic_id');
|
|
expect(colNames).toContain('query_id');
|
|
expect(colNames).toContain('transform');
|
|
});
|
|
|
|
it('should create layout_elements with all required columns', () => {
|
|
const cols = db.prepare('PRAGMA table_info(layout_elements)').all() as Array<{ name: string }>;
|
|
const colNames = cols.map((c) => c.name);
|
|
expect(colNames).toContain('layout_id');
|
|
expect(colNames).toContain('datapoint_id');
|
|
expect(colNames).toContain('type');
|
|
expect(colNames).toContain('x');
|
|
expect(colNames).toContain('y');
|
|
expect(colNames).toContain('font_size');
|
|
expect(colNames).toContain('style');
|
|
});
|
|
});
|
|
|
|
describe('Broker insert and retrieve', () => {
|
|
it('should insert and retrieve a broker', () => {
|
|
const result = db.prepare(
|
|
`INSERT INTO mqtt_brokers (name, host, port) VALUES (?, ?, ?)`
|
|
).run('Test Broker', 'mqtt.example.com', 1883);
|
|
expect(result.lastInsertRowid).toBeGreaterThan(0);
|
|
|
|
const broker = db
|
|
.prepare(`SELECT * FROM mqtt_brokers WHERE id = ?`)
|
|
.get(result.lastInsertRowid) as {
|
|
name: string;
|
|
host: string;
|
|
port: number;
|
|
status: string;
|
|
} | undefined;
|
|
|
|
expect(broker).toBeDefined();
|
|
expect(broker!.name).toBe('Test Broker');
|
|
expect(broker!.host).toBe('mqtt.example.com');
|
|
expect(broker!.port).toBe(1883);
|
|
expect(broker!.status).toBe('disconnected');
|
|
});
|
|
|
|
it('should cascade delete topics when broker is deleted', () => {
|
|
const broker = db.prepare(`INSERT INTO mqtt_brokers (name, host) VALUES (?, ?)`).run(
|
|
'Cascade Broker',
|
|
'cascade.example.com',
|
|
);
|
|
|
|
db.prepare(`INSERT INTO mqtt_topics (broker_id, topic) VALUES (?, ?)`).run(
|
|
broker.lastInsertRowid,
|
|
'sensors/temp',
|
|
);
|
|
|
|
const topicsBefore = db
|
|
.prepare(`SELECT * FROM mqtt_topics WHERE broker_id = ?`)
|
|
.all(broker.lastInsertRowid);
|
|
expect(topicsBefore.length).toBe(1);
|
|
|
|
db.prepare(`DELETE FROM mqtt_brokers WHERE id = ?`).run(broker.lastInsertRowid);
|
|
|
|
const topicsAfter = db
|
|
.prepare(`SELECT * FROM mqtt_topics WHERE broker_id = ?`)
|
|
.all(broker.lastInsertRowid);
|
|
expect(topicsAfter.length).toBe(0);
|
|
});
|
|
|
|
it('should reject invalid source_type values', () => {
|
|
expect(() => {
|
|
db.prepare(
|
|
`INSERT INTO datapoints (name, label, source_type, source_id) VALUES (?, ?, ?, ?)`
|
|
).run('dp1', 'Datapoint 1', 'invalid_source', 1);
|
|
}).toThrow();
|
|
});
|
|
});
|