UNPKG

@decaf-ts/core

Version:

Core persistence module for the decaf framework

389 lines (388 loc) 21.4 kB
import { BulkCrudOperationKeys, IRepository, OperationKeys, Repository as Rep, PrimaryKeyType } from "@decaf-ts/db-decorators"; import { Logger } from "@decaf-ts/logging"; import { ContextualizedArgs, MaybeContextualArg } from "../utils/ContextualLoggedClass"; import { Adapter } from "../persistence/Adapter"; import { ObserverHandler } from "../persistence/ObserverHandler"; import type { DirectionLimitOffset, QueryOptions } from "../query/types"; import { SelectSelector } from "../query/selectors"; import { WhereOption } from "../query/options"; import { Condition } from "../query/Condition"; import { Queriable } from "../interfaces/Queriable"; import { SequenceOptions } from "../interfaces/SequenceOptions"; import { OrderDirection } from "./constants"; import type { ContextOf, EventIds, FlagsOf, InferredAdapterConfig, ObserverFilter, PersistenceObservable, PersistenceObserver } from "../persistence/types"; import type { FlagsOf as ContextualFlagsOf } from "@decaf-ts/db-decorators"; import type { Observer } from "../interfaces/Observer"; import { Constructor } from "@decaf-ts/decoration"; import { Model } from "@decaf-ts/decorator-validation"; import { SerializedPage } from "../query/index"; /** * @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<boolean>> = Repository<M, any>; /** * @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<boolean>, A extends Adapter<any, any, any, any>> extends Rep<M, ContextOf<A>> implements PersistenceObservable<ContextOf<A>>, PersistenceObserver<ContextOf<A>>, Queriable<M>, IRepository<M, ContextOf<A>> { private static _cache; protected observers: Observer[]; protected observerHandler?: ObserverHandler; private readonly _adapter; private _tableName; protected _overrides: Partial<FlagsOf<ContextOf<A>>> & Partial<ContextualFlagsOf<ContextOf<A>>>; 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. * @deprecated for Model.sequenceFor(class) */ protected get pkProps(): SequenceOptions; constructor(adapter?: A, clazz?: Constructor<M>, ...args: any[]); protected logCtx<ARGS extends any[]>(args: ARGS, method: (...args: any[]) => any): ContextualizedArgs<ContextOf<A>, ARGS>; /** * @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<FlagsOf<ContextOf<A>>>): this; /** * @description Creates a new instance of the Repository class with a specific adapter and arguments. * * @template A - The type of the adapter. * @template Q - The type of the query builder. * @template F - The type of the filter. * @template C - The type of the context. * * @param {Partial<InferredAdapterConfig<A>>} conf - adapter configurations to override. * @param [args] - Additional arguments to be passed to the new instance. * * @return A new instance of the Repository class with the specified adapter and arguments. */ for(conf: Partial<InferredAdapterConfig<A>>, ...args: any[]): this; /** * @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: MaybeContextualArg<ContextOf<A>>): Promise<[M, ...any[], ContextOf<A>]>; /** * @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: MaybeContextualArg<ContextOf<A>>): 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: MaybeContextualArg<ContextOf<A>>): 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: MaybeContextualArg<ContextOf<A>>): Promise<[M[], ...any[], ContextOf<A>]>; /** * @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: PrimaryKeyType, ...args: MaybeContextualArg<ContextOf<A>>): Promise<[PrimaryKeyType, ...any[], ContextOf<A>]>; /** * @description Reads a model from the database by ID. * @summary Retrieves a model instance from the database using its primary key. * @param {PrimaryKeyType} id - The primary key of the model to read. * @param {...any[]} args - Additional arguments. * @return {Promise<M>} The retrieved model instance. */ read(id: PrimaryKeyType, ...args: MaybeContextualArg<ContextOf<A>>): 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: PrimaryKeyType[], ...args: MaybeContextualArg<ContextOf<A>>): Promise<[PrimaryKeyType[], ...any[], ContextOf<A>]>; /** * @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: PrimaryKeyType[], ...args: MaybeContextualArg<ContextOf<A>>): 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: MaybeContextualArg<ContextOf<A>>): 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: MaybeContextualArg<ContextOf<A>>): Promise<[M, ...args: any[], ContextOf<A>, M | undefined]>; /** * @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: MaybeContextualArg<ContextOf<A>>): 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: MaybeContextualArg<ContextOf<A>>): Promise<[M[], ...args: any[], ContextOf<A>, M[] | undefined]>; /** * @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: PrimaryKeyType, ...args: MaybeContextualArg<ContextOf<A>>): Promise<[PrimaryKeyType, ...any[], ContextOf<A>]>; /** * @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: PrimaryKeyType, ...args: MaybeContextualArg<ContextOf<A>>): 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: PrimaryKeyType[], ...args: MaybeContextualArg<ContextOf<A>>): Promise<[PrimaryKeyType[], ...any[], ContextOf<A>]>; /** * @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: PrimaryKeyType[], ...args: MaybeContextualArg<ContextOf<A>>): 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, ...args: MaybeContextualArg<ContextOf<A>>): Promise<M[]>; listBy(key: keyof M, order: OrderDirection, ...args: MaybeContextualArg<ContextOf<A>>): Promise<M[]>; paginateBy(key: keyof M, order: OrderDirection, ref?: Omit<DirectionLimitOffset, "direction">, ...args: MaybeContextualArg<ContextOf<A>>): Promise<SerializedPage<M>>; findOneBy(key: keyof M, value: any, ...args: MaybeContextualArg<ContextOf<A>>): Promise<M>; findBy(key: keyof M, value: any, ...args: MaybeContextualArg<ContextOf<A>>): Promise<M[]>; statement(name: string, ...args: MaybeContextualArg<ContextOf<A>>): Promise<any>; attr(prop: keyof M): import("../query/options").AttributeOption<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: Constructor<M> | string, event: OperationKeys | BulkCrudOperationKeys | string, id: EventIds, ...args: MaybeContextualArg<ContextOf<A>>): 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: Constructor<M>, event: OperationKeys | BulkCrudOperationKeys | string, id: EventIds, ...args: MaybeContextualArg<ContextOf<A>>): 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} [alias] - 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. * @param {string} [alias] - The adapter alias. * @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. * @param {string} [alias] the adapter alias/flavour. * @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; static statements<R extends Repository<any, any>, K extends keyof R>(repo: Constructor<R> | R, method?: K): undefined | (K extends keyof R ? boolean : (keyof R)[]); static queries<R extends Repository<any, any>, K extends keyof R>(repo: Constructor<R> | R, method?: K): undefined | (K extends keyof R ? QueryOptions : Record<keyof R, QueryOptions>); }