@mikro-orm/core 7.0.0-dev.300 → 7.0.0-dev.302
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 +1 -1
- package/EntityManager.js +94 -43
- package/MikroORM.js +4 -4
- package/cache/FileCacheAdapter.js +1 -3
- package/connections/Connection.js +16 -3
- package/drivers/DatabaseDriver.js +25 -7
- package/entity/Collection.js +43 -17
- package/entity/EntityAssigner.js +23 -11
- package/entity/EntityFactory.js +32 -12
- package/entity/EntityHelper.js +12 -8
- package/entity/EntityLoader.js +55 -22
- package/entity/Reference.d.ts +1 -1
- package/entity/Reference.js +37 -8
- package/entity/WrappedEntity.js +5 -1
- package/entity/defineEntity.d.ts +5 -7
- package/entity/utils.js +28 -26
- package/entity/validators.js +2 -1
- package/enums.js +12 -17
- package/errors.js +18 -8
- package/events/EventManager.js +1 -1
- package/exceptions.js +7 -2
- package/hydration/ObjectHydrator.js +27 -13
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.js +3 -5
- package/logging/colors.js +3 -6
- package/metadata/EntitySchema.js +12 -2
- package/metadata/MetadataDiscovery.js +101 -46
- package/metadata/MetadataProvider.js +6 -1
- package/metadata/MetadataStorage.js +1 -3
- package/metadata/MetadataValidator.js +20 -5
- package/metadata/types.d.ts +2 -2
- package/naming-strategy/AbstractNamingStrategy.js +5 -2
- package/not-supported.js +5 -1
- package/package.json +38 -38
- package/platforms/Platform.js +46 -23
- package/serialization/EntitySerializer.js +7 -3
- package/serialization/SerializationContext.js +1 -1
- package/typings.d.ts +23 -23
- package/typings.js +9 -9
- package/unit-of-work/ChangeSet.js +4 -4
- package/unit-of-work/ChangeSetComputer.js +8 -6
- package/unit-of-work/ChangeSetPersister.js +13 -8
- package/unit-of-work/CommitOrderCalculator.js +4 -2
- package/unit-of-work/UnitOfWork.d.ts +7 -1
- package/unit-of-work/UnitOfWork.js +51 -22
- package/utils/AbstractMigrator.js +3 -5
- package/utils/AbstractSchemaGenerator.js +2 -1
- package/utils/AsyncContext.js +1 -1
- package/utils/Configuration.js +8 -4
- package/utils/Cursor.js +4 -2
- package/utils/DataloaderUtils.js +15 -12
- package/utils/EntityComparator.js +51 -43
- package/utils/QueryHelper.js +38 -26
- package/utils/RawQueryFragment.js +3 -2
- package/utils/TransactionManager.js +2 -1
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +36 -30
- package/utils/env-vars.js +6 -5
- package/utils/fs-utils.js +2 -5
- package/utils/upsert-utils.js +6 -3
|
@@ -49,9 +49,7 @@ export class AbstractMigrator {
|
|
|
49
49
|
await this.init();
|
|
50
50
|
const all = await this.discoverMigrations();
|
|
51
51
|
const executed = new Set(await this.storage.executed());
|
|
52
|
-
return all
|
|
53
|
-
.filter(m => !executed.has(m.name))
|
|
54
|
-
.map(m => ({ name: m.name, path: m.path }));
|
|
52
|
+
return all.filter(m => !executed.has(m.name)).map(m => ({ name: m.name, path: m.path }));
|
|
55
53
|
}
|
|
56
54
|
/**
|
|
57
55
|
* @inheritDoc
|
|
@@ -74,7 +72,7 @@ export class AbstractMigrator {
|
|
|
74
72
|
const { fs } = await import('@mikro-orm/core/fs-utils');
|
|
75
73
|
this.detectSourceFolder(fs);
|
|
76
74
|
/* v8 ignore next */
|
|
77
|
-
const key =
|
|
75
|
+
const key = this.config.get('preferTs', Utils.detectTypeScriptSupport()) && this.options.pathTs ? 'pathTs' : 'path';
|
|
78
76
|
this.absolutePath = fs.absolutePath(this.options[key], this.config.get('baseDir'));
|
|
79
77
|
fs.ensureDir(this.absolutePath);
|
|
80
78
|
}
|
|
@@ -132,7 +130,7 @@ export class AbstractMigrator {
|
|
|
132
130
|
const buildDir = fs.pathExists(baseDir + '/build');
|
|
133
131
|
// if neither `dist` nor `build` exist, we use the `src` folder as it might be a JS project without building, but with `src` folder
|
|
134
132
|
/* v8 ignore next */
|
|
135
|
-
const path = distDir ? './dist' :
|
|
133
|
+
const path = distDir ? './dist' : buildDir ? './build' : './src';
|
|
136
134
|
// only if the user did not provide any values and if the default path does not exist
|
|
137
135
|
if (!this.options.path && !this.options.pathTs && !exists) {
|
|
138
136
|
this.options.path = `${path}/migrations`;
|
|
@@ -112,7 +112,8 @@ export class AbstractSchemaGenerator {
|
|
|
112
112
|
}
|
|
113
113
|
meta = metadata.pop();
|
|
114
114
|
}
|
|
115
|
-
return calc
|
|
115
|
+
return calc
|
|
116
|
+
.sort()
|
|
116
117
|
.map(cls => this.metadata.getById(cls))
|
|
117
118
|
.filter(meta => {
|
|
118
119
|
const targetSchema = meta.schema ?? this.config.get('schema', this.platform.getDefaultSchemaName());
|
package/utils/AsyncContext.js
CHANGED
|
@@ -13,7 +13,7 @@ function createFallbackAsyncContext() {
|
|
|
13
13
|
console.warn('AsyncLocalStorage not available');
|
|
14
14
|
return {
|
|
15
15
|
getStore: () => store,
|
|
16
|
-
enterWith: value => store = value,
|
|
16
|
+
enterWith: value => (store = value),
|
|
17
17
|
run: (value, cb) => {
|
|
18
18
|
const prev = store;
|
|
19
19
|
store = value;
|
package/utils/Configuration.js
CHANGED
|
@@ -262,7 +262,10 @@ export class Configuration {
|
|
|
262
262
|
* Gets instance of CacheAdapter for result cache. (cached)
|
|
263
263
|
*/
|
|
264
264
|
getResultCacheAdapter() {
|
|
265
|
-
return this.getCachedService(this.options.resultCache.adapter, {
|
|
265
|
+
return this.getCachedService(this.options.resultCache.adapter, {
|
|
266
|
+
expiration: this.options.resultCache.expiration,
|
|
267
|
+
...this.options.resultCache.options,
|
|
268
|
+
});
|
|
266
269
|
}
|
|
267
270
|
/**
|
|
268
271
|
* Gets EntityRepository class to be instantiated.
|
|
@@ -338,10 +341,10 @@ export class Configuration {
|
|
|
338
341
|
validateOptions() {
|
|
339
342
|
/* v8 ignore next */
|
|
340
343
|
if ('type' in this.options) {
|
|
341
|
-
throw new Error(
|
|
344
|
+
throw new Error("The `type` option has been removed in v6, please fill in the `driver` option instead or use `defineConfig` helper (to define your ORM config) or `MikroORM` class (to call the `init` method) exported from the driver package (e.g. `import { defineConfig } from '@mikro-orm/mysql'; export default defineConfig({ ... })`).");
|
|
342
345
|
}
|
|
343
346
|
if (!this.options.driver) {
|
|
344
|
-
throw new Error(
|
|
347
|
+
throw new Error("No driver specified, please fill in the `driver` option or use `defineConfig` helper (to define your ORM config) or `MikroORM` class (to call the `init` method) exported from the driver package (e.g. `import { defineConfig } from '@mikro-orm/mysql'; export defineConfig({ ... })`).");
|
|
345
348
|
}
|
|
346
349
|
if (!this.options.dbName && !this.options.clientUrl) {
|
|
347
350
|
throw new Error('No database specified, please fill in `dbName` or `clientUrl` option');
|
|
@@ -349,7 +352,8 @@ export class Configuration {
|
|
|
349
352
|
if (this.options.entities.length === 0 && this.options.discovery.warnWhenNoEntities) {
|
|
350
353
|
throw new Error('No entities found, please use `entities` option');
|
|
351
354
|
}
|
|
352
|
-
if (typeof this.options.driverOptions === 'function' &&
|
|
355
|
+
if (typeof this.options.driverOptions === 'function' &&
|
|
356
|
+
this.options.driverOptions.constructor.name === 'AsyncFunction') {
|
|
353
357
|
throw new Error('`driverOptions` callback cannot be async');
|
|
354
358
|
}
|
|
355
359
|
}
|
package/utils/Cursor.js
CHANGED
|
@@ -118,7 +118,7 @@ export class Cursor {
|
|
|
118
118
|
value = value.unwrap();
|
|
119
119
|
}
|
|
120
120
|
if (object) {
|
|
121
|
-
return
|
|
121
|
+
return { [prop]: value };
|
|
122
122
|
}
|
|
123
123
|
return value;
|
|
124
124
|
};
|
|
@@ -167,7 +167,9 @@ export class Cursor {
|
|
|
167
167
|
}
|
|
168
168
|
const prop = meta.properties[key];
|
|
169
169
|
/* v8 ignore next */
|
|
170
|
-
if (!prop ||
|
|
170
|
+
if (!prop ||
|
|
171
|
+
!([ReferenceKind.SCALAR, ReferenceKind.EMBEDDED, ReferenceKind.MANY_TO_ONE].includes(prop.kind) ||
|
|
172
|
+
(prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner))) {
|
|
171
173
|
continue;
|
|
172
174
|
}
|
|
173
175
|
ret.push([prop.name, order[prop.name]]);
|
package/utils/DataloaderUtils.js
CHANGED
|
@@ -101,26 +101,27 @@ export class DataloaderUtils {
|
|
|
101
101
|
const uniqueName = key.substring(0, key.indexOf('|'));
|
|
102
102
|
const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
|
|
103
103
|
const meta = em.getMetadata().getByUniqueName(uniqueName);
|
|
104
|
-
const res = await em.find(meta.class, opts?.where != null && Object.keys(opts.where).length > 0
|
|
105
|
-
{
|
|
104
|
+
const res = await em.find(meta.class, opts?.where != null && Object.keys(opts.where).length > 0
|
|
105
|
+
? {
|
|
106
106
|
$and: [
|
|
107
107
|
{
|
|
108
108
|
$or: Array.from(filterMap.entries()).map(([prop, pks]) => {
|
|
109
|
-
return
|
|
109
|
+
return { [prop]: Array.from(pks) };
|
|
110
110
|
}),
|
|
111
111
|
},
|
|
112
112
|
opts.where,
|
|
113
113
|
],
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
}
|
|
115
|
+
: {
|
|
116
|
+
// The entries of the filter Map will be used as the values of the $or operator
|
|
117
|
+
$or: Array.from(filterMap.entries()).map(([prop, pks]) => {
|
|
118
|
+
return { [prop]: Array.from(pks) };
|
|
119
|
+
}),
|
|
120
|
+
}, {
|
|
120
121
|
...opts,
|
|
121
122
|
// We need to populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s)
|
|
122
123
|
populate: [
|
|
123
|
-
...(opts.populate === false ? [] : opts.populate ?? []),
|
|
124
|
+
...(opts.populate === false ? [] : (opts.populate ?? [])),
|
|
124
125
|
...Array.from(filterMap.keys()).filter(
|
|
125
126
|
// We need to do so only if the inverse side is a collection, because we can already retrieve the PK from a reference without having to load it
|
|
126
127
|
prop => meta.properties[prop]?.ref !== true),
|
|
@@ -207,7 +208,9 @@ export class DataloaderUtils {
|
|
|
207
208
|
options.refresh ??= c[1]?.refresh;
|
|
208
209
|
}
|
|
209
210
|
options.where = wrap({ $or });
|
|
210
|
-
const r = await em
|
|
211
|
+
const r = await em
|
|
212
|
+
.getEntityLoader()
|
|
213
|
+
.findChildrenFromPivotTable(owners, prop, options, orderBy, populate, group[0][1]?.ref);
|
|
211
214
|
ret.push(...r);
|
|
212
215
|
}
|
|
213
216
|
return ret;
|
|
@@ -224,7 +227,7 @@ export class DataloaderUtils {
|
|
|
224
227
|
}
|
|
225
228
|
catch {
|
|
226
229
|
/* v8 ignore next */
|
|
227
|
-
throw new Error(
|
|
230
|
+
throw new Error("DataLoader is not found, make sure `dataloader` package is installed in your project's dependencies.");
|
|
228
231
|
}
|
|
229
232
|
}
|
|
230
233
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { clone } from './clone.js';
|
|
2
2
|
import { ReferenceKind } from '../enums.js';
|
|
3
|
-
import { compareArrays, compareBooleans, compareBuffers, compareObjects, equals, parseJsonSafe, Utils } from './Utils.js';
|
|
3
|
+
import { compareArrays, compareBooleans, compareBuffers, compareObjects, equals, parseJsonSafe, Utils, } from './Utils.js';
|
|
4
4
|
import { JsonType } from '../types/JsonType.js';
|
|
5
5
|
import { Raw } from './RawQueryFragment.js';
|
|
6
6
|
import { EntityIdentifier } from '../entity/EntityIdentifier.js';
|
|
@@ -91,8 +91,7 @@ export class EntityComparator {
|
|
|
91
91
|
}
|
|
92
92
|
lines.push(` return entity${this.wrap(pk)};`);
|
|
93
93
|
}
|
|
94
|
-
const code = `// compiled pk getter for entity ${meta.className}\n`
|
|
95
|
-
+ `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
94
|
+
const code = `// compiled pk getter for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
96
95
|
const fnKey = `pkGetter-${meta.uniqueName}`;
|
|
97
96
|
const pkSerializer = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
|
|
98
97
|
this.pkGetters.set(meta, pkSerializer);
|
|
@@ -142,8 +141,8 @@ export class EntityComparator {
|
|
|
142
141
|
lines.push(` return entity${this.wrap(pk)};`);
|
|
143
142
|
}
|
|
144
143
|
}
|
|
145
|
-
const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n`
|
|
146
|
-
|
|
144
|
+
const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n` +
|
|
145
|
+
`return function(entity) {\n${lines.join('\n')}\n}`;
|
|
147
146
|
const fnKey = `pkGetterConverted-${meta.uniqueName}`;
|
|
148
147
|
const pkSerializer = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
|
|
149
148
|
this.pkGettersConverted.set(meta, pkSerializer);
|
|
@@ -195,8 +194,7 @@ export class EntityComparator {
|
|
|
195
194
|
lines.push(` return '' + entity${this.wrap(pk)};`);
|
|
196
195
|
}
|
|
197
196
|
}
|
|
198
|
-
const code = `// compiled pk serializer for entity ${meta.className}\n`
|
|
199
|
-
+ `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
197
|
+
const code = `// compiled pk serializer for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
200
198
|
const fnKey = `pkSerializer-${meta.uniqueName}`;
|
|
201
199
|
const pkSerializer = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
|
|
202
200
|
this.pkSerializers.set(meta, pkSerializer);
|
|
@@ -359,7 +357,7 @@ export class EntityComparator {
|
|
|
359
357
|
context.set(`mapEmbeddedResult_${idx}`, (data) => {
|
|
360
358
|
const item = parseJsonSafe(data);
|
|
361
359
|
if (Array.isArray(item)) {
|
|
362
|
-
return item.map(row => row == null ? row : this.getResultMapper(prop.targetMeta)(row));
|
|
360
|
+
return item.map(row => (row == null ? row : this.getResultMapper(prop.targetMeta)(row)));
|
|
363
361
|
}
|
|
364
362
|
return item == null ? item : this.getResultMapper(prop.targetMeta)(item);
|
|
365
363
|
});
|
|
@@ -391,8 +389,8 @@ export class EntityComparator {
|
|
|
391
389
|
mapEntityProperties(meta);
|
|
392
390
|
}
|
|
393
391
|
lines.push(` for (let k in result) { if (Object.hasOwn(result, k) && !mapped[k] && ret[k] === undefined) ret[k] = result[k]; }`);
|
|
394
|
-
const code = `// compiled mapper for entity ${meta.className}\n`
|
|
395
|
-
|
|
392
|
+
const code = `// compiled mapper for entity ${meta.className}\n` +
|
|
393
|
+
`return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
396
394
|
const fnKey = `resultMapper-${meta.uniqueName}`;
|
|
397
395
|
const resultMapper = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
|
|
398
396
|
this.mappers.set(meta, resultMapper);
|
|
@@ -411,7 +409,7 @@ export class EntityComparator {
|
|
|
411
409
|
return '';
|
|
412
410
|
}
|
|
413
411
|
const mapped = `typeof entity${tail ? '.' + tail : ''}${this.wrap(k)} !== 'undefined'`;
|
|
414
|
-
tail += tail ?
|
|
412
|
+
tail += tail ? '.' + k : k;
|
|
415
413
|
return mapped;
|
|
416
414
|
})
|
|
417
415
|
.filter(k => k)
|
|
@@ -453,12 +451,16 @@ export class EntityComparator {
|
|
|
453
451
|
}
|
|
454
452
|
else {
|
|
455
453
|
ret += `${padding}if (${nullCond}) {\n`;
|
|
456
|
-
ret +=
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
454
|
+
ret +=
|
|
455
|
+
meta.props
|
|
456
|
+
.filter(p => p.embedded?.[0] === prop.name &&
|
|
457
|
+
// object for JSON embeddable
|
|
458
|
+
(p.object || p.persist !== false))
|
|
459
|
+
.map(childProp => {
|
|
460
|
+
const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
|
461
|
+
return `${padding} ret${childDataKey} = null;`;
|
|
462
|
+
})
|
|
463
|
+
.join('\n') + `\n`;
|
|
462
464
|
ret += `${padding}}\n`;
|
|
463
465
|
}
|
|
464
466
|
const cond = `entity${path.map(k => this.wrap(k)).join('')} != null`;
|
|
@@ -475,28 +477,34 @@ export class EntityComparator {
|
|
|
475
477
|
}
|
|
476
478
|
return true;
|
|
477
479
|
}
|
|
478
|
-
ret +=
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
.split('\n').map(l => padding + l).join('\n');
|
|
490
|
-
}
|
|
491
|
-
if (shouldProcessCustomType(childProp)) {
|
|
492
|
-
const convertorKey = this.registerCustomType(childProp, context);
|
|
493
|
-
if (['number', 'string', 'boolean', 'bigint'].includes(childProp.customType.compareAsType().toLowerCase())) {
|
|
494
|
-
return `${padding} if (${childCond}) ret${childDataKey} = convertToDatabaseValue_${convertorKey}(entity${childEntityKey});`;
|
|
480
|
+
ret +=
|
|
481
|
+
meta.props
|
|
482
|
+
.filter(p => p.embedded?.[0] === prop.name &&
|
|
483
|
+
// object for JSON embeddable
|
|
484
|
+
(p.object || p.persist !== false))
|
|
485
|
+
.map(childProp => {
|
|
486
|
+
const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
|
487
|
+
const childEntityKey = [...path, childProp.embedded[1]].map(k => this.wrap(k)).join('');
|
|
488
|
+
const childCond = `typeof entity${childEntityKey} !== 'undefined'`;
|
|
489
|
+
if (childProp.kind === ReferenceKind.EMBEDDED) {
|
|
490
|
+
return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level + 1, prop.object);
|
|
495
491
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
492
|
+
if (childProp.kind !== ReferenceKind.SCALAR) {
|
|
493
|
+
return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level, prop.object)
|
|
494
|
+
.split('\n')
|
|
495
|
+
.map(l => padding + l)
|
|
496
|
+
.join('\n');
|
|
497
|
+
}
|
|
498
|
+
if (shouldProcessCustomType(childProp)) {
|
|
499
|
+
const convertorKey = this.registerCustomType(childProp, context);
|
|
500
|
+
if (['number', 'string', 'boolean', 'bigint'].includes(childProp.customType.compareAsType().toLowerCase())) {
|
|
501
|
+
return `${padding} if (${childCond}) ret${childDataKey} = convertToDatabaseValue_${convertorKey}(entity${childEntityKey});`;
|
|
502
|
+
}
|
|
503
|
+
return `${padding} if (${childCond}) ret${childDataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${childEntityKey}));`;
|
|
504
|
+
}
|
|
505
|
+
return `${padding} if (${childCond}) ret${childDataKey} = clone(entity${childEntityKey});`;
|
|
506
|
+
})
|
|
507
|
+
.join('\n') + `\n`;
|
|
500
508
|
if (this.shouldSerialize(prop, dataKey)) {
|
|
501
509
|
return `${ret + padding} ret${dataKey} = cloneEmbeddable(ret${dataKey});\n${padding}}`;
|
|
502
510
|
}
|
|
@@ -591,7 +599,7 @@ export class EntityComparator {
|
|
|
591
599
|
if (['number', 'string', 'boolean', 'bigint'].includes(prop.customType.compareAsType().toLowerCase())) {
|
|
592
600
|
return ret + ` ret${dataKey} = convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap});\n }\n`;
|
|
593
601
|
}
|
|
594
|
-
return ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n
|
|
602
|
+
return (ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n`);
|
|
595
603
|
}
|
|
596
604
|
if (prop.runtimeType === 'Date') {
|
|
597
605
|
context.set('processDateProperty', this.platform.processDateProperty.bind(this.platform));
|
|
@@ -626,22 +634,22 @@ export class EntityComparator {
|
|
|
626
634
|
}
|
|
627
635
|
}
|
|
628
636
|
lines.push(`}`);
|
|
629
|
-
const code = `// compiled comparator for entity ${meta.className}\n`
|
|
630
|
-
|
|
637
|
+
const code = `// compiled comparator for entity ${meta.className}\n` +
|
|
638
|
+
`return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
|
|
631
639
|
const fnKey = `comparator-${meta.uniqueName}`;
|
|
632
640
|
const comparator = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
|
|
633
641
|
this.comparators.set(meta, comparator);
|
|
634
642
|
return comparator;
|
|
635
643
|
}
|
|
636
644
|
getGenericComparator(prop, cond) {
|
|
637
|
-
return ` if (current${prop} === null && last${prop} === undefined) {\n` +
|
|
645
|
+
return (` if (current${prop} === null && last${prop} === undefined) {\n` +
|
|
638
646
|
` diff${prop} = current${prop};\n` +
|
|
639
647
|
` } else if (current${prop} == null && last${prop} == null) {\n\n` +
|
|
640
648
|
` } else if ((current${prop} != null && last${prop} == null) || (current${prop} == null && last${prop} != null)) {\n` +
|
|
641
649
|
` diff${prop} = current${prop};\n` +
|
|
642
650
|
` } else if (${cond}) {\n` +
|
|
643
651
|
` diff${prop} = current${prop};\n` +
|
|
644
|
-
` }\n
|
|
652
|
+
` }\n`);
|
|
645
653
|
}
|
|
646
654
|
getPropertyComparator(prop, context) {
|
|
647
655
|
let type = prop.type.toLowerCase();
|
package/utils/QueryHelper.js
CHANGED
|
@@ -50,17 +50,21 @@ export class QueryHelper {
|
|
|
50
50
|
}
|
|
51
51
|
const keys = Object.keys(where);
|
|
52
52
|
const groupOperator = keys.find(k => {
|
|
53
|
-
return k in GroupOperator &&
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
return (k in GroupOperator &&
|
|
54
|
+
Array.isArray(where[k]) &&
|
|
55
|
+
where[k].every(cond => {
|
|
56
|
+
return (Utils.isPlainObject(cond) &&
|
|
57
|
+
Object.keys(cond).every(k2 => {
|
|
58
|
+
if (Utils.isOperator(k2, false)) {
|
|
59
|
+
if (k2 === '$not') {
|
|
60
|
+
return Object.keys(cond[k2]).every(k3 => meta.primaryKeys.includes(k3));
|
|
61
|
+
}
|
|
62
|
+
/* v8 ignore next */
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return meta.primaryKeys.includes(k2);
|
|
66
|
+
}));
|
|
67
|
+
}));
|
|
64
68
|
});
|
|
65
69
|
if (groupOperator) {
|
|
66
70
|
return groupOperator;
|
|
@@ -96,15 +100,21 @@ export class QueryHelper {
|
|
|
96
100
|
return false;
|
|
97
101
|
}
|
|
98
102
|
if (meta.primaryKeys.every(pk => pk in where) && Utils.getObjectKeysSize(where) === meta.primaryKeys.length) {
|
|
99
|
-
return !!key &&
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
return (!!key &&
|
|
104
|
+
!GroupOperator[key] &&
|
|
105
|
+
key !== '$not' &&
|
|
106
|
+
Object.keys(where).every(k => !Utils.isPlainObject(where[k]) ||
|
|
107
|
+
Object.keys(where[k]).every(v => {
|
|
108
|
+
if (Utils.isOperator(v, false)) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (meta.properties[k].primary &&
|
|
112
|
+
[ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(meta.properties[k].kind)) {
|
|
113
|
+
return this.inlinePrimaryKeyObjects(where[k], meta.properties[k].targetMeta, metadata, v);
|
|
114
|
+
}
|
|
115
|
+
/* v8 ignore next */
|
|
116
|
+
return true;
|
|
117
|
+
})));
|
|
108
118
|
}
|
|
109
119
|
Object.keys(where).forEach(k => {
|
|
110
120
|
const meta2 = metadata.find(meta.properties[k]?.targetMeta?.class) || meta;
|
|
@@ -139,7 +149,9 @@ export class QueryHelper {
|
|
|
139
149
|
let cond = { [rootPrimaryKey]: { $in: where } };
|
|
140
150
|
// @ts-ignore
|
|
141
151
|
// detect tuple comparison, use `$or` in case the number of constituents don't match
|
|
142
|
-
if (meta &&
|
|
152
|
+
if (meta &&
|
|
153
|
+
!where.every(c => Utils.isPrimaryKey(c) ||
|
|
154
|
+
(Array.isArray(c) && c.length === meta.primaryKeys.length && c.every(i => Utils.isPrimaryKey(i))))) {
|
|
143
155
|
cond = { $or: where };
|
|
144
156
|
}
|
|
145
157
|
return QueryHelper.processWhere({ ...options, where: cond, root: false });
|
|
@@ -170,10 +182,12 @@ export class QueryHelper {
|
|
|
170
182
|
if (prop?.customType && convertCustomTypes && !isRaw(value)) {
|
|
171
183
|
value = QueryHelper.processCustomType(prop, value, platform, undefined, true);
|
|
172
184
|
}
|
|
185
|
+
// oxfmt-ignore
|
|
173
186
|
const isJsonProperty = prop?.customType instanceof JsonType && Utils.isPlainObject(value) && !isRaw(value) && Object.keys(value)[0] !== '$eq';
|
|
174
187
|
if (isJsonProperty && prop?.kind !== ReferenceKind.EMBEDDED) {
|
|
175
188
|
return this.processJsonCondition(o, value, [prop.fieldNames[0]], platform, aliased);
|
|
176
189
|
}
|
|
190
|
+
// oxfmt-ignore
|
|
177
191
|
if (Array.isArray(value) && !Utils.isOperator(key) && !QueryHelper.isSupportedOperator(key) && !(customExpression && Raw.getKnownFragment(key).params.length > 0) && options.type !== 'orderBy') {
|
|
178
192
|
// comparing single composite key - use $eq instead of $in
|
|
179
193
|
const op = composite && !value.every(v => Array.isArray(v)) ? '$eq' : '$in';
|
|
@@ -200,10 +214,10 @@ export class QueryHelper {
|
|
|
200
214
|
}
|
|
201
215
|
const opts = {};
|
|
202
216
|
if (Array.isArray(options)) {
|
|
203
|
-
options.forEach(filter => opts[filter] = true);
|
|
217
|
+
options.forEach(filter => (opts[filter] = true));
|
|
204
218
|
}
|
|
205
219
|
else if (Utils.isPlainObject(options)) {
|
|
206
|
-
Object.keys(options).forEach(filter => opts[filter] = options[filter]);
|
|
220
|
+
Object.keys(options).forEach(filter => (opts[filter] = options[filter]));
|
|
207
221
|
}
|
|
208
222
|
return Object.keys(filters)
|
|
209
223
|
.filter(f => QueryHelper.isFilterActive(meta, f, filters[f], opts))
|
|
@@ -252,9 +266,7 @@ export class QueryHelper {
|
|
|
252
266
|
}, {});
|
|
253
267
|
}
|
|
254
268
|
if (key && JSON_KEY_OPERATORS.includes(key)) {
|
|
255
|
-
return Array.isArray(cond)
|
|
256
|
-
? platform.marshallArray(cond)
|
|
257
|
-
: cond;
|
|
269
|
+
return Array.isArray(cond) ? platform.marshallArray(cond) : cond;
|
|
258
270
|
}
|
|
259
271
|
if (Array.isArray(cond) && !(key && ARRAY_OPERATORS.includes(key))) {
|
|
260
272
|
return cond.map(v => QueryHelper.processCustomType(prop, v, platform, key, fromQuery));
|
|
@@ -39,7 +39,8 @@ export class RawQueryFragment {
|
|
|
39
39
|
return typeof key === 'symbol' && this.#rawQueryReferences.has(key);
|
|
40
40
|
}
|
|
41
41
|
static hasObjectFragments(object) {
|
|
42
|
-
return Utils.isPlainObject(object) &&
|
|
42
|
+
return (Utils.isPlainObject(object) &&
|
|
43
|
+
Object.getOwnPropertySymbols(object).some(symbol => this.isKnownFragmentSymbol(symbol)));
|
|
43
44
|
}
|
|
44
45
|
static isKnownFragment(key) {
|
|
45
46
|
if (key instanceof RawQueryFragment) {
|
|
@@ -181,7 +182,7 @@ export function createSqlFunction(func, key) {
|
|
|
181
182
|
if (typeof key === 'string') {
|
|
182
183
|
return raw(`${func}(${key})`);
|
|
183
184
|
}
|
|
184
|
-
return raw(a => `${func}(${
|
|
185
|
+
return raw(a => `${func}(${key(a)})`);
|
|
185
186
|
}
|
|
186
187
|
sql.ref = (...keys) => raw('??', [keys.join('.')]);
|
|
187
188
|
sql.now = (length) => raw('current_timestamp' + (length == null ? '' : `(${length})`));
|
|
@@ -183,7 +183,8 @@ export class TransactionManager {
|
|
|
183
183
|
registerDeletionHandler(fork, parent) {
|
|
184
184
|
fork.getEventManager().registerSubscriber({
|
|
185
185
|
afterFlush: (args) => {
|
|
186
|
-
const deletionChangeSets = args.uow
|
|
186
|
+
const deletionChangeSets = args.uow
|
|
187
|
+
.getChangeSets()
|
|
187
188
|
.filter(cs => cs.type === ChangeSetType.DELETE || cs.type === ChangeSetType.DELETE_EARLY);
|
|
188
189
|
for (const cs of deletionChangeSets) {
|
|
189
190
|
parent.getUnitOfWork(false).unsetIdentity(cs.entity);
|
package/utils/Utils.d.ts
CHANGED
|
@@ -147,7 +147,7 @@ export declare class Utils {
|
|
|
147
147
|
static callCompiledFunction<T extends unknown[], R>(fn: (...args: T) => R, ...args: T): R;
|
|
148
148
|
static unwrapProperty<T>(entity: T, meta: EntityMetadata<T>, prop: EntityProperty<T>, payload?: boolean): [unknown, number[]][];
|
|
149
149
|
static setPayloadProperty<T>(entity: EntityDictionary<T>, meta: EntityMetadata<T>, prop: EntityProperty<T>, value: unknown, idx: number[]): void;
|
|
150
|
-
static tryImport<T extends Dictionary = any>({ module, warning }: {
|
|
150
|
+
static tryImport<T extends Dictionary = any>({ module, warning, }: {
|
|
151
151
|
module: string;
|
|
152
152
|
warning?: string;
|
|
153
153
|
}): Promise<T | undefined>;
|