UNPKG

@decaf-ts/db-decorators

Version:

Agnostic database decorators and repository

169 lines 5.33 kB
import { DefaultRepositoryFlags } from "./constants.js"; import { ObjectAccumulator } from "typed-object-accumulator"; import { Logging } from "@decaf-ts/logging"; /** * @description Default factory for creating context instances. * @summary A factory function that creates new Context instances with the provided repository flags. * It automatically adds a timestamp to the context and returns a properly typed context instance. * @const DefaultContextFactory * @memberOf module:db-decorators */ export const DefaultContextFactory = (arg) => { return new Context().accumulate(Object.assign({}, arg, { timestamp: new Date(), logger: arg.logger || Logging.get(), })); }; /** * @description A context management class for handling repository operations. * @summary The Context class provides a mechanism for managing repository operations with flags, * parent-child relationships, and state accumulation. It allows for hierarchical context chains * and maintains operation-specific configurations while supporting type safety through generics. * * @template F - Type extending RepositoryFlags that defines the context configuration * * @param {ObjectAccumulator<F>} cache - The internal cache storing accumulated values * * @class * * @example * ```typescript * // Creating a new context with repository flags * const context = new Context<RepositoryFlags>(); * * // Accumulating values * const enrichedContext = context.accumulate({ * writeOperation: true, * affectedTables: ['users'], * operation: OperationKeys.CREATE * }); * * // Accessing values * const isWrite = enrichedContext.get('writeOperation'); // true * const tables = enrichedContext.get('affectedTables'); // ['users'] * ``` * * @mermaid * sequenceDiagram * participant C as Client * participant Ctx as Context * participant Cache as ObjectAccumulator * * C->>Ctx: new Context() * Ctx->>Cache: create cache * * C->>Ctx: accumulate(value) * Ctx->>Cache: accumulate(value) * Cache-->>Ctx: updated cache * Ctx-->>C: updated context * * C->>Ctx: get(key) * Ctx->>Cache: get(key) * alt Key exists in cache * Cache-->>Ctx: value * else Key not found * Ctx->>Ctx: check parent context * alt Parent exists * Ctx->>Parent: get(key) * Parent-->>Ctx: value * else No parent * Ctx-->>C: throw error * end * end * Ctx-->>C: requested value */ export class Context { constructor(ctx) { this.cache = new ObjectAccumulator(); Object.defineProperty(this, "cache", { value: ctx ? ctx["cache"] : new ObjectAccumulator(), writable: false, enumerable: false, configurable: true, }); } static { this.factory = DefaultContextFactory; } /** * @description Accumulates new values into the context. * @summary Merges the provided value object with the existing context state, * creating a new immutable cache state. */ accumulate(value) { Object.defineProperty(this, "cache", { value: this.cache.accumulate(value), writable: false, enumerable: false, configurable: true, }); return this; } get logger() { return this.cache.logger; } get timestamp() { return this.cache.timestamp; } /** * @description Retrieves a value from the context by key. * @param {string} key * @return {any} */ get(key) { try { return this.cache.get(key); } catch (e) { const parent = this.cache.parentContext; if (parent) return parent.get(key); throw e; } } /** * @description Creates a child context from another context */ static childFrom(context, overrides) { return Context.factory(Object.assign({}, context.cache, overrides || {})); } /** * @description Creates a new context from operation parameters */ static async from(operation, overrides, model, // eslint-disable-next-line @typescript-eslint/no-unused-vars ...args) { return Context.factory(Object.assign({}, DefaultRepositoryFlags, overrides, { operation: operation, model: model, logger: overrides.logger || Logging.get(), })); } /** * @description Prepares arguments for context operations */ static async args(operation, model, args, contextual, overrides) { const last = args.pop(); async function getContext() { if (contextual) return contextual.context(operation, overrides || {}, model, ...args); return Context.from(operation, overrides || {}, model, ...args); } let c; if (last) { if (last instanceof Context) { c = last; args.push(last); } else { args.push(last); c = (await getContext()); args.push(c); } } else { c = (await getContext()); args.push(c); } return { context: c, args: args }; } } //# sourceMappingURL=Context.js.map