import { DataTable } from '../database/DataTable'; import { PaginationResult } from '../database/PaginationResult'; import { Field } from '../database/query'; import { Condition, ConditionGroup, ExistsSubquery } from '../database/query/conditions'; import { OrderByDirection } from '../database/query/features/HasOrderByFields'; import { EntityQuery } from './EntityQuery'; import { Scope } from './Scope'; /** A concrete entity class: constructible and carrying the BaseEntity statics. */ export type EntityClass = typeof BaseEntity & (new () => T); /** * Optional Active Record base class. Entities that extend BaseEntity get * instance-level save()/delete() and class-level query methods as convenience * delegates. All real logic lives in EntityRepository — BaseEntity is a * thin shell that calls Repository.get(this) and forwards. * * Entities that do NOT extend BaseEntity work identically through the * Repository directly: Repository.get(Country).where(...).find() * * Note: BaseEntity holds NO metadata. All metadata is stored inside * EntityRepository's internal store, populated exclusively by @Entity. */ export declare abstract class BaseEntity { private static _repo; /** * Called once per entity class the first time its repository is accessed. * Override to register global scopes: * * protected static booted(): void { * static.addGlobalScope('active', query => query.where('status', 'active')) * } */ protected static booted(): void; /** * Registers a named global scope applied to every query for this entity. * * // Inline callback: * static::addGlobalScope('active', query => query.where('status', 'active')) * * // Reusable Scope object (key = class name): * static::addGlobalScope(new ActiveScope) */ static addGlobalScope(this: EntityClass, nameOrScope: string | Scope, callback?: (query: EntityQuery) => void | Promise): void; /** * Returns an EntityQuery with the given named global scope(s) disabled. * * Product.withoutGlobalScope('active').get() */ static withoutGlobalScope(this: EntityClass, ...names: string[]): EntityQuery; /** * Returns an EntityQuery with ALL global scopes disabled. * * Product.withoutGlobalScopes().get() */ static withoutGlobalScopes(this: EntityClass): EntityQuery; static query(this: EntityClass): DataTable; static fromRow(this: EntityClass, row: Record): T; /** * Re-hydrates a plain object (typically the output of toJSON, or JSON.parse * of a serialized entity) back into a typed entity instance. Date fields and * related entities are restored recursively. */ static fromJSON(this: EntityClass, json: Record): T; static find(this: EntityClass, id: any): Promise; static get(this: EntityClass): Promise; static first(this: EntityClass): Promise; static count(this: EntityClass, column?: Field): Promise; static paginate(this: EntityClass, perPage?: number, page?: number): Promise>; /** * SUM of a column across every row this entity's global scopes let you see. * Sums to 0 over an empty result set. * * await Order.sum('amount') * await Order.where('paid', true).sum('amount') */ static sum(this: EntityClass, column: Field): Promise; /** AVG of a column, scoped. Null when nothing matched. */ static avg(this: EntityClass, column: Field): Promise; /** * MIN of a column, scoped and uncast (see `DataTable.min`). Null when nothing * matched. * * The value type comes first among the type parameters so it can be given * explicitly — `Payment.min('settledAt')` — while the entity type stays * inferred from the call. */ static min(this: EntityClass, column: Field): Promise; /** MAX of a column, scoped and uncast (see `DataTable.min`). Null when nothing matched. */ static max(this: EntityClass, column: Field): Promise; /** * Drops down to the underlying DataTable with this entity's global scopes * already applied, so rows come back raw instead of hydrated. For grouped * aggregates and other projections that are not a row of the table — see * `EntityQuery.toBase`. */ static toBase(this: EntityClass): Promise; static where(this: EntityClass, callback: (group: ConditionGroup) => void): EntityQuery; static where(this: EntityClass, condition: Condition): EntityQuery; static where(this: EntityClass, field: Field, value: any): EntityQuery; static where(this: EntityClass, field: Field, operator: string, value: any): EntityQuery; static whereIn(this: EntityClass, field: Field, values: any[]): EntityQuery; static whereNotIn(this: EntityClass, field: Field, values: any[]): EntityQuery; static whereBetween(this: EntityClass, field: Field, range: [any, any]): EntityQuery; static whereNotBetween(this: EntityClass, field: Field, range: [any, any]): EntityQuery; static whereNull(this: EntityClass, field: Field): EntityQuery; static whereNotNull(this: EntityClass, field: Field): EntityQuery; static whereLike(this: EntityClass, field: Field, pattern: string): EntityQuery; static whereNotLike(this: EntityClass, field: Field, pattern: string): EntityQuery; static whereColumn(this: EntityClass, field: Field, column: Field): EntityQuery; static whereColumn(this: EntityClass, field: Field, operator: string, column: Field): EntityQuery; static whereExists(this: EntityClass, subquery: ExistsSubquery): EntityQuery; static whereArrayContains(this: EntityClass, field: Field, value: any): EntityQuery; static whereNotExists(this: EntityClass, subquery: ExistsSubquery): EntityQuery; static orderBy(this: EntityClass, field: Field, direction?: OrderByDirection): EntityQuery; static orderByDesc(this: EntityClass, field: Field): EntityQuery; static groupBy(this: EntityClass, ...fields: Field[]): EntityQuery; static having(this: EntityClass, condition: Condition): EntityQuery; static having(this: EntityClass, field: Field, value: any): EntityQuery; static having(this: EntityClass, field: Field, operator: string, value: any): EntityQuery; static orHaving(this: EntityClass, condition: Condition): EntityQuery; static orHaving(this: EntityClass, field: Field, value: any): EntityQuery; static orHaving(this: EntityClass, field: Field, operator: string, value: any): EntityQuery; static distinct(this: EntityClass): EntityQuery; static limit(this: EntityClass, value: number): EntityQuery; static offset(this: EntityClass, value: number): EntityQuery; static select(this: EntityClass, ...fields: (Field | Field[])[]): EntityQuery; static when(this: EntityClass, condition: any, callback: (query: EntityQuery) => void): EntityQuery; static with(this: EntityClass, relations: Record) => void>): EntityQuery; static with(this: EntityClass, relations: string | string[], ...rest: string[]): EntityQuery; static whereHas(this: EntityClass, relationName: string, callback?: (query: EntityQuery) => void): EntityQuery; static orWhereHas(this: EntityClass, relationName: string, callback?: (query: EntityQuery) => void): EntityQuery; static joinRelationship(this: EntityClass, relationName: string): EntityQuery; static innerJoinRelationship(this: EntityClass, relationName: string): EntityQuery; static leftJoinRelationship(this: EntityClass, relationName: string): EntityQuery; /** * Inserts the given records in a single batch statement. Mirrors Eloquent's * `Model::insert($values)`: * * await Match.insert([ * { roundId: 4, position: 0, homeCompetitorIds: [1], status: 0 }, * { roundId: 4, position: 1, homeCompetitorIds: [2], status: 0 } * ]) * * Values are expressed as entity properties and mapped to columns with their * declared casts. Auto-generated columns are never written and generated keys * are not read back. Returns the number of affected rows. */ static insert(this: EntityClass, values: Record[]): Promise; /** * Inserts the given records, updating the conflicting columns when a row * already exists. Mirrors Eloquent's `Model::upsert($values, $uniqueBy, $update)`: * * await PlayerStatistics.upsert( * [{ playerId: 7, points: 120, updatedAt: new Date() }], * 'playerId', // unique-by property (or properties) * ['points', 'updatedAt'] // properties to overwrite on conflict (optional) * ) * * When `update` is omitted, every provided column that is not part of * `uniqueBy` is updated. Returns the number of affected rows. */ static upsert(this: EntityClass, values: Record[], uniqueBy: string | string[], update?: string[]): Promise; save(): Promise; delete(): Promise; /** * True if this entity (or, when given, a specific property) has unsaved * changes relative to its last hydration/save. * * user.email = 'new@x.com' * user.isDirty() // true * user.isDirty('name') // false */ isDirty(field?: string): boolean; /** * Returns a `{ property: value }` map of only the properties that changed * since this entity's last hydration/save. */ getDirty(): Record; toDto(): Record; /** * Serializes this entity into a plain, JSON-safe object: Date values become * ISO-8601 strings and loaded relationships are serialized recursively. * Delegates to the EntityRepository so behaviour matches * Repository.get(EntityClass).toJSON(instance). */ toJSON(): Record; }