Optimized deepCopy & fixed cache object bugs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ztimson/utils",
|
||||
"version": "0.27.9",
|
||||
"version": "0.27.10",
|
||||
"description": "Utility library",
|
||||
"author": "Zak Timson",
|
||||
"license": "MIT",
|
||||
|
||||
79
src/cache.ts
79
src/cache.ts
@@ -85,6 +85,7 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
return <K>(value as any)[this.key];
|
||||
}
|
||||
|
||||
/** Save item to storage */
|
||||
private save(key?: K) {
|
||||
const persists: {storage: any, key: string} = <any>this.options.persistentStorage;
|
||||
if(!!persists?.storage) {
|
||||
@@ -131,16 +132,13 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
const out: CachedValue<T>[] = [];
|
||||
for(const v of this.store.values()) {
|
||||
const val: any = v;
|
||||
if(expired || !val?._expired) out.push(deepCopy<any>(val));
|
||||
if(expired || !val?._expired) out.push(deepCopy(val));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new item to the cache. Like set, but finds key automatically
|
||||
* @param {T} value Item to add to cache
|
||||
* @param {number | undefined} ttl Override default expiry
|
||||
* @return {this}
|
||||
*/
|
||||
add(value: T, ttl = this.ttl): this {
|
||||
const key = this.getKey(value);
|
||||
@@ -150,9 +148,6 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
|
||||
/**
|
||||
* Add several rows to the cache
|
||||
* @param {T[]} rows Several items that will be cached using the default key
|
||||
* @param complete Mark cache as complete & reliable, defaults to true
|
||||
* @return {this}
|
||||
*/
|
||||
addAll(rows: T[], complete = true): this {
|
||||
this.clear();
|
||||
@@ -161,9 +156,7 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all keys from cache
|
||||
*/
|
||||
/** Remove all keys */
|
||||
clear(): this {
|
||||
this.complete = false;
|
||||
for (const [k, t] of this.timers) clearTimeout(t);
|
||||
@@ -174,10 +167,7 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an item from the cache
|
||||
* @param {K} key Item's primary key
|
||||
*/
|
||||
/** Delete a cached item */
|
||||
delete(key: K): this {
|
||||
this.clearTimer(key);
|
||||
const idx = this.lruOrder.indexOf(key);
|
||||
@@ -187,23 +177,17 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return cache as an array of key-value pairs
|
||||
* @return {[K, T][]} Key-value pairs array
|
||||
*/
|
||||
/** Return entries as array */
|
||||
entries(expired?: boolean): [K, CachedValue<T>][] {
|
||||
const out: [K, CachedValue<T>][] = [];
|
||||
for(const [k, v] of this.store.entries()) {
|
||||
const val: any = v;
|
||||
if(expired || !val?._expired) out.push([k, deepCopy<any>(val)]);
|
||||
if(expired || !val?._expired) out.push([k, deepCopy(val)]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually expire a cached item
|
||||
* @param {K} key Key to expire
|
||||
*/
|
||||
/** Manually expire a cached item */
|
||||
expire(key: K): this {
|
||||
this.complete = false;
|
||||
if(this.options.expiryPolicy == 'keep') {
|
||||
@@ -217,39 +201,26 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first cached item to match a filter
|
||||
* @param {Partial<T>} filter Partial item to match
|
||||
* @param {Boolean} expired Include expired items, defaults to false
|
||||
* @returns {T | undefined} Cached item or undefined if nothing matched
|
||||
*/
|
||||
/** Find first matching item */
|
||||
find(filter: Partial<T>, expired?: boolean): T | undefined {
|
||||
for(const v of this.store.values()) {
|
||||
const row: any = v;
|
||||
if((expired || !row._expired) && includes(row, filter)) return deepCopy<any>(row);
|
||||
if((expired || !row._expired) && includes(row, filter)) return deepCopy(row);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item from the cache
|
||||
* @param {K} key Key to lookup
|
||||
* @param expired Include expired items
|
||||
* @return {T} Cached item
|
||||
*/
|
||||
/** Get cached item by key */
|
||||
get(key: K, expired?: boolean): CachedValue<T> | null {
|
||||
const raw = this.store.get(key);
|
||||
if(raw == null) return null;
|
||||
const cached: any = deepCopy<any>(raw);
|
||||
this.touchLRU(key);
|
||||
if(expired || !cached?._expired) return cached;
|
||||
const isExpired = (raw as any)?._expired;
|
||||
if(expired || !isExpired) return deepCopy(raw);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of cached keys
|
||||
* @return {K[]} Array of keys
|
||||
*/
|
||||
/** Return list of keys */
|
||||
keys(expired?: boolean): K[] {
|
||||
const out: K[] = [];
|
||||
for(const [k, v] of this.store.entries()) {
|
||||
@@ -259,26 +230,17 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get map of cached items
|
||||
* @return {Record<K, T>}
|
||||
*/
|
||||
/** Return map of key → item */
|
||||
map(expired?: boolean): Record<K, CachedValue<T>> {
|
||||
const copy: any = {};
|
||||
for(const [k, v] of this.store.entries()) {
|
||||
const val: any = v;
|
||||
if(expired || !val?._expired) copy[k as any] = deepCopy<any>(val);
|
||||
if(expired || !val?._expired) copy[k as any] = deepCopy(val);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the cache manually specifying the key
|
||||
* @param {K} key Key item will be cached under
|
||||
* @param {T} value Item to cache
|
||||
* @param {number | undefined} ttl Override default expiry in seconds
|
||||
* @return {this}
|
||||
*/
|
||||
/** Add item manually specifying the key */
|
||||
set(key: K, value: T, ttl = this.options.ttl): this {
|
||||
if(this.options.expiryPolicy == 'keep') delete (<any>value)._expired;
|
||||
this.clearTimer(key);
|
||||
@@ -289,15 +251,12 @@ export class Cache<K extends string | number | symbol, T> {
|
||||
const t = setTimeout(() => {
|
||||
this.expire(key);
|
||||
this.save(key);
|
||||
}, (ttl || 0) * 1000);
|
||||
}, ttl * 1000);
|
||||
this.timers.set(key, t);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all cached items
|
||||
* @return {T[]} Array of items
|
||||
*/
|
||||
values = this.all
|
||||
/** Get all cached items */
|
||||
values = this.all;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,9 @@ export function clean<T>(obj: T, undefinedOnly = false): Partial<T> {
|
||||
* @returns {T} Type
|
||||
*/
|
||||
export function deepCopy<T>(value: T): T {
|
||||
if(value == null) return value;
|
||||
const t = typeof value;
|
||||
if(t === 'string' || t === 'number' || t === 'boolean' || t === 'function') return value;
|
||||
try {return structuredClone(value); }
|
||||
catch { return JSON.parse(JSONSanitize(value)); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user