UNPKG

@decaf-ts/core

Version:

Core persistence module for the decaf framework

433 lines (432 loc) 22.2 kB
import { BulkCrudOperationKeys, Context, IRepository, OperationKeys, Repository as Rep, RepositoryFlags } from "@decaf-ts/db-decorators"; import { Observable } from "../interfaces/Observable"; import { type Observer } from "../interfaces/Observer"; import { Adapter } from "../persistence/Adapter"; import { Constructor, Model } from "@decaf-ts/decorator-validation"; import { OrderDirection } from "./constants"; import { SequenceOptions } from "../interfaces/SequenceOptions"; import { Queriable } from "../interfaces/Queriable"; import { IndexMetadata } from "./types"; import { Condition } from "../query/Condition"; import { WhereOption } from "../query/options"; import { SelectSelector } from "../query/selectors"; import { Logger } from "@decaf-ts/logging"; import { ObserverHandler } from "../persistence/ObserverHandler"; import type { EventIds, ObserverFilter } from "../persistence"; /** * @description Type alias for Repository class with simplified generic parameters. * @summary Provides a more concise way to reference the Repository class with its generic parameters. * @template M - The model type that extends Model. * @template F - The repository flags type. * @template C - The context type. * @template Q - The query type. * @template A - The adapter type. * @typedef Repo * @memberOf module:core */ export type Repo<M extends Model<true | false>, F extends RepositoryFlags = any, C extends Context<F> = any, Q = any, A extends Adapter<any, Q, F, C> = any> = Repository<M, Q, A, F, C>; /** * @description Core repository implementation for database operations on models on a table by table way. * @summary Provides CRUD operations, querying capabilities, and observer pattern implementation for model persistence. * @template M - The model type that extends Model. * @template Q - The query type used by the adapter. * @template A - The adapter type for database operations. * @template F - The repository flags type. * @template C - The context type for operations. * @param {A} [adapter] - Optional adapter instance for database operations. * @param {Constructor<M>} [clazz] - Optional constructor for the model class. * @param {...any[]} [args] - Additional arguments for repository initialization. * @class Repository * @example * // Creating a repository for User model * const userRepo = Repository.forModel(User); * * // Using the repository for CRUD operations * const user = await userRepo.create(new User({ name: 'John' })); * const retrievedUser = await userRepo.read(user.id); * user.name = 'Jane'; * await userRepo.update(user); * await userRepo.delete(user.id); * * // Querying with conditions * const users = await userRepo * .select() * .where({ name: 'Jane' }) * .orderBy('createdAt', OrderDirection.DSC) * .limit(10) * .execute(); * @mermaid * sequenceDiagram * participant C as Client Code * participant R as Repository * participant A as Adapter * participant DB as Database * participant O as Observers * * C->>+R: create(model) * R->>R: createPrefix(model) * R->>+A: prepare(model) * A-->>-R: prepared data * R->>+A: create(table, id, record) * A->>+DB: Insert Operation * DB-->>-A: Result * A-->>-R: record * R->>+A: revert(record) * A-->>-R: model instance * R->>R: createSuffix(model) * R->>+O: updateObservers(table, CREATE, id) * O-->>-R: Notification complete * R-->>-C: created model */ export declare class Repository<M extends Model<true | false>, Q, A extends Adapter<any, Q, F, C>, F extends RepositoryFlags = RepositoryFlags, C extends Context<F> = Context<F>> extends Rep<M, F, C> implements Observable, Observer, Queriable<M>, IRepository<M, F, C> { private static _cache; protected observers: Observer[]; protected observerHandler?: ObserverHandler; private readonly _adapter; private _tableName; protected _overrides?: Partial<F>; private logger; /** * @description Logger instance for this repository. * @summary Provides access to the logger for this repository instance. * @return {Logger} The logger instance. */ get log(): Logger; /** * @description Adapter for database operations. * @summary Provides access to the adapter instance for this repository. * @template A - The adapter type. * @return {A} The adapter instance. * @throws {InternalError} If no adapter is found. */ protected get adapter(): A; /** * @description Table name for this repository's model. * @summary Gets the database table name associated with this repository's model. * @return {string} The table name. */ protected get tableName(): string; /** * @description Primary key properties for this repository's model. * @summary Gets the sequence options containing primary key information. * @return {SequenceOptions} The primary key properties. */ protected get pkProps(): SequenceOptions; constructor(adapter?: A, clazz?: Constructor<M>, ...args: any[]); /** * @description Creates a proxy with overridden repository flags. * @summary Returns a proxy of this repository with the specified flags overridden. * @param {Partial<F>} flags - The flags to override. * @return {Repository} A proxy of this repository with overridden flags. */ override(flags: Partial<F>): Repository<M, Q, A, F, C>; /** * @description Creates a new observer handler. * @summary Factory method for creating an observer handler instance. * @return {ObserverHandler} A new observer handler instance. */ protected ObserverHandler(): ObserverHandler; /** * @description Prepares a model for creation. * @summary Validates the model and prepares it for creation in the database. * @template M - The model type. * @param {M} model - The model to create. * @param {...any[]} args - Additional arguments. * @return The prepared model and context arguments. * @throws {ValidationError} If the model fails validation. */ protected createPrefix(model: M, ...args: any[]): Promise<[M, ...any[]]>; /** * @description Creates a model in the database. * @summary Persists a model instance to the database. * @param {M} model - The model to create. * @param {...any[]} args - Additional arguments. * @return {Promise<M>} The created model with updated properties. */ create(model: M, ...args: any[]): Promise<M>; /** * @description Post-creation hook. * @summary Executes after a model is created to perform additional operations. * @param {M} model - The created model. * @param {C} context - The operation context. * @return {Promise<M>} The processed model. */ createSuffix(model: M, context: C): Promise<M>; /** * @description Creates multiple models in the database. * @summary Persists multiple model instances to the database in a batch operation. * @param {M[]} models - The models to create. * @param {...any[]} args - Additional arguments. * @return {Promise<M[]>} The created models with updated properties. */ createAll(models: M[], ...args: any[]): Promise<M[]>; /** * @description Prepares multiple models for creation. * @summary Validates multiple models and prepares them for creation in the database. * @param {M[]} models - The models to create. * @param {...any[]} args - Additional arguments. * @return The prepared models and context arguments. * @throws {ValidationError} If any model fails validation. */ protected createAllPrefix(models: M[], ...args: any[]): Promise<any[]>; /** * @description Prepares for reading a model by ID. * @summary Prepares the context and enforces decorators before reading a model. * @param {string} key - The primary key of the model to read. * @param {...any[]} args - Additional arguments. * @return The key and context arguments. */ protected readPrefix(key: string, ...args: any[]): Promise<any[]>; /** * @description Reads a model from the database by ID. * @summary Retrieves a model instance from the database using its primary key. * @param {string|number|bigint} id - The primary key of the model to read. * @param {...any[]} args - Additional arguments. * @return {Promise<M>} The retrieved model instance. */ read(id: string | number | bigint, ...args: any[]): Promise<M>; /** * @description Prepares for reading multiple models by IDs. * @summary Prepares the context and enforces decorators before reading multiple models. * @param {string[]|number[]} keys - The primary keys of the models to read. * @param {...any[]} args - Additional arguments. * @return The keys and context arguments. */ protected readAllPrefix(keys: string[] | number[], ...args: any[]): Promise<any[]>; /** * @description Reads multiple models from the database by IDs. * @summary Retrieves multiple model instances from the database using their primary keys. * @param {string[]|number[]} keys - The primary keys of the models to read. * @param {...any[]} args - Additional arguments. * @return {Promise<M[]>} The retrieved model instances. */ readAll(keys: string[] | number[], ...args: any[]): Promise<M[]>; /** * @description Updates a model in the database. * @summary Persists changes to an existing model instance in the database. * @param {M} model - The model to update. * @param {...any[]} args - Additional arguments. * @return {Promise<M>} The updated model with refreshed properties. */ update(model: M, ...args: any[]): Promise<M>; /** * @description Prepares a model for update. * @summary Validates the model and prepares it for update in the database. * @param {M} model - The model to update. * @param {...any[]} args - Additional arguments. * @return The prepared model and context arguments. * @throws {InternalError} If the model has no primary key value. * @throws {ValidationError} If the model fails validation. */ protected updatePrefix(model: M, ...args: any[]): Promise<[M, ...args: any[]]>; /** * @description Updates multiple models in the database. * @summary Persists changes to multiple existing model instances in the database in a batch operation. * @param {M[]} models - The models to update. * @param {...any[]} args - Additional arguments. * @return {Promise<M[]>} The updated models with refreshed properties. */ updateAll(models: M[], ...args: any[]): Promise<M[]>; /** * @description Prepares multiple models for update. * @summary Validates multiple models and prepares them for update in the database. * @param {M[]} models - The models to update. * @param {...any[]} args - Additional arguments. * @return {Promise<any[]>} The prepared models and context arguments. * @throws {InternalError} If any model has no primary key value. * @throws {ValidationError} If any model fails validation. */ protected updateAllPrefix(models: M[], ...args: any[]): Promise<any[]>; /** * @description Prepares for deleting a model by ID. * @summary Prepares the context and enforces decorators before deleting a model. * @param {any} key - The primary key of the model to delete. * @param {...any[]} args - Additional arguments. * @return The key and context arguments. */ protected deletePrefix(key: any, ...args: any[]): Promise<any[]>; /** * @description Deletes a model from the database by ID. * @summary Removes a model instance from the database using its primary key. * @param {string|number|bigint} id - The primary key of the model to delete. * @param {...any[]} args - Additional arguments. * @return {Promise<M>} The deleted model instance. */ delete(id: string | number | bigint, ...args: any[]): Promise<M>; /** * @description Prepares for deleting multiple models by IDs. * @summary Prepares the context and enforces decorators before deleting multiple models. * @param {string[]|number[]} keys - The primary keys of the models to delete. * @param {...any[]} args - Additional arguments. * @return The keys and context arguments. */ protected deleteAllPrefix(keys: string[] | number[], ...args: any[]): Promise<any[]>; /** * @description Deletes multiple models from the database by IDs. * @summary Removes multiple model instances from the database using their primary keys. * @param {string[]|number[]} keys - The primary keys of the models to delete. * @param {...any[]} args - Additional arguments. * @return {Promise<M[]>} The deleted model instances. */ deleteAll(keys: string[] | number[], ...args: any[]): Promise<M[]>; /** * @description Creates a select query without specifying fields. * @summary Starts building a query that will return all fields of the model. * @template S - The array type of select selectors. * @return A query builder for the model. */ select<S extends readonly SelectSelector<M>[]>(): WhereOption<M, M[]>; /** * @description Creates a select query with specific fields. * @summary Starts building a query that will return only the specified fields of the model. * @template S - The array type of select selectors. * @param selector - The fields to select. * @return A query builder for the selected fields. */ select<S extends readonly SelectSelector<M>[]>(selector: readonly [...S]): WhereOption<M, Pick<M, S[number]>[]>; /** * @description Executes a query with the specified conditions and options. * @summary Provides a simplified way to query the database with common query parameters. * @param {Condition<M>} condition - The condition to filter records. * @param orderBy - The field to order results by. * @param {OrderDirection} [order=OrderDirection.ASC] - The sort direction. * @param {number} [limit] - Optional maximum number of results to return. * @param {number} [skip] - Optional number of results to skip. * @return {Promise<M[]>} The query results as model instances. */ query(condition: Condition<M>, orderBy: keyof M, order?: OrderDirection, limit?: number, skip?: number): Promise<M[]>; /** * @description Registers an observer for this repository. * @summary Adds an observer that will be notified of changes to models in this repository. * @param {Observer} observer - The observer to register. * @param {ObserverFilter} [filter] - Optional filter to limit which events the observer receives. * @return {void} * @see {Observable#observe} */ observe(observer: Observer, filter?: ObserverFilter): void; /** * @description Unregisters an observer from this repository. * @summary Removes an observer so it will no longer receive notifications of changes. * @param {Observer} observer - The observer to unregister. * @return {void} * @throws {InternalError} If the observer handler is not initialized. * @see {Observable#unObserve} */ unObserve(observer: Observer): void; /** * @description Notifies all observers of an event. * @summary Updates all registered observers with information about a database event. * @param {string} table - The table name where the event occurred. * @param {OperationKeys|BulkCrudOperationKeys|string} event - The type of event that occurred. * @param {EventIds} id - The ID or IDs of the affected records. * @param {...any[]} args - Additional arguments. * @return {Promise<void>} A promise that resolves when all observers have been notified. * @throws {InternalError} If the observer handler is not initialized. */ updateObservers(table: string, event: OperationKeys | BulkCrudOperationKeys | string, id: EventIds, ...args: any[]): Promise<void>; /** * @description Alias for updateObservers. * @summary Notifies all observers of an event (alias for updateObservers). * @param {string} table - The table name where the event occurred. * @param {OperationKeys|BulkCrudOperationKeys|string} event - The type of event that occurred. * @param {EventIds} id - The ID or IDs of the affected records. * @param {...any[]} args - Additional arguments. * @return {Promise<void>} A promise that resolves when all observers have been notified. */ refresh(table: string, event: OperationKeys | BulkCrudOperationKeys | string, id: EventIds, ...args: any[]): Promise<void>; /** * @description Creates or retrieves a repository for a model. * @summary Factory method that returns a repository instance for the specified model. * @template M - The model type that extends Model. * @template R - The repository type that extends Repo<M>. * @param {Constructor<M>} model - The model constructor. * @param {string} [defaultFlavour] - Optional default adapter flavour if not specified on the model. * @param {...any[]} [args] - Additional arguments to pass to the repository constructor. * @return {R} A repository instance for the model. * @throws {InternalError} If no adapter is registered for the flavour. */ static forModel<M extends Model, R extends Repo<M>>(model: Constructor<M>, alias?: string, ...args: any[]): R; /** * @description Retrieves a repository for a model from the cache. * @summary Gets a repository constructor or instance for the specified model from the internal cache. * @template M - The model type that extends Model. * @param {Constructor<M>} model - The model constructor. * @return {Constructor<Repo<M>> | Repo<M>} The repository constructor or instance. * @throws {InternalError} If no repository is registered for the model. */ private static get; /** * @description Registers a repository for a model. * @summary Associates a repository constructor or instance with a model in the internal cache. * @template M - The model type that extends Model. * @param {Constructor<M>} model - The model constructor. * @param {Constructor<Repo<M>> | Repo<M>} repo - The repository constructor or instance. * @throws {InternalError} If a repository is already registered for the model. */ static register<M extends Model>(model: Constructor<M>, repo: Constructor<Repo<M>> | Repo<M>, alias?: string): void; /** * @description Sets metadata on a model instance. * @summary Attaches metadata to a model instance using a non-enumerable property. * @template M - The model type that extends Model. * @param {M} model - The model instance. * @param {any} metadata - The metadata to attach to the model. */ static setMetadata<M extends Model>(model: M, metadata: any): void; /** * @description Gets metadata from a model instance. * @summary Retrieves previously attached metadata from a model instance. * @template M - The model type that extends Model. * @param {M} model - The model instance. * @return {any} The metadata or undefined if not found. */ static getMetadata<M extends Model>(model: M): any; /** * @description Removes metadata from a model instance. * @summary Deletes the metadata property from a model instance. * @template M - The model type that extends Model. * @param {M} model - The model instance. */ static removeMetadata<M extends Model>(model: M): void; /** * @description Gets sequence options for a model's primary key. * @summary Retrieves the sequence configuration for a model's primary key from metadata. * @template M - The model type that extends Model. * @param {M} model - The model instance. * @return {SequenceOptions} The sequence options for the model's primary key. * @throws {InternalError} If no sequence options are defined for the model. */ static getSequenceOptions<M extends Model>(model: M): SequenceOptions; /** * @description Gets all indexes defined on a model. * @summary Retrieves all index metadata from a model's property decorators. * @template M - The model type that extends Model. * @param {M | Constructor<M>} model - The model instance or constructor. * @return {Record<string, Record<string, IndexMetadata>>} A nested record of property names to index metadata. */ static indexes<M extends Model>(model: M | Constructor<M>): Record<string, Record<string, IndexMetadata>>; /** * @description Gets all relation properties defined on a model. * @summary Retrieves the names of all properties marked as relations in the model hierarchy. * @template M - The model type that extends Model. * @param {M | Constructor<M>} model - The model instance or constructor. * @return {string[]} An array of property names that are relations. */ static relations<M extends Model>(model: M | Constructor<M>): string[]; /** * @description Gets the table name for a model. * @summary Retrieves the database table name associated with a model. * @template M - The model type that extends Model. * @param {M | Constructor<M>} model - The model instance or constructor. * @return {string} The table name for the model. */ static table<M extends Model>(model: M | Constructor<M>): string; /** * @description Gets the column name for a model attribute. * @summary Retrieves the database column name for a model property. * @template M - The model type that extends Model. * @param {M} model - The model instance. * @param {string} attribute - The attribute/property name. * @return {string} The column name for the attribute. */ static column<M extends Model>(model: M, attribute: string): string; }