/home/techb158/cosmic.abdallabala.com/src/storage
Edit: /home/techb158/cosmic.abdallabala.com/src/storage/jsonDatabase.js (3473B)
const fs = require("fs");
const path = require("path");
class JsonDatabase {
constructor(filePath) {
if (!filePath) throw new Error("JsonDatabase requires a file path");
this.filePath = filePath;
}
read() {
if (!fs.existsSync(this.filePath)) {
throw new Error(`Database file not found: ${this.filePath}`);
}
return JSON.parse(fs.readFileSync(this.filePath, "utf8"));
}
write(database) {
const directory = path.dirname(this.filePath);
if (!fs.existsSync(directory)) fs.mkdirSync(directory, { recursive: true });
const tempFile = `${this.filePath}.tmp`;
const payload = JSON.stringify(database, null, 2);
fs.writeFileSync(tempFile, `${payload}\n`, "utf8");
fs.renameSync(tempFile, this.filePath);
return database;
}
transaction(callback) {
const database = this.read();
const result = callback(database);
this.write(database);
return result;
}
}
function nowIso() {
return new Date().toISOString();
}
function clone(value) {
return JSON.parse(JSON.stringify(value));
}
function getTable(database, tableName) {
if (!database.tables) database.tables = {};
if (!Array.isArray(database.tables[tableName])) database.tables[tableName] = [];
return database.tables[tableName];
}
function list(database, tableName, predicate = () => true) {
return getTable(database, tableName).filter(predicate).map(clone);
}
function findById(database, tableName, id) {
const row = getTable(database, tableName).find(item => item.id === id);
return row ? clone(row) : null;
}
function nextId(prefix) {
const random = Math.random().toString(36).slice(2, 8).toUpperCase();
return `${prefix}-${Date.now().toString(36).toUpperCase()}-${random}`;
}
function insert(database, tableName, row, prefix) {
const table = getTable(database, tableName);
const timestamp = nowIso();
const record = Object.assign({}, row, {
id: row.id || nextId(prefix || tableName.toUpperCase()),
created_at: row.created_at || timestamp,
updated_at: row.updated_at || timestamp
});
if (table.some(item => item.id === record.id)) {
throw new Error(`${tableName} already contains id ${record.id}`);
}
table.push(record);
return clone(record);
}
function update(database, tableName, id, patch) {
const table = getTable(database, tableName);
const index = table.findIndex(item => item.id === id);
if (index === -1) return null;
const updated = Object.assign({}, table[index], patch, { updated_at: nowIso() });
table[index] = updated;
return clone(updated);
}
function remove(database, tableName, id) {
const table = getTable(database, tableName);
const index = table.findIndex(item => item.id === id);
if (index === -1) return false;
table.splice(index, 1);
return true;
}
function audit(database, event) {
const timestamp = nowIso();
return insert(database, "audit_events", Object.assign({
project_id: event.project_id || "unknown",
actor_user_id: event.actor_user_id || "system",
entity_type: event.entity_type,
entity_id: event.entity_id,
action: event.action,
before_json: event.before_json ? JSON.stringify(event.before_json) : null,
after_json: event.after_json ? JSON.stringify(event.after_json) : null,
created_at: timestamp,
updated_at: timestamp
}, event), "AUDIT");
}
module.exports = {
JsonDatabase,
nowIso,
clone,
getTable,
list,
findById,
insert,
update,
remove,
audit,
nextId
};