| 1 | import { DatabaseSync } from 'node:sqlite';
|
| 2 | import type { AuditStore } from '../../core/src/index.js';
|
| 3 |
|
| 4 | export * from './hosted.js';
|
| 5 |
|
| 6 | export class SqliteAuditStore implements AuditStore {
|
| 7 | private db: DatabaseSync;
|
| 8 | constructor(path = 'openclasp.db') {
|
| 9 | this.db = new DatabaseSync(path);
|
| 10 | this.db.exec(`
|
| 11 | PRAGMA journal_mode=WAL;
|
| 12 | CREATE TABLE IF NOT EXISTS audit_records (
|
| 13 | kind TEXT NOT NULL, id TEXT NOT NULL, value TEXT NOT NULL, created_at TEXT NOT NULL,
|
| 14 | PRIMARY KEY (kind, id)
|
| 15 | );
|
| 16 | `);
|
| 17 | }
|
| 18 | append(kind: string, id: string, value: unknown): void {
|
| 19 | const encoded = JSON.stringify(value);
|
| 20 | const row = this.db
|
| 21 | .prepare('SELECT value FROM audit_records WHERE kind=? AND id=?')
|
| 22 | .get(kind, id) as { value: string } | undefined;
|
| 23 | if (row && row.value !== encoded) throw new Error(`Conflicting duplicate ${kind}:${id}`);
|
| 24 | if (!row)
|
| 25 | this.db
|
| 26 | .prepare('INSERT INTO audit_records(kind,id,value,created_at) VALUES(?,?,?,?)')
|
| 27 | .run(kind, id, encoded, new Date().toISOString());
|
| 28 | }
|
| 29 | list(kind: string): unknown[] {
|
| 30 | return (
|
| 31 | this.db
|
| 32 | .prepare('SELECT value FROM audit_records WHERE kind=? ORDER BY created_at')
|
| 33 | .all(kind) as { value: string }[]
|
| 34 | ).map((row) => JSON.parse(row.value));
|
| 35 | }
|
| 36 | close(): void {
|
| 37 | this.db.close();
|
| 38 | }
|
| 39 | }
|