UNPKG

@decaf-ts/core

Version:

Core persistence module for the decaf framework

171 lines 7.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InjectablesRegistry = void 0; const injectable_decorators_1 = require("@decaf-ts/injectable-decorators"); const Repository_1 = require("./Repository.cjs"); const decorator_validation_1 = require("@decaf-ts/decorator-validation"); const utils_1 = require("./utils.cjs"); const constants_1 = require("./../persistence/constants.cjs"); const Adapter_1 = require("./../persistence/Adapter.cjs"); const logging_1 = require("@decaf-ts/logging"); const decoration_1 = require("@decaf-ts/decoration"); /** * @description Registry for injectable repositories with auto-resolution. * @summary Provides an InjectableRegistry implementation that resolves repositories by model name or constructor. If a repository * is not explicitly registered, it attempts to infer the correct repository using model metadata and the active or specified adapter flavour. * @param {void} [constructor] No constructor parameters required; the superclass handles internal state. * @class InjectablesRegistry * @example * // Basic usage: retrieve a repository by model name * const registry = new InjectablesRegistry(); * const userRepo = registry.get<UserRepository>('User'); * // If UserRepository is registered, it will be returned. Otherwise, a repository will be created if a User model exists. * * // Retrieve by constructor and specify adapter flavour * const repoByCtor = registry.get<UserRepository>(UserModel, 'ram'); * * // Retrieve by symbol (e.g., injectable token) * const token = Symbol.for('UserRepository'); * const byToken = registry.get<UserRepository>(token); * @mermaid * sequenceDiagram * participant C as Consumer * participant R as InjectablesRegistry * participant B as BaseRegistry * participant M as Model * participant A as Adapter * participant RP as Repository * C->>R: get(name, flavour?) * activate R * R->>B: super.get(name) * alt Found in base registry * B-->>R: injectable * R-->>C: injectable * else Not found * R->>M: Model.get(name) * alt Model found * R->>A: resolve flavour (from arg/metadata/current) * R->>RP: Repository.forModel(modelCtor, alias) * alt Repository instance * RP-->>R: repository instance * R-->>C: repository instance * else Repository ctor * R->>A: Adapter.get(resolvedFlavour) or Adapter.current * A-->>R: adapter instance * R->>RP: new repoCtor(adapter, modelCtor) * R-->>C: repository instance * end * else Model not found * R-->>C: undefined * end * end */ class InjectablesRegistry extends injectable_decorators_1.InjectableRegistryImp { get log() { if (!this.logger) this.logger = logging_1.Logging.for(this); return this.logger; } constructor() { super(); } /** * @description Retrieve an injectable with repository auto-resolution. * @summary Attempts to get an injectable from the base registry; if not found and the name refers to a known model, it * resolves the appropriate repository using the specified flavour or model metadata, falling back to the current adapter when needed. * @template T The injectable type to be returned. * @param {string | symbol | Constructor<T>} name Token, model name, or constructor associated with the injectable or model. * @param {string} [flavour] Optional adapter flavour (e.g., "ram"). If omitted, derives from metadata or current adapter. * @return {T | undefined} The located or auto-created injectable instance; otherwise undefined if it cannot be resolved. * @mermaid * sequenceDiagram * participant G as get(name, flavour?) * participant BR as BaseRegistry * participant M as Model * participant A as Adapter * participant RP as Repository * G->>BR: super.get(name) * alt Found * BR-->>G: injectable * else Not found * G->>M: derive modelCtor from name * alt modelCtor resolved * G->>A: resolve flavour (arg | metadata | current) * G->>RP: Repository.forModel(modelCtor, alias) * alt returns instance * RP-->>G: Repository instance * else returns ctor * G->>A: Adapter.get(flavour) | Adapter.current * A-->>G: adapter instance * G->>RP: new repoCtor(adapter, modelCtor) * end * else no modelCtor * G-->>G: return undefined * end * end */ get(name, flavour) { const log = this.log.for(this.get); // First, try base registry, but guard against thrown errors let injectable; try { injectable = super.get(name); } catch { // do nothing. we handle it later } if (!injectable) { let modelCtor; if (typeof name === "function") modelCtor = decorator_validation_1.Model.get(name.toString()) || name; else if (typeof name === "symbol" || typeof name === "string") { modelCtor = decorator_validation_1.Model.get(name.toString()); } if (!modelCtor) return undefined; // Resolve flavour from metadata if not provided const metaKey = constants_1.PersistenceKeys.ADAPTER; const resolvedFlavour = flavour || decoration_1.Metadata.get(modelCtor, metaKey); try { // Determine an alias to use: prefer a directly registered adapter; otherwise, if the current adapter // has the same flavour, use its alias to satisfy Repository.forModel/Adapter.get lookups. let aliasToUse = resolvedFlavour; try { if (resolvedFlavour) Adapter_1.Adapter.get(resolvedFlavour); } catch { const current = Adapter_1.Adapter.current; if (current && current.flavour === resolvedFlavour) aliasToUse = current.alias; } injectable = Repository_1.Repository.forModel(modelCtor, aliasToUse); if (injectable instanceof Repository_1.Repository) return injectable; // Otherwise, register the resolved injectable name for later retrieval const f = resolvedFlavour || decoration_1.Metadata.get(injectable.constructor, metaKey) || decoration_1.Metadata.get(modelCtor, metaKey); injectable_decorators_1.Injectables.register(injectable, (0, utils_1.generateInjectableNameForRepository)(modelCtor, f)); } catch (e) { log.debug(`No registered repository or adapter found. falling back to default adapter. Error: ${e?.message || JSON.stringify(e)}`); const repoCtor = Repository_1.Repository["get"](modelCtor, resolvedFlavour); if (typeof repoCtor === "function") { const adapter = resolvedFlavour ? Adapter_1.Adapter.get(resolvedFlavour) : Adapter_1.Adapter.current; if (!adapter) return undefined; const instance = new repoCtor(adapter, modelCtor); return instance; } } } return injectable; } } exports.InjectablesRegistry = InjectablesRegistry; //# sourceMappingURL=injectables.js.map