@mikro-orm/core 7.0.0-rc.2 → 7.0.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 +4 -16
- package/EntityManager.js +248 -181
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +24 -24
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -24
- package/cache/GeneratedCacheAdapter.d.ts +1 -1
- package/cache/GeneratedCacheAdapter.js +6 -6
- package/cache/MemoryCacheAdapter.d.ts +1 -2
- package/cache/MemoryCacheAdapter.js +8 -8
- package/cache/index.d.ts +1 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +1 -0
- package/connections/Connection.js +43 -14
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +28 -12
- package/drivers/IDatabaseDriver.d.ts +43 -0
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +124 -108
- package/entity/EntityAssigner.js +23 -11
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +79 -59
- package/entity/EntityHelper.js +25 -16
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +90 -60
- package/entity/Reference.d.ts +2 -3
- package/entity/Reference.js +48 -19
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/WrappedEntity.js +5 -1
- package/entity/defineEntity.d.ts +42 -85
- package/entity/utils.js +28 -26
- package/entity/validators.js +2 -1
- package/enums.d.ts +2 -1
- package/enums.js +13 -17
- package/errors.d.ts +11 -11
- package/errors.js +8 -8
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +26 -23
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +9 -2
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +41 -27
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.js +6 -7
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +2 -5
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +3 -3
- package/metadata/EntitySchema.js +12 -2
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +251 -179
- package/metadata/MetadataProvider.js +26 -1
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +37 -39
- package/metadata/MetadataValidator.js +20 -5
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/metadata/types.d.ts +2 -2
- package/naming-strategy/AbstractNamingStrategy.js +6 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/not-supported.js +5 -1
- package/package.json +38 -38
- package/platforms/Platform.d.ts +24 -1
- package/platforms/Platform.js +106 -27
- package/serialization/EntitySerializer.js +8 -4
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +21 -16
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +35 -24
- package/typings.js +9 -9
- package/unit-of-work/ChangeSet.js +4 -4
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +29 -27
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +63 -58
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +17 -15
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +12 -20
- package/unit-of-work/UnitOfWork.js +228 -191
- package/utils/AbstractMigrator.d.ts +2 -2
- package/utils/AbstractMigrator.js +10 -12
- package/utils/AbstractSchemaGenerator.js +2 -1
- package/utils/AsyncContext.js +1 -1
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +97 -77
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +8 -6
- package/utils/DataloaderUtils.js +15 -12
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +100 -92
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +108 -50
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/RawQueryFragment.js +3 -2
- package/utils/TransactionManager.js +3 -3
- package/utils/Utils.d.ts +2 -2
- package/utils/Utils.js +39 -32
- package/utils/clone.js +5 -0
- package/utils/env-vars.js +6 -5
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +2 -5
- package/utils/upsert-utils.js +7 -4
package/platforms/Platform.js
CHANGED
|
@@ -3,7 +3,7 @@ import { EntityRepository } from '../entity/EntityRepository.js';
|
|
|
3
3
|
import { UnderscoreNamingStrategy } from '../naming-strategy/UnderscoreNamingStrategy.js';
|
|
4
4
|
import { ExceptionConverter } from './ExceptionConverter.js';
|
|
5
5
|
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
|
-
import { parseJsonSafe } from '../utils/Utils.js';
|
|
6
|
+
import { parseJsonSafe, Utils } from '../utils/Utils.js';
|
|
7
7
|
import { ReferenceKind } from '../enums.js';
|
|
8
8
|
import { Raw } from '../utils/RawQueryFragment.js';
|
|
9
9
|
export const JsonProperty = Symbol('JsonProperty');
|
|
@@ -104,6 +104,11 @@ export class Platform {
|
|
|
104
104
|
getRegExpOperator(val, flags) {
|
|
105
105
|
return 'regexp';
|
|
106
106
|
}
|
|
107
|
+
mapRegExpCondition(mappedKey, value) {
|
|
108
|
+
const operator = this.getRegExpOperator(value.$re, value.$flags);
|
|
109
|
+
const quotedKey = this.quoteIdentifier(mappedKey);
|
|
110
|
+
return { sql: `${quotedKey} ${operator} ?`, params: [value.$re] };
|
|
111
|
+
}
|
|
107
112
|
getRegExpValue(val) {
|
|
108
113
|
if (val.flags.includes('i')) {
|
|
109
114
|
return { $re: `(?i)${val.source}` };
|
|
@@ -156,7 +161,7 @@ export class Platform {
|
|
|
156
161
|
return 'interval' + (column.length ? `(${column.length})` : '');
|
|
157
162
|
}
|
|
158
163
|
getTextTypeDeclarationSQL(_column) {
|
|
159
|
-
return
|
|
164
|
+
return 'text';
|
|
160
165
|
}
|
|
161
166
|
getEnumTypeDeclarationSQL(column) {
|
|
162
167
|
if (column.items?.every(item => typeof item === 'string')) {
|
|
@@ -180,7 +185,7 @@ export class Platform {
|
|
|
180
185
|
return this.getVarcharTypeDeclarationSQL(column);
|
|
181
186
|
}
|
|
182
187
|
extractSimpleType(type) {
|
|
183
|
-
return
|
|
188
|
+
return /[^(), ]+/.exec(type.toLowerCase())[0];
|
|
184
189
|
}
|
|
185
190
|
/**
|
|
186
191
|
* This should be used only to compare types, it can strip some information like the length.
|
|
@@ -198,43 +203,76 @@ export class Platform {
|
|
|
198
203
|
}
|
|
199
204
|
switch (this.extractSimpleType(type)) {
|
|
200
205
|
case 'character':
|
|
201
|
-
case 'char':
|
|
206
|
+
case 'char':
|
|
207
|
+
return Type.getType(CharacterType);
|
|
202
208
|
case 'string':
|
|
203
|
-
case 'varchar':
|
|
204
|
-
|
|
205
|
-
case '
|
|
209
|
+
case 'varchar':
|
|
210
|
+
return Type.getType(StringType);
|
|
211
|
+
case 'interval':
|
|
212
|
+
return Type.getType(IntervalType);
|
|
213
|
+
case 'text':
|
|
214
|
+
return Type.getType(TextType);
|
|
206
215
|
case 'int':
|
|
207
|
-
case 'number':
|
|
208
|
-
|
|
209
|
-
case '
|
|
210
|
-
|
|
211
|
-
case '
|
|
212
|
-
|
|
213
|
-
case '
|
|
214
|
-
|
|
216
|
+
case 'number':
|
|
217
|
+
return Type.getType(IntegerType);
|
|
218
|
+
case 'bigint':
|
|
219
|
+
return Type.getType(BigIntType);
|
|
220
|
+
case 'smallint':
|
|
221
|
+
return Type.getType(SmallIntType);
|
|
222
|
+
case 'tinyint':
|
|
223
|
+
return Type.getType(TinyIntType);
|
|
224
|
+
case 'mediumint':
|
|
225
|
+
return Type.getType(MediumIntType);
|
|
226
|
+
case 'float':
|
|
227
|
+
return Type.getType(FloatType);
|
|
228
|
+
case 'double':
|
|
229
|
+
return Type.getType(DoubleType);
|
|
230
|
+
case 'integer':
|
|
231
|
+
return Type.getType(IntegerType);
|
|
215
232
|
case 'decimal':
|
|
216
|
-
case 'numeric':
|
|
217
|
-
|
|
233
|
+
case 'numeric':
|
|
234
|
+
return Type.getType(DecimalType);
|
|
235
|
+
case 'boolean':
|
|
236
|
+
return Type.getType(BooleanType);
|
|
218
237
|
case 'blob':
|
|
219
|
-
case 'buffer':
|
|
220
|
-
|
|
221
|
-
case '
|
|
222
|
-
|
|
238
|
+
case 'buffer':
|
|
239
|
+
return Type.getType(BlobType);
|
|
240
|
+
case 'uint8array':
|
|
241
|
+
return Type.getType(Uint8ArrayType);
|
|
242
|
+
case 'uuid':
|
|
243
|
+
return Type.getType(UuidType);
|
|
244
|
+
case 'date':
|
|
245
|
+
return Type.getType(DateType);
|
|
223
246
|
case 'datetime':
|
|
224
|
-
case 'timestamp':
|
|
225
|
-
|
|
247
|
+
case 'timestamp':
|
|
248
|
+
return Type.getType(DateTimeType);
|
|
249
|
+
case 'time':
|
|
250
|
+
return Type.getType(TimeType);
|
|
226
251
|
case 'object':
|
|
227
|
-
case 'json':
|
|
228
|
-
|
|
229
|
-
|
|
252
|
+
case 'json':
|
|
253
|
+
return Type.getType(JsonType);
|
|
254
|
+
case 'enum':
|
|
255
|
+
return Type.getType(EnumType);
|
|
256
|
+
default:
|
|
257
|
+
return Type.getType(UnknownType);
|
|
230
258
|
}
|
|
231
259
|
}
|
|
232
260
|
supportsMultipleCascadePaths() {
|
|
233
261
|
return true;
|
|
234
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Returns true if the platform supports ON UPDATE foreign key rules.
|
|
265
|
+
* Oracle doesn't support ON UPDATE rules.
|
|
266
|
+
*/
|
|
267
|
+
supportsOnUpdate() {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
235
270
|
supportsMultipleStatements() {
|
|
236
271
|
return this.config.get('multipleStatements');
|
|
237
272
|
}
|
|
273
|
+
supportsUnionWhere() {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
238
276
|
getArrayDeclarationSQL() {
|
|
239
277
|
return 'text';
|
|
240
278
|
}
|
|
@@ -259,6 +297,31 @@ export class Platform {
|
|
|
259
297
|
getSearchJsonPropertyKey(path, type, aliased, value) {
|
|
260
298
|
return path.join('.');
|
|
261
299
|
}
|
|
300
|
+
processJsonCondition(o, value, path, alias) {
|
|
301
|
+
if (Utils.isPlainObject(value) && !Object.keys(value).some(k => Utils.isOperator(k))) {
|
|
302
|
+
Utils.keys(value).forEach(k => {
|
|
303
|
+
this.processJsonCondition(o, value[k], [...path, k], alias);
|
|
304
|
+
});
|
|
305
|
+
return o;
|
|
306
|
+
}
|
|
307
|
+
if (path.length === 1) {
|
|
308
|
+
o[path[0]] = value;
|
|
309
|
+
return o;
|
|
310
|
+
}
|
|
311
|
+
const type = this.getJsonValueType(value);
|
|
312
|
+
const k = this.getSearchJsonPropertyKey(path, type, alias, value);
|
|
313
|
+
o[k] = value;
|
|
314
|
+
return o;
|
|
315
|
+
}
|
|
316
|
+
getJsonValueType(value) {
|
|
317
|
+
if (Array.isArray(value)) {
|
|
318
|
+
return typeof value[0];
|
|
319
|
+
}
|
|
320
|
+
if (Utils.isPlainObject(value) && Object.keys(value).every(k => Utils.isOperator(k))) {
|
|
321
|
+
return this.getJsonValueType(Object.values(value)[0]);
|
|
322
|
+
}
|
|
323
|
+
return typeof value;
|
|
324
|
+
}
|
|
262
325
|
/* v8 ignore next */
|
|
263
326
|
getJsonIndexDefinition(index) {
|
|
264
327
|
return index.columnNames;
|
|
@@ -290,6 +353,22 @@ export class Platform {
|
|
|
290
353
|
convertIntervalToDatabaseValue(value) {
|
|
291
354
|
return value;
|
|
292
355
|
}
|
|
356
|
+
usesAsKeyword() {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Determines how UUID values are compared in the change set tracking.
|
|
361
|
+
* Return `'string'` for inline string comparison (fast), or `'any'` for deep comparison via type methods.
|
|
362
|
+
*/
|
|
363
|
+
compareUuids() {
|
|
364
|
+
return 'string';
|
|
365
|
+
}
|
|
366
|
+
convertUuidToJSValue(value) {
|
|
367
|
+
return value;
|
|
368
|
+
}
|
|
369
|
+
convertUuidToDatabaseValue(value) {
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
293
372
|
parseDate(value) {
|
|
294
373
|
const date = new Date(value);
|
|
295
374
|
/* v8 ignore next */
|
|
@@ -354,7 +433,7 @@ export class Platform {
|
|
|
354
433
|
let j = 0;
|
|
355
434
|
let pos = 0;
|
|
356
435
|
let ret = '';
|
|
357
|
-
if (sql
|
|
436
|
+
if (sql.startsWith('?')) {
|
|
358
437
|
if (sql[1] === '?') {
|
|
359
438
|
ret += this.quoteIdentifier(params[j++]);
|
|
360
439
|
pos = 2;
|
|
@@ -9,7 +9,8 @@ function isVisible(meta, propName, options) {
|
|
|
9
9
|
if (options.groups && prop?.groups) {
|
|
10
10
|
return prop.groups.some(g => options.groups.includes(g));
|
|
11
11
|
}
|
|
12
|
-
if (Array.isArray(options.populate) &&
|
|
12
|
+
if (Array.isArray(options.populate) &&
|
|
13
|
+
options.populate?.find(item => item === propName || item.startsWith(propName + '.') || item === '*')) {
|
|
13
14
|
return true;
|
|
14
15
|
}
|
|
15
16
|
if (options.exclude?.find(item => item === propName)) {
|
|
@@ -20,7 +21,8 @@ function isVisible(meta, propName, options) {
|
|
|
20
21
|
return visible && !prefixed;
|
|
21
22
|
}
|
|
22
23
|
function isPopulated(propName, options) {
|
|
23
|
-
if (typeof options.populate !== 'boolean' &&
|
|
24
|
+
if (typeof options.populate !== 'boolean' &&
|
|
25
|
+
options.populate?.find(item => item === propName || item.startsWith(propName + '.') || item === '*')) {
|
|
24
26
|
return true;
|
|
25
27
|
}
|
|
26
28
|
if (typeof options.populate === 'boolean') {
|
|
@@ -34,7 +36,7 @@ export class EntitySerializer {
|
|
|
34
36
|
const meta = wrapped.__meta;
|
|
35
37
|
let contextCreated = false;
|
|
36
38
|
if (!wrapped.__serializationContext.root) {
|
|
37
|
-
const root = new SerializationContext(
|
|
39
|
+
const root = new SerializationContext();
|
|
38
40
|
SerializationContext.propagate(root, entity, (meta, prop) => meta.properties[prop]?.kind !== ReferenceKind.SCALAR);
|
|
39
41
|
options.populate = (options.populate ? Utils.asArray(options.populate) : options.populate);
|
|
40
42
|
contextCreated = true;
|
|
@@ -176,7 +178,9 @@ export class EntitySerializer {
|
|
|
176
178
|
static extractChildOptions(options, prop) {
|
|
177
179
|
return {
|
|
178
180
|
...options,
|
|
179
|
-
populate: Array.isArray(options.populate)
|
|
181
|
+
populate: Array.isArray(options.populate)
|
|
182
|
+
? Utils.extractChildElements(options.populate, prop, '*')
|
|
183
|
+
: options.populate,
|
|
180
184
|
exclude: Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop) : options.exclude,
|
|
181
185
|
};
|
|
182
186
|
}
|
|
@@ -20,7 +20,7 @@ export class EntityTransformer {
|
|
|
20
20
|
return entity;
|
|
21
21
|
}
|
|
22
22
|
if (!wrapped.__serializationContext.root) {
|
|
23
|
-
const root = new SerializationContext(wrapped.
|
|
23
|
+
const root = new SerializationContext(wrapped.__serializationContext.populate, wrapped.__serializationContext.fields, wrapped.__serializationContext.exclude);
|
|
24
24
|
SerializationContext.propagate(root, entity, isVisible);
|
|
25
25
|
contextCreated = true;
|
|
26
26
|
}
|
|
@@ -64,6 +64,9 @@ export class EntityTransformer {
|
|
|
64
64
|
if (!partiallyLoaded && !populated && !isPrimary) {
|
|
65
65
|
continue;
|
|
66
66
|
}
|
|
67
|
+
if (root.isExcluded(meta.class, prop) && !populated) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
67
70
|
}
|
|
68
71
|
const cycle = root.visit(meta.class, prop);
|
|
69
72
|
if (cycle && visited) {
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import type { AnyEntity, EntityMetadata, EntityName, PopulateOptions } from '../typings.js';
|
|
2
|
-
import type { Configuration } from '../utils/Configuration.js';
|
|
3
2
|
/**
|
|
4
3
|
* Helper that allows to keep track of where we are currently at when serializing complex entity graph with cycles.
|
|
5
4
|
* Before we process a property, we call `visit` that checks if it is not a cycle path (but allows to pass cycles that
|
|
6
5
|
* are defined in populate hint). If not, we proceed and call `leave` afterwards.
|
|
7
6
|
*/
|
|
8
7
|
export declare class SerializationContext<T extends object> {
|
|
9
|
-
private
|
|
10
|
-
private readonly populate;
|
|
11
|
-
private readonly fields?;
|
|
12
|
-
private readonly exclude?;
|
|
8
|
+
#private;
|
|
13
9
|
readonly path: [EntityName, string][];
|
|
14
|
-
readonly visited: Set<
|
|
15
|
-
|
|
16
|
-
constructor(config: Configuration, populate?: PopulateOptions<T>[], fields?: Set<string> | undefined, exclude?: string[] | undefined);
|
|
10
|
+
readonly visited: Set<AnyEntity>;
|
|
11
|
+
constructor(populate?: PopulateOptions<T>[], fields?: Set<string>, exclude?: readonly string[]);
|
|
17
12
|
/**
|
|
18
13
|
* Returns true when there is a cycle detected.
|
|
19
14
|
*/
|
|
@@ -25,6 +20,7 @@ export declare class SerializationContext<T extends object> {
|
|
|
25
20
|
*/
|
|
26
21
|
static propagate(root: SerializationContext<any>, entity: AnyEntity, isVisible: (meta: EntityMetadata, prop: string) => boolean): void;
|
|
27
22
|
isMarkedAsPopulated(entityName: EntityName, prop: string): boolean;
|
|
23
|
+
isExcluded(entityName: EntityName, prop: string): boolean;
|
|
28
24
|
isPartiallyLoaded(entityName: EntityName, prop: string): boolean;
|
|
29
25
|
private register;
|
|
30
26
|
}
|
|
@@ -6,18 +6,16 @@ import { helper } from '../entity/wrap.js';
|
|
|
6
6
|
* are defined in populate hint). If not, we proceed and call `leave` afterwards.
|
|
7
7
|
*/
|
|
8
8
|
export class SerializationContext {
|
|
9
|
-
config;
|
|
10
|
-
populate;
|
|
11
|
-
fields;
|
|
12
|
-
exclude;
|
|
13
9
|
path = [];
|
|
14
10
|
visited = new Set();
|
|
15
|
-
entities = new Set();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this
|
|
11
|
+
#entities = new Set();
|
|
12
|
+
#populate;
|
|
13
|
+
#fields;
|
|
14
|
+
#exclude;
|
|
15
|
+
constructor(populate = [], fields, exclude) {
|
|
16
|
+
this.#populate = populate;
|
|
17
|
+
this.#fields = fields;
|
|
18
|
+
this.#exclude = exclude;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
21
|
* Returns true when there is a cycle detected.
|
|
@@ -42,7 +40,7 @@ export class SerializationContext {
|
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
close() {
|
|
45
|
-
for (const entity of this
|
|
43
|
+
for (const entity of this.#entities) {
|
|
46
44
|
delete helper(entity).__serializationContext.root;
|
|
47
45
|
}
|
|
48
46
|
}
|
|
@@ -73,7 +71,7 @@ export class SerializationContext {
|
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
73
|
isMarkedAsPopulated(entityName, prop) {
|
|
76
|
-
let populate = this
|
|
74
|
+
let populate = this.#populate ?? [];
|
|
77
75
|
for (const segment of this.path) {
|
|
78
76
|
const hints = populate.filter(p => p.field === segment[1]);
|
|
79
77
|
if (hints.length > 0) {
|
|
@@ -92,11 +90,18 @@ export class SerializationContext {
|
|
|
92
90
|
}
|
|
93
91
|
return !!populate?.some(p => p.field === prop);
|
|
94
92
|
}
|
|
93
|
+
isExcluded(entityName, prop) {
|
|
94
|
+
if (!this.#exclude || this.#exclude.length === 0) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const fullPath = this.path.map(segment => segment[1] + '.').join('') + prop;
|
|
98
|
+
return this.#exclude.includes(fullPath);
|
|
99
|
+
}
|
|
95
100
|
isPartiallyLoaded(entityName, prop) {
|
|
96
|
-
if (!this
|
|
101
|
+
if (!this.#fields) {
|
|
97
102
|
return true;
|
|
98
103
|
}
|
|
99
|
-
let fields = [...this
|
|
104
|
+
let fields = [...this.#fields];
|
|
100
105
|
for (const segment of this.path) {
|
|
101
106
|
/* v8 ignore next */
|
|
102
107
|
if (fields.length === 0) {
|
|
@@ -104,12 +109,12 @@ export class SerializationContext {
|
|
|
104
109
|
}
|
|
105
110
|
fields = fields
|
|
106
111
|
.filter(field => field.startsWith(`${segment[1]}.`) || field === '*')
|
|
107
|
-
.map(field => field === '*' ? field : field.substring(segment[1].length + 1));
|
|
112
|
+
.map(field => (field === '*' ? field : field.substring(segment[1].length + 1)));
|
|
108
113
|
}
|
|
109
114
|
return fields.some(p => p === prop || p === '*');
|
|
110
115
|
}
|
|
111
116
|
register(entity) {
|
|
112
117
|
helper(entity).__serializationContext.root = this;
|
|
113
|
-
this
|
|
118
|
+
this.#entities.add(entity);
|
|
114
119
|
}
|
|
115
120
|
}
|
package/types/UuidType.d.ts
CHANGED
|
@@ -4,5 +4,7 @@ import type { EntityProperty } from '../typings.js';
|
|
|
4
4
|
export declare class UuidType extends Type<string | null | undefined> {
|
|
5
5
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
6
6
|
compareAsType(): string;
|
|
7
|
+
convertToDatabaseValue(value: string | null | undefined, platform: Platform): string | null;
|
|
8
|
+
convertToJSValue(value: string | null | undefined, platform: Platform): string | null | undefined;
|
|
7
9
|
ensureComparable(): boolean;
|
|
8
10
|
}
|
package/types/UuidType.js
CHANGED
|
@@ -4,9 +4,21 @@ export class UuidType extends Type {
|
|
|
4
4
|
return platform.getUuidTypeDeclarationSQL(prop);
|
|
5
5
|
}
|
|
6
6
|
compareAsType() {
|
|
7
|
-
return 'string';
|
|
7
|
+
return this.platform?.compareUuids() ?? 'string';
|
|
8
|
+
}
|
|
9
|
+
convertToDatabaseValue(value, platform) {
|
|
10
|
+
if (value == null) {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
return platform.convertUuidToDatabaseValue(value);
|
|
14
|
+
}
|
|
15
|
+
convertToJSValue(value, platform) {
|
|
16
|
+
if (value == null) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
return platform.convertUuidToJSValue(value);
|
|
8
20
|
}
|
|
9
21
|
ensureComparable() {
|
|
10
|
-
return
|
|
22
|
+
return this.platform?.compareUuids() !== 'string';
|
|
11
23
|
}
|
|
12
24
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -23,7 +23,8 @@ import { type IType, type TransformContext, Type } from './Type.js';
|
|
|
23
23
|
import { Uint8ArrayType } from './Uint8ArrayType.js';
|
|
24
24
|
import { UnknownType } from './UnknownType.js';
|
|
25
25
|
import { UuidType } from './UuidType.js';
|
|
26
|
-
export {
|
|
26
|
+
export type { TransformContext, IType };
|
|
27
|
+
export { Type, DateType, TimeType, DateTimeType, BigIntType, BlobType, Uint8ArrayType, ArrayType, EnumArrayType, EnumType, JsonType, IntegerType, SmallIntType, TinyIntType, MediumIntType, FloatType, DoubleType, BooleanType, DecimalType, StringType, UuidType, TextType, UnknownType, IntervalType, CharacterType, };
|
|
27
28
|
export declare const types: {
|
|
28
29
|
readonly date: typeof DateType;
|
|
29
30
|
readonly time: typeof TimeType;
|
package/typings.d.ts
CHANGED
|
@@ -36,11 +36,11 @@ export type Compute<T> = {
|
|
|
36
36
|
[K in keyof T]: T[K];
|
|
37
37
|
} & {};
|
|
38
38
|
type InternalKeys = 'EntityRepositoryType' | 'PrimaryKeyProp' | 'OptionalProps' | 'EagerProps' | 'HiddenProps' | '__selectedType' | '__loadedType';
|
|
39
|
-
export type CleanKeys<T, K extends keyof T, B extends boolean = false> =
|
|
39
|
+
export type CleanKeys<T, K extends keyof T, B extends boolean = false> = T[K] & {} extends Function ? never : K extends symbol | InternalKeys ? never : B extends true ? T[K] & {} extends Scalar ? never : K : K;
|
|
40
40
|
export type FunctionKeys<T, K extends keyof T> = T[K] extends Function ? K : never;
|
|
41
41
|
export type Cast<T, R> = T extends R ? T : R;
|
|
42
|
-
export type IsUnknown<T> = T extends unknown ? unknown extends T ? true : never : never;
|
|
43
|
-
export type IsAny<T> = 0 extends
|
|
42
|
+
export type IsUnknown<T> = T extends unknown ? (unknown extends T ? true : never) : never;
|
|
43
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
44
44
|
export type IsNever<T, True = true, False = false> = [T] extends [never] ? True : False;
|
|
45
45
|
export type MaybePromise<T> = T | Promise<T>;
|
|
46
46
|
/**
|
|
@@ -98,9 +98,9 @@ type LoadableShape = CollectionShape | ReferenceShape | readonly any[];
|
|
|
98
98
|
export type UnionKeys<T> = T extends any ? keyof T : never;
|
|
99
99
|
export type UnionPropertyType<T, K extends PropertyKey> = T extends any ? (K extends keyof T ? T[K] : never) : never;
|
|
100
100
|
type IsUnion<T, U = T> = T extends any ? ([U] extends [T] ? false : true) : false;
|
|
101
|
-
export type MergeUnion<T> = [T] extends [object] ?
|
|
101
|
+
export type MergeUnion<T> = [T] extends [object] ? T extends Scalar ? T : IsUnion<T> extends true ? {
|
|
102
102
|
[K in UnionKeys<T>]: UnionPropertyType<T, K>;
|
|
103
|
-
} : T
|
|
103
|
+
} : T : T;
|
|
104
104
|
export type DeepPartial<T> = T & {
|
|
105
105
|
[P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends Readonly<infer U>[] ? Readonly<DeepPartial<U>>[] : DeepPartial<T[P]>;
|
|
106
106
|
};
|
|
@@ -113,7 +113,7 @@ export declare const Config: unique symbol;
|
|
|
113
113
|
export declare const EntityName: unique symbol;
|
|
114
114
|
export type InferEntityName<T> = T extends {
|
|
115
115
|
[EntityName]?: infer Name;
|
|
116
|
-
} ? Name extends string ? Name : never : never;
|
|
116
|
+
} ? (Name extends string ? Name : never) : never;
|
|
117
117
|
export type Opt<T = unknown> = T & Opt.Brand;
|
|
118
118
|
export declare namespace Opt {
|
|
119
119
|
const __optional: unique symbol;
|
|
@@ -173,11 +173,11 @@ export type Primary<T> = IsAny<T> extends true ? any : T extends {
|
|
|
173
173
|
/** @internal */
|
|
174
174
|
export type PrimaryProperty<T> = T extends {
|
|
175
175
|
[PrimaryKeyProp]?: infer PK;
|
|
176
|
-
} ?
|
|
176
|
+
} ? PK extends keyof T ? PK : PK extends any[] ? PK[number] : never : T extends {
|
|
177
177
|
_id?: any;
|
|
178
|
-
} ?
|
|
178
|
+
} ? T extends {
|
|
179
179
|
id?: any;
|
|
180
|
-
} ? 'id' | '_id' : '_id'
|
|
180
|
+
} ? 'id' | '_id' : '_id' : T extends {
|
|
181
181
|
id?: any;
|
|
182
182
|
} ? 'id' : T extends {
|
|
183
183
|
uuid?: any;
|
|
@@ -234,10 +234,20 @@ export type FilterItemValue<T> = T | ExpandScalar<T> | Primary<T> | Raw;
|
|
|
234
234
|
export type FilterValue<T> = OperatorMap<FilterItemValue<T>> | FilterItemValue<T> | FilterItemValue<T>[] | null;
|
|
235
235
|
type FilterObjectProp<T, K extends PropertyKey> = K extends keyof MergeUnion<T> ? MergeUnion<T>[K] : K extends keyof T ? T[K] : never;
|
|
236
236
|
type ExpandQueryMerged<T> = [T] extends [object] ? [T] extends [Scalar] ? never : FilterQuery<MergeUnion<T>> : FilterValue<T>;
|
|
237
|
+
type ElemMatchCondition<T extends Record<string, any>> = {
|
|
238
|
+
[K in keyof T]?: T[K] | OperatorMap<T[K]>;
|
|
239
|
+
} & {
|
|
240
|
+
$or?: ElemMatchCondition<T>[];
|
|
241
|
+
$and?: ElemMatchCondition<T>[];
|
|
242
|
+
$not?: ElemMatchCondition<T>;
|
|
243
|
+
};
|
|
244
|
+
type ElemMatchFilter<T> = T extends readonly (infer E)[] ? E extends Record<string, any> ? {
|
|
245
|
+
$elemMatch: ElemMatchCondition<E>;
|
|
246
|
+
} : never : never;
|
|
237
247
|
export type FilterObject<T> = {
|
|
238
|
-
-readonly [K in EntityKey<T>]?: ExpandQuery<ExpandProperty<FilterObjectProp<T, K>>> | ExpandQueryMerged<ExpandProperty<FilterObjectProp<T, K>>> | FilterValue<ExpandProperty<FilterObjectProp<T, K>>> | null;
|
|
248
|
+
-readonly [K in EntityKey<T>]?: ExpandQuery<ExpandProperty<FilterObjectProp<T, K>>> | ExpandQueryMerged<ExpandProperty<FilterObjectProp<T, K>>> | FilterValue<ExpandProperty<FilterObjectProp<T, K>>> | ElemMatchFilter<FilterObjectProp<T, K>> | null;
|
|
239
249
|
};
|
|
240
|
-
export type ExpandQuery<T> = T extends object ? T extends Scalar ? never : FilterQuery<T> : FilterValue<T>;
|
|
250
|
+
export type ExpandQuery<T> = T extends object ? (T extends Scalar ? never : FilterQuery<T>) : FilterValue<T>;
|
|
241
251
|
export type EntityProps<T> = {
|
|
242
252
|
-readonly [K in EntityKey<T>]?: T[K];
|
|
243
253
|
};
|
|
@@ -324,11 +334,11 @@ type NonArrayObject = object & {
|
|
|
324
334
|
export type EntityDataProp<T, C extends boolean> = T extends Date ? string | Date : T extends Scalar ? T : T extends ScalarReference<infer U> ? EntityDataProp<U, C> : T extends {
|
|
325
335
|
__runtime?: infer Runtime;
|
|
326
336
|
__raw?: infer Raw;
|
|
327
|
-
} ?
|
|
337
|
+
} ? C extends true ? Raw : Runtime : T extends ReferenceShape<infer U> ? EntityDataNested<U, C> : T extends CollectionShape<infer U> ? U | U[] | EntityDataNested<U & object, C> | EntityDataNested<U & object, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | EntityDataNested<U, C> | EntityDataNested<U, C>[] : U[] | EntityDataNested<U, C>[] : EntityDataNested<T, C>;
|
|
328
338
|
export type RequiredEntityDataProp<T, O, C extends boolean> = T extends Date ? string | Date : Exclude<T, null> extends RequiredNullable.Brand ? T | null : T extends Scalar ? T : T extends ScalarReference<infer U> ? RequiredEntityDataProp<U, O, C> : T extends {
|
|
329
339
|
__runtime?: infer Runtime;
|
|
330
340
|
__raw?: infer Raw;
|
|
331
|
-
} ?
|
|
341
|
+
} ? C extends true ? Raw : Runtime : T extends ReferenceShape<infer U> ? RequiredEntityDataNested<U, O, C> : T extends CollectionShape<infer U> ? U | U[] | RequiredEntityDataNested<U & object, O, C> | RequiredEntityDataNested<U & object, O, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | RequiredEntityDataNested<U, O, C> | RequiredEntityDataNested<U, O, C>[] : U[] | RequiredEntityDataNested<U, O, C>[] : RequiredEntityDataNested<T, O, C>;
|
|
332
342
|
export type EntityDataNested<T, C extends boolean = false> = T extends undefined ? never : T extends any[] ? Readonly<T> : EntityData<T, C> | ExpandEntityProp<T, C>;
|
|
333
343
|
type UnwrapScalarRef<T> = T extends ScalarReference<infer U> ? U : T;
|
|
334
344
|
type EntityDataItem<T, C extends boolean> = C extends false ? UnwrapScalarRef<T> | EntityDataProp<T, C> | Raw | null : EntityDataProp<T, C> | Raw | null;
|
|
@@ -368,9 +378,9 @@ export type Rel<T> = T;
|
|
|
368
378
|
/** Alias for `ScalarReference` (see {@apilink Ref}). */
|
|
369
379
|
export type ScalarRef<T> = ScalarReference<T>;
|
|
370
380
|
/** Alias for `Reference<T> & { id: number }` (see {@apilink Ref}). */
|
|
371
|
-
export type EntityRef<T extends object> = true extends IsUnknown<PrimaryProperty<T>> ? Reference<T> : IsAny<T> extends true ? Reference<T> :
|
|
381
|
+
export type EntityRef<T extends object> = true extends IsUnknown<PrimaryProperty<T>> ? Reference<T> : IsAny<T> extends true ? Reference<T> : {
|
|
372
382
|
[K in PrimaryProperty<T> & keyof T]: T[K];
|
|
373
|
-
} & Reference<T
|
|
383
|
+
} & Reference<T>;
|
|
374
384
|
/**
|
|
375
385
|
* Ref type represents a `Reference` instance, and adds the primary keys to its prototype automatically, so you can do
|
|
376
386
|
* `ref.id` instead of `ref.unwrap().id`. It resolves to either `ScalarRef` or `EntityRef`, based on the type argument.
|
|
@@ -384,7 +394,7 @@ type ExtractHiddenProps<T> = (T extends {
|
|
|
384
394
|
type ExcludeHidden<T, K extends keyof T> = K extends ExtractHiddenProps<T> ? never : K;
|
|
385
395
|
type ExtractConfig<T> = T extends {
|
|
386
396
|
[Config]?: infer K;
|
|
387
|
-
} ?
|
|
397
|
+
} ? K & TypeConfig : TypeConfig;
|
|
388
398
|
type PreferExplicitConfig<E, I> = IsNever<E, I, E>;
|
|
389
399
|
type PrimaryOrObject<T, U, C extends TypeConfig> = PreferExplicitConfig<C, ExtractConfig<T>>['forceObject'] extends true ? {
|
|
390
400
|
[K in PrimaryProperty<U> & keyof U]: U[K];
|
|
@@ -392,7 +402,7 @@ type PrimaryOrObject<T, U, C extends TypeConfig> = PreferExplicitConfig<C, Extra
|
|
|
392
402
|
type DTOWrapper<T, C extends TypeConfig, Flat extends boolean> = Flat extends true ? EntityDTOFlat<T, C> : EntityDTO<T, C>;
|
|
393
403
|
export type EntityDTOProp<E, T, C extends TypeConfig = never, Flat extends boolean = false> = T extends Scalar ? T : T extends ScalarReference<infer U> ? U : T extends {
|
|
394
404
|
__serialized?: infer U;
|
|
395
|
-
} ?
|
|
405
|
+
} ? IsUnknown<U> extends false ? U : T : T extends LoadedReferenceShape<infer U> ? DTOWrapper<U, C, Flat> : T extends ReferenceShape<infer U> ? PrimaryOrObject<E, U, C> : T extends LoadedCollectionShape<infer U> ? DTOWrapper<U & object, C, Flat>[] : T extends CollectionShape<infer U> ? PrimaryOrObject<E, U & object, C>[] : T extends readonly (infer U)[] ? U extends Scalar ? T : EntityDTOProp<E, U, C, Flat>[] : T extends Relation<T> ? DTOWrapper<T, C, Flat> : T;
|
|
396
406
|
type UnwrapLoadedEntity<T> = T extends {
|
|
397
407
|
[__loadedType]?: infer U;
|
|
398
408
|
} ? NonNullable<U> : T;
|
|
@@ -422,7 +432,7 @@ export type EntityDTOFlat<T, C extends TypeConfig = never> = {
|
|
|
422
432
|
*/
|
|
423
433
|
type SerializeTopHints<H extends string> = H extends `${infer Top}.${string}` ? Top : H;
|
|
424
434
|
type SerializeSubHints<K extends string, H extends string> = H extends `${K}.${infer Rest}` ? Rest : never;
|
|
425
|
-
type SerializePropValue<T, K extends keyof T, H extends string, C extends TypeConfig = never> =
|
|
435
|
+
type SerializePropValue<T, K extends keyof T, H extends string, C extends TypeConfig = never> = K & string extends SerializeTopHints<H> ? NonNullable<T[K]> extends CollectionShape<infer U> ? SerializeDTO<U & object, SerializeSubHints<K & string, H>, never, C>[] : SerializeDTO<ExpandProperty<T[K]>, SerializeSubHints<K & string, H>, never, C> | Extract<T[K], null | undefined> : EntityDTOProp<T, T[K], C>;
|
|
426
436
|
export type SerializeDTO<T, H extends string = never, E extends string = never, C extends TypeConfig = never> = string extends H ? EntityDTOFlat<T, C> : {
|
|
427
437
|
[K in keyof T as ExcludeHidden<T, K> & CleanKeys<T, K> & (IsNever<E> extends true ? K : Exclude<K, E>)]: SerializePropValue<T, K, H, C> | Extract<T[K], null | undefined>;
|
|
428
438
|
};
|
|
@@ -523,6 +533,7 @@ export interface EntityProperty<Owner = any, Target = any> {
|
|
|
523
533
|
nullable?: boolean;
|
|
524
534
|
inherited?: boolean;
|
|
525
535
|
renamedFrom?: string;
|
|
536
|
+
stiMerged?: boolean;
|
|
526
537
|
stiFieldNames?: string[];
|
|
527
538
|
stiFieldNameMap?: Dictionary<string>;
|
|
528
539
|
unsigned?: boolean;
|
|
@@ -975,7 +986,7 @@ type ExtractStringKeys<T> = {
|
|
|
975
986
|
* Simplified to just check `T extends object` since ExtractType handles the unwrapping.
|
|
976
987
|
*/
|
|
977
988
|
type StringKeys<T, E extends string = never> = T extends object ? ExtractStringKeys<ExtractType<T>> | E : never;
|
|
978
|
-
type GetStringKey<T, K extends StringKeys<T, string>, E extends string> = K extends keyof T ? ExtractType<T[K]> :
|
|
989
|
+
type GetStringKey<T, K extends StringKeys<T, string>, E extends string> = K extends keyof T ? ExtractType<T[K]> : K extends E ? keyof T : never;
|
|
979
990
|
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
980
991
|
type RelationKeys<T> = T extends object ? {
|
|
981
992
|
[K in keyof T]-?: CleanKeys<T, K, true>;
|
|
@@ -985,12 +996,12 @@ export type UnboxArray<T> = T extends any[] ? ArrayElement<T> : T;
|
|
|
985
996
|
export type ArrayElement<ArrayType extends unknown[]> = ArrayType extends (infer ElementType)[] ? ElementType : never;
|
|
986
997
|
export type ExpandProperty<T> = T extends ReferenceShape<infer U> ? NonNullable<U> : T extends CollectionShape<infer U> ? NonNullable<U> : T extends (infer U)[] ? NonNullable<U> : NonNullable<T>;
|
|
987
998
|
type LoadedLoadable<T, E extends object> = T extends CollectionShape ? LoadedCollection<E> : T extends ScalarReference<infer U> ? LoadedScalarReference<U> : T extends ReferenceShape ? T & LoadedReference<E> : T extends Scalar ? T : T extends (infer U)[] ? U extends Scalar ? T : E[] : E;
|
|
988
|
-
type IsTrue<T> = IsNever<T> extends true ? false : T extends boolean ? T extends true ? true : false : false;
|
|
989
|
-
type StringLiteral<T> = T extends string ? string extends T ? never : T : never;
|
|
990
|
-
type Prefix<T, K> = K extends `${infer S}.${string}` ? S :
|
|
999
|
+
type IsTrue<T> = IsNever<T> extends true ? false : T extends boolean ? (T extends true ? true : false) : false;
|
|
1000
|
+
type StringLiteral<T> = T extends string ? (string extends T ? never : T) : never;
|
|
1001
|
+
type Prefix<T, K> = K extends `${infer S}.${string}` ? S : K extends '*' ? keyof T : K;
|
|
991
1002
|
type IsPrefixedExclude<T, K extends keyof T, E extends string> = K extends E ? never : K;
|
|
992
|
-
export type IsPrefixed<T, K extends keyof T, L extends string, E extends string = never> = IsNever<E> extends false ? IsPrefixedExclude<T, K, E> : K extends symbol ? never : IsTrue<L> extends true ?
|
|
993
|
-
type Suffix<Key, Hint extends string, All = true | '*'> = Hint extends `${infer Pref}.${infer Suf}` ?
|
|
1003
|
+
export type IsPrefixed<T, K extends keyof T, L extends string, E extends string = never> = IsNever<E> extends false ? IsPrefixedExclude<T, K, E> : K extends symbol ? never : IsTrue<L> extends true ? T[K] & {} extends LoadableShape ? K : never : IsNever<StringLiteral<L>> extends true ? never : '*' extends L ? K : K extends Prefix<T, L> ? K : K extends PrimaryProperty<T> ? K : never;
|
|
1004
|
+
type Suffix<Key, Hint extends string, All = true | '*'> = Hint extends `${infer Pref}.${infer Suf}` ? Pref extends Key ? Suf : never : Hint extends All ? Hint : never;
|
|
994
1005
|
export type IsSubset<T, U> = keyof U extends keyof T ? {} : string extends keyof U ? {} : {
|
|
995
1006
|
[K in keyof U as K extends keyof T ? never : CleanKeys<U, K>]: never;
|
|
996
1007
|
};
|
package/typings.js
CHANGED
|
@@ -31,11 +31,9 @@ export class EntityMetadata {
|
|
|
31
31
|
Object.assign(this, meta);
|
|
32
32
|
const name = meta.className ?? meta.name;
|
|
33
33
|
if (!this.class && name) {
|
|
34
|
-
const Class = this.extends === BaseEntity
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
: ({ [name]: class {
|
|
38
|
-
} })[name];
|
|
34
|
+
const Class = this.extends === BaseEntity ? { [name]: class extends BaseEntity {
|
|
35
|
+
} }[name] : { [name]: class {
|
|
36
|
+
} }[name];
|
|
39
37
|
this.class = Class;
|
|
40
38
|
}
|
|
41
39
|
}
|
|
@@ -108,9 +106,7 @@ export class EntityMetadata {
|
|
|
108
106
|
*/
|
|
109
107
|
createSchemaColumnMappingObject() {
|
|
110
108
|
// For TPT entities, only include properties that belong to this entity's table
|
|
111
|
-
const props = this.inheritanceType === 'tpt' && this.ownProps
|
|
112
|
-
? this.ownProps
|
|
113
|
-
: Object.values(this.properties);
|
|
109
|
+
const props = this.inheritanceType === 'tpt' && this.ownProps ? this.ownProps : Object.values(this.properties);
|
|
114
110
|
return props.reduce((o, prop) => {
|
|
115
111
|
if (prop.fieldNames) {
|
|
116
112
|
o[prop.name] = prop.fieldNames[0];
|
|
@@ -208,7 +204,11 @@ export class EntityMetadata {
|
|
|
208
204
|
const hydrator = wrapped.hydrator;
|
|
209
205
|
const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
|
|
210
206
|
const old = Reference.unwrapReference(wrapped.__data[prop.name]);
|
|
211
|
-
if (old &&
|
|
207
|
+
if (old &&
|
|
208
|
+
old !== entity &&
|
|
209
|
+
prop.kind === ReferenceKind.MANY_TO_ONE &&
|
|
210
|
+
prop.inversedBy &&
|
|
211
|
+
old[prop.inversedBy]) {
|
|
212
212
|
old[prop.inversedBy].removeWithoutPropagation(this);
|
|
213
213
|
}
|
|
214
214
|
wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
|
|
@@ -27,10 +27,10 @@ export class ChangeSet {
|
|
|
27
27
|
else {
|
|
28
28
|
this.primaryKey = this.originalEntity[this.meta.primaryKeys[0]];
|
|
29
29
|
}
|
|
30
|
-
if (!this.meta.compositePK
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
if (!this.meta.compositePK &&
|
|
31
|
+
this.meta.getPrimaryProp().targetMeta?.compositePK &&
|
|
32
|
+
typeof this.primaryKey === 'object' &&
|
|
33
|
+
this.primaryKey !== null) {
|
|
34
34
|
this.primaryKey = this.meta.getPrimaryProp().targetMeta.primaryKeys.map(childPK => {
|
|
35
35
|
return this.primaryKey[childPK];
|
|
36
36
|
});
|