mcp-quiz-server
Version:
🧠AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.
103 lines (102 loc) • 3.42 kB
JavaScript
"use strict";
/**
* @fileoverview Simple In-Memory Cache Implementation
* @version 1.0.0
* @since 2025-07-29
* @lastUpdated 2025-07-29
* @module InMemoryCache
* @description High-performance in-memory cache implementation for Clean Architecture.
* Provides LRU eviction, TTL support, and thread-safe operations.
*
* @architecture
* Layer: Infrastructure (Service Implementations)
* Pattern: Cache-Aside Pattern + LRU Eviction
* Dependencies: ICacheService interface
*
* @relationships
* DEPENDS_ON:
* - ICacheService (Infrastructure Interface)
* USED_BY:
* - GetQuizQueryHandler (Application Layer)
* - Repository implementations (Infrastructure)
* - DI Container service resolution
* COLLABORATES_WITH:
* - ServiceRegistry for configuration and lifecycle
*
* @dataFlow
* get(key) → Map.get() → TTL check → return value OR null
* set(key, value, ttl) → LRU eviction check → Map.set() → TTL timer setup
* Cleanup: Timer expires → Map.delete() → memory freed
*
* @responsibilities
* - Store key-value pairs with TTL support
* - Implement LRU eviction when memory limits reached
* - Provide fast O(1) cache operations
* - Automatic cleanup of expired entries
* - Thread-safe concurrent access
*
* @performance
* - Get/Set: O(1) average case
* - Memory: Configurable max keys limit
* - TTL: Automatic cleanup with timers
* - Eviction: LRU policy for memory management
*
* @requirements
* {@link Requirements.REQ_ARCH_v2_007} Performance and Scalability
* {@link Requirements.REQ_PERF_001} Query Response Time < 100ms
*
* @contributors Claude Code Agent
* @testCoverage Unit tests for cache operations, TTL behavior, and LRU eviction
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemoryCache = void 0;
class InMemoryCache {
constructor(config = {}) {
this.cache = new Map();
this.config = {
defaultTTL: 3600,
maxKeys: 1000,
keyPrefix: '',
...config,
};
}
async get(key) {
const fullKey = this.getFullKey(key);
const entry = this.cache.get(fullKey);
if (!entry)
return null;
if (Date.now() > entry.expiresAt) {
this.cache.delete(fullKey);
return null;
}
return entry.value;
}
async set(key, value, ttlSeconds) {
const fullKey = this.getFullKey(key);
const ttl = ttlSeconds !== null && ttlSeconds !== void 0 ? ttlSeconds : this.config.defaultTTL;
const expiresAt = Date.now() + ttl * 1000;
// Simple LRU eviction if needed
if (this.cache.size >= this.config.maxKeys && !this.cache.has(fullKey)) {
const oldestKey = this.cache.keys().next().value;
if (oldestKey) {
this.cache.delete(oldestKey);
}
}
this.cache.set(fullKey, { value, expiresAt });
}
async delete(key) {
const fullKey = this.getFullKey(key);
return this.cache.delete(fullKey);
}
async clear() {
this.cache.clear();
}
async has(key) {
const value = await this.get(key);
return value !== null;
}
getFullKey(key) {
return this.config.keyPrefix ? `${this.config.keyPrefix}:${key}` : key;
}
}
exports.InMemoryCache = InMemoryCache;