import type { AbstractDataSource } from '../../datasources'; import type { AbstractEntity, IdType } from '../../models'; import type { IModelMetadata } from '../../../helpers/inversion'; import type { TClass, TNullable } from '@venizia/ignis-helpers/common'; import { BaseHelper } from '@venizia/ignis-helpers/core'; import type { IExtraOptions, IPersistableRepository, IWithReadRetry, TCount, TDataWithRange, TFindOneOptions, TFindOptions, TFindRangeOptions, TRepositoryOperationScope } from '../common'; import type { TByIdFilter, TFields, TFilter, TRow, TWhere } from '@venizia/ignis-filter'; /** * Engine-neutral repository plumbing - lazy dataSource/entity resolution, class-keyed `@model` * settings, operation scope. `TOptions` defaults to `IExtraOptions` so connectors can narrow it * while staying assignable to this base. */ export declare abstract class AbstractRepository extends BaseHelper implements IPersistableRepository { protected _operationScope: TRepositoryOperationScope; /** Lazy-resolved on first access if not provided in constructor. */ protected _dataSource?: AbstractDataSource; /** Lazy-resolved from @repository metadata on first access. */ protected _entity?: AbstractEntity; /** * Memoized @model settings for `this.entity`'s class. `null` means not yet resolved - `undefined` * is itself a valid resolved value: the model declares no settings. */ private _modelSettings; constructor(dataSource?: AbstractDataSource, opts?: { scope?: string; entityClass?: TClass; operationScope?: TRepositoryOperationScope; }); get dataSource(): AbstractDataSource; set dataSource(value: AbstractDataSource); /** Auto-resolves from @repository metadata if not explicitly set. */ get entity(): AbstractEntity; set entity(value: AbstractEntity); get operationScope(): TRepositoryOperationScope; setDataSource(opts: { dataSource: AbstractDataSource; }): void; getEntity(): AbstractEntity; /** * Resolved `@model` settings for `this.entity`'s class, keyed by Reflect target - not by * `entity.name`, which can diverge from the `@model` registry key. */ protected get modelSettings(): IModelMetadata['settings']; protected get hiddenFields(): string[]; /** Default where from @model settings.query.filter.where, AND-merged into every query unless skipped. */ protected get defaultWhere(): TWhere | undefined; protected get defaultLimit(): number | undefined; /** Largest `limit` a caller may ask for, when the model declares one; undefined leaves the tier's own default in force. */ protected get maxLimit(): number | undefined; /** * Both bounds, in one place, for every tier. * * The upper bound is the point: `@model({ settings: { maxLimit } })` is public and validated at * decoration time, but the relational tier read it nowhere, so `maxLimit: 2` still issued * `LIMIT 50000000`. * * The lower bound matters just as much and is easy to miss: a NEGATIVE limit is not a smaller * page. Drizzle renders the LIMIT clause only when the value is `>= 0`, so a negative one removes * the clause and returns the whole table. The wire schema now rejects it too, but a server-side * caller reaches this method without passing through the schema at all. */ protected assertLimitWithinCeiling(opts: { limit?: number; scope?: string; }): void; /** * The whole filter, relations included. Checking only the top-level `limit` left the identical * defect reachable one level down: a relation scope's negative limit drops Drizzle's LIMIT clause * for that relation and loads the entire related table. * * A relation's limit gets the SHAPE check only, not a ceiling. The ceiling belongs to the * relation's own model, which this repository cannot resolve - claiming otherwise would enforce * the parent's `maxLimit` on a different entity. */ protected assertFilterLimits(opts: { filter?: TFilter; scope?: string; }): void; /** Resolves the entity instance from @repository metadata on first access. */ protected resolveEntity(): AbstractEntity; /** Rejects a verb the current operation scope does not permit. */ protected denyOperation(opts: { methodName: string; }): never; /** * Shared retry orchestration for read verbs. Inside a transaction retry is skipped - the pool * routes transactions to the primary, so there is no replica lag to wait out. */ protected executeReadWithRetry(opts: { operation: string; options: IExtraOptions & IWithReadRetry; defaultUntil: (result: TResult) => boolean; execution: () => Promise; }): Promise; /** * A copy of `options` without `retry`, so re-entering a read verb takes its non-retry path - this * is what keeps the retry recursion single-depth. Copy-then-delete rather than a rest-destructure * (lint rejects the unused rest sibling) or `lodash/omit` (its `Omit<>` return type is not * assignable back to `TOptions`). */ private omitReadRetry; /** `find`, re-executed until the retry predicate holds - connectors dispatch here from `find` when `options.retry` is set. */ protected findUntil(opts: { filter: TFilter; options: TFindOptions; }): Promise>; /** `find` with the range envelope, re-executed until the retry predicate holds - split from `findUntil` so each result shape is checked against its own `find` overload. */ protected findRangeUntil(opts: { filter: TFilter; options: TFindRangeOptions; }): Promise>; /** `findOne`, re-executed until the retry predicate holds - also serves `findById` via its findOne delegation. */ protected findOneUntil(opts: { filter: TFilter; options: TFindOneOptions; }): Promise>; abstract count(opts: { where: TWhere; options?: TOptions; }): Promise; abstract existsWith(opts: { where: TWhere; options?: TOptions; }): Promise; abstract find = TFields>(opts: { filter: TFilter; options: TFindRangeOptions>; }): Promise>>; abstract find = TFields>(opts: { filter: TFilter; options?: TFindOptions>; }): Promise>>; abstract findOne = TFields>(opts: { filter: TFilter; options?: TFindOneOptions>; }): Promise>>; abstract findById = TFields>(opts: { id: IdType; filter?: TByIdFilter; options?: TFindOneOptions>; }): Promise>>; abstract create(opts: { data: TPersistObject; options: TOptions & { shouldReturn: false; }; }): Promise; abstract create(opts: { data: TPersistObject; options?: TOptions & { shouldReturn?: true; }; }): Promise; abstract createAll(opts: { data: Array; options: TOptions & { shouldReturn: false; }; }): Promise; abstract createAll(opts: { data: Array; options?: TOptions & { shouldReturn?: true; }; }): Promise; }>; abstract updateById(opts: { id: IdType; data: Partial; options: TOptions & { shouldReturn: false; }; }): Promise; abstract updateById(opts: { id: IdType; data: Partial; options?: TOptions & { shouldReturn?: true; }; }): Promise; abstract updateAll(opts: { data: Partial; where: TWhere; options: TOptions & { shouldReturn: false; force?: boolean; }; }): Promise; abstract updateAll(opts: { data: Partial; where: TWhere; options?: TOptions & { shouldReturn?: true; force?: boolean; }; }): Promise | null; }>; /** Alias for updateAll. */ updateBy(opts: { data: Partial; where: TWhere; options: TOptions & { shouldReturn: false; force?: boolean; }; }): Promise; updateBy(opts: { data: Partial; where: TWhere; options?: TOptions & { shouldReturn?: true; force?: boolean; }; }): Promise | null; }>; abstract deleteById(opts: { id: IdType; options: TOptions & { shouldReturn: false; }; }): Promise; abstract deleteById(opts: { id: IdType; options?: TOptions & { shouldReturn?: true; }; }): Promise; abstract deleteAll(opts: { where?: TWhere; options: TOptions & { shouldReturn: false; force?: boolean; }; }): Promise; abstract deleteAll(opts: { where?: TWhere; options?: TOptions & { shouldReturn?: true; force?: boolean; }; }): Promise | null; }>; /** Alias for deleteAll. */ deleteBy(opts: { where: TWhere; options: TOptions & { shouldReturn: false; force?: boolean; }; }): Promise; deleteBy(opts: { where: TWhere; options?: TOptions & { shouldReturn?: true; force?: boolean; }; }): Promise | null; }>; } //# sourceMappingURL=abstract.d.ts.map