ryuudb
Version:
A lightweight, customizable JSON/YAML database for Node.js by Jr Busaco
110 lines (97 loc) • 3.09 kB
JavaScript
import { FileAdapter } from './adapters/file.js';
import { MemoryAdapter } from './adapters/memory.js';
import { EventEmitter } from 'events';
export default class RyuuDB extends EventEmitter {
constructor(options = {}) {
super();
this.options = {
filePath: 'db.json',
format: 'json',
adapter: 'file',
debounce: 100,
defaultData: {},
...options
};
this.data = this.options.defaultData;
this.adapter = this._createAdapter();
this.timeout = null;
this.load();
}
_createAdapter() {
if (typeof this.options.adapter === 'object') return this.options.adapter;
if (this.options.adapter === 'memory') return new MemoryAdapter();
return new FileAdapter(this.options.filePath, this.options.format);
}
async load() {
this.data = await this.adapter.read() || this.options.defaultData;
this.emit('load', this.data);
}
async save() {
await this.adapter.write(this.data);
this.emit('save', this.data);
}
debounceSave() {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => this.save(), this.options.debounce);
}
get(path) {
if (!path) return this.data;
return path.split('.').reduce((obj, key) => obj?.[key], this.data);
}
set(path, value) {
let obj = this.data;
const keys = path.split('.');
for (let i = 0; i < keys.length - 1; i++) {
obj = obj[keys[i]] = obj[keys[i]] || {};
}
obj[keys[keys.length - 1]] = value;
this.debounceSave();
this.emit('set', { path, value });
return this;
}
find(path, query) {
const arr = this.get(path);
if (!Array.isArray(arr)) return null;
if (typeof query === 'function') return arr.find(query);
return arr.find(item => Object.entries(query).every(([k, v]) => item[k] === v)) || null;
}
filter(path, query) {
const arr = this.get(path);
if (!Array.isArray(arr)) return [];
if (typeof query === 'function') return arr.filter(query);
return arr.filter(item => Object.entries(query).every(([k, v]) => item[k] === v));
}
update(path, query, updates) {
const arr = this.get(path);
if (!Array.isArray(arr)) return this;
const index = typeof query === 'function'
? arr.findIndex(query)
: arr.findIndex(item => Object.entries(query).every(([k, v]) => item[k] === v));
if (index >= 0) {
arr[index] = { ...arr[index], ...updates };
this.set(path, arr);
this.emit('update', { path, index, updates });
}
return this;
}
remove(path, query) {
const arr = this.get(path);
if (!Array.isArray(arr)) return this;
const filtered = typeof query === 'function'
? arr.filter(item => !query(item))
: arr.filter(item => !Object.entries(query).every(([k, v]) => item[k] === v));
this.set(path, filtered);
this.emit('remove', { path, query });
return this;
}
clear(path) {
if (path) {
this.set(path, {});
} else {
this.data = this.options.defaultData;
this.debounceSave();
}
this.emit('clear', { path });
return this;
}
}