Source

repository/utils.ts

import { InternalError } from "@decaf-ts/db-decorators";
import { Constructor, sf } from "@decaf-ts/decorator-validation";
import { Adapter } from "../persistence/Adapter";
import { PersistenceKeys } from "../persistence/constants";
import { Model } from "@decaf-ts/decorator-validation";
import { getTableName } from "../identity/utils";

/**
 * @description Generates a unique injectable name for a repository.
 * @summary Creates a standardized injectable token for repositories using the adapter flavour and model table name.
 * This helps the DI system register and resolve repository instances consistently across adapters.
 * @template T The model type that extends Model.
 * @param {Constructor<T> | T} model The model constructor or instance from which to derive the table name.
 * @param {string} [flavour] Optional adapter flavour/alias. If omitted, it is read from model metadata.
 * @return {string} A namespaced injectable token for the repository (e.g., "db:repo:ram:users").
 * @throws {InternalError} If the flavour cannot be determined from arguments or metadata.
 * @function generateInjectableNameForRepository
 * @mermaid
 * sequenceDiagram
 *   participant C as Caller
 *   participant U as generateInjectableNameForRepository
 *   participant R as Reflect Metadata
 *   participant A as Adapter
 *   participant S as String Formatter
 *   C->>U: call(model, flavour?)
 *   alt flavour provided
 *     U-->>U: use provided flavour
 *   else flavour not provided
 *     U->>A: Adapter.key(ADAPTER)
 *     U->>R: getMetadata(key, model|model.ctor)
 *     alt metadata present
 *       R-->>U: flavour
 *     else missing
 *       U-->>C: throw InternalError
 *     end
 *   end
 *   U->>S: sf(INJECTABLE, flavour, Repository.table(model))
 *   S-->>C: token string
 * @memberOf module:core
 */
export function generateInjectableNameForRepository<T extends Model>(
  model: Constructor<T> | T,
  flavour?: string
): string {
  if (!flavour) {
    const key = Adapter.key(PersistenceKeys.ADAPTER);
    flavour = Reflect.getMetadata(
      key,
      model instanceof Model ? model.constructor : model
    );
    if (!flavour)
      throw new InternalError(
        `Could not retrieve flavour from model ${model instanceof Model ? model.constructor.name : model.name}`
      );
  }
  return sf(PersistenceKeys.INJECTABLE, flavour, getTableName(model));
}