UNPKG

axoncore

Version:

The best fully featured discord bot framework. Universal Client, Command and Event handler.

349 lines (320 loc) 8.94 kB
import AxonError from '../Errors/AxonError'; /** * Generic class that expose all data manipulation methods. * A Store can be constructed with any Key => Value structure (Map like object) * Map-like object can be anything as long as it implements the following: * - `size` property * - `entries`, `values`, `keys` iterators * - `has`, `get`, `set`, `delete` methods * It exposes all methods similar to array methods in one place. * * @author KhaaZ * * @template T * @class Store * @prop {Map<string, T>} cache - Key => Value Data structure */ class Store { /** * Creates an instance of Store. * * @param {Map<string, T>} cache - Key => Value data structure * @memberof Store */ constructor(cache) { this.cache = cache || new Map(); } // Direct action on cache /** * Current size of the cache * * @readonly * @type {Number} * @memberof Store */ get size() { return this.cache.size; } /** * Iterator over `cache.entries` * * @returns {IterableIterator<[string, T]>} * @memberof Store */ entries() { return this.cache.entries(); } /** * Iterator over `cache.keys` * * @returns {IterableIterator<String>} * @memberof Store */ keys() { return this.cache.keys(); } /** * Iterator over `cache.values` * * @returns {IterableIterator<T>} * @memberof Store */ values() { return this.cache.values(); } /** * Iterator over cache * * @returns {IterableIterator<[string, T]>;} * @memberof Store */ [Symbol.iterator]() { return this.cache[Symbol.iterator](); } /** * Whether an element exists in the Store * * @param {String} key * @returns {Boolean} * @memberof Store */ has(key) { return this.cache.has(key); } /** * Get an element by key in the Store * * @param {String} key * @returns {T} * @memberof Store */ get(key) { return this.cache.get(key); } /** * Set an element in the Store * * @param {String} key * @param {T} value * @returns {Store} - Current Store * @memberof Store */ set(key, value) { this.cache.set(key, value); return this; } /** * Delete an element by key in the Store * * @param {String} key * @returns {Boolean} - Whether the element was deleted or not * @memberof Store */ delete(key) { return this.cache.delete(key); } // General cache manipulation /** * `Store.cache` to array (simple array of value) * * @returns {Array<T>} * @memberof Store */ toArray() { return [...this.values()]; } /** * `Store.cache` to object * * @returns {Object.<string, T>} * @memberof Store */ toObject() { const obj = {}; for (const [key, value] of this.entries() ) { obj[key] = value; } return obj; } /** * The first value of the Store * * @returns {T} - The first element * @memberof Store */ first() { return this.values().next().value; } /** * Apply a function to the Store and returns a new Store. * Usable over: `map`, `filter`, `toArray`. * Using apply with toArray is pretty much "cloning" the Store. * * @param {String} key - The property to use as key for the new Store * @param {String} func - The function name to apply to the Store * @param {...any} args - All the arguments that need to be applied to the function * @returns {Store<T>} A new Store modified by the apply call * @memberof Store */ apply(key, func, ...args) { if (![ 'map', 'filter', 'toArray', ].includes(func) ) { throw new AxonError(`You can't use apply on function: ${func}.`, 'Store'); } return new Store(new Map(this[func](...args).map(e => [e[key], e] ) ) ); } /** * Execute a function over each element of the Store in a synchronous fashion * * @param {(i: T) => void} func - A function that takes an object and do something on it * @returns {Store} The current Store * @memberof Store */ forEach(func) { for (const item of this.values() ) { func(item); } return this; } /** * Execute a function over each element of the Store in an asynchronous fashion * * @param {(i: T) => Promise<void>} func - A function that takes an object and do something on it * @returns {Promise<Store>} The current Store * @memberof Store */ async forEachAsync(func) { for (const item of this.values() ) { await func(item); } return this; } /** * Removes from the Store all element that satisfy the function in parameter * * @param {(value: T, key: String) => Boolean} func * @returns {Store} - The current Store * @memberof Store */ sweep(func) { for (const [key, val] of this.entries() ) { if (func(val, key) ) { this.delete(key); } } return this; } /** * Return the first object to make the function evaluate true * * @param {(i: T) => Boolean} func - A function that takes an object and returns true if it matches * @returns {T} The first matching object, or null if no match * @memberof Store */ find(func) { for (const item of this.values() ) { if (func(item) ) { return item; } } return null; } /** * Return an array with the results of applying the given function to each element * * @template R * @param {(i: T) => R} func - A function that takes an object and returns something * @returns {Array<R>} An array containing the results * @memberof Store */ map(func) { const arr = []; for (const item of this.values() ) { arr.push(func(item) ); } return arr; } /** * Return all the objects that make the function evaluate true * * @param {(i: T) => Boolean} func - A function that takes an object and returns true if it matches * @returns {Array<T>} An array containing all the objects that matched * @memberof Store */ filter(func) { const arr = []; for (const item of this.values() ) { if (func(item) ) { arr.push(item); } } return arr; } /** * Reduce values by function * * @template U * @param {(accumulator: U, val: T) => U} func - Function to execute on each element in the array * @param {Number} [initialValue=0] - Value to use as the first argument to the first call of the callback * @returns {U} Accumulator * @memberof Store */ reduce(func, initialValue = 0) { const iter = this.values(); let val; let result = initialValue === undefined ? iter.next().value : initialValue; while ( (val = iter.next().value) !== undefined) { result = func(result, val); } return result; } /** * Test if at least one element passes the test implemented by the provided function. Returns true if yes, or false if not. * * @param {(i: T) => Boolean} func - A function that takes an object and returns true if it matches * @returns {Boolean} Whether or not any of the elements returned true * @memberof Store */ some(func) { for (const item of this.values() ) { if (func(item) ) { return true; } } return false; } /** * Test if all elements pass the test implemented by the provided function. Returns true if yes, or false if not. * * @param {(i: T) => Boolean} func - A function that takes an object and returns true if it matches * @returns {Boolean} Whether or not all of the elements returned true * @memberof Store */ every(func) { for (const item of this.values() ) { if (!func(item) ) { return false; } } return true; } /** * Get a random object from the Store * * @returns {T?} The random object, or null if there is no match * @memberof Store */ random() { if (!this.size) { return null; } return this.toArray()[Math.floor(Math.random() * this.size)]; } toString() { return `[Store<${this.baseObject.name}>]`; } } export default Store;