UNPKG

@v4fire/core

Version:
171 lines (142 loc) 4.05 kB
/*! * V4Fire Core * https://github.com/V4Fire/Core * * Released under the MIT license * https://github.com/V4Fire/Core/blob/master/LICENSE */ import type { ClearFilter } from 'core/kv-storage/interface'; import { defaultDataSeparators } from 'core/kv-storage/engines/string/const'; import type { StorageOptions, DataSeparators } from 'core/kv-storage/engines/string/interface'; export default class StringEngine { /** * Serialized storage data */ get serializedData(): string { return this.data; } /** * Serialized storage data */ protected data: string; /** * Separators for keys and values for serialization into a string */ protected separators: DataSeparators = defaultDataSeparators; /** * Replaces serialized storage data with new ones */ // eslint-disable-next-line @typescript-eslint/adjacent-overload-signatures protected set serializedData(data: string) { this.data = data; } /** * @param [opts] - additional options */ constructor(opts: StorageOptions = {}) { this.data = opts.data ?? ''; Object.assign(this.separators, opts.separators); } /** * Returns true if a value by the specified key exists in the storage * @param key */ has(key: string): boolean { return key in this.getDataFromRaw(); } /** * Returns a value from the storage by the specified key * @param key */ get(key: string): CanUndef<string> { return this.getDataFromRaw()[key]; } /** * Stores a value to the storage by the specified key * * @param key * @param value * @throws {TypeError} if forbidden characters are used in the key or value when storing data */ set(key: string, value: string): void { const separators = Object.values(this.separators), isForbiddenCharacterUsed = separators.some((el) => key.includes(el) || String(value).includes(el)); if (isForbiddenCharacterUsed) { throw new TypeError(`The forbidden character used in string storage keys is "${key}", with value "${String(value)}"`); } this.updateData({[key]: String(value)}); } /** * Removes a value from the storage by the specified key * @param key */ remove(key: string): void { this.updateData({[key]: undefined}); } /** * Returns a list of keys that are stored in the storage */ keys(): string[] { return Object.keys(this.getDataFromRaw()); } /** * Clears either the entire data storage or records that match the specified filter * @param filter */ clear(filter?: ClearFilter<string>): void { if (filter != null) { const state = this.getDataFromRaw(); Object.entries(state).forEach(([key, value]) => { if (filter(String(value), key) === true) { delete state[key]; } }); this.overwriteData(state); } else { this.overwriteData({}); } } /** * Update the data in the storage with the data passed from the dictionary * @param data - the dictionary with the data to be added to the storage */ protected updateData(data: Dictionary<CanUndef<string>>): void { const currentState = this.getDataFromRaw(); Object.entries(data).forEach(([key, value]) => { if (value === undefined) { delete currentState[key]; } else { currentState[key] = value; } }); this.overwriteData(currentState); } /** * Overwrites the data in the storage with the new data from the passed dictionary * @param data - the dictionary with the data to be saved in the storage */ protected overwriteData(data: Dictionary<string>): void { const s = this.separators; this.serializedData = Object.entries(data) .map(([key, value]) => `${key}${s.record}${value}`) .join(s.chunk); } /** * Returns data parsed as a dictionary from the serialized data string */ protected getDataFromRaw(): StrictDictionary<string> { const {serializedData} = this; if (serializedData === '') { return {}; } const s = this.separators; return serializedData.split(s.chunk).reduce((acc, el) => { const [key, value] = el.split(s.record); acc[key] = value; return acc; }, {}); } }