UNPKG

@elsikora/cladi

Version:

ClaDI is a library for creating and managing classes in TypeScript.

221 lines (218 loc) 8.3 kB
import { BaseError } from './error.class.js'; import { ConsoleLoggerService } from '../../service/console-logger.service.js'; /** * Generic registry implementation that stores items by name. * @template T The type of items stored in the registry. * @see {@link https://elsikora.com/docs/cladi/core-concepts/registry} */ class BaseRegistry { CACHE; ITEMS; LOGGER; /** * Creates a new registry instance. * @param {IBaseRegistryOptions} options Registry creation options including logger. */ constructor(options) { this.ITEMS = new Map(); this.CACHE = new Map(); this.LOGGER = options.logger ?? new ConsoleLoggerService(); } /** * Clear the registry. */ clear() { this.LOGGER.debug("Clearing registry", { source: "Registry" }); this.ITEMS.clear(); this.clearCache(); this.LOGGER.debug("Registry cleared", { source: "Registry" }); } /** * Get a single item from the registry by name. * @param {string} name The name of the item to get. * @returns {T | undefined} The item or undefined if it doesn't exist. */ get(name) { this.LOGGER.debug(`Getting item with name: ${name}`, { source: "Registry" }); if (!name) { this.LOGGER.warn("Attempted to get item with empty name", { source: "Registry" }); return undefined; } const item = this.ITEMS.get(name); if (item) { this.LOGGER.debug(`Item found: ${name}`, { source: "Registry" }); } else { this.LOGGER.debug(`Item not found: ${name}`, { source: "Registry" }); } return item; } /** * Get all items from the registry. * @returns {Array<T>} An array of all items. */ getAll() { this.LOGGER.debug("Getting all items", { source: "Registry" }); const cacheKey = "getAll"; const cachedResult = this.CACHE.get(cacheKey); if (cachedResult) { this.LOGGER.debug("Cache hit for getAll query", { source: "Registry" }); return cachedResult; } const result = [...this.ITEMS.values()]; this.CACHE.set(cacheKey, result); this.LOGGER.debug(`Cached result for getAll query with ${String(result.length)} items`, { source: "Registry" }); return result; } /** * Get multiple items from the registry by their names. * @param {Array<string>} names The names of the items to get. * @returns {Array<T>} An array of items. */ getMany(names) { if (!names) { throw new BaseError("Names cannot be null or undefined", { code: "REGISTRY_NAMES_NOT_NULL_OR_UNDEFINED", source: "Registry", }); } if (!Array.isArray(names)) { throw new BaseError("Names must be an array", { code: "REGISTRY_NAMES_NOT_ARRAY", source: "Registry", }); } this.LOGGER.debug(`Getting ${String(names.length)} items by name`, { source: "Registry" }); const cacheKey = `getMany:${names.join(",")}`; const cachedResult = this.CACHE.get(cacheKey); if (cachedResult) { this.LOGGER.debug(`Cache hit for query: ${cacheKey}`, { source: "Registry" }); return cachedResult; } const result = names.map((name) => this.get(name)).filter((item) => item !== undefined); this.CACHE.set(cacheKey, result); this.LOGGER.debug(`Cached result for query: ${cacheKey}`, { source: "Registry" }); return result; } /** * Check if an item exists in the registry by name. * @param {string} name The name of the item to check. * @returns {boolean} True if the item exists, false otherwise. */ has(name) { this.LOGGER.debug(`Checking if item exists: ${name}`, { source: "Registry" }); if (!name) { return false; } const isExisting = this.ITEMS.has(name); this.LOGGER.debug(`Item ${isExisting ? "exists" : "does not exist"}: ${name}`, { source: "Registry" }); return isExisting; } /** * Register a single item in the registry. * @param {T} item The item to register. * @throws ValidationError if the item is invalid. */ register(item) { if (!item) { throw new BaseError("Item cannot be null or undefined", { code: "REGISTRY_ITEM_NOT_NULL_OR_UNDEFINED", source: "Registry", }); } this.LOGGER.debug(`Registering item with name: ${item.getName()}`, { source: "Registry" }); if (this.has(item.getName())) { throw new BaseError("Item already exists in registry", { code: "REGISTRY_ITEM_ALREADY_EXISTS", source: "Registry", }); } this.ITEMS.set(item.getName(), item); this.clearCache(); this.LOGGER.debug(`Item registered successfully: ${item.getName()}`, { source: "Registry" }); } /** * Register multiple items in the registry. * @param {Array<T>} items The items to register. * @throws ValidationError if any item is invalid. */ registerMany(items) { if (!items) { throw new BaseError("Items cannot be null or undefined", { code: "REGISTRY_ITEMS_NOT_NULL_OR_UNDEFINED", source: "Registry", }); } if (!Array.isArray(items)) { throw new BaseError("Items must be an array", { code: "REGISTRY_ITEMS_NOT_ARRAY", source: "Registry", }); } this.LOGGER.debug(`Registering ${String(items.length)} items`, { source: "Registry" }); for (const item of items) { this.register(item); } this.LOGGER.debug(`${String(items.length)} items registered successfully`, { source: "Registry" }); } /** * Unregister a single item from the registry by name. * @param {string} name The name of the item to unregister. */ unregister(name) { this.LOGGER.debug(`Unregistering item with name: ${name}`, { source: "Registry" }); if (!name) { throw new BaseError("Name cannot be empty", { code: "REGISTRY_NAME_NOT_EMPTY", source: "Registry", }); } const wasDeleted = this.ITEMS.delete(name); this.clearCache(); if (wasDeleted) { this.LOGGER.debug(`Item unregistered successfully: ${name}`, { source: "Registry" }); } else { this.LOGGER.debug(`Item not found for unregistering: ${name}`, { source: "Registry" }); } } /** * Unregister multiple items from the registry by their names. * @param {Array<string>} names The names of the items to unregister. */ unregisterMany(names) { if (!names) { throw new BaseError("Names cannot be null or undefined", { code: "REGISTRY_NAMES_NOT_NULL_OR_UNDEFINED", source: "Registry", }); } if (!Array.isArray(names)) { throw new BaseError("Names must be an array", { code: "REGISTRY_NAMES_NOT_ARRAY", source: "Registry", }); } this.LOGGER.debug(`Unregistering ${String(names.length)} items`, { source: "Registry" }); for (const name of names) { this.unregister(name); } this.LOGGER.debug(`${String(names.length)} items unregistered`, { source: "Registry" }); } /** * Clear the cache for a specific query or all caches if no query is provided. * @param {string} [cacheKey] Optional cache key to clear. If not provided, all caches are cleared. */ clearCache(cacheKey) { if (cacheKey) { this.CACHE.delete(cacheKey); this.LOGGER.debug(`Cache cleared for key: ${cacheKey}`, { source: "Registry" }); } else { this.CACHE.clear(); this.LOGGER.debug("All caches cleared", { source: "Registry" }); } } } export { BaseRegistry }; //# sourceMappingURL=registry.class.js.map