pre-2
This commit is contained in:
parent
42c4aa51cb
commit
f5c3712b18
198
greenbean.js~
198
greenbean.js~
@ -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;
|
|
||||||
Loading…
Reference in New Issue
Block a user