@heliomarpm/kvs
Version:
A simple and robust KeyValues Storage's library
337 lines (336 loc) • 10 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.KeyValues = void 0;
const lodash_1 = require("lodash");
const utils_1 = require("./utils");
/** @internal */
const defaultOptions = {
atomicSave: true,
dir: utils_1.DEFAULT_DIR_NAME,
fileName: utils_1.DEFAULT_FILE_NAME,
prettify: false,
numSpaces: 2,
};
/**
*
* KeyValues is a class that provides a simple key-value storage system.
* It allows you to set, get, check existence, and remove key-value pairs in a JSON file.
* It supports nested keys and complex data types, and provides both asynchronous and synchronous methods
*
* It is designed to be used in Node.js applications
* and can be easily configured to use a custom directory
* and file name for storing key-value pairs.
*
* @author Heliomar Marques
* @example
*
* import { KeyValues } from '@heliomarpm/kvs';
*
* // Create a new instance of KeyValues with custom options
* const keyValues = new KeyValues({
* fileName: 'config.json',
* prettify: true,
* numSpaces: 4
* });
*
* // Set a key-value pair
* await keyValues.set('color.name', 'sapphire');
*
* // Get the value at a specific key path
* const value = await keyValues.get('color.name');
* // output: 'sapphire'
*
* // Get the nested key
* const value = await keyValues.get('color');
* // output: { name: 'sapphire' }
*
* // Get all
* const value = await keyValues.get();
* // output: { color: { name: 'sapphire' } }
*
* // Check if a key path exists
* const exists = await keyValues.has('color.name');
*
* // Remove a key-value pair
* await keyValues.unset('color.name');
*
* @category Core
*/
class KeyValues {
/**
* Sets the configuration for KeyValues Storage's.
*
* To reset to defaults, use [`reset()`].
*
* ```js
* Defaults:
* {
* atomicSave: true,
* dir: 'localdb',
* fileName: 'keyvalues.json',
* numSpaces: 2,
* prettify: false
* }
* ```
* @param options {@link Options} The custom configuration to use.
* @example
*
* Update the filename to `config.json` and prettify the output.
* ```js
* new KeyValues({ fileName: 'config.json', prettify: true });
* ```
*/
constructor(options) {
/**
* @internal
*/
Object.defineProperty(this, "options", {
enumerable: true,
configurable: true,
writable: true,
value: Object.assign({}, defaultOptions)
});
/**
* @internal
*/
Object.defineProperty(this, "jsonHelper", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
if (options)
this.options = Object.assign(Object.assign({}, this.options), options);
this.jsonHelper = new utils_1.JsonFileHelper(this.options);
}
/**
* Returns the path to the json file.
*
* In general, the json file is stored
* in then install location of your app's
* user data directory in a file called `keyvalues.json`.
* The default user data directory varies by system.
*
* - **macOS** - `~/Library/Application\ Support/<Your App>`
* - **Windows** - `%LOCALAPPDATA%/PROGRAMS/<Your App>`
* - **Linux** - Either `$XDG_CONFIG_HOME/<Your App>` or `~/.config/<Your App>`
*
* Although it is not recommended, you may change the name
* or location of the keyvalues file using
*
* new KeyValye({dir: 'newpath'})
*
* @returns The path to the keyvalues file.
*
* @example
*
* Get the path to the keyvalues file.
* ```js
* keyValues.file();
* // => c:/users/<userprofile>/appdata/local/programs/<AppName>/keyvalues.json
* ```
*
* @category Auxiliary Methods
*/
file() {
return this.jsonHelper.getJsonFilePath();
}
/**
* Resets the KeyValues Storage's configuration to defaults.
*
* @example
*
* Reset configuration to defaults.
* ```js
* keyValues.resetOptions();
* ```
*
* @category Auxiliary Methods
* @see {@link Options}
*/
resetOptions() {
this.options = Object.assign({}, defaultOptions);
}
set(...args) {
return __awaiter(this, void 0, void 0, function* () {
if (args.length === 1) {
const [value] = args;
return this.jsonHelper.saveKeyValues(value);
}
const [keyPath, value] = args;
const obj = yield this.jsonHelper.loadKeyValues();
(0, lodash_1.set)(obj, keyPath, value);
return this.jsonHelper.saveKeyValues(obj);
});
}
setSync(...args) {
if (args.length === 1) {
const [value] = args;
this.jsonHelper.saveKeyValuesSync(value);
}
else {
const [keyPath, value] = args;
const obj = this.jsonHelper.loadKeyValuesSync();
(0, lodash_1.set)(obj, keyPath, value);
this.jsonHelper.saveKeyValuesSync(obj);
}
}
get(keyPath) {
return __awaiter(this, void 0, void 0, function* () {
try {
const obj = yield this.jsonHelper.loadKeyValues();
if (keyPath) {
return (0, lodash_1.get)(obj, keyPath);
}
return obj;
}
catch (error) {
// Add proper error handling
if (error instanceof Error) {
throw new Error(`Failed to get value: ${error.message}`);
}
throw new Error("Failed to get value: Unknown error");
}
});
}
getSync(keyPath) {
const obj = this.jsonHelper.loadKeyValuesSync();
if (keyPath) {
return (0, lodash_1.get)(obj, keyPath);
}
return obj;
}
/**
* Checks if the given key path exists.
*
* _For sync method, use_ [`hasSync()`].
*
* @param keyPath The key path to check.
* @returns A promise which resolves to `true` if the `keyPath` exists, else `false`.
* @example
*
* Check if the value at `color.name` exists.
* ```js
* // Given:
* {
* "color": {
* "name": "cerulean",
* "code": {
* "rgb": [0, 179, 230],
* "hex": "#003BE6"
* }
* }
* }
*
* const exists = await keyValues.has('color.name');
* // => true
* ```
* @example
*
* Check if the value at `color.hue` exists.
* ```js
* const exists = await keyValues.has(['color', 'hue']);
* // => false
* ```
* @example
*
* Check if the value at `color.code.rgb[1]` exists.
* ```js
* const exists = await keyValues.has(color.code.rgb[1]);
* // => true
* ```
*
* @category Has Methods
*/
has(keyPath) {
return __awaiter(this, void 0, void 0, function* () {
const obj = yield this.jsonHelper.loadKeyValues();
return (0, lodash_1.has)(obj, keyPath);
});
}
/**
* Checks if the given key path exists.
*
* _For async method, use_ [`has()`].
*
* @param keyPath The key path to check.
* @returns `true` if the `keyPath` exists, else `false`.
* @example
*
* Check if the value at `color.name` exists.
* ```js
* // Given:
* {
* "color": {
* "name": "cerulean",
* "code": {
* "rgb": [0, 179, 230],
* "hex": "#003BE6"
* }
* }
* }
*
* const exists = keyValues.hasSync('color.name');
* // => true
* ```
* @example
*
* Check if the value at `color.hue` exists.
* ```js
* const exists = keyValues.hasSync(['color', 'hue']);
* // => false
* ```
* @example
*
* Check if the value at `color.code.rgb[1]` exists.
* ```js
* const exists = keyValues.hasSync(color.code.rgb[1]);
* // => true
* ```
*
* @category Has Methods
*/
hasSync(keyPath) {
const obj = this.jsonHelper.loadKeyValuesSync();
return (0, lodash_1.has)(obj, keyPath);
}
unset(keyPath) {
return __awaiter(this, void 0, void 0, function* () {
const obj = yield this.jsonHelper.loadKeyValues();
if (JSON.stringify(obj) !== "{}") {
if (keyPath && (0, lodash_1.unset)(obj, keyPath)) {
yield this.jsonHelper.saveKeyValues(obj);
}
else {
yield this.jsonHelper.saveKeyValues({});
}
return true;
}
return false;
});
}
unsetSync(keyPath) {
const obj = this.jsonHelper.loadKeyValuesSync();
if (JSON.stringify(obj) !== "{}") {
if (keyPath && (0, lodash_1.unset)(obj, keyPath)) {
this.jsonHelper.saveKeyValuesSync(obj);
}
else {
// Unset all keyValues by saving empty object.
this.jsonHelper.saveKeyValuesSync({});
}
return true;
}
return false;
}
}
exports.KeyValues = KeyValues;