424 lines
15 KiB
TypeScript
424 lines
15 KiB
TypeScript
import {
|
|
type AnyEntity,
|
|
type Collection,
|
|
type Configuration,
|
|
type ConnectionType,
|
|
type Constructor,
|
|
type CountOptions,
|
|
DatabaseDriver,
|
|
type DeleteOptions,
|
|
type Dictionary,
|
|
type DriverMethodOptions,
|
|
type EntityData,
|
|
type EntityDictionary,
|
|
type EntityField,
|
|
EntityManagerType,
|
|
type EntityMetadata,
|
|
type EntityName,
|
|
type EntityProperty,
|
|
type FilterQuery,
|
|
type FindOneOptions,
|
|
type FindOptions,
|
|
type FormulaTable,
|
|
type LockOptions,
|
|
type LoggingOptions,
|
|
type NativeInsertUpdateManyOptions,
|
|
type NativeInsertUpdateOptions,
|
|
type ObjectQuery,
|
|
type Options,
|
|
type OrderDefinition,
|
|
type PopulateOptions,
|
|
type PopulatePath,
|
|
type Primary,
|
|
type QueryOrderMap,
|
|
type QueryResult,
|
|
type Raw,
|
|
RawQueryFragment,
|
|
type StreamOptions,
|
|
type Transaction,
|
|
type UpsertManyOptions,
|
|
type UpsertOptions,
|
|
} from '@mikro-orm/core';
|
|
import type { AbstractSqlConnection } from './AbstractSqlConnection.js';
|
|
import type { AbstractSqlPlatform } from './AbstractSqlPlatform.js';
|
|
import { type AnyQueryBuilder } from './query/QueryBuilder.js';
|
|
import { type NativeQueryBuilder } from './query/NativeQueryBuilder.js';
|
|
import { QueryType } from './query/enums.js';
|
|
import { SqlEntityManager } from './SqlEntityManager.js';
|
|
import type { InternalField } from './typings.js';
|
|
/** Base class for SQL database drivers, implementing find/insert/update/delete using QueryBuilder. */
|
|
export declare abstract class AbstractSqlDriver<
|
|
Connection extends AbstractSqlConnection = AbstractSqlConnection,
|
|
Platform extends AbstractSqlPlatform = AbstractSqlPlatform,
|
|
> extends DatabaseDriver<Connection> {
|
|
[EntityManagerType]: SqlEntityManager<this>;
|
|
protected readonly connection: Connection;
|
|
protected readonly replicas: Connection[];
|
|
protected readonly platform: Platform;
|
|
protected constructor(
|
|
config: Configuration,
|
|
platform: Platform,
|
|
connection: Constructor<Connection>,
|
|
connector: string[],
|
|
);
|
|
getPlatform(): Platform;
|
|
/** Evaluates a formula callback, handling both string and Raw return values. */
|
|
evaluateFormula(formula: (...args: any[]) => string | Raw, columns: any, table: FormulaTable): string;
|
|
/** For TPT entities, returns ownProps (columns in this table); otherwise returns all props. */
|
|
private getTableProps;
|
|
/** Creates a FormulaTable object for use in formula callbacks. */
|
|
private createFormulaTable;
|
|
private validateSqlOptions;
|
|
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
|
private createQueryBuilderFromOptions;
|
|
find<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(
|
|
entityName: EntityName<T>,
|
|
where: ObjectQuery<T>,
|
|
options?: FindOptions<T, P, F, E>,
|
|
): Promise<EntityData<T>[]>;
|
|
findOne<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(
|
|
entityName: EntityName<T>,
|
|
where: ObjectQuery<T>,
|
|
options?: FindOneOptions<T, P, F, E>,
|
|
): Promise<EntityData<T> | null>;
|
|
protected hasToManyJoins<T extends object>(hint: PopulateOptions<T>, meta: EntityMetadata<T>): boolean;
|
|
findVirtual<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: ObjectQuery<T>,
|
|
options: FindOptions<T, any, any, any>,
|
|
): Promise<EntityData<T>[]>;
|
|
countVirtual<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: ObjectQuery<T>,
|
|
options: CountOptions<T, any>,
|
|
): Promise<number>;
|
|
protected findFromVirtual<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: ObjectQuery<T>,
|
|
options: FindOptions<T, any> | CountOptions<T, any>,
|
|
type: QueryType,
|
|
): Promise<EntityData<T>[] | number>;
|
|
protected streamFromVirtual<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: FilterQuery<T>,
|
|
options: StreamOptions<T, any>,
|
|
): AsyncIterableIterator<EntityData<T>>;
|
|
protected wrapVirtualExpressionInSubquery<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
expression: string,
|
|
where: FilterQuery<T>,
|
|
options: FindOptions<T, any>,
|
|
type: QueryType,
|
|
): Promise<T[] | number>;
|
|
protected wrapVirtualExpressionInSubqueryStream<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
expression: string,
|
|
where: FilterQuery<T>,
|
|
options: FindOptions<T, any, any, any>,
|
|
type: QueryType.SELECT,
|
|
): AsyncIterableIterator<T>;
|
|
/**
|
|
* Virtual entities have no PKs, so to-many populate joins can't be deduplicated.
|
|
* Force balanced strategy to load to-many relations via separate queries.
|
|
*/
|
|
private forceBalancedStrategy;
|
|
mapResult<T extends object>(
|
|
result: EntityData<T>,
|
|
meta: EntityMetadata<T>,
|
|
populate?: PopulateOptions<T>[],
|
|
qb?: AnyQueryBuilder<T>,
|
|
map?: Dictionary,
|
|
): EntityData<T> | null;
|
|
/**
|
|
* Maps aliased columns from TPT parent tables back to their original field names.
|
|
* TPT parent columns are selected with aliases like `parent_alias__column_name`,
|
|
* and need to be renamed back to `column_name` for the result mapper to work.
|
|
*/
|
|
private mapTPTColumns;
|
|
private mapJoinedProps;
|
|
/**
|
|
* Maps a single property from a joined result row into the relation pojo.
|
|
* Handles polymorphic FKs, composite keys, Date parsing, and embedded objects.
|
|
*/
|
|
private mapJoinedProp;
|
|
count<T extends object>(entityName: EntityName<T>, where: any, options?: CountOptions<T>): Promise<number>;
|
|
nativeInsert<T extends object>(
|
|
entityName: EntityName<T>,
|
|
data: EntityDictionary<T>,
|
|
options?: NativeInsertUpdateOptions<T>,
|
|
): Promise<QueryResult<T>>;
|
|
nativeInsertMany<T extends object>(
|
|
entityName: EntityName<T>,
|
|
data: EntityDictionary<T>[],
|
|
options?: NativeInsertUpdateManyOptions<T>,
|
|
transform?: (sql: string) => string,
|
|
): Promise<QueryResult<T>>;
|
|
nativeUpdate<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: FilterQuery<T>,
|
|
data: EntityDictionary<T>,
|
|
options?: NativeInsertUpdateOptions<T> & UpsertOptions<T>,
|
|
): Promise<QueryResult<T>>;
|
|
nativeUpdateMany<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: FilterQuery<T>[],
|
|
data: EntityDictionary<T>[],
|
|
options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>,
|
|
transform?: (sql: string, params: any[]) => string,
|
|
): Promise<QueryResult<T>>;
|
|
nativeDelete<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: FilterQuery<T> | string | any,
|
|
options?: DeleteOptions<T>,
|
|
): Promise<QueryResult<T>>;
|
|
/**
|
|
* Fast comparison for collection snapshots that are represented by PK arrays.
|
|
* Compares scalars via `===` and fallbacks to Utils.equals()` for more complex types like Buffer.
|
|
* Always expects the same length of the arrays, since we only compare PKs of the same entity type.
|
|
*/
|
|
private comparePrimaryKeyArrays;
|
|
syncCollections<T extends object, O extends object>(
|
|
collections: Iterable<Collection<T, O>>,
|
|
options?: DriverMethodOptions,
|
|
): Promise<void>;
|
|
loadFromPivotTable<T extends object, O extends object>(
|
|
prop: EntityProperty,
|
|
owners: Primary<O>[][],
|
|
where?: FilterQuery<any>,
|
|
orderBy?: OrderDefinition<T>,
|
|
ctx?: Transaction,
|
|
options?: FindOptions<T, any, any, any>,
|
|
pivotJoin?: boolean,
|
|
): Promise<Dictionary<T[]>>;
|
|
/**
|
|
* Load from a polymorphic M:N pivot table.
|
|
*/
|
|
protected loadFromPolymorphicPivotTable<T extends object, O extends object>(
|
|
prop: EntityProperty,
|
|
owners: Primary<O>[][],
|
|
where?: FilterQuery<any>,
|
|
orderBy?: OrderDefinition<T>,
|
|
ctx?: Transaction,
|
|
options?: FindOptions<T, any, any, any>,
|
|
pivotJoin?: boolean,
|
|
): Promise<Dictionary<T[]>>;
|
|
/**
|
|
* Load from owner side of polymorphic M:N (e.g., Post -> Tags)
|
|
*/
|
|
protected loadPolymorphicPivotOwnerSide<T extends object, O extends object>(
|
|
prop: EntityProperty,
|
|
owners: Primary<O>[][],
|
|
where: FilterQuery<any>,
|
|
orderBy?: OrderDefinition<T>,
|
|
ctx?: Transaction,
|
|
options?: FindOptions<T, any, any, any>,
|
|
pivotJoin?: boolean,
|
|
inverseProp?: EntityProperty,
|
|
): Promise<Dictionary<T[]>>;
|
|
/**
|
|
* Load from inverse side of polymorphic M:N (e.g., Tag -> Posts)
|
|
* Uses single query with join via virtual relation on pivot.
|
|
*/
|
|
protected loadPolymorphicPivotInverseSide<T extends object, O extends object>(
|
|
prop: EntityProperty,
|
|
owners: Primary<O>[][],
|
|
where: FilterQuery<any>,
|
|
orderBy?: OrderDefinition<T>,
|
|
ctx?: Transaction,
|
|
options?: FindOptions<T, any, any, any>,
|
|
): Promise<Dictionary<T[]>>;
|
|
/**
|
|
* Build a map from owner PKs to their related entities from pivot table results.
|
|
*/
|
|
private buildPivotResultMap;
|
|
private wrapPopulateFilter;
|
|
private getPivotOrderBy;
|
|
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(
|
|
query: string | NativeQueryBuilder | RawQueryFragment,
|
|
params?: any[],
|
|
method?: 'all' | 'get' | 'run',
|
|
ctx?: Transaction,
|
|
loggerContext?: LoggingOptions,
|
|
): Promise<T>;
|
|
stream<T extends object>(
|
|
entityName: EntityName<T>,
|
|
where: FilterQuery<T>,
|
|
options: StreamOptions<T, any, any, any>,
|
|
): AsyncIterableIterator<T>;
|
|
/**
|
|
* 1:1 owner side needs to be marked for population so QB auto-joins the owner id
|
|
*/
|
|
protected autoJoinOneToOneOwner<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
populate: PopulateOptions<T>[],
|
|
fields?: readonly EntityField<T, any>[],
|
|
): PopulateOptions<T>[];
|
|
/**
|
|
* @internal
|
|
*/
|
|
joinedProps<T>(
|
|
meta: EntityMetadata,
|
|
populate: readonly PopulateOptions<T>[],
|
|
options?: {
|
|
strategy?: Options['loadStrategy'];
|
|
},
|
|
): PopulateOptions<T>[];
|
|
/**
|
|
* @internal
|
|
*/
|
|
mergeJoinedResult<T extends object>(
|
|
rawResults: EntityData<T>[],
|
|
meta: EntityMetadata<T>,
|
|
joinedProps: PopulateOptions<T>[],
|
|
): EntityData<T>[];
|
|
protected shouldHaveColumn<T, U>(
|
|
meta: EntityMetadata<T>,
|
|
prop: EntityProperty<U>,
|
|
populate: readonly PopulateOptions<U>[],
|
|
fields?: readonly InternalField<U>[],
|
|
exclude?: readonly InternalField<U>[],
|
|
): boolean;
|
|
protected getFieldsForJoinedLoad<T extends object>(
|
|
qb: AnyQueryBuilder<T>,
|
|
meta: EntityMetadata<T>,
|
|
options: FieldsForJoinedLoadOptions<T>,
|
|
): InternalField<T>[];
|
|
/**
|
|
* Adds LEFT JOINs and fields for TPT polymorphic loading when populating a relation to a TPT base class.
|
|
* @internal
|
|
*/
|
|
protected addTPTPolymorphicJoinsForRelation<T extends object>(
|
|
qb: AnyQueryBuilder<T>,
|
|
meta: EntityMetadata<T>,
|
|
baseAlias: string,
|
|
fields: InternalField<T>[],
|
|
): void;
|
|
/**
|
|
* Find the alias for a TPT child table in the query builder.
|
|
* @internal
|
|
*/
|
|
protected findTPTChildAlias<T extends object>(qb: AnyQueryBuilder<T>, childMeta: EntityMetadata): string | undefined;
|
|
/**
|
|
* Builds a CASE WHEN expression for TPT discriminator.
|
|
* Determines concrete entity type based on which child table has a non-null PK.
|
|
* @internal
|
|
*/
|
|
buildTPTDiscriminatorExpression(
|
|
meta: EntityMetadata,
|
|
descendants: EntityMetadata[],
|
|
aliasMap: Dictionary<string>,
|
|
baseAlias: string,
|
|
): Raw;
|
|
/**
|
|
* Maps TPT child-specific fields during hydration.
|
|
* When a relation points to a TPT base class, the actual entity might be a child class.
|
|
* This method reads the discriminator to determine the concrete type and maps child-specific fields.
|
|
* @internal
|
|
*/
|
|
protected mapTPTChildFields<T extends object>(
|
|
relationPojo: EntityData<T>,
|
|
meta: EntityMetadata<T>,
|
|
relationAlias: string,
|
|
qb: AnyQueryBuilder<T>,
|
|
root: EntityData<T>,
|
|
): void;
|
|
/**
|
|
* @internal
|
|
*/
|
|
mapPropToFieldNames<T extends object>(
|
|
qb: AnyQueryBuilder<T>,
|
|
prop: EntityProperty<T>,
|
|
tableAlias: string,
|
|
meta: EntityMetadata<T>,
|
|
schema?: string,
|
|
explicitFields?: readonly InternalField<T>[],
|
|
): InternalField<T>[];
|
|
/** @internal */
|
|
createQueryBuilder<T extends object>(
|
|
entityName: EntityName<T> | AnyQueryBuilder<T>,
|
|
ctx?: Transaction,
|
|
preferredConnectionType?: ConnectionType,
|
|
convertCustomTypes?: boolean,
|
|
loggerContext?: LoggingOptions,
|
|
alias?: string,
|
|
em?: SqlEntityManager,
|
|
): AnyQueryBuilder<T>;
|
|
protected resolveConnectionType(args: { ctx?: Transaction; connectionType?: ConnectionType }): ConnectionType;
|
|
protected extractManyToMany<T>(meta: EntityMetadata<T>, data: EntityDictionary<T>): EntityData<T>;
|
|
protected processManyToMany<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
pks: Primary<T>[],
|
|
collections: EntityData<T>,
|
|
clear: boolean,
|
|
options?: DriverMethodOptions,
|
|
): Promise<void>;
|
|
lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
|
|
protected buildPopulateWhere<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
joinedProps: PopulateOptions<T>[],
|
|
options: Pick<FindOptions<any>, 'populateWhere'>,
|
|
): ObjectQuery<T>;
|
|
/**
|
|
* Builds a UNION ALL (or UNION) subquery from `unionWhere` branches and merges it
|
|
* into the main WHERE as `pk IN (branch_1 UNION ALL branch_2 ...)`.
|
|
* Each branch is planned independently by the database, enabling per-table index usage.
|
|
*/
|
|
protected applyUnionWhere<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
where: ObjectQuery<T>,
|
|
options: FindOptions<T, any, any, any> | CountOptions<T> | NativeInsertUpdateOptions<T> | DeleteOptions<T>,
|
|
forDml?: boolean,
|
|
): Promise<ObjectQuery<T>>;
|
|
protected buildOrderBy<T extends object>(
|
|
qb: AnyQueryBuilder<T>,
|
|
meta: EntityMetadata<T>,
|
|
populate: PopulateOptions<T>[],
|
|
options: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>,
|
|
): QueryOrderMap<T>[];
|
|
protected buildPopulateOrderBy<T extends object>(
|
|
qb: AnyQueryBuilder<T>,
|
|
meta: EntityMetadata<T>,
|
|
populateOrderBy: QueryOrderMap<T>[],
|
|
parentPath: string,
|
|
explicit: boolean,
|
|
parentAlias?: string,
|
|
): QueryOrderMap<T>[];
|
|
protected buildJoinedPropsOrderBy<T extends object>(
|
|
qb: AnyQueryBuilder<T>,
|
|
meta: EntityMetadata<T>,
|
|
populate: PopulateOptions<T>[],
|
|
options?: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>,
|
|
parentPath?: string,
|
|
): QueryOrderMap<T>[];
|
|
private buildToManyOrderBy;
|
|
protected normalizeFields<T extends object>(fields: InternalField<T>[], prefix?: string): string[];
|
|
protected processField<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
prop: EntityProperty<T> | undefined,
|
|
field: string,
|
|
ret: InternalField<T>[],
|
|
): void;
|
|
protected buildFields<T extends object>(
|
|
meta: EntityMetadata<T>,
|
|
populate: PopulateOptions<T>[],
|
|
joinedProps: PopulateOptions<T>[],
|
|
qb: AnyQueryBuilder<T>,
|
|
alias: string,
|
|
options: Pick<FindOptions<T, any, any, any>, 'strategy' | 'fields' | 'exclude'>,
|
|
schema?: string,
|
|
): InternalField<T>[];
|
|
}
|
|
interface FieldsForJoinedLoadOptions<T extends object> {
|
|
explicitFields?: readonly InternalField<T>[];
|
|
exclude?: readonly InternalField<T>[];
|
|
populate?: readonly PopulateOptions<T>[];
|
|
strategy?: Options['loadStrategy'];
|
|
populateWhere?: FindOptions<any>['populateWhere'];
|
|
populateFilter?: FindOptions<any>['populateFilter'];
|
|
parentTableAlias: string;
|
|
parentJoinPath?: string;
|
|
count?: boolean;
|
|
schema?: string;
|
|
}
|
|
export {};
|