@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/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;
|
|
@@ -123,6 +133,9 @@ export class QueryHelper {
|
|
|
123
133
|
QueryHelper.liftGroupOperators(where, meta, metadata);
|
|
124
134
|
QueryHelper.inlinePrimaryKeyObjects(where, meta, metadata);
|
|
125
135
|
}
|
|
136
|
+
if (meta && root) {
|
|
137
|
+
QueryHelper.convertCompositeEntityRefs(where, meta);
|
|
138
|
+
}
|
|
126
139
|
if (platform.getConfig().get('ignoreUndefinedInQuery') && where && typeof where === 'object') {
|
|
127
140
|
Utils.dropUndefinedProperties(where);
|
|
128
141
|
}
|
|
@@ -139,7 +152,9 @@ export class QueryHelper {
|
|
|
139
152
|
let cond = { [rootPrimaryKey]: { $in: where } };
|
|
140
153
|
// @ts-ignore
|
|
141
154
|
// detect tuple comparison, use `$or` in case the number of constituents don't match
|
|
142
|
-
if (meta &&
|
|
155
|
+
if (meta &&
|
|
156
|
+
!where.every(c => Utils.isPrimaryKey(c) ||
|
|
157
|
+
(Array.isArray(c) && c.length === meta.primaryKeys.length && c.every(i => Utils.isPrimaryKey(i))))) {
|
|
143
158
|
cond = { $or: where };
|
|
144
159
|
}
|
|
145
160
|
return QueryHelper.processWhere({ ...options, where: cond, root: false });
|
|
@@ -170,10 +185,12 @@ export class QueryHelper {
|
|
|
170
185
|
if (prop?.customType && convertCustomTypes && !isRaw(value)) {
|
|
171
186
|
value = QueryHelper.processCustomType(prop, value, platform, undefined, true);
|
|
172
187
|
}
|
|
173
|
-
|
|
188
|
+
// oxfmt-ignore
|
|
189
|
+
const isJsonProperty = prop?.customType instanceof JsonType && !isRaw(value) && (Utils.isPlainObject(value) ? !['$eq', '$elemMatch'].includes(Object.keys(value)[0]) : !Array.isArray(value));
|
|
174
190
|
if (isJsonProperty && prop?.kind !== ReferenceKind.EMBEDDED) {
|
|
175
191
|
return this.processJsonCondition(o, value, [prop.fieldNames[0]], platform, aliased);
|
|
176
192
|
}
|
|
193
|
+
// oxfmt-ignore
|
|
177
194
|
if (Array.isArray(value) && !Utils.isOperator(key) && !QueryHelper.isSupportedOperator(key) && !(customExpression && Raw.getKnownFragment(key).params.length > 0) && options.type !== 'orderBy') {
|
|
178
195
|
// comparing single composite key - use $eq instead of $in
|
|
179
196
|
const op = composite && !value.every(v => Array.isArray(v)) ? '$eq' : '$in';
|
|
@@ -200,10 +217,10 @@ export class QueryHelper {
|
|
|
200
217
|
}
|
|
201
218
|
const opts = {};
|
|
202
219
|
if (Array.isArray(options)) {
|
|
203
|
-
options.forEach(filter => opts[filter] = true);
|
|
220
|
+
options.forEach(filter => (opts[filter] = true));
|
|
204
221
|
}
|
|
205
222
|
else if (Utils.isPlainObject(options)) {
|
|
206
|
-
Object.keys(options).forEach(filter => opts[filter] = options[filter]);
|
|
223
|
+
Object.keys(options).forEach(filter => (opts[filter] = options[filter]));
|
|
207
224
|
}
|
|
208
225
|
return Object.keys(filters)
|
|
209
226
|
.filter(f => QueryHelper.isFilterActive(meta, f, filters[f], opts))
|
|
@@ -252,9 +269,7 @@ export class QueryHelper {
|
|
|
252
269
|
}, {});
|
|
253
270
|
}
|
|
254
271
|
if (key && JSON_KEY_OPERATORS.includes(key)) {
|
|
255
|
-
return Array.isArray(cond)
|
|
256
|
-
? platform.marshallArray(cond)
|
|
257
|
-
: cond;
|
|
272
|
+
return Array.isArray(cond) ? platform.marshallArray(cond) : cond;
|
|
258
273
|
}
|
|
259
274
|
if (Array.isArray(cond) && !(key && ARRAY_OPERATORS.includes(key))) {
|
|
260
275
|
return cond.map(v => QueryHelper.processCustomType(prop, v, platform, key, fromQuery));
|
|
@@ -268,29 +283,7 @@ export class QueryHelper {
|
|
|
268
283
|
return !!QueryHelper.SUPPORTED_OPERATORS.find(op => key === op);
|
|
269
284
|
}
|
|
270
285
|
static processJsonCondition(o, value, path, platform, alias) {
|
|
271
|
-
|
|
272
|
-
Utils.keys(value).forEach(k => {
|
|
273
|
-
this.processJsonCondition(o, value[k], [...path, k], platform, alias);
|
|
274
|
-
});
|
|
275
|
-
return o;
|
|
276
|
-
}
|
|
277
|
-
if (path.length === 1) {
|
|
278
|
-
o[path[0]] = value;
|
|
279
|
-
return o;
|
|
280
|
-
}
|
|
281
|
-
const type = this.getValueType(value);
|
|
282
|
-
const k = platform.getSearchJsonPropertyKey(path, type, alias, value);
|
|
283
|
-
o[k] = value;
|
|
284
|
-
return o;
|
|
285
|
-
}
|
|
286
|
-
static getValueType(value) {
|
|
287
|
-
if (Array.isArray(value)) {
|
|
288
|
-
return typeof value[0];
|
|
289
|
-
}
|
|
290
|
-
if (Utils.isPlainObject(value) && Object.keys(value).every(k => Utils.isOperator(k))) {
|
|
291
|
-
return this.getValueType(Object.values(value)[0]);
|
|
292
|
-
}
|
|
293
|
-
return typeof value;
|
|
286
|
+
return platform.processJsonCondition(o, value, path, alias);
|
|
294
287
|
}
|
|
295
288
|
static findProperty(fieldName, options) {
|
|
296
289
|
const parts = fieldName.split('.');
|
|
@@ -300,6 +293,71 @@ export class QueryHelper {
|
|
|
300
293
|
const meta = entityName ? options.metadata.find(entityName) : undefined;
|
|
301
294
|
return meta?.properties[propName];
|
|
302
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Converts entity references for composite FK properties into flat arrays
|
|
298
|
+
* of correctly-ordered join column values, before processParams flattens them
|
|
299
|
+
* incorrectly due to shared FK columns.
|
|
300
|
+
*/
|
|
301
|
+
static convertCompositeEntityRefs(where, meta) {
|
|
302
|
+
if (!Utils.isPlainObject(where)) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
for (const k of Object.keys(where)) {
|
|
306
|
+
if (k in GroupOperator) {
|
|
307
|
+
if (Array.isArray(where[k])) {
|
|
308
|
+
where[k].forEach((sub) => this.convertCompositeEntityRefs(sub, meta));
|
|
309
|
+
}
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (k === '$not') {
|
|
313
|
+
this.convertCompositeEntityRefs(where[k], meta);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const prop = meta.properties[k];
|
|
317
|
+
if (!prop?.joinColumns || prop.joinColumns.length <= 1) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const w = where[k];
|
|
321
|
+
if (Utils.isEntity(w)) {
|
|
322
|
+
where[k] = this.extractJoinColumnValues(w, prop);
|
|
323
|
+
}
|
|
324
|
+
else if (Utils.isPlainObject(w)) {
|
|
325
|
+
for (const op of Object.keys(w)) {
|
|
326
|
+
if (Utils.isOperator(op, false) && Array.isArray(w[op])) {
|
|
327
|
+
w[op] = w[op].map((item) => Utils.isEntity(item) ? this.extractJoinColumnValues(item, prop) : item);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Extracts values for a FK's join columns from an entity by traversing the FK chain.
|
|
335
|
+
* Handles shared FK columns (e.g., tenant_id referenced by multiple FKs) correctly.
|
|
336
|
+
*/
|
|
337
|
+
static extractJoinColumnValues(entity, prop) {
|
|
338
|
+
return prop.referencedColumnNames.map(refCol => {
|
|
339
|
+
return this.extractColumnValue(entity, prop.targetMeta, refCol);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Extracts the value for a specific column from an entity by finding which PK property
|
|
344
|
+
* owns that column and recursively traversing FK references.
|
|
345
|
+
*/
|
|
346
|
+
static extractColumnValue(entity, meta, columnName) {
|
|
347
|
+
for (const pk of meta.primaryKeys) {
|
|
348
|
+
const pkProp = meta.properties[pk];
|
|
349
|
+
const colIdx = pkProp.fieldNames.indexOf(columnName);
|
|
350
|
+
if (colIdx !== -1) {
|
|
351
|
+
const value = entity[pk];
|
|
352
|
+
if (pkProp.targetMeta && Utils.isEntity(value, true)) {
|
|
353
|
+
const refCol = pkProp.referencedColumnNames[colIdx];
|
|
354
|
+
return this.extractColumnValue(value, pkProp.targetMeta, refCol);
|
|
355
|
+
}
|
|
356
|
+
return value;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
303
361
|
/**
|
|
304
362
|
* Merges multiple orderBy sources with key-level deduplication (first-seen key wins).
|
|
305
363
|
* RawQueryFragment symbol keys are never deduped (each is unique).
|
|
@@ -19,7 +19,7 @@ export declare class RawQueryFragment<Alias extends string = string> {
|
|
|
19
19
|
static isKnownFragmentSymbol(key: unknown): key is RawQueryFragmentSymbol;
|
|
20
20
|
static hasObjectFragments(object: unknown): boolean;
|
|
21
21
|
static isKnownFragment(key: unknown): key is RawQueryFragment | symbol;
|
|
22
|
-
static getKnownFragment(key: unknown): RawQueryFragment
|
|
22
|
+
static getKnownFragment(key: unknown): RawQueryFragment | undefined;
|
|
23
23
|
}
|
|
24
24
|
export { RawQueryFragment as Raw };
|
|
25
25
|
export declare function isRaw(value: unknown): value is RawQueryFragment;
|
|
@@ -102,8 +102,8 @@ export declare function raw<R = RawQueryFragment & symbol, T extends object = an
|
|
|
102
102
|
*/
|
|
103
103
|
export declare function sql<R = RawQueryFragment & symbol>(sql: readonly string[], ...values: unknown[]): R;
|
|
104
104
|
export declare namespace sql {
|
|
105
|
-
var ref: <T extends object = any>(...keys: string[]) => RawQueryFragment
|
|
106
|
-
var now: (length?: number) => RawQueryFragment
|
|
105
|
+
var ref: <T extends object = any>(...keys: string[]) => RawQueryFragment & symbol;
|
|
106
|
+
var now: (length?: number) => RawQueryFragment & symbol;
|
|
107
107
|
var lower: <R = RawQueryFragment<string> & symbol, T extends object = any>(key: string | ((alias: string) => string)) => R;
|
|
108
108
|
var upper: <R = RawQueryFragment<string> & symbol, T extends object = any>(key: string | ((alias: string) => string)) => R;
|
|
109
109
|
}
|
|
@@ -123,4 +123,4 @@ export declare function createSqlFunction<R = RawQueryFragment & symbol, T exten
|
|
|
123
123
|
*/
|
|
124
124
|
export declare function quote(expParts: readonly string[], ...values: (string | {
|
|
125
125
|
toString(): string;
|
|
126
|
-
})[]): RawQueryFragment
|
|
126
|
+
})[]): RawQueryFragment & symbol;
|
|
@@ -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})`));
|
|
@@ -160,8 +160,7 @@ export class TransactionManager {
|
|
|
160
160
|
for (const entity of fork.getUnitOfWork(false).getIdentityMap()) {
|
|
161
161
|
const wrapped = helper(entity);
|
|
162
162
|
const meta = wrapped.__meta;
|
|
163
|
-
|
|
164
|
-
const parentEntity = parentUoW.getById(meta.class, wrapped.getPrimaryKey(), parent['_schema'], true);
|
|
163
|
+
const parentEntity = parentUoW.getById(meta.class, wrapped.getPrimaryKey(), parent.schema, true);
|
|
165
164
|
if (parentEntity && parentEntity !== entity) {
|
|
166
165
|
const parentWrapped = helper(parentEntity);
|
|
167
166
|
parentWrapped.__data = wrapped.__data;
|
|
@@ -183,7 +182,8 @@ export class TransactionManager {
|
|
|
183
182
|
registerDeletionHandler(fork, parent) {
|
|
184
183
|
fork.getEventManager().registerSubscriber({
|
|
185
184
|
afterFlush: (args) => {
|
|
186
|
-
const deletionChangeSets = args.uow
|
|
185
|
+
const deletionChangeSets = args.uow
|
|
186
|
+
.getChangeSets()
|
|
187
187
|
.filter(cs => cs.type === ChangeSetType.DELETE || cs.type === ChangeSetType.DELETE_EARLY);
|
|
188
188
|
for (const cs of deletionChangeSets) {
|
|
189
189
|
parent.getUnitOfWork(false).unsetIdentity(cs.entity);
|
package/utils/Utils.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare class Utils {
|
|
|
22
22
|
/**
|
|
23
23
|
* Removes `undefined` properties (recursively) so they are not saved as nulls
|
|
24
24
|
*/
|
|
25
|
-
static dropUndefinedProperties(o: any, value?:
|
|
25
|
+
static dropUndefinedProperties(o: any, value?: null, visited?: Set<unknown>): void;
|
|
26
26
|
/**
|
|
27
27
|
* Returns the number of properties on `obj`. This is 20x faster than Object.keys(obj).length.
|
|
28
28
|
* @see https://github.com/deepkit/deepkit-framework/blob/master/packages/core/src/core.ts
|
|
@@ -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>;
|
package/utils/Utils.js
CHANGED
|
@@ -25,7 +25,7 @@ export function compareObjects(a, b) {
|
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
26
26
|
return a.sql === b.sql && compareArrays(a.params, b.params);
|
|
27
27
|
}
|
|
28
|
-
if (
|
|
28
|
+
if (a instanceof Date && b instanceof Date) {
|
|
29
29
|
const timeA = a.getTime();
|
|
30
30
|
const timeB = b.getTime();
|
|
31
31
|
if (isNaN(timeA) || isNaN(timeB)) {
|
|
@@ -123,7 +123,7 @@ export function parseJsonSafe(value) {
|
|
|
123
123
|
}
|
|
124
124
|
export class Utils {
|
|
125
125
|
static PK_SEPARATOR = '~~~';
|
|
126
|
-
static #ORM_VERSION = '7.0.0
|
|
126
|
+
static #ORM_VERSION = '7.0.0';
|
|
127
127
|
/**
|
|
128
128
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
129
129
|
*/
|
|
@@ -305,7 +305,7 @@ export class Utils {
|
|
|
305
305
|
.split(',')
|
|
306
306
|
.map(s => s.trim().replace(/=.*$/, '').trim())
|
|
307
307
|
.filter(Boolean)
|
|
308
|
-
.map(raw => raw.startsWith('{') && raw.endsWith('}') ? '' : raw);
|
|
308
|
+
.map(raw => (raw.startsWith('{') && raw.endsWith('}') ? '' : raw));
|
|
309
309
|
}
|
|
310
310
|
/**
|
|
311
311
|
* Checks whether the argument looks like primary key (string, number or ObjectId).
|
|
@@ -374,7 +374,8 @@ export class Utils {
|
|
|
374
374
|
return Utils.getPrimaryKeyHash(pks);
|
|
375
375
|
}
|
|
376
376
|
static getPrimaryKeyHash(pks) {
|
|
377
|
-
return pks
|
|
377
|
+
return pks
|
|
378
|
+
.map(pk => {
|
|
378
379
|
if (Buffer.isBuffer(pk)) {
|
|
379
380
|
return pk.toString('hex');
|
|
380
381
|
}
|
|
@@ -382,7 +383,8 @@ export class Utils {
|
|
|
382
383
|
return pk.toISOString();
|
|
383
384
|
}
|
|
384
385
|
return pk;
|
|
385
|
-
})
|
|
386
|
+
})
|
|
387
|
+
.join(this.PK_SEPARATOR);
|
|
386
388
|
}
|
|
387
389
|
static splitPrimaryKeys(key) {
|
|
388
390
|
return key.split(this.PK_SEPARATOR);
|
|
@@ -419,7 +421,7 @@ export class Utils {
|
|
|
419
421
|
}
|
|
420
422
|
if (allowScalar) {
|
|
421
423
|
if (Utils.isPlainObject(pk)) {
|
|
422
|
-
return pk[
|
|
424
|
+
return pk[meta.primaryKeys[0]];
|
|
423
425
|
}
|
|
424
426
|
return pk;
|
|
425
427
|
}
|
|
@@ -527,7 +529,7 @@ export class Utils {
|
|
|
527
529
|
static extractChildElements(items, prefix, allSymbol) {
|
|
528
530
|
return items
|
|
529
531
|
.filter(field => field === allSymbol || field.startsWith(`${prefix}.`))
|
|
530
|
-
.map(field => field === allSymbol ? allSymbol : field.substring(prefix.length + 1));
|
|
532
|
+
.map(field => (field === allSymbol ? allSymbol : field.substring(prefix.length + 1)));
|
|
531
533
|
}
|
|
532
534
|
/**
|
|
533
535
|
* Tries to detect TypeScript support.
|
|
@@ -536,17 +538,17 @@ export class Utils {
|
|
|
536
538
|
/* v8 ignore next */
|
|
537
539
|
const process = globalThis.process ?? {};
|
|
538
540
|
/* v8 ignore next */
|
|
539
|
-
return process.argv?.[0]?.endsWith('ts-node') // running via ts-node directly
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
return arg.includes('ts-node') // check for ts-node loader
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
});
|
|
541
|
+
return (process.argv?.[0]?.endsWith('ts-node') || // running via ts-node directly
|
|
542
|
+
!!process.env?.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS || // forced explicitly or enabled via `registerTypeScriptSupport()`
|
|
543
|
+
!!process.env?.TS_JEST || // check if ts-jest is used
|
|
544
|
+
!!process.env?.VITEST || // check if vitest is used
|
|
545
|
+
!!process.versions?.bun || // check if bun is used
|
|
546
|
+
process.argv?.slice(1).some(arg => /\.([mc]?ts|tsx)$/.exec(arg)) || // executing `.ts` file
|
|
547
|
+
process.execArgv?.some(arg => {
|
|
548
|
+
return (arg.includes('ts-node') || // check for ts-node loader
|
|
549
|
+
arg.includes('@swc-node/register') || // check for swc-node/register loader
|
|
550
|
+
arg.includes('node_modules/tsx/')); // check for tsx loader
|
|
551
|
+
}));
|
|
550
552
|
}
|
|
551
553
|
/**
|
|
552
554
|
* Gets the type of the argument.
|
|
@@ -557,7 +559,7 @@ export class Utils {
|
|
|
557
559
|
return simple;
|
|
558
560
|
}
|
|
559
561
|
const objectType = Object.prototype.toString.call(value);
|
|
560
|
-
const type =
|
|
562
|
+
const type = /^\[object (.+)]$/.exec(objectType)[1];
|
|
561
563
|
if (type === 'Uint8Array') {
|
|
562
564
|
return 'Buffer';
|
|
563
565
|
}
|
|
@@ -567,12 +569,13 @@ export class Utils {
|
|
|
567
569
|
* Checks whether the value is POJO (e.g. `{ foo: 'bar' }`, and not instance of `Foo`)
|
|
568
570
|
*/
|
|
569
571
|
static isPlainObject(value) {
|
|
570
|
-
return (value !== null
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
572
|
+
return ((value !== null &&
|
|
573
|
+
typeof value === 'object' &&
|
|
574
|
+
typeof value.constructor === 'function' &&
|
|
575
|
+
(Object.hasOwn(value.constructor.prototype, 'isPrototypeOf') ||
|
|
576
|
+
Object.getPrototypeOf(value.constructor.prototype) === null)) ||
|
|
577
|
+
(value && Object.getPrototypeOf(value) === null) ||
|
|
578
|
+
value instanceof PlainObject);
|
|
576
579
|
}
|
|
577
580
|
/**
|
|
578
581
|
* Executes the `cb` promise serially on every element of the `items` array and returns array of resolved values.
|
|
@@ -610,7 +613,7 @@ export class Utils {
|
|
|
610
613
|
}
|
|
611
614
|
static findDuplicates(items) {
|
|
612
615
|
return items.reduce((acc, v, i, arr) => {
|
|
613
|
-
return arr.indexOf(v) !== i && acc.
|
|
616
|
+
return arr.indexOf(v) !== i && !acc.includes(v) ? acc.concat(v) : acc;
|
|
614
617
|
}, []);
|
|
615
618
|
}
|
|
616
619
|
static removeDuplicates(items) {
|
|
@@ -633,17 +636,20 @@ export class Utils {
|
|
|
633
636
|
const keys = Object.keys(target);
|
|
634
637
|
const values = Object.values(target);
|
|
635
638
|
const numeric = !!values.find(v => typeof v === 'number');
|
|
636
|
-
const constEnum = values.length % 2 === 0 // const enum will have even number of items
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
639
|
+
const constEnum = values.length % 2 === 0 && // const enum will have even number of items
|
|
640
|
+
values.slice(0, values.length / 2).every(v => typeof v === 'string') && // first half are strings
|
|
641
|
+
values.slice(values.length / 2).every(v => typeof v === 'number') && // second half are numbers
|
|
642
|
+
this.equals(keys, values
|
|
643
|
+
.slice(values.length / 2)
|
|
644
|
+
.concat(values.slice(0, values.length / 2))
|
|
645
|
+
.map(v => '' + v)); // and when swapped, it will match the keys
|
|
640
646
|
if (numeric || constEnum) {
|
|
641
647
|
return values.filter(val => !keys.includes(val));
|
|
642
648
|
}
|
|
643
649
|
return values;
|
|
644
650
|
}
|
|
645
651
|
static flatten(arrays, deep) {
|
|
646
|
-
return arrays.flatMap(v => deep && Array.isArray(v) ? this.flatten(v, true) : v);
|
|
652
|
+
return arrays.flatMap(v => (deep && Array.isArray(v) ? this.flatten(v, true) : v));
|
|
647
653
|
}
|
|
648
654
|
static isOperator(key, includeGroupOperators = true) {
|
|
649
655
|
if (!includeGroupOperators) {
|
|
@@ -671,6 +677,7 @@ export class Utils {
|
|
|
671
677
|
return compiledFunctions[key](...context.values());
|
|
672
678
|
}
|
|
673
679
|
try {
|
|
680
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
674
681
|
return new Function(...context.keys(), `'use strict';\n` + code)(...context.values());
|
|
675
682
|
/* v8 ignore next */
|
|
676
683
|
}
|
|
@@ -784,7 +791,7 @@ export class Utils {
|
|
|
784
791
|
}
|
|
785
792
|
}
|
|
786
793
|
}
|
|
787
|
-
static async tryImport({ module, warning }) {
|
|
794
|
+
static async tryImport({ module, warning, }) {
|
|
788
795
|
try {
|
|
789
796
|
return await import(module);
|
|
790
797
|
}
|
package/utils/clone.js
CHANGED
|
@@ -20,6 +20,7 @@ function getPropertyDescriptor(obj, prop) {
|
|
|
20
20
|
}
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
|
+
const TypedArray = Object.getPrototypeOf(Uint8Array);
|
|
23
24
|
export function clone(parent, respectCustomCloneMethod = true) {
|
|
24
25
|
const allParents = [];
|
|
25
26
|
const allChildren = [];
|
|
@@ -74,6 +75,10 @@ export function clone(parent, respectCustomCloneMethod = true) {
|
|
|
74
75
|
parent.copy(child);
|
|
75
76
|
return child;
|
|
76
77
|
}
|
|
78
|
+
else if (parent instanceof TypedArray) {
|
|
79
|
+
child = parent.slice();
|
|
80
|
+
return child;
|
|
81
|
+
}
|
|
77
82
|
else if (parent instanceof Error) {
|
|
78
83
|
child = new parent.constructor(parent.message);
|
|
79
84
|
}
|
package/utils/env-vars.js
CHANGED
|
@@ -13,10 +13,11 @@ export function getEnv(key) {
|
|
|
13
13
|
export function loadEnvironmentVars() {
|
|
14
14
|
const ret = {};
|
|
15
15
|
const getEnvKey = (key, envPrefix = 'MIKRO_ORM_') => {
|
|
16
|
-
return envPrefix +
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
return (envPrefix +
|
|
17
|
+
key
|
|
18
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
19
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')
|
|
20
|
+
.toUpperCase());
|
|
20
21
|
};
|
|
21
22
|
const array = (v) => v.split(',').map(vv => vv.trim());
|
|
22
23
|
const bool = (v) => ['true', 't', '1'].includes(v.toLowerCase());
|
|
@@ -28,7 +29,7 @@ export function loadEnvironmentVars() {
|
|
|
28
29
|
o[key] = mapper(getEnv(envKey));
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
|
-
const cleanup = (o, k) => Utils.hasObjectKeys(o[k]) ? {} : delete o[k];
|
|
32
|
+
const cleanup = (o, k) => (Utils.hasObjectKeys(o[k]) ? {} : delete o[k]);
|
|
32
33
|
const read0 = read.bind(null, ret, 'MIKRO_ORM_');
|
|
33
34
|
read0('baseDir');
|
|
34
35
|
read0('entities', array);
|
package/utils/fs-utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Dictionary } from '../typings.js';
|
|
2
|
-
export
|
|
2
|
+
export interface FsUtils {
|
|
3
3
|
init(): Promise<void>;
|
|
4
4
|
pathExists(path: string): boolean;
|
|
5
5
|
ensureDir(path: string): void;
|
|
@@ -10,25 +10,11 @@ export declare const fs: {
|
|
|
10
10
|
getORMPackages(): Set<string>;
|
|
11
11
|
getORMPackageVersion(name: string): string | undefined;
|
|
12
12
|
checkPackageVersion(): void;
|
|
13
|
-
/**
|
|
14
|
-
* Resolves and normalizes a series of path parts relative to each preceding part.
|
|
15
|
-
* If any part is a `file:` URL, it is converted to a local path. If any part is an
|
|
16
|
-
* absolute path, it replaces preceding paths (similar to `path.resolve` in NodeJS).
|
|
17
|
-
* Trailing directory separators are removed, and all directory separators are converted
|
|
18
|
-
* to POSIX-style separators (`/`).
|
|
19
|
-
*/
|
|
20
13
|
normalizePath(...parts: string[]): string;
|
|
21
|
-
/**
|
|
22
|
-
* Determines the relative path between two paths. If either path is a `file:` URL,
|
|
23
|
-
* it is converted to a local path.
|
|
24
|
-
*/
|
|
25
14
|
relativePath(path: string, relativeTo: string): string;
|
|
26
|
-
/**
|
|
27
|
-
* Computes the absolute path to for the given path relative to the provided base directory.
|
|
28
|
-
* If either `path` or `baseDir` are `file:` URLs, they are converted to local paths.
|
|
29
|
-
*/
|
|
30
15
|
absolutePath(path: string, baseDir?: string): string;
|
|
31
16
|
writeFile(path: string, data: string, options?: Record<string, any>): Promise<void>;
|
|
32
17
|
dynamicImport<T = any>(id: string): Promise<T>;
|
|
33
|
-
}
|
|
18
|
+
}
|
|
19
|
+
export declare const fs: FsUtils;
|
|
34
20
|
export * from '../cache/FileCacheAdapter.js';
|
package/utils/fs-utils.js
CHANGED
|
@@ -95,10 +95,7 @@ export const fs = {
|
|
|
95
95
|
},
|
|
96
96
|
getORMPackages() {
|
|
97
97
|
const pkg = this.getPackageConfig();
|
|
98
|
-
return new Set([
|
|
99
|
-
...Object.keys(pkg.dependencies ?? {}),
|
|
100
|
-
...Object.keys(pkg.devDependencies ?? {}),
|
|
101
|
-
]);
|
|
98
|
+
return new Set([...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]);
|
|
102
99
|
},
|
|
103
100
|
getORMPackageVersion(name) {
|
|
104
101
|
try {
|
|
@@ -153,7 +150,7 @@ export const fs = {
|
|
|
153
150
|
}
|
|
154
151
|
let path = parts.join('/').replace(/\\/g, '/').replace(/\/$/, '');
|
|
155
152
|
path = normalize(path).replace(/\\/g, '/');
|
|
156
|
-
return
|
|
153
|
+
return /^[/.]|[a-zA-Z]:/.exec(path) || path.startsWith('!') ? path : './' + path;
|
|
157
154
|
},
|
|
158
155
|
/**
|
|
159
156
|
* Determines the relative path between two paths. If either path is a `file:` URL,
|
package/utils/upsert-utils.js
CHANGED
|
@@ -73,7 +73,8 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
|
|
|
73
73
|
if (!meta) {
|
|
74
74
|
return '*';
|
|
75
75
|
}
|
|
76
|
-
const keys = meta.comparableProps
|
|
76
|
+
const keys = meta.comparableProps
|
|
77
|
+
.filter(p => {
|
|
77
78
|
if (p.lazy || p.embeddable) {
|
|
78
79
|
return false;
|
|
79
80
|
}
|
|
@@ -81,7 +82,8 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
|
|
|
81
82
|
return true;
|
|
82
83
|
}
|
|
83
84
|
return Array.isArray(uniqueFields) && !uniqueFields.includes(p.name);
|
|
84
|
-
})
|
|
85
|
+
})
|
|
86
|
+
.map(p => p.name);
|
|
85
87
|
if (meta.versionProperty) {
|
|
86
88
|
keys.push(meta.versionProperty);
|
|
87
89
|
}
|
|
@@ -99,7 +101,7 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
|
|
|
99
101
|
return keys.filter(key => !(key in data));
|
|
100
102
|
}
|
|
101
103
|
function getPropertyValue(obj, key) {
|
|
102
|
-
if (key.
|
|
104
|
+
if (!key.includes('.')) {
|
|
103
105
|
return obj[key];
|
|
104
106
|
}
|
|
105
107
|
const parts = key.split('.');
|
|
@@ -113,7 +115,8 @@ function getPropertyValue(obj, key) {
|
|
|
113
115
|
/** @internal */
|
|
114
116
|
export function getWhereCondition(meta, onConflictFields, data, where) {
|
|
115
117
|
const unique = onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
116
|
-
const propIndex = !isRaw(unique) &&
|
|
118
|
+
const propIndex = !isRaw(unique) &&
|
|
119
|
+
unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
117
120
|
if (onConflictFields || where == null) {
|
|
118
121
|
if (propIndex !== false && propIndex >= 0) {
|
|
119
122
|
let key = unique[propIndex];
|