SQL adjustments

This commit is contained in:
Luke Hagar
2025-08-13 12:14:30 -05:00
parent 4c1b555094
commit d10916bcbf

View File

@@ -1,31 +1,51 @@
import Database from 'better-sqlite3'; import Database from 'better-sqlite3';
import fs from 'fs';
import path from 'path';
import type { StorageAdapter } from './types.js'; import type { StorageAdapter } from './types.js';
export class SQLiteStorage implements StorageAdapter { export class SQLiteStorage implements StorageAdapter {
private db: Database.Database | null = null; private db: Database.Database | null = null;
async init(dbPath: string): Promise<void> { async init(dbFilePath: string): Promise<void> {
this.db = new Database(dbPath); const resolvedPath = path.resolve(dbFilePath);
this.db.pragma('journal_mode = WAL'); const dir = path.dirname(resolvedPath);
this.db.exec(` try {
CREATE TABLE IF NOT EXISTS har_entries ( if (!fs.existsSync(dir)) {
id INTEGER PRIMARY KEY AUTOINCREMENT, fs.mkdirSync(dir, { recursive: true });
startedDateTime TEXT NOT NULL, }
time INTEGER NOT NULL, } catch {}
request TEXT NOT NULL,
response TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_har_started ON har_entries(startedDateTime);
CREATE TABLE IF NOT EXISTS endpoints ( // Open or create database
id INTEGER PRIMARY KEY AUTOINCREMENT, this.db = new Database(resolvedPath);
path TEXT NOT NULL, this.db.pragma('journal_mode = WAL');
method TEXT NOT NULL, try {
data TEXT NOT NULL, this.db.exec(`
UNIQUE(path, method) CREATE TABLE IF NOT EXISTS har_entries (
); id INTEGER PRIMARY KEY AUTOINCREMENT,
CREATE INDEX IF NOT EXISTS idx_endpoints_path_method ON endpoints(path, method); startedDateTime TEXT NOT NULL,
`); time INTEGER NOT NULL,
request TEXT NOT NULL,
response TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_har_started ON har_entries(startedDateTime);
CREATE TABLE IF NOT EXISTS endpoints (
id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT NOT NULL,
method TEXT NOT NULL,
data TEXT NOT NULL,
UNIQUE(path, method)
);
CREATE INDEX IF NOT EXISTS idx_endpoints_path_method ON endpoints(path, method);
`);
} catch (e) {
// If schema creation fails, close DB to avoid holding a bad handle
try {
this.db.close();
} catch {}
this.db = null;
throw e;
}
} }
isReady(): boolean { isReady(): boolean {
@@ -41,53 +61,80 @@ export class SQLiteStorage implements StorageAdapter {
async saveHarEntry(entry: any): Promise<void> { async saveHarEntry(entry: any): Promise<void> {
if (!this.db) return; if (!this.db) return;
const stmt = this.db.prepare( try {
'INSERT INTO har_entries (startedDateTime, time, request, response) VALUES (?, ?, ?, ?)' const stmt = this.db.prepare(
); 'INSERT INTO har_entries (startedDateTime, time, request, response) VALUES (?, ?, ?, ?)'
stmt.run( );
entry.startedDateTime, stmt.run(
entry.time, entry.startedDateTime,
JSON.stringify(entry.request), entry.time,
JSON.stringify(entry.response) JSON.stringify(entry.request ?? {}),
); JSON.stringify(entry.response ?? {})
);
} catch {}
} }
async getHarLog(): Promise<any> { async getHarLog(): Promise<any> {
if (!this.db) return { log: { version: '1.2', creator: { name: 'Arbiter', version: '1.0.0' }, entries: [] } }; const empty = { log: { version: '1.2', creator: { name: 'Arbiter', version: '1.0.0' }, entries: [] as any[] } };
const rows = this.db.prepare('SELECT startedDateTime, time, request, response FROM har_entries ORDER BY id ASC').all(); if (!this.db) return empty;
const entries = rows.map((r) => ({ try {
startedDateTime: r.startedDateTime, const rows = this.db
time: r.time, .prepare('SELECT startedDateTime, time, request, response FROM har_entries ORDER BY id ASC')
request: JSON.parse(r.request), .all();
response: JSON.parse(r.response), const entries = rows.map((r) => {
})); let req: any = {};
return { let res: any = {};
log: { try {
version: '1.2', req = JSON.parse(r.request);
creator: { name: 'Arbiter', version: '1.0.0' }, } catch {}
entries, try {
}, res = JSON.parse(r.response);
}; } catch {}
return {
startedDateTime: r.startedDateTime,
time: r.time,
request: req,
response: res,
};
});
return { log: { ...empty.log, entries } };
} catch {
return empty;
}
} }
async clearHar(): Promise<void> { async clearHar(): Promise<void> {
if (!this.db) return; if (!this.db) return;
this.db.prepare('DELETE FROM har_entries').run(); try {
this.db.prepare('DELETE FROM har_entries').run();
} catch {}
} }
async upsertEndpoint(path: string, method: string, data: any): Promise<void> { async upsertEndpoint(pathStr: string, method: string, data: any): Promise<void> {
if (!this.db) return; if (!this.db) return;
const stmt = this.db.prepare( try {
'INSERT INTO endpoints (path, method, data) VALUES (?, ?, ?) const stmt = this.db.prepare(
ON CONFLICT(path, method) DO UPDATE SET data=excluded.data' `INSERT INTO endpoints (path, method, data) VALUES (?, ?, ?)
); ON CONFLICT(path, method) DO UPDATE SET data=excluded.data`
stmt.run(path, method.toLowerCase(), JSON.stringify(data)); );
stmt.run(pathStr, method.toLowerCase(), JSON.stringify(data ?? {}));
} catch {}
} }
async getAllEndpoints(): Promise<Array<{ path: string; method: string; data: any }>> { async getAllEndpoints(): Promise<Array<{ path: string; method: string; data: any }>> {
if (!this.db) return []; if (!this.db) return [];
const rows = this.db.prepare('SELECT path, method, data FROM endpoints').all(); try {
return rows.map((r) => ({ path: r.path, method: r.method, data: JSON.parse(r.data) })); const rows = this.db.prepare('SELECT path, method, data FROM endpoints').all();
return rows.map((r) => {
let data: any = {};
try {
data = JSON.parse(r.data);
} catch {}
return { path: r.path, method: r.method, data };
});
} catch {
return [];
}
} }
} }