@mikro-orm/core 6.4.17-dev.7 → 6.4.17-dev.71
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 +11 -2
- package/EntityManager.js +26 -20
- package/README.md +1 -2
- package/connections/Connection.d.ts +4 -2
- package/connections/Connection.js +2 -2
- package/decorators/Entity.d.ts +14 -0
- package/decorators/Indexed.d.ts +2 -2
- package/decorators/Transactional.d.ts +1 -0
- package/decorators/Transactional.js +3 -3
- package/drivers/IDatabaseDriver.d.ts +4 -0
- package/entity/ArrayCollection.d.ts +3 -1
- package/entity/ArrayCollection.js +7 -2
- package/entity/EntityFactory.d.ts +6 -0
- package/entity/EntityFactory.js +12 -1
- package/entity/EntityHelper.js +4 -1
- package/entity/EntityLoader.js +25 -17
- package/entity/Reference.d.ts +5 -0
- package/entity/Reference.js +16 -0
- package/entity/WrappedEntity.js +1 -1
- package/entity/defineEntity.d.ts +528 -0
- package/entity/defineEntity.js +684 -0
- package/entity/index.d.ts +2 -0
- package/entity/index.js +2 -0
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -2
- package/enums.d.ts +3 -1
- package/enums.js +2 -0
- package/hydration/ObjectHydrator.js +1 -1
- package/index.d.ts +1 -1
- package/index.mjs +4 -0
- package/metadata/MetadataDiscovery.d.ts +0 -1
- package/metadata/MetadataDiscovery.js +7 -12
- package/package.json +3 -3
- package/platforms/Platform.d.ts +3 -1
- package/types/BooleanType.d.ts +1 -1
- package/typings.d.ts +17 -8
- package/typings.js +10 -2
- package/unit-of-work/ChangeSetComputer.js +3 -1
- package/unit-of-work/ChangeSetPersister.d.ts +4 -2
- package/unit-of-work/ChangeSetPersister.js +13 -9
- package/unit-of-work/UnitOfWork.d.ts +1 -0
- package/unit-of-work/UnitOfWork.js +25 -11
- package/utils/Configuration.d.ts +7 -1
- package/utils/Configuration.js +1 -0
- package/utils/ConfigurationLoader.js +2 -2
- package/utils/Cursor.js +3 -0
- package/utils/EntityComparator.js +6 -3
- package/utils/QueryHelper.js +3 -3
- package/utils/RawQueryFragment.d.ts +34 -0
- package/utils/RawQueryFragment.js +35 -0
- package/utils/Utils.d.ts +2 -2
- package/utils/Utils.js +32 -8
- package/utils/upsert-utils.js +9 -1
|
@@ -534,9 +534,12 @@ class EntityComparator {
|
|
|
534
534
|
context.set('compareBuffers', Utils_1.compareBuffers);
|
|
535
535
|
context.set('compareObjects', Utils_1.compareObjects);
|
|
536
536
|
context.set('equals', Utils_1.equals);
|
|
537
|
-
meta.comparableProps
|
|
538
|
-
|
|
539
|
-
|
|
537
|
+
for (const prop of meta.comparableProps) {
|
|
538
|
+
// skip properties that are not hydrated
|
|
539
|
+
if (prop.hydrate !== false) {
|
|
540
|
+
lines.push(this.getPropertyComparator(prop, context));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
540
543
|
const code = `// compiled comparator for entity ${meta.className}\n`
|
|
541
544
|
+ `return function(last, current) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
|
|
542
545
|
const comparator = Utils_1.Utils.createFunction(context, code);
|
package/utils/QueryHelper.js
CHANGED
|
@@ -40,7 +40,7 @@ class QueryHelper {
|
|
|
40
40
|
if (Array.isArray(where)) {
|
|
41
41
|
where.forEach((item, i) => {
|
|
42
42
|
if (this.inlinePrimaryKeyObjects(item, meta, metadata, key)) {
|
|
43
|
-
where[i] = Utils_1.Utils.getPrimaryKeyValues(item, meta
|
|
43
|
+
where[i] = Utils_1.Utils.getPrimaryKeyValues(item, meta, false);
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
}
|
|
@@ -61,7 +61,7 @@ class QueryHelper {
|
|
|
61
61
|
Object.keys(where).forEach(k => {
|
|
62
62
|
const meta2 = metadata.find(meta.properties[k]?.type) || meta;
|
|
63
63
|
if (this.inlinePrimaryKeyObjects(where[k], meta2, metadata, k)) {
|
|
64
|
-
where[k] = Utils_1.Utils.getPrimaryKeyValues(where[k], meta2
|
|
64
|
+
where[k] = Utils_1.Utils.getPrimaryKeyValues(where[k], meta2, true);
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
return false;
|
|
@@ -121,7 +121,7 @@ class QueryHelper {
|
|
|
121
121
|
value = QueryHelper.processCustomType(prop, value, platform, undefined, true);
|
|
122
122
|
}
|
|
123
123
|
const isJsonProperty = prop?.customType instanceof JsonType_1.JsonType && Utils_1.Utils.isPlainObject(value) && !platform.isRaw(value) && Object.keys(value)[0] !== '$eq';
|
|
124
|
-
if (isJsonProperty) {
|
|
124
|
+
if (isJsonProperty && prop?.kind !== enums_1.ReferenceKind.EMBEDDED) {
|
|
125
125
|
return this.processJsonCondition(o, value, [prop.fieldNames[0]], platform, aliased);
|
|
126
126
|
}
|
|
127
127
|
if (Array.isArray(value) && !Utils_1.Utils.isOperator(key) && !QueryHelper.isSupportedOperator(key) && !key.includes('?') && options.type !== 'orderBy') {
|
|
@@ -70,6 +70,24 @@ export declare const ALIAS_REPLACEMENT_RE = "\\[::alias::\\]";
|
|
|
70
70
|
* ```ts
|
|
71
71
|
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
|
|
72
72
|
* ```
|
|
73
|
+
*
|
|
74
|
+
* The `raw` helper can be used within indexes and uniques to write database-agnostic SQL expressions. In that case, you can use `'??'` to tag your database identifiers (table name, column names, index name, ...) inside your expression, and pass those identifiers as a second parameter to the `raw` helper. Internally, those will automatically be quoted according to the database in use:
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
|
|
78
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
|
|
79
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
|
|
80
|
+
* @Entity({ schema: 'library' })
|
|
81
|
+
* export class Author { ... }
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* You can also use the `quote` tag function to write database-agnostic SQL expressions. The end-result is the same as using the `raw` function regarding database identifiers quoting, only to have a more elegant expression syntax:
|
|
85
|
+
*
|
|
86
|
+
* ```ts
|
|
87
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
88
|
+
* @Entity({ schema: 'library' })
|
|
89
|
+
* export class Author { ... }
|
|
90
|
+
* ```
|
|
73
91
|
*/
|
|
74
92
|
export declare function raw<T extends object = any, R = any>(sql: EntityKey<T> | EntityKey<T>[] | AnyString | ((alias: string) => string) | RawQueryFragment, params?: readonly unknown[] | Dictionary<unknown>): R;
|
|
75
93
|
/**
|
|
@@ -94,3 +112,19 @@ export declare namespace sql {
|
|
|
94
112
|
var upper: <T extends object>(key: string | ((alias: string) => string)) => string;
|
|
95
113
|
}
|
|
96
114
|
export declare function createSqlFunction<T extends object, R = string>(func: string, key: string | ((alias: string) => string)): R;
|
|
115
|
+
/**
|
|
116
|
+
* Tag function providing quoting of db identifiers (table name, columns names, index names, ...).
|
|
117
|
+
*
|
|
118
|
+
* Within the template literal on which the tag function is applied, all placeholders are considered to be database identifiers, and will thus be quoted as so according to the database in use.
|
|
119
|
+
*
|
|
120
|
+
* ```ts
|
|
121
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("name")
|
|
122
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`name`)
|
|
123
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
124
|
+
* @Entity({ schema: 'library' })
|
|
125
|
+
* export class Author { ... }
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function quote(expParts: readonly string[], ...values: (string | {
|
|
129
|
+
toString(): string;
|
|
130
|
+
})[]): any;
|
|
@@ -4,6 +4,7 @@ exports.ALIAS_REPLACEMENT_RE = exports.ALIAS_REPLACEMENT = exports.RawQueryFragm
|
|
|
4
4
|
exports.raw = raw;
|
|
5
5
|
exports.sql = sql;
|
|
6
6
|
exports.createSqlFunction = createSqlFunction;
|
|
7
|
+
exports.quote = quote;
|
|
7
8
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
8
9
|
const node_util_1 = require("node:util");
|
|
9
10
|
const Utils_1 = require("./Utils");
|
|
@@ -150,6 +151,24 @@ exports.ALIAS_REPLACEMENT_RE = '\\[::alias::\\]';
|
|
|
150
151
|
* ```ts
|
|
151
152
|
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
|
|
152
153
|
* ```
|
|
154
|
+
*
|
|
155
|
+
* The `raw` helper can be used within indexes and uniques to write database-agnostic SQL expressions. In that case, you can use `'??'` to tag your database identifiers (table name, column names, index name, ...) inside your expression, and pass those identifiers as a second parameter to the `raw` helper. Internally, those will automatically be quoted according to the database in use:
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
|
|
159
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
|
|
160
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
|
|
161
|
+
* @Entity({ schema: 'library' })
|
|
162
|
+
* export class Author { ... }
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* You can also use the `quote` tag function to write database-agnostic SQL expressions. The end-result is the same as using the `raw` function regarding database identifiers quoting, only to have a more elegant expression syntax:
|
|
166
|
+
*
|
|
167
|
+
* ```ts
|
|
168
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
169
|
+
* @Entity({ schema: 'library' })
|
|
170
|
+
* export class Author { ... }
|
|
171
|
+
* ```
|
|
153
172
|
*/
|
|
154
173
|
function raw(sql, params) {
|
|
155
174
|
if (sql instanceof RawQueryFragment) {
|
|
@@ -207,3 +226,19 @@ sql.ref = (...keys) => raw('??', [keys.join('.')]);
|
|
|
207
226
|
sql.now = (length) => raw('current_timestamp' + (length == null ? '' : `(${length})`));
|
|
208
227
|
sql.lower = (key) => createSqlFunction('lower', key);
|
|
209
228
|
sql.upper = (key) => createSqlFunction('upper', key);
|
|
229
|
+
/**
|
|
230
|
+
* Tag function providing quoting of db identifiers (table name, columns names, index names, ...).
|
|
231
|
+
*
|
|
232
|
+
* Within the template literal on which the tag function is applied, all placeholders are considered to be database identifiers, and will thus be quoted as so according to the database in use.
|
|
233
|
+
*
|
|
234
|
+
* ```ts
|
|
235
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("name")
|
|
236
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`name`)
|
|
237
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
238
|
+
* @Entity({ schema: 'library' })
|
|
239
|
+
* export class Author { ... }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
function quote(expParts, ...values) {
|
|
243
|
+
return raw(expParts.join('??'), values);
|
|
244
|
+
}
|
package/utils/Utils.d.ts
CHANGED
|
@@ -134,14 +134,14 @@ export declare class Utils {
|
|
|
134
134
|
static getCompositeKeyHash<T>(data: EntityData<T>, meta: EntityMetadata<T>, convertCustomTypes?: boolean, platform?: Platform, flat?: boolean): string;
|
|
135
135
|
static getPrimaryKeyHash(pks: (string | Buffer | Date)[]): string;
|
|
136
136
|
static splitPrimaryKeys<T extends object>(key: string): EntityKey<T>[];
|
|
137
|
-
static getPrimaryKeyValues<T>(entity: T, primaryKeys: string[]
|
|
137
|
+
static getPrimaryKeyValues<T>(entity: T, primaryKeys: string[] | EntityMetadata<T>, allowScalar?: boolean, convertCustomTypes?: boolean): any;
|
|
138
138
|
static getPrimaryKeyCond<T>(entity: T, primaryKeys: EntityKey<T>[]): Record<string, Primary<T>> | null;
|
|
139
139
|
/**
|
|
140
140
|
* Maps nested FKs from `[1, 2, 3]` to `[1, [2, 3]]`.
|
|
141
141
|
*/
|
|
142
142
|
static mapFlatCompositePrimaryKey(fk: Primary<any>[], prop: EntityProperty, fieldNames?: string[], idx?: number): Primary<any> | Primary<any>[];
|
|
143
143
|
static getPrimaryKeyCondFromArray<T extends object>(pks: Primary<T>[], meta: EntityMetadata<T>): Record<string, Primary<T>>;
|
|
144
|
-
static getOrderedPrimaryKeys<T>(id: Primary<T> | Record<string, Primary<T>>, meta: EntityMetadata<T>, platform?: Platform, convertCustomTypes?: boolean): Primary<T>[];
|
|
144
|
+
static getOrderedPrimaryKeys<T>(id: Primary<T> | Record<string, Primary<T>>, meta: EntityMetadata<T>, platform?: Platform, convertCustomTypes?: boolean, allowScalar?: boolean): Primary<T>[];
|
|
145
145
|
/**
|
|
146
146
|
* Checks whether given object is an entity instance.
|
|
147
147
|
*/
|
package/utils/Utils.js
CHANGED
|
@@ -498,6 +498,7 @@ class Utils {
|
|
|
498
498
|
static splitPrimaryKeys(key) {
|
|
499
499
|
return key.split(this.PK_SEPARATOR);
|
|
500
500
|
}
|
|
501
|
+
// TODO v7: remove support for `primaryKeys: string[]`
|
|
501
502
|
static getPrimaryKeyValues(entity, primaryKeys, allowScalar = false, convertCustomTypes = false) {
|
|
502
503
|
/* istanbul ignore next */
|
|
503
504
|
if (entity == null) {
|
|
@@ -509,9 +510,24 @@ class Utils {
|
|
|
509
510
|
}
|
|
510
511
|
return val;
|
|
511
512
|
}
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
513
|
+
const meta = Array.isArray(primaryKeys) ? undefined : primaryKeys;
|
|
514
|
+
primaryKeys = Array.isArray(primaryKeys) ? primaryKeys : meta.primaryKeys;
|
|
515
|
+
let pk;
|
|
516
|
+
if (Utils.isEntity(entity, true)) {
|
|
517
|
+
pk = (0, wrap_1.helper)(entity).getPrimaryKey(convertCustomTypes);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
pk = primaryKeys.reduce((o, pk) => {
|
|
521
|
+
const targetMeta = meta?.properties[pk].targetMeta;
|
|
522
|
+
if (targetMeta && Utils.isPlainObject(entity[pk])) {
|
|
523
|
+
o[pk] = Utils.getPrimaryKeyValues(entity[pk], targetMeta, allowScalar, convertCustomTypes);
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
o[pk] = entity[pk];
|
|
527
|
+
}
|
|
528
|
+
return o;
|
|
529
|
+
}, {});
|
|
530
|
+
}
|
|
515
531
|
if (primaryKeys.length > 1) {
|
|
516
532
|
return toArray(pk);
|
|
517
533
|
}
|
|
@@ -561,7 +577,7 @@ class Utils {
|
|
|
561
577
|
return o;
|
|
562
578
|
}, {});
|
|
563
579
|
}
|
|
564
|
-
static getOrderedPrimaryKeys(id, meta, platform, convertCustomTypes = false) {
|
|
580
|
+
static getOrderedPrimaryKeys(id, meta, platform, convertCustomTypes = false, allowScalar = false) {
|
|
565
581
|
const data = (Utils.isPrimaryKey(id) ? { [meta.primaryKeys[0]]: id } : id);
|
|
566
582
|
const pks = meta.primaryKeys.map((pk, idx) => {
|
|
567
583
|
const prop = meta.properties[pk];
|
|
@@ -571,11 +587,14 @@ class Utils {
|
|
|
571
587
|
value = prop.customType.convertToJSValue(value, platform);
|
|
572
588
|
}
|
|
573
589
|
if (prop.kind !== enums_1.ReferenceKind.SCALAR && prop.targetMeta) {
|
|
574
|
-
const value2 = this.getOrderedPrimaryKeys(value, prop.targetMeta, platform, convertCustomTypes);
|
|
590
|
+
const value2 = this.getOrderedPrimaryKeys(value, prop.targetMeta, platform, convertCustomTypes, allowScalar);
|
|
575
591
|
value = value2.length > 1 ? value2 : value2[0];
|
|
576
592
|
}
|
|
577
593
|
return value;
|
|
578
594
|
});
|
|
595
|
+
if (allowScalar && pks.length === 1) {
|
|
596
|
+
return pks[0];
|
|
597
|
+
}
|
|
579
598
|
// we need to flatten the PKs as composite PKs can be build from another composite PKs
|
|
580
599
|
// and this method is used to get the PK hash in identity map, that expects flat array
|
|
581
600
|
return Utils.flatten(pks);
|
|
@@ -928,9 +947,14 @@ class Utils {
|
|
|
928
947
|
return require('../../package.json').version;
|
|
929
948
|
}
|
|
930
949
|
catch {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
950
|
+
try {
|
|
951
|
+
// this works with node in production build (where we do not have the `src` folder)
|
|
952
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
953
|
+
return require('../package.json').version;
|
|
954
|
+
}
|
|
955
|
+
catch {
|
|
956
|
+
return 'N/A';
|
|
957
|
+
}
|
|
934
958
|
}
|
|
935
959
|
}
|
|
936
960
|
/* istanbul ignore next */
|
package/utils/upsert-utils.js
CHANGED
|
@@ -75,7 +75,15 @@ function getOnConflictReturningFields(meta, data, uniqueFields, options) {
|
|
|
75
75
|
if (!meta) {
|
|
76
76
|
return '*';
|
|
77
77
|
}
|
|
78
|
-
const keys = meta.comparableProps.filter(p =>
|
|
78
|
+
const keys = meta.comparableProps.filter(p => {
|
|
79
|
+
if (p.lazy || p.embeddable) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (p.autoincrement) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return Array.isArray(uniqueFields) && !uniqueFields.includes(p.name);
|
|
86
|
+
}).map(p => p.name);
|
|
79
87
|
if (meta.versionProperty) {
|
|
80
88
|
keys.push(meta.versionProperty);
|
|
81
89
|
}
|