UNPKG

@push.rocks/smartdata

Version:

An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.

142 lines (123 loc) 4.24 kB
import * as plugins from './plugins.js'; import { Collection } from './classes.collection.js'; import { SmartdataDb } from './classes.db.js'; import { SmartDataDbDoc, svDb, unI } from './classes.doc.js'; /** * EasyStore allows the storage of easy objects. It also allows easy sharing of the object between different instances */ export class EasyStore<T> { // instance public smartdataDbRef: SmartdataDb; public nameId: string; private easyStoreClass = (() => { @Collection(() => this.smartdataDbRef) class SmartdataEasyStore extends SmartDataDbDoc<SmartdataEasyStore, SmartdataEasyStore> { @unI() public nameId!: string; @svDb() public ephemeral!: { activated: boolean; timeout: number; }; @svDb() lastEdit!: number; @svDb() public data!: Partial<T>; } return SmartdataEasyStore; })(); constructor(nameIdArg: string, smartdataDbRefArg: SmartdataDb) { this.smartdataDbRef = smartdataDbRefArg; this.nameId = nameIdArg; } private easyStorePromise?: Promise<InstanceType<typeof this.easyStoreClass>>; private async getEasyStore(): Promise<InstanceType<typeof this.easyStoreClass>> { if (this.easyStorePromise) { return this.easyStorePromise; } // first run from here const deferred = plugins.smartpromise.defer<InstanceType<typeof this.easyStoreClass>>(); this.easyStorePromise = deferred.promise; try { let easyStore = await this.easyStoreClass.getInstance({ nameId: this.nameId, }); if (!easyStore) { easyStore = new this.easyStoreClass(); easyStore.nameId = this.nameId; easyStore.data = {}; await easyStore.save(); } deferred.resolve(easyStore); } catch (error) { // settle the deferred and clear the cache so concurrent callers get the // error instead of awaiting forever, and later callers can retry this.easyStorePromise = undefined; deferred.reject(error); } return deferred.promise; } /** * reads all keyValue pairs at once and returns them */ public async readAll() { const easyStore = await this.getEasyStore(); return easyStore.data; } /** * reads a keyValueFile from disk */ public async readKey<TKey extends keyof T>(keyArg: TKey): Promise<Partial<T>[TKey]> { const easyStore = await this.getEasyStore(); return easyStore.data[keyArg]; } /** * writes a specific key to the keyValueStore */ public async writeKey<TKey extends keyof T>(keyArg: TKey, valueArg: T[TKey]) { const easyStore = await this.getEasyStore(); easyStore.data[keyArg] = valueArg; await easyStore.save(); } public async deleteKey(keyArg: keyof T) { const easyStore = await this.getEasyStore(); delete easyStore.data[keyArg]; await easyStore.save(); } /** * merges all keyValue pairs from the object argument into the store. * Existing keys that are not present in `keyValueObject` are preserved. * To overwrite the entire store and drop missing keys, use `replace()`. */ public async writeAll(keyValueObject: Partial<T>) { const easyStore = await this.getEasyStore(); easyStore.data = { ...easyStore.data, ...keyValueObject }; await easyStore.save(); } /** * atomically replaces the entire store with the given object. * Unlike `writeAll` (which merges), `replace` clears any keys not * present in `keyValueObject`. Useful when you need to drop a key. */ public async replace(keyValueObject: Partial<T>) { const easyStore = await this.getEasyStore(); easyStore.data = { ...keyValueObject }; await easyStore.save(); } /** * wipes a key value store from disk */ public async wipe() { const easyStore = await this.getEasyStore(); easyStore.data = {}; await easyStore.save(); } public async cleanUpEphemeral() { // Clean up ephemeral data periodically while connected while (this.smartdataDbRef.status === 'connected') { await plugins.smartdelay.delayFor(60000); // Check every minute // TODO: Implement actual cleanup logic for ephemeral data // For now, this prevents the infinite CPU loop } } }