@mcabreradev/filter
Version:
A powerful, SQL-like array filtering library for TypeScript and JavaScript with advanced pattern matching, MongoDB-style operators, deep object comparison, and zero dependencies
147 lines • 4.87 kB
JavaScript
class LRUCache {
cache = new Map();
maxSize;
maxAge;
constructor(maxSize = 1000, maxAge = 300000) {
this.maxSize = maxSize;
this.maxAge = maxAge;
}
get(key) {
const entry = this.cache.get(key);
if (!entry)
return undefined;
if (Date.now() - entry.timestamp > this.maxAge) {
this.cache.delete(key);
return undefined;
}
this.cache.delete(key);
this.cache.set(key, { ...entry, timestamp: Date.now() });
return entry.value;
}
set(key, value) {
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
if (firstKey !== undefined) {
this.cache.delete(firstKey);
}
}
this.cache.set(key, { value, timestamp: Date.now() });
}
clear() {
this.cache.clear();
}
size() {
return this.cache.size;
}
}
export class MemoizationManager {
static instance;
predicateCache;
regexCache;
expressionHashCache;
constructor() {
this.predicateCache = new LRUCache(500, 300000);
this.regexCache = new Map();
this.expressionHashCache = new WeakMap();
}
static getInstance() {
if (!MemoizationManager.instance) {
MemoizationManager.instance = new MemoizationManager();
}
return MemoizationManager.instance;
}
createExpressionHash(expression, config) {
if (typeof expression === 'function') {
return `fn:${expression.toString()}`;
}
if (typeof expression === 'string') {
return `str:${expression}:${config.caseSensitive}`;
}
if (typeof expression === 'object' && expression !== null) {
const cached = this.expressionHashCache.get(expression);
if (cached)
return cached;
const hash = this.hashObject(expression, config);
this.expressionHashCache.set(expression, hash);
return hash;
}
return `primitive:${String(expression)}`;
}
hashObject(obj, config) {
const parts = [];
const sortedKeys = Object.keys(obj).sort();
for (const key of sortedKeys) {
const value = obj[key];
if (value === null) {
parts.push(`${key}:null`);
}
else if (value === undefined) {
parts.push(`${key}:undefined`);
}
else if (typeof value === 'object') {
if (value instanceof Date) {
parts.push(`${key}:date:${value.getTime()}`);
}
else if (value instanceof RegExp) {
parts.push(`${key}:regex:${value.source}:${value.flags}`);
}
else if (Array.isArray(value)) {
parts.push(`${key}:arr:[${value.map((v) => this.hashValue(v)).join(',')}]`);
}
else {
parts.push(`${key}:obj:{${this.hashObject(value, config)}}`);
}
}
else {
parts.push(`${key}:${typeof value}:${String(value)}`);
}
}
return `${parts.join('|')}:cs:${config.caseSensitive}:md:${config.maxDepth}`;
}
hashValue(value) {
if (value === null)
return 'null';
if (value === undefined)
return 'undefined';
if (value instanceof Date)
return `date:${value.getTime()}`;
if (value instanceof RegExp)
return `regex:${value.source}:${value.flags}`;
if (typeof value === 'object')
return `obj:${this.hashObject(value, { caseSensitive: false, maxDepth: 3, enableCache: false })}`;
return `${typeof value}:${String(value)}`;
}
getCachedPredicate(key) {
return this.predicateCache.get(key);
}
setCachedPredicate(key, predicate) {
this.predicateCache.set(key, predicate);
}
getCachedRegex(pattern, flags) {
const key = `${pattern}:${flags || ''}`;
return this.regexCache.get(key);
}
setCachedRegex(pattern, regex, flags) {
const key = `${pattern}:${flags || ''}`;
this.regexCache.set(key, regex);
}
clearPredicateCache() {
this.predicateCache.clear();
}
clearRegexCache() {
this.regexCache.clear();
}
clearAll() {
this.predicateCache.clear();
this.regexCache.clear();
this.expressionHashCache = new WeakMap();
}
getStats() {
return {
predicateCacheSize: this.predicateCache.size(),
regexCacheSize: this.regexCache.size,
};
}
}
export const memoization = MemoizationManager.getInstance();
//# sourceMappingURL=memoization.js.map