@decaf-ts/core
Version:
Core persistence module for the decaf framework
389 lines (388 loc) • 21.4 kB
TypeScript
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>);
}