This commit is contained in:
Vufer 2025-02-17 21:47:50 +03:00
parent 42c4aa51cb
commit f5c3712b18

View File

@ -1,198 +0,0 @@
import fs from 'fs/promises';
import { EventEmitter } from 'events';
import { v4 as uuidv4 } from 'uuid';
class GreenBean extends EventEmitter {
constructor(dbPath = 'data.json') {
super();
this.dbPath = dbPath;
this.data = null;
this.initialized = false;
this.frozen = false;
}
// Базовые операции с бинами
async R(type, id = null) {
if (!this.initialized) await this.init();
if (id === null) {
return this.dispense(type);
}
return this.load(type, id);
}
async dispense(type) {
if (!this.initialized) await this.init();
const bean = {
id: uuidv4(),
__type: type,
__meta: {
created: new Date().toISOString(),
modified: new Date().toISOString()
}
};
return new Proxy(bean, this.createHandler(type));
}
async load(type, id) {
if (!this.initialized) await this.init();
const item = this.data[type]?.find(item => item.id === id);
if (!item) return null;
return new Proxy({...item}, this.createHandler(type));
}
async store(bean) {
if (this.frozen) throw new Error('Cannot modify frozen beans');
if (!this.initialized) await this.init();
const type = bean.__type;
if (!this.data[type]) this.data[type] = [];
bean.__meta.modified = new Date().toISOString();
const index = this.data[type].findIndex(item => item.id === bean.id);
if (index !== -1) {
this.data[type][index] = {...bean};
} else {
this.data[type].push({...bean});
}
await this.save();
return bean.id;
}
async trash(bean) {
if (this.frozen) throw new Error('Cannot modify frozen beans');
if (!this.initialized) await this.init();
const type = bean.__type;
if (!this.data[type]) return;
this.data[type] = this.data[type].filter(item => item.id !== bean.id);
await this.save();
}
// Работа со связями
async own(bean, property, related) {
if (!Array.isArray(related)) related = [related];
bean[property] = related.map(item => ({
id: item.id,
__type: item.__type
}));
await this.store(bean);
}
async link(bean, linkType, attributes = {}) {
const link = await this.dispense(linkType);
Object.assign(link, attributes, {
[`${bean.__type}Id`]: bean.id
});
await this.store(link);
return link;
}
async find(type, criteria = {}) {
if (!this.initialized) await this.init();
if (!this.data[type]) return [];
return this.data[type]
.filter(item => {
return Object.entries(criteria).every(([key, value]) =>
item[key] === value
);
})
.map(item => new Proxy({...item}, this.createHandler(type)));
}
async findOne(type, criteria = {}) {
const results = await this.find(type, criteria);
return results[0] || null;
}
// Вспомогательные методы
async init() {
try {
const exists = await fs.access(this.dbPath)
.then(() => true)
.catch(() => false);
if (exists) {
const content = await fs.readFile(this.dbPath, 'utf-8');
this.data = JSON.parse(content);
} else {
this.data = {};
}
this.initialized = true;
} catch (error) {
throw new Error(`Failed to initialize database: ${error.message}`);
}
}
async save() {
try {
const tempPath = `${this.dbPath}.tmp`;
await fs.writeFile(tempPath, JSON.stringify(this.data, null, 2));
await fs.rename(tempPath, this.dbPath);
this.emit('save');
} catch (error) {
throw new Error(`Failed to save database: ${error.message}`);
}
}
createHandler(type) {
return {
get: (target, prop) => {
if (prop.endsWith('List') && !target[prop]) {
target[prop] = [];
}
return target[prop];
},
set: (target, prop, value) => {
if (this.frozen) throw new Error('Cannot modify frozen beans');
if (prop.endsWith('List') && Array.isArray(value)) {
target[prop] = value.map(item => ({
id: item.id,
__type: item.__type || type
}));
} else {
target[prop] = value;
}
return true;
}
};
}
// Утилиты
freeze(frozen = true) {
this.frozen = frozen;
}
async nuke() {
if (this.frozen) throw new Error('Cannot nuke frozen database');
this.data = {};
await this.save();
}
async transaction(callback) {
const snapshot = JSON.stringify(this.data);
try {
const result = await callback();
await this.save();
return result;
} catch (error) {
this.data = JSON.parse(snapshot);
throw error;
}
}
}
export default GreenBean;