@mikro-orm/core 7.0.9-dev.0 → 7.0.9-dev.10
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/entity/Collection.d.ts +2 -1
- package/entity/EntityFactory.js +3 -1
- package/metadata/MetadataDiscovery.js +12 -0
- package/package.json +1 -1
- package/typings.d.ts +3 -1
- package/typings.js +2 -0
- package/unit-of-work/ChangeSetPersister.d.ts +6 -0
- package/unit-of-work/ChangeSetPersister.js +22 -2
- package/utils/Utils.js +1 -1
package/entity/Collection.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type EntityDTO, type EntityKey, type EntityProperty, type FilterQuery, type IPrimaryKey, type Loaded, type LoadedCollection, type Populate, type Primary, CollectionBrand } from '../typings.js';
|
|
2
2
|
import { Reference } from './Reference.js';
|
|
3
3
|
import type { Transaction } from '../connections/Connection.js';
|
|
4
4
|
import type { CountOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
|
|
@@ -17,6 +17,7 @@ export declare class Collection<T extends object, O extends object = object> {
|
|
|
17
17
|
#private;
|
|
18
18
|
readonly owner: O;
|
|
19
19
|
[k: number]: T;
|
|
20
|
+
readonly [CollectionBrand]: true;
|
|
20
21
|
constructor(owner: O, items?: T[], initialized?: boolean);
|
|
21
22
|
/**
|
|
22
23
|
* Creates new Collection instance, assigns it to the owning entity and sets the items to it (propagating them to their inverse sides)
|
package/entity/EntityFactory.js
CHANGED
|
@@ -167,9 +167,11 @@ export class EntityFactory {
|
|
|
167
167
|
return diff2[key] === undefined;
|
|
168
168
|
})
|
|
169
169
|
.forEach(key => delete diff2[key]);
|
|
170
|
-
// but always add collection properties and
|
|
170
|
+
// but always add collection properties, formulas, and generated columns if they are part of the `data`,
|
|
171
|
+
// as these are excluded from `comparableProps` and won't appear in the diff
|
|
171
172
|
Utils.keys(data)
|
|
172
173
|
.filter(key => meta.properties[key]?.formula ||
|
|
174
|
+
(meta.properties[key]?.generated && !meta.properties[key]?.primary) ||
|
|
173
175
|
[ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(meta.properties[key]?.kind))
|
|
174
176
|
.forEach(key => (diff2[key] = data[key]));
|
|
175
177
|
// rehydrated with the new values, skip those changed by user
|
|
@@ -1267,6 +1267,18 @@ export class MetadataDiscovery {
|
|
|
1267
1267
|
if (prop.enum && prop.items && rootProp?.items) {
|
|
1268
1268
|
newProp.items = Utils.unique([...rootProp.items, ...prop.items]);
|
|
1269
1269
|
}
|
|
1270
|
+
// When multiple STI children share the same unique relation (OneToOne/ManyToOne),
|
|
1271
|
+
// replace the simple unique with a composite one including the discriminator column
|
|
1272
|
+
// so different subtypes can independently reference the same target row.
|
|
1273
|
+
if (rootProp?.unique &&
|
|
1274
|
+
newProp.unique &&
|
|
1275
|
+
[ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(newProp.kind)) {
|
|
1276
|
+
newProp.unique = false;
|
|
1277
|
+
rootProp.unique = false;
|
|
1278
|
+
meta.root.uniques.push({
|
|
1279
|
+
properties: [prop.name, meta.root.discriminatorColumn],
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1270
1282
|
newProp.nullable = true;
|
|
1271
1283
|
newProp.inherited = !rootProp;
|
|
1272
1284
|
meta.root.addProperty(newProp);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.0.9-dev.
|
|
3
|
+
"version": "7.0.9-dev.10",
|
|
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/typings.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ export type MaybePromise<T> = T | Promise<T>;
|
|
|
74
74
|
*/
|
|
75
75
|
type CollectionShape<T = any> = {
|
|
76
76
|
[k: number]: T;
|
|
77
|
-
readonly
|
|
77
|
+
readonly [CollectionBrand]: true;
|
|
78
78
|
};
|
|
79
79
|
/**
|
|
80
80
|
* Structural type for matching LoadedCollection (extends CollectionShape with `$` property).
|
|
@@ -134,6 +134,8 @@ export type DeepPartial<T> = T & {
|
|
|
134
134
|
export declare const EntityRepositoryType: unique symbol;
|
|
135
135
|
/** Symbol used to declare the primary key property name(s) on an entity (e.g., `[PrimaryKeyProp]?: 'id'`). */
|
|
136
136
|
export declare const PrimaryKeyProp: unique symbol;
|
|
137
|
+
/** Symbol used as a brand on `CollectionShape` to prevent false structural matches with entities that have properties like `owner`. */
|
|
138
|
+
export declare const CollectionBrand: unique symbol;
|
|
137
139
|
/** Symbol used to declare which properties are optional in `em.create()` (e.g., `[OptionalProps]?: 'createdAt'`). */
|
|
138
140
|
export declare const OptionalProps: unique symbol;
|
|
139
141
|
/** Symbol used to declare which relation properties should be eagerly loaded (e.g., `[EagerProps]?: 'author'`). */
|
package/typings.js
CHANGED
|
@@ -9,6 +9,8 @@ import { BaseEntity } from './entity/BaseEntity.js';
|
|
|
9
9
|
export const EntityRepositoryType = Symbol('EntityRepositoryType');
|
|
10
10
|
/** Symbol used to declare the primary key property name(s) on an entity (e.g., `[PrimaryKeyProp]?: 'id'`). */
|
|
11
11
|
export const PrimaryKeyProp = Symbol('PrimaryKeyProp');
|
|
12
|
+
/** Symbol used as a brand on `CollectionShape` to prevent false structural matches with entities that have properties like `owner`. */
|
|
13
|
+
export const CollectionBrand = Symbol('CollectionBrand');
|
|
12
14
|
/** Symbol used to declare which properties are optional in `em.create()` (e.g., `[OptionalProps]?: 'createdAt'`). */
|
|
13
15
|
export const OptionalProps = Symbol('OptionalProps');
|
|
14
16
|
/** Symbol used to declare which relation properties should be eagerly loaded (e.g., `[EagerProps]?: 'author'`). */
|
|
@@ -24,6 +24,12 @@ export declare class ChangeSetPersister {
|
|
|
24
24
|
private checkConcurrencyKeys;
|
|
25
25
|
private persistManagedEntitiesBatch;
|
|
26
26
|
private mapPrimaryKey;
|
|
27
|
+
/**
|
|
28
|
+
* After INSERT + hydration, sync all EntityIdentifier placeholders in composite PK arrays
|
|
29
|
+
* with the real values now present on the entity. This is needed because `mapPrimaryKey`
|
|
30
|
+
* only handles the first PK column, but any scalar PK in a composite key may be auto-generated.
|
|
31
|
+
*/
|
|
32
|
+
private syncCompositeIdentifiers;
|
|
27
33
|
/**
|
|
28
34
|
* Sets populate flag to new entities so they are serialized like if they were loaded from the db
|
|
29
35
|
*/
|
|
@@ -132,6 +132,7 @@ export class ChangeSetPersister {
|
|
|
132
132
|
this.mapPrimaryKey(meta, res.insertId ?? res.row?.[meta.primaryKeys[0]], changeSet);
|
|
133
133
|
}
|
|
134
134
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
|
|
135
|
+
this.syncCompositeIdentifiers(changeSet);
|
|
135
136
|
this.markAsPopulated(changeSet, meta);
|
|
136
137
|
wrapped.__initialized = true;
|
|
137
138
|
wrapped.__managed = true;
|
|
@@ -178,6 +179,7 @@ export class ChangeSetPersister {
|
|
|
178
179
|
if (res.rows) {
|
|
179
180
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.rows[i], meta);
|
|
180
181
|
}
|
|
182
|
+
this.syncCompositeIdentifiers(changeSet);
|
|
181
183
|
this.markAsPopulated(changeSet, meta);
|
|
182
184
|
wrapped.__initialized = true;
|
|
183
185
|
wrapped.__managed = true;
|
|
@@ -255,6 +257,24 @@ export class ChangeSetPersister {
|
|
|
255
257
|
wrapped.__identifier.setValue(value);
|
|
256
258
|
}
|
|
257
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* After INSERT + hydration, sync all EntityIdentifier placeholders in composite PK arrays
|
|
262
|
+
* with the real values now present on the entity. This is needed because `mapPrimaryKey`
|
|
263
|
+
* only handles the first PK column, but any scalar PK in a composite key may be auto-generated.
|
|
264
|
+
*/
|
|
265
|
+
syncCompositeIdentifiers(changeSet) {
|
|
266
|
+
const wrapped = helper(changeSet.entity);
|
|
267
|
+
if (!Array.isArray(wrapped.__identifier)) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const pks = changeSet.meta.getPrimaryProps();
|
|
271
|
+
for (let i = 0; i < pks.length; i++) {
|
|
272
|
+
const ident = wrapped.__identifier[i];
|
|
273
|
+
if (ident instanceof EntityIdentifier && pks[i].kind === ReferenceKind.SCALAR) {
|
|
274
|
+
ident.setValue(changeSet.entity[pks[i].name]);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
258
278
|
/**
|
|
259
279
|
* Sets populate flag to new entities so they are serialized like if they were loaded from the db
|
|
260
280
|
*/
|
|
@@ -413,8 +433,8 @@ export class ChangeSetPersister {
|
|
|
413
433
|
}
|
|
414
434
|
return;
|
|
415
435
|
}
|
|
416
|
-
if (Array.isArray(value) && value.
|
|
417
|
-
changeSet.payload[prop.name] = value.map(item => item.getValue());
|
|
436
|
+
if (Array.isArray(value) && value.some(item => item instanceof EntityIdentifier)) {
|
|
437
|
+
changeSet.payload[prop.name] = value.map(item => (item instanceof EntityIdentifier ? item.getValue() : item));
|
|
418
438
|
return;
|
|
419
439
|
}
|
|
420
440
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && Array.isArray(value)) {
|
package/utils/Utils.js
CHANGED
|
@@ -132,7 +132,7 @@ export function parseJsonSafe(value) {
|
|
|
132
132
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
133
133
|
export class Utils {
|
|
134
134
|
static PK_SEPARATOR = '~~~';
|
|
135
|
-
static #ORM_VERSION = '7.0.9-dev.
|
|
135
|
+
static #ORM_VERSION = '7.0.9-dev.10';
|
|
136
136
|
/**
|
|
137
137
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
138
138
|
*/
|