diff --git a/package.json b/package.json index ec52912..5694f8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ztimson/utils", - "version": "0.27.9", + "version": "0.27.10", "description": "Utility library", "author": "Zak Timson", "license": "MIT", diff --git a/src/cache.ts b/src/cache.ts index 55b7b9f..fe12733 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -85,6 +85,7 @@ export class Cache { return (value as any)[this.key]; } + /** Save item to storage */ private save(key?: K) { const persists: {storage: any, key: string} = this.options.persistentStorage; if(!!persists?.storage) { @@ -131,16 +132,13 @@ export class Cache { const out: CachedValue[] = []; for(const v of this.store.values()) { const val: any = v; - if(expired || !val?._expired) out.push(deepCopy(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 { /** * 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 { 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 { 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 { 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][] { const out: [K, CachedValue][] = []; for(const [k, v] of this.store.entries()) { const val: any = v; - if(expired || !val?._expired) out.push([k, deepCopy(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 { return this; } - /** - * Find the first cached item to match a filter - * @param {Partial} 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, expired?: boolean): T | undefined { for(const v of this.store.values()) { const row: any = v; - if((expired || !row._expired) && includes(row, filter)) return deepCopy(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 | null { const raw = this.store.get(key); if(raw == null) return null; - const cached: any = deepCopy(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 { return out; } - /** - * Get map of cached items - * @return {Record} - */ + /** Return map of key → item */ map(expired?: boolean): Record> { const copy: any = {}; for(const [k, v] of this.store.entries()) { const val: any = v; - if(expired || !val?._expired) copy[k as any] = deepCopy(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 (value)._expired; this.clearTimer(key); @@ -289,15 +251,12 @@ export class Cache { 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; } diff --git a/src/objects.ts b/src/objects.ts index e5081a8..86f9885 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -82,6 +82,9 @@ export function clean(obj: T, undefinedOnly = false): Partial { * @returns {T} Type */ export function deepCopy(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)); } }