@mikro-orm/core 7.1.0-dev.2 → 7.1.0-dev.4
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 +19 -0
- package/EntityManager.js +48 -0
- package/drivers/DatabaseDriver.d.ts +1 -0
- package/drivers/DatabaseDriver.js +3 -0
- package/drivers/IDatabaseDriver.d.ts +5 -0
- package/entity/defineEntity.d.ts +6 -2
- package/metadata/MetadataDiscovery.js +32 -1
- package/metadata/types.d.ts +6 -0
- package/package.json +1 -1
- package/utils/Utils.js +1 -1
package/EntityManager.d.ts
CHANGED
|
@@ -307,6 +307,25 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
|
|
|
307
307
|
* Fires native insert query. Calling this has no side effects on the context (identity map).
|
|
308
308
|
*/
|
|
309
309
|
insert<Entity extends object>(entityNameOrEntity: EntityName<Entity> | Entity, data?: RequiredEntityData<Entity> | Entity, options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>>;
|
|
310
|
+
/**
|
|
311
|
+
* Clones rows matching the condition at the database level via INSERT...SELECT.
|
|
312
|
+
* Automatically excludes auto-increment PKs, generated columns, and resets version properties.
|
|
313
|
+
* Returns the cloned entity, registered in the identity map.
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* // Clone by entity class + where + overrides
|
|
318
|
+
* const cloned = await em.clone(Author, { id: 1 }, { email: 'new@email.com' });
|
|
319
|
+
*
|
|
320
|
+
* // Pure clone (all non-PK fields copied)
|
|
321
|
+
* const cloned = await em.clone(Author, { id: 1 });
|
|
322
|
+
*
|
|
323
|
+
* // Clone a loaded entity
|
|
324
|
+
* const author = await em.findOneOrFail(Author, 1);
|
|
325
|
+
* const cloned = await em.clone(author, { email: 'new@email.com' });
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
clone<Entity extends object>(entityNameOrEntity: EntityName<Entity> | Entity, whereOrOverrides?: FilterQuery<NoInfer<Entity>> | EntityData<Entity>, overridesOrOptions?: EntityData<Entity> | NativeInsertUpdateOptions<Entity>, options?: NativeInsertUpdateOptions<Entity>): Promise<Entity>;
|
|
310
329
|
/**
|
|
311
330
|
* Fires native multi-insert query. Calling this has no side effects on the context (identity map).
|
|
312
331
|
*/
|
package/EntityManager.js
CHANGED
|
@@ -1211,6 +1211,54 @@ export class EntityManager {
|
|
|
1211
1211
|
});
|
|
1212
1212
|
return res.insertId;
|
|
1213
1213
|
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Clones rows matching the condition at the database level via INSERT...SELECT.
|
|
1216
|
+
* Automatically excludes auto-increment PKs, generated columns, and resets version properties.
|
|
1217
|
+
* Returns the cloned entity, registered in the identity map.
|
|
1218
|
+
*
|
|
1219
|
+
* @example
|
|
1220
|
+
* ```ts
|
|
1221
|
+
* // Clone by entity class + where + overrides
|
|
1222
|
+
* const cloned = await em.clone(Author, { id: 1 }, { email: 'new@email.com' });
|
|
1223
|
+
*
|
|
1224
|
+
* // Pure clone (all non-PK fields copied)
|
|
1225
|
+
* const cloned = await em.clone(Author, { id: 1 });
|
|
1226
|
+
*
|
|
1227
|
+
* // Clone a loaded entity
|
|
1228
|
+
* const author = await em.findOneOrFail(Author, 1);
|
|
1229
|
+
* const cloned = await em.clone(author, { email: 'new@email.com' });
|
|
1230
|
+
* ```
|
|
1231
|
+
*/
|
|
1232
|
+
async clone(entityNameOrEntity, whereOrOverrides, overridesOrOptions, options) {
|
|
1233
|
+
const em = this.getContext(false);
|
|
1234
|
+
let entityName;
|
|
1235
|
+
let where;
|
|
1236
|
+
let overrides;
|
|
1237
|
+
if (Utils.isEntity(entityNameOrEntity)) {
|
|
1238
|
+
// clone(entity, overrides?, options?)
|
|
1239
|
+
entityName = entityNameOrEntity.constructor;
|
|
1240
|
+
where = helper(entityNameOrEntity).getPrimaryKey();
|
|
1241
|
+
overrides = whereOrOverrides;
|
|
1242
|
+
options = overridesOrOptions;
|
|
1243
|
+
}
|
|
1244
|
+
else {
|
|
1245
|
+
// clone(EntityClass, where, overrides?, options?)
|
|
1246
|
+
entityName = entityNameOrEntity;
|
|
1247
|
+
where = whereOrOverrides;
|
|
1248
|
+
overrides = overridesOrOptions;
|
|
1249
|
+
}
|
|
1250
|
+
options ??= {};
|
|
1251
|
+
em.prepareOptions(options);
|
|
1252
|
+
const meta = em.metadata.get(entityName);
|
|
1253
|
+
const res = await em.driver.nativeClone(entityName, where, overrides, {
|
|
1254
|
+
ctx: em.#transactionContext,
|
|
1255
|
+
...options,
|
|
1256
|
+
});
|
|
1257
|
+
const pk = res.insertId ?? res.row?.[meta.primaryKeys[0]];
|
|
1258
|
+
return em.findOneOrFail(entityName, pk, {
|
|
1259
|
+
schema: options.schema,
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1214
1262
|
/**
|
|
1215
1263
|
* Fires native multi-insert query. Calling this has no side effects on the context (identity map).
|
|
1216
1264
|
*/
|
|
@@ -28,6 +28,7 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
|
|
|
28
28
|
abstract nativeUpdate<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
|
|
29
29
|
nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
|
|
30
30
|
abstract nativeDelete<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
|
|
31
|
+
nativeClone<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, overrides?: EntityData<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
|
|
31
32
|
abstract count<T extends object, P extends string = never>(entityName: EntityName<T>, where: FilterQuery<T>, options?: CountOptions<T, P>): Promise<number>;
|
|
32
33
|
/** Creates a new EntityManager instance bound to this driver. */
|
|
33
34
|
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
|
@@ -27,6 +27,9 @@ export class DatabaseDriver {
|
|
|
27
27
|
async nativeUpdateMany(entityName, where, data, options) {
|
|
28
28
|
throw new Error(`Batch updates are not supported by ${this.constructor.name} driver`);
|
|
29
29
|
}
|
|
30
|
+
async nativeClone(entityName, where, overrides, options) {
|
|
31
|
+
throw new Error(`${this.constructor.name} does not support nativeClone`);
|
|
32
|
+
}
|
|
30
33
|
/** Creates a new EntityManager instance bound to this driver. */
|
|
31
34
|
createEntityManager(useContext) {
|
|
32
35
|
const EntityManagerClass = this.config.get('entityManager', EntityManager);
|
|
@@ -52,6 +52,11 @@ export interface IDatabaseDriver<C extends Connection = Connection> {
|
|
|
52
52
|
nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
|
|
53
53
|
/** Deletes rows matching the given condition. */
|
|
54
54
|
nativeDelete<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options?: NativeDeleteOptions<T>): Promise<QueryResult<T>>;
|
|
55
|
+
/**
|
|
56
|
+
* Clones rows matching the condition at the database level via INSERT...SELECT.
|
|
57
|
+
* Automatically excludes auto-increment PKs, generated columns, and resets version properties.
|
|
58
|
+
*/
|
|
59
|
+
nativeClone<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, overrides?: EntityData<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
|
|
55
60
|
/** Persists changes to M:N collections (inserts/deletes pivot table rows). */
|
|
56
61
|
syncCollections<T extends object, O extends object>(collections: Iterable<Collection<T, O>>, options?: DriverMethodOptions): Promise<void>;
|
|
57
62
|
/** Counts entities matching the given condition. */
|
package/entity/defineEntity.d.ts
CHANGED
|
@@ -127,9 +127,13 @@ export interface PropertyChain<Value, Options> {
|
|
|
127
127
|
pivotEntity(pivotEntity: () => EntityName): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
128
128
|
fixedOrder(fixedOrder?: boolean): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
129
129
|
fixedOrderColumn(fixedOrderColumn: string): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
130
|
-
array():
|
|
130
|
+
array(): Options extends {
|
|
131
|
+
kind: infer K extends string;
|
|
132
|
+
} ? K extends 'embedded' | 'enum' ? PropertyChain<Value, Omit<Options, 'array'> & {
|
|
131
133
|
array: true;
|
|
132
|
-
}> : never
|
|
134
|
+
}> : never : PropertyChain<Value, Omit<Options, 'array'> & {
|
|
135
|
+
array: true;
|
|
136
|
+
}>;
|
|
133
137
|
prefix(prefix: string | boolean): HasKind<Options, 'embedded'> extends true ? PropertyChain<Value, Options> : never;
|
|
134
138
|
prefixMode(prefixMode: EmbeddedPrefixMode): HasKind<Options, 'embedded'> extends true ? PropertyChain<Value, Options> : never;
|
|
135
139
|
object(object?: boolean): HasKind<Options, 'embedded'> extends true ? PropertyChain<Value, Options> : never;
|
|
@@ -1646,7 +1646,14 @@ export class MetadataDiscovery {
|
|
|
1646
1646
|
return (!Type.getType(t[type]).ensureComparable(meta, prop) && (prop.type === t[type] || brand === type));
|
|
1647
1647
|
});
|
|
1648
1648
|
if (type) {
|
|
1649
|
-
prop.
|
|
1649
|
+
if (prop.array) {
|
|
1650
|
+
// built-in type + array: true — force-create instance for ArrayType wrapping
|
|
1651
|
+
prop.customType = new prop.type();
|
|
1652
|
+
prop.type = prop.customType.constructor.name;
|
|
1653
|
+
}
|
|
1654
|
+
else {
|
|
1655
|
+
prop.type = type === 'datetime' ? 'Date' : type;
|
|
1656
|
+
}
|
|
1650
1657
|
}
|
|
1651
1658
|
else {
|
|
1652
1659
|
prop.customType = new prop.type();
|
|
@@ -1656,6 +1663,30 @@ export class MetadataDiscovery {
|
|
|
1656
1663
|
if (simple) {
|
|
1657
1664
|
return;
|
|
1658
1665
|
}
|
|
1666
|
+
if (prop.array &&
|
|
1667
|
+
prop.customType &&
|
|
1668
|
+
!(prop.customType instanceof t.array) &&
|
|
1669
|
+
!(prop.customType instanceof t.enumArray) &&
|
|
1670
|
+
prop.kind === ReferenceKind.SCALAR) {
|
|
1671
|
+
const innerType = prop.customType;
|
|
1672
|
+
innerType.platform = this.#platform;
|
|
1673
|
+
innerType.meta = meta;
|
|
1674
|
+
innerType.prop = prop;
|
|
1675
|
+
if (!prop.columnTypes) {
|
|
1676
|
+
const arrayDecl = this.#platform.getArrayDeclarationSQL();
|
|
1677
|
+
if (arrayDecl.endsWith('[]')) {
|
|
1678
|
+
// native array support (e.g. postgres) — use inner type's column type with [] suffix
|
|
1679
|
+
prop.columnTypes = [innerType.getColumnType(prop, this.#platform) + '[]'];
|
|
1680
|
+
}
|
|
1681
|
+
else {
|
|
1682
|
+
// non-native (e.g. mysql, sqlite) — store as text/clob
|
|
1683
|
+
prop.columnTypes = [arrayDecl];
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
const platform = this.#platform;
|
|
1687
|
+
prop.customType = new t.array(v => innerType.convertToJSValue(v, platform), v => innerType.convertToDatabaseValue(v, platform));
|
|
1688
|
+
prop.type = prop.customType.constructor.name;
|
|
1689
|
+
}
|
|
1659
1690
|
if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
|
|
1660
1691
|
prop.customType = new t.json();
|
|
1661
1692
|
}
|
package/metadata/types.d.ts
CHANGED
|
@@ -202,6 +202,12 @@ export interface PropertyOptions<Owner> {
|
|
|
202
202
|
* @see https://mikro-orm.io/docs/defining-entities#lazy-scalar-properties
|
|
203
203
|
*/
|
|
204
204
|
lazy?: boolean;
|
|
205
|
+
/**
|
|
206
|
+
* Marks this property as an array. When used with a custom type, the type is automatically
|
|
207
|
+
* wrapped in an `ArrayType` that delegates element conversion to the inner type.
|
|
208
|
+
* The column type is inferred as `innerType[]` (e.g. `int[]`, `time[]`).
|
|
209
|
+
*/
|
|
210
|
+
array?: boolean;
|
|
205
211
|
/**
|
|
206
212
|
* Set true to define entity's unique primary key identifier.
|
|
207
213
|
* Alias for `@PrimaryKey()` decorator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.1.0-dev.
|
|
3
|
+
"version": "7.1.0-dev.4",
|
|
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/utils/Utils.js
CHANGED
|
@@ -141,7 +141,7 @@ export function parseJsonSafe(value) {
|
|
|
141
141
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
142
142
|
export class Utils {
|
|
143
143
|
static PK_SEPARATOR = '~~~';
|
|
144
|
-
static #ORM_VERSION = '7.1.0-dev.
|
|
144
|
+
static #ORM_VERSION = '7.1.0-dev.4';
|
|
145
145
|
/**
|
|
146
146
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
147
147
|
*/
|