npmextra/ts/npmextra.classes.keyvaluestore.ts
2023-08-24 10:44:42 +02:00

147 lines
4.2 KiB
TypeScript

import * as plugins from './npmextra.plugins.js';
import * as paths from './npmextra.paths.js';
import { Task } from '@push.rocks/taskbuffer';
export type TKeyValueStore = 'custom' | 'userHomeDir';
/**
* kvStore is a simple key value store to store data about projects between runs
*/
export class KeyValueStore {
private dataObject: any = {};
private deletedObject: any = {};
public syncTask = new Task({
name: 'syncTask',
buffered: true,
bufferMax: 1,
execDelay: 0,
taskFunction: async () => {
this.dataObject = {
...plugins.smartfile.fs.toObjectSync(this.filePath),
...this.dataObject,
};
for (const key of Object.keys(this.deletedObject)) {
delete this.dataObject[key];
}
this.deletedObject = {};
await plugins.smartfile.memory.toFs(
plugins.smartjson.stringify(this.dataObject),
this.filePath
);
},
});
/**
* computes the identity and filePath
*/
private initFilePath = () => {
if (this.customPath) {
// Use custom path if provided
const absolutePath = plugins.smartpath.transform.makeAbsolute(this.customPath, paths.cwd);
this.filePath = absolutePath;
if (plugins.smartfile.fs.isDirectorySync(this.filePath)) {
this.filePath = plugins.path.join(this.filePath, this.identity + '.json');
}
plugins.smartfile.fs.ensureFileSync(this.filePath, '{}');
return;
}
let baseDir: string;
if (this.type === 'userHomeDir') {
baseDir = paths.kvUserHomeDirBase;
} else {
throw new Error('kv type not supported');
}
this.filePath = plugins.path.join(baseDir, this.identity + '.json');
plugins.smartfile.fs.ensureDirSync(baseDir);
plugins.smartfile.fs.ensureFileSync(this.filePath, '{}');
};
// if no custom path is provided, try to store at home directory
public type: TKeyValueStore;
public identity: string;
public filePath: string;
private customPath?: string; // Optionally allow custom path
/**
* the constructor of keyvalue store
* @param typeArg
* @param identityArg
* @param customPath Optional custom path for the keyValue store
*/
constructor(typeArg: TKeyValueStore, identityArg: string, customPath?: string) {
if (customPath && typeArg !== 'custom') {
throw new Error('customPath can only be provided if typeArg is custom');
}
if (typeArg === 'custom' && !customPath) {
throw new Error('customPath must be provided if typeArg is custom');
}
this.type = typeArg;
this.identity = identityArg;
this.customPath = customPath; // Store custom path if provided
this.initFilePath();
}
/**
* reads all keyValue pairs at once and returns them
*/
public async readAll() {
await this.syncTask.trigger();
return this.dataObject;
}
/**
* reads a keyValueFile from disk
*/
public async readKey(keyArg: string) {
await this.syncTask.trigger();
return this.dataObject[keyArg];
}
/**
* writes a specific key to the keyValueStore
*/
public async writeKey(keyArg: string, valueArg: any) {
await this.writeAll({
[keyArg]: valueArg,
});
}
public async deleteKey(keyArg: string) {
this.deletedObject[keyArg] = this.dataObject[keyArg];
await this.syncTask.trigger();
}
/**
* writes all keyValue pairs in the object argument
*/
public async writeAll(keyValueObject: { [key: string]: any }) {
this.dataObject = { ...this.dataObject, ...keyValueObject };
await this.syncTask.trigger();
}
/**
* wipes a key value store from disk
*/
public async wipe() {
this.dataObject = {};
await plugins.smartfile.fs.remove(this.filePath);
}
/**
* resets the KeyValueStore to the initial state by syncing first, deleting all keys, and then triggering a sync again
*/
public async reset() {
await this.syncTask.trigger(); // Sync to get the latest state
// Delete all keys from the dataObject and add them to deletedObject
for (const key of Object.keys(this.dataObject)) {
this.deletedObject[key] = this.dataObject[key];
delete this.dataObject[key];
}
await this.syncTask.trigger(); // Sync again to reflect the deletion
}
}