mirror of
https://github.com/LukeHagar/arbiter.git
synced 2025-12-06 04:19:14 +00:00
SQL adjustments
This commit is contained in:
@@ -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 [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user