@mikro-orm/core 7.1.0-dev.8 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EntityManager.d.ts +70 -5
- package/EntityManager.js +175 -23
- package/README.md +2 -1
- package/connections/Connection.d.ts +67 -1
- package/connections/Connection.js +64 -0
- package/drivers/IDatabaseDriver.d.ts +30 -6
- package/entity/BaseEntity.d.ts +68 -1
- package/entity/BaseEntity.js +18 -0
- package/entity/Collection.d.ts +4 -1
- package/entity/Collection.js +15 -4
- package/entity/EntityAssigner.js +8 -0
- package/entity/EntityFactory.js +5 -3
- package/entity/EntityLoader.d.ts +8 -1
- package/entity/EntityLoader.js +97 -29
- package/entity/EntityRepository.d.ts +12 -2
- package/entity/EntityRepository.js +12 -0
- package/entity/Reference.d.ts +42 -1
- package/entity/Reference.js +9 -0
- package/entity/defineEntity.d.ts +69 -16
- package/entity/defineEntity.js +17 -0
- package/entity/utils.js +4 -5
- package/enums.d.ts +8 -1
- package/index.d.ts +1 -1
- package/metadata/EntitySchema.js +18 -0
- package/metadata/MetadataDiscovery.d.ts +1 -0
- package/metadata/MetadataDiscovery.js +79 -15
- package/metadata/MetadataValidator.d.ts +26 -0
- package/metadata/MetadataValidator.js +228 -1
- package/metadata/Routine.d.ts +74 -0
- package/metadata/Routine.js +140 -0
- package/metadata/index.d.ts +1 -0
- package/metadata/index.js +1 -0
- package/metadata/types.d.ts +75 -8
- package/package.json +1 -1
- package/platforms/Platform.d.ts +13 -3
- package/platforms/Platform.js +51 -6
- package/serialization/EntitySerializer.js +4 -3
- package/typings.d.ts +323 -21
- package/typings.js +32 -12
- package/unit-of-work/UnitOfWork.js +43 -5
- package/utils/AbstractMigrator.d.ts +9 -4
- package/utils/AbstractMigrator.js +60 -28
- package/utils/AbstractSchemaGenerator.d.ts +1 -1
- package/utils/AbstractSchemaGenerator.js +4 -1
- package/utils/Configuration.d.ts +30 -0
- package/utils/Configuration.js +45 -0
- package/utils/DataloaderUtils.d.ts +10 -1
- package/utils/DataloaderUtils.js +78 -0
- package/utils/EntityComparator.js +1 -1
- package/utils/TransactionManager.js +2 -0
- package/utils/Utils.js +1 -1
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/partition-utils.d.ts +17 -0
- package/utils/partition-utils.js +79 -0
- package/utils/upsert-utils.d.ts +2 -0
- package/utils/upsert-utils.js +26 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { RoutineArgsOf, RoutineConfig, RoutineDataAccess, RoutineIgnoreField, RoutineKind, RoutineParamMap, RoutineProperty, RoutineReturnOf, RoutineReturns, RoutineSecurity } from '../typings.js';
|
|
2
|
+
import type { Type } from '../types/Type.js';
|
|
3
|
+
import type { Raw } from '../utils/RawQueryFragment.js';
|
|
4
|
+
/**
|
|
5
|
+
* Stored procedure or function declaration. Register instances via the `routines` config option
|
|
6
|
+
* passed to `MikroORM.init`, then call them through `em.callRoutine(routine, args)`.
|
|
7
|
+
*
|
|
8
|
+
* `TArgs` and `TReturn` are inferred from the literal config, so `em.callRoutine` is fully typed
|
|
9
|
+
* without threading generics through the call site. Reach for {@link Routine.create} when the
|
|
10
|
+
* inferred type is too loose — typically an `object` return that should be a concrete shape
|
|
11
|
+
* rather than `Dictionary`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const HashUser = new Routine({
|
|
16
|
+
* name: 'hash_user',
|
|
17
|
+
* type: 'function',
|
|
18
|
+
* params: {
|
|
19
|
+
* name: { type: 'varchar(255)' },
|
|
20
|
+
* salt: { type: 'varchar(255)' },
|
|
21
|
+
* },
|
|
22
|
+
* returns: { runtimeType: 'string', columnType: 'char(40)' },
|
|
23
|
+
* body: 'SELECT SHA1(CONCAT(name, salt))',
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* await MikroORM.init({ entities: [User], routines: [HashUser] });
|
|
27
|
+
*
|
|
28
|
+
* // args typed as `{ name: string; salt: string }`, result typed as `string`:
|
|
29
|
+
* const hash = await em.callRoutine(HashUser, { name: 'jon', salt: 'pepper' });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class Routine<const TConfig extends RoutineConfig = RoutineConfig, TArgs = RoutineArgsOf<TConfig>, TReturn = RoutineReturnOf<TConfig>> {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly type: RoutineKind;
|
|
35
|
+
readonly schema?: string;
|
|
36
|
+
readonly comment?: string;
|
|
37
|
+
readonly security?: RoutineSecurity;
|
|
38
|
+
readonly definer?: string;
|
|
39
|
+
readonly deterministic?: boolean;
|
|
40
|
+
readonly dataAccess?: RoutineDataAccess;
|
|
41
|
+
readonly language?: string;
|
|
42
|
+
readonly body?: string | Raw | ((params: RoutineParamMap<any>, em: any) => string | Raw);
|
|
43
|
+
readonly expression?: string;
|
|
44
|
+
readonly bodyJs?: (params: any) => unknown;
|
|
45
|
+
readonly returns?: RoutineReturns;
|
|
46
|
+
readonly returnCustomType?: Type<unknown>;
|
|
47
|
+
readonly ignoreSchemaChanges?: RoutineIgnoreField[];
|
|
48
|
+
readonly params: RoutineProperty[];
|
|
49
|
+
constructor(config: TConfig);
|
|
50
|
+
/** @internal */
|
|
51
|
+
createParamMappingObject(): Record<string, string>;
|
|
52
|
+
/**
|
|
53
|
+
* Overrides the inferred TArgs/TReturn. Omit a generic to keep inference; pass `never` in the
|
|
54
|
+
* args slot to refine only the return type.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* interface UserStats { totalOrders: number; lastOrderAt: Date }
|
|
59
|
+
* const GetStats = Routine.create<never, UserStats>({
|
|
60
|
+
* name: 'get_user_stats',
|
|
61
|
+
* type: 'function',
|
|
62
|
+
* params: { user_id: { type: 'int', runtimeType: 'number' } },
|
|
63
|
+
* returns: { runtimeType: 'object', columnType: 'json' },
|
|
64
|
+
* body: '...',
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
static create<TArgs = never, TReturn = never, const TConfig extends RoutineConfig = RoutineConfig>(config: TConfig): Routine<TConfig, [
|
|
69
|
+
TArgs
|
|
70
|
+
] extends [never] ? RoutineArgsOf<TConfig> : TArgs, [
|
|
71
|
+
TReturn
|
|
72
|
+
] extends [never] ? RoutineReturnOf<TConfig> : TReturn>;
|
|
73
|
+
static is(item: unknown): item is Routine;
|
|
74
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Resolve a `Type<unknown> | Constructor<Type<unknown>>` to an instance. Each built-in `Type` has
|
|
2
|
+
// `__mappedType` on its prototype so any constructed instance carries it; a missing brand means a
|
|
3
|
+
// raw constructor that we instantiate.
|
|
4
|
+
const toTypeInstance = (value) => {
|
|
5
|
+
return value.__mappedType ? value : new value();
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Stored procedure or function declaration. Register instances via the `routines` config option
|
|
9
|
+
* passed to `MikroORM.init`, then call them through `em.callRoutine(routine, args)`.
|
|
10
|
+
*
|
|
11
|
+
* `TArgs` and `TReturn` are inferred from the literal config, so `em.callRoutine` is fully typed
|
|
12
|
+
* without threading generics through the call site. Reach for {@link Routine.create} when the
|
|
13
|
+
* inferred type is too loose — typically an `object` return that should be a concrete shape
|
|
14
|
+
* rather than `Dictionary`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const HashUser = new Routine({
|
|
19
|
+
* name: 'hash_user',
|
|
20
|
+
* type: 'function',
|
|
21
|
+
* params: {
|
|
22
|
+
* name: { type: 'varchar(255)' },
|
|
23
|
+
* salt: { type: 'varchar(255)' },
|
|
24
|
+
* },
|
|
25
|
+
* returns: { runtimeType: 'string', columnType: 'char(40)' },
|
|
26
|
+
* body: 'SELECT SHA1(CONCAT(name, salt))',
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* await MikroORM.init({ entities: [User], routines: [HashUser] });
|
|
30
|
+
*
|
|
31
|
+
* // args typed as `{ name: string; salt: string }`, result typed as `string`:
|
|
32
|
+
* const hash = await em.callRoutine(HashUser, { name: 'jon', salt: 'pepper' });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class Routine {
|
|
36
|
+
name;
|
|
37
|
+
type;
|
|
38
|
+
schema;
|
|
39
|
+
comment;
|
|
40
|
+
security;
|
|
41
|
+
definer;
|
|
42
|
+
deterministic;
|
|
43
|
+
dataAccess;
|
|
44
|
+
language;
|
|
45
|
+
body;
|
|
46
|
+
expression;
|
|
47
|
+
bodyJs;
|
|
48
|
+
returns;
|
|
49
|
+
returnCustomType;
|
|
50
|
+
ignoreSchemaChanges;
|
|
51
|
+
params;
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.name = config.name;
|
|
54
|
+
this.type = config.type;
|
|
55
|
+
this.schema = config.schema;
|
|
56
|
+
this.comment = config.comment;
|
|
57
|
+
this.security = config.security;
|
|
58
|
+
this.definer = config.definer;
|
|
59
|
+
this.deterministic = config.deterministic;
|
|
60
|
+
this.dataAccess = config.dataAccess;
|
|
61
|
+
this.language = config.language;
|
|
62
|
+
this.body = config.body;
|
|
63
|
+
this.expression = config.expression;
|
|
64
|
+
this.bodyJs = config.bodyJs;
|
|
65
|
+
this.returns = config.returns;
|
|
66
|
+
this.ignoreSchemaChanges = config.ignoreSchemaChanges;
|
|
67
|
+
this.params = Object.entries(config.params ?? {}).map(([name, opts], index) => {
|
|
68
|
+
const explicitCustom = opts.customType ? toTypeInstance(opts.customType) : undefined;
|
|
69
|
+
const rawType = opts.type;
|
|
70
|
+
let type;
|
|
71
|
+
let customType;
|
|
72
|
+
if (rawType == null || typeof rawType === 'string') {
|
|
73
|
+
type = rawType ?? 'string';
|
|
74
|
+
customType = explicitCustom;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// A `Type` instance or constructor at `type` both defines the column (via
|
|
78
|
+
// `getColumnType` at schema-gen time) and acts as the default `customType` for
|
|
79
|
+
// marshalling. An explicit `customType` on the same param overrides the marshalling side.
|
|
80
|
+
const instance = toTypeInstance(rawType);
|
|
81
|
+
type = instance;
|
|
82
|
+
customType = explicitCustom ?? instance;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
name,
|
|
86
|
+
direction: opts.direction ?? 'in',
|
|
87
|
+
type,
|
|
88
|
+
runtimeType: opts.runtimeType ?? 'any',
|
|
89
|
+
columnTypes: [typeof type === 'string' ? type : ''],
|
|
90
|
+
customType,
|
|
91
|
+
ref: opts.ref,
|
|
92
|
+
length: opts.length,
|
|
93
|
+
precision: opts.precision,
|
|
94
|
+
scale: opts.scale,
|
|
95
|
+
nullable: opts.nullable,
|
|
96
|
+
defaultRaw: opts.defaultRaw,
|
|
97
|
+
index,
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
if (config.returns && typeof config.returns === 'object') {
|
|
101
|
+
// `returns: { type: SomeType }` is the canonical scalar-return shape — the Type drives
|
|
102
|
+
// both the column type (via `getColumnType` at schema-gen time) and the marshalling.
|
|
103
|
+
if ('type' in config.returns && config.returns.type) {
|
|
104
|
+
this.returnCustomType = toTypeInstance(config.returns.type);
|
|
105
|
+
}
|
|
106
|
+
else if ('customType' in config.returns && config.returns.customType) {
|
|
107
|
+
this.returnCustomType = toTypeInstance(config.returns.customType);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** @internal */
|
|
112
|
+
createParamMappingObject() {
|
|
113
|
+
return this.params.reduce((o, p) => {
|
|
114
|
+
o[p.name] = p.name;
|
|
115
|
+
return o;
|
|
116
|
+
}, {});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Overrides the inferred TArgs/TReturn. Omit a generic to keep inference; pass `never` in the
|
|
120
|
+
* args slot to refine only the return type.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* interface UserStats { totalOrders: number; lastOrderAt: Date }
|
|
125
|
+
* const GetStats = Routine.create<never, UserStats>({
|
|
126
|
+
* name: 'get_user_stats',
|
|
127
|
+
* type: 'function',
|
|
128
|
+
* params: { user_id: { type: 'int', runtimeType: 'number' } },
|
|
129
|
+
* returns: { runtimeType: 'object', columnType: 'json' },
|
|
130
|
+
* body: '...',
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
static create(config) {
|
|
135
|
+
return new Routine(config);
|
|
136
|
+
}
|
|
137
|
+
static is(item) {
|
|
138
|
+
return item instanceof Routine;
|
|
139
|
+
}
|
|
140
|
+
}
|
package/metadata/index.d.ts
CHANGED
package/metadata/index.js
CHANGED
package/metadata/types.d.ts
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
|
-
import type { AnyEntity, Constructor, EntityName, AnyString, CheckCallback, GeneratedColumnCallback, FormulaCallback, FilterQuery, Dictionary, AutoPath, EntityClass, IndexCallback, ObjectQuery, Raw, TriggerDef } from '../typings.js';
|
|
1
|
+
import type { AnyEntity, Constructor, EntityName, AnyString, CheckCallback, GeneratedColumnCallback, FormulaCallback, FilterQuery, Dictionary, AutoPath, EntityClass, IndexCallback, ObjectQuery, Raw, SchemaColumns, TriggerDef } from '../typings.js';
|
|
2
2
|
import type { Cascade, LoadStrategy, DeferMode, QueryOrderMap, EmbeddedPrefixMode } from '../enums.js';
|
|
3
3
|
import type { Type, types } from '../types/index.js';
|
|
4
4
|
import type { EntityManager } from '../EntityManager.js';
|
|
5
5
|
import type { FilterOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
|
|
6
6
|
import type { SerializeOptions } from '../serialization/EntitySerializer.js';
|
|
7
|
+
/** Supported PostgreSQL partitioning strategies. */
|
|
8
|
+
export type EntityPartitionType = 'hash' | 'list' | 'range';
|
|
9
|
+
/**
|
|
10
|
+
* Partition key expression for PostgreSQL partitioned tables.
|
|
11
|
+
*
|
|
12
|
+
* You can use:
|
|
13
|
+
* - a property name, e.g. `'type'`
|
|
14
|
+
* - a list of property names for composite expressions, e.g. `['tenant', 'createdAt']`
|
|
15
|
+
* - a raw SQL expression string, e.g. `"date_trunc('month', created_at)"`
|
|
16
|
+
* - a callback that receives schema column mappings and returns SQL
|
|
17
|
+
*/
|
|
18
|
+
export type EntityPartitionExpression<E = AnyEntity> = (keyof E & string) | readonly (keyof E & string)[] | AnyString | ((columns: SchemaColumns<E>) => string);
|
|
19
|
+
/** Explicit child partition definition for PostgreSQL `list` and `range` partitioning. */
|
|
20
|
+
export interface EntityPartition<E = AnyEntity> {
|
|
21
|
+
/**
|
|
22
|
+
* Optional child table name. Defaults to `<tableName>_<index>`. A single `.` is treated as a
|
|
23
|
+
* `schema.table` separator; names with more than one `.` are rejected to avoid ambiguity.
|
|
24
|
+
*/
|
|
25
|
+
name?: string;
|
|
26
|
+
/** Partition bound clause, either as `for values ...` or the trailing part such as `in (...)`, `from ... to ...`, or `default`. */
|
|
27
|
+
values: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* PostgreSQL table partitioning definition.
|
|
31
|
+
*
|
|
32
|
+
* - `hash` partitions generate child tables automatically from the partition count
|
|
33
|
+
* - `list` and `range` partitions require explicit child partition definitions
|
|
34
|
+
*/
|
|
35
|
+
export type EntityPartitionBy<E = AnyEntity> = {
|
|
36
|
+
type: Extract<EntityPartitionType, 'hash'>;
|
|
37
|
+
expression: EntityPartitionExpression<E>;
|
|
38
|
+
/**
|
|
39
|
+
* Hash partition fan-out: either a number (auto-named as `${tableName}_N`) or an array of
|
|
40
|
+
* explicit partition names in remainder order. Names may be `schema.name` to create the
|
|
41
|
+
* child in a non-default schema.
|
|
42
|
+
*/
|
|
43
|
+
partitions: number | readonly string[];
|
|
44
|
+
} | {
|
|
45
|
+
type: Exclude<EntityPartitionType, 'hash'>;
|
|
46
|
+
expression: EntityPartitionExpression<E>;
|
|
47
|
+
/** Explicit child partitions created in the order provided. */
|
|
48
|
+
partitions: EntityPartition<E>[];
|
|
49
|
+
};
|
|
7
50
|
export type EntityOptions<T, E = T extends EntityClass<infer P> ? P : T> = {
|
|
8
51
|
/** Override default collection/table name. Alias for `collection`. */
|
|
9
52
|
tableName?: string;
|
|
@@ -22,8 +65,10 @@ export type EntityOptions<T, E = T extends EntityClass<infer P> ? P : T> = {
|
|
|
22
65
|
* 3. Entity-level `@Entity({ orderBy })`
|
|
23
66
|
*/
|
|
24
67
|
orderBy?: QueryOrderMap<E> | QueryOrderMap<E>[];
|
|
25
|
-
/** For {@doclink inheritance-mapping#single-table-inheritance | Single Table Inheritance}. */
|
|
26
|
-
|
|
68
|
+
/** For {@doclink inheritance-mapping#single-table-inheritance | Single Table Inheritance}. Property name on the entity that stores the discriminator value. */
|
|
69
|
+
discriminator?: (T extends EntityClass<infer P> ? keyof P : string) | AnyString;
|
|
70
|
+
/** For {@doclink inheritance-mapping#single-table-inheritance | Single Table Inheritance}. Override the discriminator column name (the property is named via `discriminator`; defaults to the naming-strategy-derived column). */
|
|
71
|
+
discriminatorColumn?: string;
|
|
27
72
|
/** For {@doclink inheritance-mapping#single-table-inheritance | Single Table Inheritance}. */
|
|
28
73
|
discriminatorMap?: Dictionary<string>;
|
|
29
74
|
/** For {@doclink inheritance-mapping#single-table-inheritance | Single Table Inheritance}. */
|
|
@@ -59,6 +104,13 @@ export type EntityOptions<T, E = T extends EntityClass<infer P> ? P : T> = {
|
|
|
59
104
|
hasTriggers?: boolean;
|
|
60
105
|
/** Database triggers to create for this entity's table. (SQL drivers only) */
|
|
61
106
|
triggers?: TriggerDef<E>[];
|
|
107
|
+
/**
|
|
108
|
+
* PostgreSQL partitioning definition for this table.
|
|
109
|
+
*
|
|
110
|
+
* Partitioned tables are tracked by the schema generator and introspected back from PostgreSQL.
|
|
111
|
+
* Changing an existing partition layout still requires a manual migration.
|
|
112
|
+
*/
|
|
113
|
+
partitionBy?: EntityPartitionBy<E>;
|
|
62
114
|
/** SQL query that maps to a {@doclink virtual-entities | virtual entity}, or for view entities, the view definition. */
|
|
63
115
|
expression?: string | ((em: any, where: ObjectQuery<E>, options: FindOptions<E, any, any, any>, stream?: boolean) => object);
|
|
64
116
|
/** Set {@doclink repositories#custom-repository | custom repository class}. */
|
|
@@ -331,6 +383,11 @@ export interface PropertyOptions<Owner> {
|
|
|
331
383
|
* Specify comment of column for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
|
332
384
|
*/
|
|
333
385
|
comment?: string;
|
|
386
|
+
/**
|
|
387
|
+
* Specify column-level collation for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
|
388
|
+
* Emits a `COLLATE` clause on the column definition; the accepted collation names are dialect-specific.
|
|
389
|
+
*/
|
|
390
|
+
collation?: string;
|
|
334
391
|
/** mysql only */
|
|
335
392
|
extra?: string;
|
|
336
393
|
/**
|
|
@@ -338,7 +395,7 @@ export interface PropertyOptions<Owner> {
|
|
|
338
395
|
*
|
|
339
396
|
* @see https://mikro-orm.io/docs/defining-entities#sql-generated-columns
|
|
340
397
|
*/
|
|
341
|
-
ignoreSchemaChanges?: ('type' | 'extra' | 'default')[];
|
|
398
|
+
ignoreSchemaChanges?: ('type' | 'extra' | 'default' | 'collation')[];
|
|
342
399
|
}
|
|
343
400
|
export interface ReferenceOptions<Owner, Target> extends PropertyOptions<Owner> {
|
|
344
401
|
/** Set target entity type. For polymorphic relations, pass an array of entity types. */
|
|
@@ -498,16 +555,16 @@ export interface EmbeddedOptions<Owner, Target> extends PropertyOptions<Owner> {
|
|
|
498
555
|
export interface EmbeddableOptions<Owner> {
|
|
499
556
|
/** Specify constructor parameters to be used in `em.create` or when `forceConstructor` is enabled. Those should be names of declared entity properties in the same order as your constructor uses them. The ORM tries to infer those automatically, use this option in case the inference fails. */
|
|
500
557
|
constructorParams?: (Owner extends EntityClass<infer P> ? keyof P : string)[];
|
|
501
|
-
/** For polymorphic embeddables.
|
|
558
|
+
/** For polymorphic embeddables. Property name on the embeddable class that stores the discriminator value. */
|
|
502
559
|
discriminator?: (Owner extends EntityClass<infer P> ? keyof P : string) | AnyString;
|
|
503
|
-
/** For polymorphic embeddables.
|
|
504
|
-
discriminatorColumn?:
|
|
560
|
+
/** For polymorphic embeddables. Override the discriminator column name (the property is named via `discriminator`; defaults to the naming-strategy-derived column). */
|
|
561
|
+
discriminatorColumn?: string;
|
|
505
562
|
discriminatorMap?: Dictionary<string>;
|
|
506
563
|
discriminatorValue?: number | string;
|
|
507
564
|
abstract?: boolean;
|
|
508
565
|
}
|
|
509
566
|
export interface EnumOptions<T> extends PropertyOptions<T> {
|
|
510
|
-
items?: readonly (number | string)[] | (() => Dictionary);
|
|
567
|
+
items?: readonly (number | string)[] | Dictionary | (() => Dictionary);
|
|
511
568
|
array?: boolean;
|
|
512
569
|
/** for postgres, by default it uses text column with check constraint */
|
|
513
570
|
nativeEnumName?: string;
|
|
@@ -551,6 +608,16 @@ interface BaseOptions<T, H extends string> {
|
|
|
551
608
|
include?: T extends EntityClass<infer P> ? Properties<P, H> : Properties<T, H>;
|
|
552
609
|
/** Fill factor for the index as a percentage 0-100 (PostgreSQL, MSSQL). */
|
|
553
610
|
fillFactor?: number;
|
|
611
|
+
/**
|
|
612
|
+
* Predicate for partial indexes. Object form is a `FilterQuery` and is portable across
|
|
613
|
+
* SQL drivers and MongoDB; string form is a raw SQL fragment (SQL drivers only).
|
|
614
|
+
*
|
|
615
|
+
* Native support: PostgreSQL, SQLite, MSSQL (`WHERE`), MongoDB (`partialFilterExpression`).
|
|
616
|
+
* MySQL 8.0.13+ / Oracle: emulated via `CASE WHEN` functional index (uniqueness only enforced
|
|
617
|
+
* where the predicate holds). MariaDB is not supported — it has no inline expression indexes;
|
|
618
|
+
* define a virtual generated column and index that instead.
|
|
619
|
+
*/
|
|
620
|
+
where?: string | FilterQuery<NoInfer<T> extends EntityClass<infer P> ? P : NoInfer<T>>;
|
|
554
621
|
}
|
|
555
622
|
export interface UniqueOptions<T, H extends string = string> extends BaseOptions<T, H> {
|
|
556
623
|
deferMode?: DeferMode | `${DeferMode}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.1.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
package/platforms/Platform.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export declare abstract class Platform {
|
|
|
43
43
|
getEnumArrayCheckConstraintExpression(column: string, items: string[]): string | null;
|
|
44
44
|
/** Whether this platform supports materialized views. */
|
|
45
45
|
supportsMaterializedViews(): boolean;
|
|
46
|
+
/** Whether this platform supports declarative table partitioning in schema generation. */
|
|
47
|
+
supportsPartitionedTables(): boolean;
|
|
46
48
|
/** Returns the schema helper instance for this platform, or undefined if not supported. */
|
|
47
49
|
getSchemaHelper(): unknown;
|
|
48
50
|
/** Whether the platform automatically creates indexes on foreign key columns. */
|
|
@@ -168,7 +170,7 @@ export declare abstract class Platform {
|
|
|
168
170
|
getUuidTypeDeclarationSQL(column: {
|
|
169
171
|
length?: number;
|
|
170
172
|
}): string;
|
|
171
|
-
/** Extracts the base type name from a full SQL type declaration (e.g.
|
|
173
|
+
/** Extracts the base type name from a full SQL type declaration (e.g. `varchar(255)` -> `varchar`). */
|
|
172
174
|
extractSimpleType(type: string): string;
|
|
173
175
|
/**
|
|
174
176
|
* This should be used only to compare types, it can strip some information like the length.
|
|
@@ -276,9 +278,17 @@ export declare abstract class Platform {
|
|
|
276
278
|
/** Whether the platform supports unsigned integer columns. */
|
|
277
279
|
supportsUnsigned(): boolean;
|
|
278
280
|
/**
|
|
279
|
-
*
|
|
281
|
+
* Maximum length of identifiers (table, column, index, constraint, …) the platform supports.
|
|
282
|
+
* Names produced by {@link getIndexName} above this limit are hash-truncated. Defaults to
|
|
283
|
+
* `Infinity` (no truncation); SQL platforms override with their engine's limit
|
|
284
|
+
* (PG 63, MySQL/MariaDB 64, MSSQL/Oracle 128).
|
|
280
285
|
*/
|
|
281
|
-
|
|
286
|
+
getMaxIdentifierLength(): number;
|
|
287
|
+
/**
|
|
288
|
+
* Returns the default name of index for the given columns, hash-truncated if it would
|
|
289
|
+
* exceed {@link getMaxIdentifierLength}.
|
|
290
|
+
*/
|
|
291
|
+
getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence' | 'check'): string;
|
|
282
292
|
/** Returns the default primary key constraint name. */
|
|
283
293
|
getDefaultPrimaryName(tableName: string, columns: string[]): string;
|
|
284
294
|
/** Whether the platform supports custom names for primary key constraints. */
|
package/platforms/Platform.js
CHANGED
|
@@ -2,12 +2,22 @@ import { clone } from '../utils/clone.js';
|
|
|
2
2
|
import { EntityRepository } from '../entity/EntityRepository.js';
|
|
3
3
|
import { UnderscoreNamingStrategy } from '../naming-strategy/UnderscoreNamingStrategy.js';
|
|
4
4
|
import { ExceptionConverter } from './ExceptionConverter.js';
|
|
5
|
+
import { MetadataError } from '../errors.js';
|
|
5
6
|
import { ArrayType, BigIntType, BlobType, BooleanType, CharacterType, DateTimeType, DateType, DecimalType, DoubleType, EnumType, FloatType, IntegerType, IntervalType, JsonType, MediumIntType, SmallIntType, StringType, TextType, TimeType, TinyIntType, Type, Uint8ArrayType, UnknownType, UuidType, } from '../types/index.js';
|
|
6
7
|
import { parseJsonSafe, Utils } from '../utils/Utils.js';
|
|
7
8
|
import { ReferenceKind } from '../enums.js';
|
|
8
9
|
import { Raw } from '../utils/RawQueryFragment.js';
|
|
9
10
|
/** Symbol used to tag cloned embeddable data for JSON serialization handling. */
|
|
10
11
|
export const JsonProperty = Symbol('JsonProperty');
|
|
12
|
+
const MULTI_WORD_SQL_TYPES = [
|
|
13
|
+
'timestamp with time zone',
|
|
14
|
+
'timestamp without time zone',
|
|
15
|
+
'time with time zone',
|
|
16
|
+
'time without time zone',
|
|
17
|
+
'character varying',
|
|
18
|
+
'double precision',
|
|
19
|
+
'bit varying',
|
|
20
|
+
];
|
|
11
21
|
/** Abstract base class providing database-specific behavior and SQL dialect differences. */
|
|
12
22
|
export class Platform {
|
|
13
23
|
exceptionConverter = new ExceptionConverter();
|
|
@@ -62,6 +72,10 @@ export class Platform {
|
|
|
62
72
|
supportsMaterializedViews() {
|
|
63
73
|
return false;
|
|
64
74
|
}
|
|
75
|
+
/** Whether this platform supports declarative table partitioning in schema generation. */
|
|
76
|
+
supportsPartitionedTables() {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
65
79
|
/** Returns the schema helper instance for this platform, or undefined if not supported. */
|
|
66
80
|
getSchemaHelper() {
|
|
67
81
|
return undefined;
|
|
@@ -222,9 +236,15 @@ export class Platform {
|
|
|
222
236
|
column.length ??= 36;
|
|
223
237
|
return this.getVarcharTypeDeclarationSQL(column);
|
|
224
238
|
}
|
|
225
|
-
/** Extracts the base type name from a full SQL type declaration (e.g.
|
|
239
|
+
/** Extracts the base type name from a full SQL type declaration (e.g. `varchar(255)` -> `varchar`). */
|
|
226
240
|
extractSimpleType(type) {
|
|
227
|
-
|
|
241
|
+
const lower = type.toLowerCase();
|
|
242
|
+
for (const multiWord of MULTI_WORD_SQL_TYPES) {
|
|
243
|
+
if (lower.startsWith(multiWord)) {
|
|
244
|
+
return multiWord;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return /[^(), ]+/.exec(lower)[0];
|
|
228
248
|
}
|
|
229
249
|
/**
|
|
230
250
|
* This should be used only to compare types, it can strip some information like the length.
|
|
@@ -248,6 +268,7 @@ export class Platform {
|
|
|
248
268
|
return Type.getType(CharacterType);
|
|
249
269
|
case 'string':
|
|
250
270
|
case 'varchar':
|
|
271
|
+
case 'character varying':
|
|
251
272
|
return Type.getType(StringType);
|
|
252
273
|
case 'interval':
|
|
253
274
|
return Type.getType(IntervalType);
|
|
@@ -267,6 +288,7 @@ export class Platform {
|
|
|
267
288
|
case 'float':
|
|
268
289
|
return Type.getType(FloatType);
|
|
269
290
|
case 'double':
|
|
291
|
+
case 'double precision':
|
|
270
292
|
return Type.getType(DoubleType);
|
|
271
293
|
case 'integer':
|
|
272
294
|
return Type.getType(IntegerType);
|
|
@@ -286,8 +308,12 @@ export class Platform {
|
|
|
286
308
|
return Type.getType(DateType);
|
|
287
309
|
case 'datetime':
|
|
288
310
|
case 'timestamp':
|
|
311
|
+
case 'timestamp with time zone':
|
|
312
|
+
case 'timestamp without time zone':
|
|
289
313
|
return Type.getType(DateTimeType);
|
|
290
314
|
case 'time':
|
|
315
|
+
case 'time with time zone':
|
|
316
|
+
case 'time without time zone':
|
|
291
317
|
return Type.getType(TimeType);
|
|
292
318
|
case 'object':
|
|
293
319
|
case 'json':
|
|
@@ -513,7 +539,8 @@ export class Platform {
|
|
|
513
539
|
if (raw) {
|
|
514
540
|
return this.formatQuery(raw.sql, raw.params);
|
|
515
541
|
}
|
|
516
|
-
|
|
542
|
+
const escaped = id.toString().replaceAll(quote, quote + quote);
|
|
543
|
+
return `${quote}${escaped.replace('.', `${quote}.${quote}`)}${quote}`;
|
|
517
544
|
}
|
|
518
545
|
/** Quotes a literal value for safe embedding in SQL. */
|
|
519
546
|
quoteValue(value) {
|
|
@@ -603,10 +630,26 @@ export class Platform {
|
|
|
603
630
|
return false;
|
|
604
631
|
}
|
|
605
632
|
/**
|
|
606
|
-
*
|
|
633
|
+
* Maximum length of identifiers (table, column, index, constraint, …) the platform supports.
|
|
634
|
+
* Names produced by {@link getIndexName} above this limit are hash-truncated. Defaults to
|
|
635
|
+
* `Infinity` (no truncation); SQL platforms override with their engine's limit
|
|
636
|
+
* (PG 63, MySQL/MariaDB 64, MSSQL/Oracle 128).
|
|
637
|
+
*/
|
|
638
|
+
getMaxIdentifierLength() {
|
|
639
|
+
return Infinity;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Returns the default name of index for the given columns, hash-truncated if it would
|
|
643
|
+
* exceed {@link getMaxIdentifierLength}.
|
|
607
644
|
*/
|
|
608
645
|
getIndexName(tableName, columns, type) {
|
|
609
|
-
|
|
646
|
+
const indexName = this.namingStrategy.indexName(tableName, columns, type);
|
|
647
|
+
const max = this.getMaxIdentifierLength();
|
|
648
|
+
if (indexName.length > max) {
|
|
649
|
+
const suffix = type === 'primary' ? 'pkey' : type;
|
|
650
|
+
return `${indexName.substring(0, max - 8 - type.length)}_${Utils.hash(indexName, 5)}_${suffix}`;
|
|
651
|
+
}
|
|
652
|
+
return indexName;
|
|
610
653
|
}
|
|
611
654
|
/** Returns the default primary key constraint name. */
|
|
612
655
|
getDefaultPrimaryName(tableName, columns) {
|
|
@@ -658,7 +701,9 @@ export class Platform {
|
|
|
658
701
|
}
|
|
659
702
|
/** Platform-specific validation of entity metadata. */
|
|
660
703
|
validateMetadata(meta) {
|
|
661
|
-
|
|
704
|
+
if (meta.partitionBy && !this.supportsPartitionedTables()) {
|
|
705
|
+
throw new MetadataError(`Entity ${meta.className} uses partitionBy, but ${this.constructor.name} does not support partitioned tables`);
|
|
706
|
+
}
|
|
662
707
|
}
|
|
663
708
|
/**
|
|
664
709
|
* Generates a custom order by statement given a set of in order values, eg.
|
|
@@ -16,7 +16,8 @@ function isVisible(meta, propName, options) {
|
|
|
16
16
|
if (Array.isArray(options.fields) && options.fields.length > 0 && !matchesPath(options.fields, propName)) {
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
if (Array.isArray(options.populate) &&
|
|
19
|
+
if (Array.isArray(options.populate) &&
|
|
20
|
+
options.populate.find(item => item === propName || item.startsWith(propName + '.'))) {
|
|
20
21
|
return true;
|
|
21
22
|
}
|
|
22
23
|
if (options.exclude?.find(item => item === propName)) {
|
|
@@ -224,7 +225,7 @@ export class EntitySerializer {
|
|
|
224
225
|
return this.serialize(child, childOptions);
|
|
225
226
|
}
|
|
226
227
|
const pk = this.processCustomType(wrapped.getPrimaryKey(), prop, wrapped.__platform, options.convertCustomTypes);
|
|
227
|
-
if (options.forceObject
|
|
228
|
+
if (options.forceObject ?? wrapped.__config.get('serialization').forceObject) {
|
|
228
229
|
return Utils.primaryKeyToObject(meta, pk, visible);
|
|
229
230
|
}
|
|
230
231
|
if (Utils.isPlainObject(pk)) {
|
|
@@ -248,7 +249,7 @@ export class EntitySerializer {
|
|
|
248
249
|
return this.serialize(item, this.extractChildOptions(options, prop.name));
|
|
249
250
|
}
|
|
250
251
|
const pk = this.processCustomType(wrapped.getPrimaryKey(), prop, wrapped.__platform, options.convertCustomTypes);
|
|
251
|
-
if (options.forceObject
|
|
252
|
+
if (options.forceObject ?? wrapped.__config.get('serialization').forceObject) {
|
|
252
253
|
return Utils.primaryKeyToObject(wrapped.__meta, pk);
|
|
253
254
|
}
|
|
254
255
|
return pk;
|