{"version":3,"sources":["../../../src/plugins/cache/plugin.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Cache Plugin for GQP\n * Query result caching with multiple backends\n */\n\nimport type {\n  GQPPlugin,\n  GQPNode,\n  PluginContext,\n  QueryFilters,\n  GQPEngine,\n} from \"../../core/types.js\";\n\ninterface CacheEntry<T = unknown> {\n  value: T;\n  expiresAt: number;\n  createdAt: number;\n}\n\nexport interface CacheProvider {\n  get<T>(key: string): Promise<T | null>;\n  set<T>(key: string, value: T, ttl: number): Promise<void>;\n  delete(key: string): Promise<void>;\n  clear(): Promise<void>;\n}\n\nexport class MemoryCacheProvider implements CacheProvider {\n  private cache: Map<string, CacheEntry> = new Map();\n  private maxSize: number;\n  private cleanupInterval?: ReturnType<typeof setInterval>;\n\n  constructor(maxSize = 1000, cleanupIntervalMs = 60000) {\n    this.maxSize = maxSize;\n\n    if (cleanupIntervalMs > 0) {\n      this.cleanupInterval = setInterval(() => {\n        this.evictExpired();\n      }, cleanupIntervalMs);\n    }\n  }\n\n  async get<T>(key: string): Promise<T | null> {\n    const entry = this.cache.get(key);\n\n    if (!entry) return null;\n\n    if (Date.now() > entry.expiresAt) {\n      this.cache.delete(key);\n      return null;\n    }\n\n    return entry.value as T;\n  }\n\n  async set<T>(key: string, value: T, ttl: number): Promise<void> {\n    if (this.cache.size >= this.maxSize) {\n      this.evictOldest();\n    }\n\n    this.cache.set(key, {\n      value,\n      expiresAt: Date.now() + ttl * 1000,\n      createdAt: Date.now(),\n    });\n  }\n\n  async delete(key: string): Promise<void> {\n    this.cache.delete(key);\n  }\n\n  async clear(): Promise<void> {\n    this.cache.clear();\n  }\n\n  destroy(): void {\n    if (this.cleanupInterval) {\n      clearInterval(this.cleanupInterval);\n      this.cleanupInterval = undefined;\n    }\n    this.cache.clear();\n  }\n\n  private evictOldest(): void {\n    let oldestKey: string | null = null;\n    let oldestTime = Infinity;\n\n    for (const [key, entry] of this.cache.entries()) {\n      if (entry.createdAt < oldestTime) {\n        oldestTime = entry.createdAt;\n        oldestKey = key;\n      }\n    }\n\n    if (oldestKey) {\n      this.cache.delete(oldestKey);\n    }\n  }\n\n  private evictExpired(): void {\n    const now = Date.now();\n    for (const [key, entry] of this.cache.entries()) {\n      if (now > entry.expiresAt) {\n        this.cache.delete(key);\n      }\n    }\n  }\n\n  size(): number {\n    return this.cache.size;\n  }\n}\n\nexport interface CachePluginConfig {\n  provider?: \"memory\" | \"redis\" | CacheProvider;\n  redis?: {\n    url: string;\n    prefix?: string;\n  };\n  ttl?: number;\n  maxSize?: number;\n  cleanupInterval?: number;\n  strategies?: Record<\n    string,\n    {\n      ttl?: number;\n      invalidateOn?: string[];\n    }\n  >;\n}\n\nexport class CachePlugin implements GQPPlugin {\n  name = \"cache\";\n  private config: CachePluginConfig;\n  private provider: CacheProvider;\n  private memoryProvider?: MemoryCacheProvider;\n  private pendingQueries: Map<string, Promise<unknown[]>> = new Map();\n  private stats = {\n    hits: 0,\n    misses: 0,\n  };\n\n  constructor(config: CachePluginConfig = {}) {\n    this.config = {\n      ttl: 300,\n      maxSize: 1000,\n      cleanupInterval: 60000,\n      ...config,\n    };\n\n    if (config.provider instanceof Object && \"get\" in config.provider) {\n      this.provider = config.provider as CacheProvider;\n    } else if (config.provider === \"redis\" && config.redis) {\n      this.memoryProvider = new MemoryCacheProvider(\n        this.config.maxSize,\n        this.config.cleanupInterval,\n      );\n      this.provider = this.memoryProvider;\n    } else {\n      this.memoryProvider = new MemoryCacheProvider(\n        this.config.maxSize,\n        this.config.cleanupInterval,\n      );\n      this.provider = this.memoryProvider;\n    }\n  }\n\n  async onInit(_engine: GQPEngine): Promise<void> {}\n\n  async onDestroy(): Promise<void> {\n    if (this.memoryProvider) {\n      this.memoryProvider.destroy();\n    }\n    this.pendingQueries.clear();\n  }\n\n  async onPreQuery(\n    node: GQPNode,\n    filters: QueryFilters,\n    context: PluginContext,\n  ): Promise<QueryFilters> {\n    const cacheKey = this.generateCacheKey(node.name, context);\n\n    const cached = await this.provider.get<unknown[]>(cacheKey);\n    if (cached !== null) {\n      this.stats.hits++;\n      (context as { _cachedResults?: unknown[] })._cachedResults = cached;\n    } else {\n      this.stats.misses++;\n      (context as { _cacheKey?: string })._cacheKey = cacheKey;\n    }\n\n    return filters;\n  }\n\n  async onPostQuery(\n    node: GQPNode,\n    results: unknown[],\n    context: PluginContext,\n  ): Promise<unknown[]> {\n    const ctx = context as { _cachedResults?: unknown[]; _cacheKey?: string };\n\n    if (ctx._cachedResults) {\n      return ctx._cachedResults;\n    }\n\n    if (ctx._cacheKey) {\n      const ttl = this.getTTL(node.name);\n      await this.provider.set(ctx._cacheKey, results, ttl);\n    }\n\n    return results;\n  }\n\n  private generateCacheKey(nodeName: string, context: PluginContext): string {\n    const parts = [\n      \"gqp\",\n      nodeName,\n      this.safeStringify(context.filters),\n      this.safeStringify(context.options),\n    ];\n\n    if (context.query) {\n      parts.push(context.query);\n    }\n\n    const str = parts.join(\":\");\n    let hash = 0;\n    for (let i = 0; i < str.length; i++) {\n      const char = str.charCodeAt(i);\n      hash = (hash << 5) - hash + char;\n      hash = hash & hash;\n    }\n\n    return `gqp:${nodeName}:${Math.abs(hash).toString(36)}`;\n  }\n\n  private safeStringify(obj: unknown): string {\n    const seen = new WeakSet();\n    return JSON.stringify(obj, (_, value) => {\n      if (typeof value === \"object\" && value !== null) {\n        if (seen.has(value)) return \"[circular]\";\n        seen.add(value);\n      }\n      return value;\n    });\n  }\n\n  private getTTL(nodeName: string): number {\n    const strategy = this.config.strategies?.[nodeName];\n    return strategy?.ttl || this.config.ttl || 300;\n  }\n\n  async invalidate(_pattern: string): Promise<void> {\n    if (this.memoryProvider) {\n      await this.memoryProvider.clear();\n    }\n  }\n\n  getStats(): {\n    hits: number;\n    misses: number;\n    hitRate: number;\n  } {\n    const total = this.stats.hits + this.stats.misses;\n    return {\n      ...this.stats,\n      hitRate: total > 0 ? this.stats.hits / total : 0,\n    };\n  }\n\n  async clear(): Promise<void> {\n    await this.provider.clear();\n    this.stats.hits = 0;\n    this.stats.misses = 0;\n  }\n}\n\nexport function createCachePlugin(config: CachePluginConfig = {}): CachePlugin {\n  return new CachePlugin(config);\n}\n"]}