@elsikora/cladi
Version:
ClaDI is a library for creating and managing classes in TypeScript.
221 lines (218 loc) • 8.3 kB
JavaScript
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