@gati-framework/runtime
Version:
Gati runtime execution engine for running handler-based applications
141 lines • 4.48 kB
JavaScript
import fs from 'fs';
import path from 'path';
export class SQLiteTimelineStore {
db;
constructor(dbPath = ':memory:') {
// Ensure directory exists if not memory
if (dbPath !== ':memory:') {
const dir = path.dirname(dbPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
try {
// Dynamic import to avoid hard dependency on better-sqlite3
const Database = require('better-sqlite3');
this.db = new Database(dbPath);
this.init();
}
catch (e) {
throw new Error('better-sqlite3 is not installed. Please install it or use JSONTimelineStore.');
}
}
init() {
this.db.exec(`
CREATE TABLE IF NOT EXISTS timeline (
id TEXT PRIMARY KEY,
timestamp INTEGER NOT NULL,
type TEXT NOT NULL,
actor TEXT NOT NULL,
payload TEXT,
diff TEXT,
parents TEXT
);
CREATE INDEX IF NOT EXISTS idx_timestamp ON timeline(timestamp);
CREATE INDEX IF NOT EXISTS idx_type_actor ON timeline(type, actor);
`);
}
async append(item) {
const stmt = this.db.prepare(`
INSERT INTO timeline (id, timestamp, type, actor, payload, diff, parents)
VALUES (?, ?, ?, ?, ?, ?, ?)
`);
stmt.run(item.id, item.timestamp, item.type, item.actor, JSON.stringify(item.payload), item.diff ? JSON.stringify(item.diff) : null, JSON.stringify(item.parents));
}
async getLatest(type, id) {
const row = this.db.prepare(`
SELECT * FROM timeline WHERE type = ? ORDER BY timestamp DESC LIMIT 1
`).get(type);
if (!row)
return null;
return this.mapRow(row);
}
async query(filter) {
let sql = 'SELECT * FROM timeline WHERE 1=1';
const params = [];
if (filter.from) {
sql += ' AND timestamp >= ?';
params.push(filter.from);
}
if (filter.to) {
sql += ' AND timestamp <= ?';
params.push(filter.to);
}
if (filter.type) {
sql += ' AND type = ?';
params.push(filter.type);
}
if (filter.actor) {
sql += ' AND actor = ?';
params.push(filter.actor);
}
sql += ' ORDER BY timestamp ASC';
const rows = this.db.prepare(sql).all(...params);
return rows.map(this.mapRow);
}
async close() {
if (this.db) {
this.db.close();
}
}
mapRow(row) {
return {
id: row.id,
timestamp: row.timestamp,
type: row.type,
actor: row.actor,
payload: JSON.parse(row.payload),
diff: row.diff ? JSON.parse(row.diff) : undefined,
parents: JSON.parse(row.parents),
};
}
}
export class JSONTimelineStore {
items = [];
filePath = null;
constructor(filePath) {
if (filePath) {
this.filePath = filePath;
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
this.items = content.trim().split('\n').map(line => JSON.parse(line));
}
}
}
async append(item) {
this.items.push(item);
if (this.filePath) {
fs.appendFileSync(this.filePath, JSON.stringify(item) + '\n');
}
}
async getLatest(type, id) {
// Simple in-memory search
for (let i = this.items.length - 1; i >= 0; i--) {
if (this.items[i].type === type) {
return this.items[i];
}
}
return null;
}
async query(filter) {
return this.items.filter(item => {
if (filter.from && item.timestamp < filter.from)
return false;
if (filter.to && item.timestamp > filter.to)
return false;
if (filter.type && item.type !== filter.type)
return false;
if (filter.actor && item.actor !== filter.actor)
return false;
return true;
});
}
async close() {
// No-op for JSON store
}
}
//# sourceMappingURL=timeline-store.js.map