@mikro-orm/core 6.4.17-dev.2 → 6.4.17-dev.21
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/decorators/ManyToMany.d.ts +2 -0
- package/decorators/ManyToOne.d.ts +2 -0
- package/decorators/OneToOne.d.ts +2 -0
- package/decorators/Transactional.d.ts +1 -0
- package/decorators/Transactional.js +3 -3
- package/entity/Reference.d.ts +5 -0
- package/entity/Reference.js +16 -0
- package/metadata/EntitySchema.js +10 -2
- package/metadata/MetadataDiscovery.js +5 -1
- package/package.json +2 -2
- package/typings.d.ts +1 -0
- package/unit-of-work/ChangeSetComputer.js +3 -1
- package/unit-of-work/UnitOfWork.d.ts +1 -0
- package/unit-of-work/UnitOfWork.js +15 -8
- package/utils/QueryHelper.js +1 -1
|
@@ -37,4 +37,6 @@ export interface ManyToManyOptions<Owner, Target> extends ReferenceOptions<Owner
|
|
|
37
37
|
deleteRule?: 'cascade' | 'no action' | 'set null' | 'set default' | AnyString;
|
|
38
38
|
/** What to do when the reference to the target entity gets updated. */
|
|
39
39
|
updateRule?: 'cascade' | 'no action' | 'set null' | 'set default' | AnyString;
|
|
40
|
+
/** Enable/disable foreign key constraint creation on this relation */
|
|
41
|
+
createForeignKeyConstraint?: boolean;
|
|
40
42
|
}
|
|
@@ -27,6 +27,8 @@ export interface ManyToOneOptions<Owner, Target> extends ReferenceOptions<Owner,
|
|
|
27
27
|
updateRule?: 'cascade' | 'no action' | 'set null' | 'set default' | AnyString;
|
|
28
28
|
/** Set the constraint type. Immediate constraints are checked for each statement, while deferred ones are only checked at the end of the transaction. Only for postgres unique constraints. */
|
|
29
29
|
deferMode?: DeferMode | `${DeferMode}`;
|
|
30
|
+
/** Enable/disable foreign key constraint creation on this relation */
|
|
31
|
+
createForeignKeyConstraint?: boolean;
|
|
30
32
|
/** Set a custom foreign key constraint name, overriding NamingStrategy.indexName(). */
|
|
31
33
|
foreignKeyName?: string;
|
|
32
34
|
}
|
package/decorators/OneToOne.d.ts
CHANGED
|
@@ -23,4 +23,6 @@ export interface OneToOneOptions<Owner, Target> extends Partial<Omit<OneToManyOp
|
|
|
23
23
|
deferMode?: DeferMode | `${DeferMode}`;
|
|
24
24
|
/** Set a custom foreign key constraint name, overriding NamingStrategy.indexName(). */
|
|
25
25
|
foreignKeyName?: string;
|
|
26
|
+
/** Enable/disable foreign key constraint creation on this relation */
|
|
27
|
+
createForeignKeyConstraint?: boolean;
|
|
26
28
|
}
|
|
@@ -2,6 +2,7 @@ import type { TransactionOptions } from '../enums';
|
|
|
2
2
|
import type { ContextProvider } from '../typings';
|
|
3
3
|
type TransactionalOptions<T> = TransactionOptions & {
|
|
4
4
|
context?: ContextProvider<T>;
|
|
5
|
+
contextName?: string;
|
|
5
6
|
};
|
|
6
7
|
/**
|
|
7
8
|
* This decorator wraps the method with `em.transactional()`, so you can provide `TransactionOptions` just like with `em.transactional()`.
|
|
@@ -17,10 +17,10 @@ function Transactional(options = {}) {
|
|
|
17
17
|
throw new Error('@Transactional() should be use with async functions');
|
|
18
18
|
}
|
|
19
19
|
descriptor.value = async function (...args) {
|
|
20
|
-
const { context, ...txOptions } = options;
|
|
20
|
+
const { context, contextName, ...txOptions } = options;
|
|
21
21
|
const em = await (0, resolveContextProvider_1.resolveContextProvider)(this, context)
|
|
22
|
-
|| TransactionContext_1.TransactionContext.getEntityManager()
|
|
23
|
-
|| RequestContext_1.RequestContext.getEntityManager();
|
|
22
|
+
|| TransactionContext_1.TransactionContext.getEntityManager(contextName)
|
|
23
|
+
|| RequestContext_1.RequestContext.getEntityManager(contextName);
|
|
24
24
|
if (!em) {
|
|
25
25
|
throw new Error(`@Transactional() decorator can only be applied to methods of classes with \`orm: MikroORM\` property, \`em: EntityManager\` property, or with a callback parameter like \`@Transactional(() => orm)\` that returns one of those types. The parameter will contain a reference to current \`this\`. Returning an EntityRepository from it is also supported.`);
|
|
26
26
|
}
|
package/entity/Reference.d.ts
CHANGED
|
@@ -56,6 +56,11 @@ export declare class ScalarReference<Value> {
|
|
|
56
56
|
* Returns either the whole entity, or the requested property.
|
|
57
57
|
*/
|
|
58
58
|
load(options?: Omit<LoadReferenceOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value | undefined>;
|
|
59
|
+
/**
|
|
60
|
+
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
|
61
|
+
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
|
62
|
+
*/
|
|
63
|
+
loadOrFail(options?: Omit<LoadReferenceOrFailOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value>;
|
|
59
64
|
set(value: Value): void;
|
|
60
65
|
bind<Entity extends object>(entity: Entity, property: EntityKey<Entity>): void;
|
|
61
66
|
unwrap(): Value | undefined;
|
package/entity/Reference.js
CHANGED
|
@@ -7,6 +7,7 @@ const node_util_1 = require("node:util");
|
|
|
7
7
|
const enums_1 = require("../enums");
|
|
8
8
|
const wrap_1 = require("./wrap");
|
|
9
9
|
const utils_1 = require("../utils");
|
|
10
|
+
const errors_1 = require("../errors");
|
|
10
11
|
class Reference {
|
|
11
12
|
entity;
|
|
12
13
|
constructor(entity) {
|
|
@@ -178,6 +179,21 @@ class ScalarReference {
|
|
|
178
179
|
}
|
|
179
180
|
return this.value;
|
|
180
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
|
184
|
+
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
|
185
|
+
*/
|
|
186
|
+
async loadOrFail(options = {}) {
|
|
187
|
+
const ret = await this.load(options);
|
|
188
|
+
if (!ret) {
|
|
189
|
+
const wrapped = (0, wrap_1.helper)(this.entity);
|
|
190
|
+
options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
|
|
191
|
+
const entityName = this.entity.constructor.name;
|
|
192
|
+
const where = wrapped.getPrimaryKey();
|
|
193
|
+
throw new errors_1.NotFoundError(`${entityName} (${where}) failed to load property '${this.property}'`);
|
|
194
|
+
}
|
|
195
|
+
return ret;
|
|
196
|
+
}
|
|
181
197
|
set(value) {
|
|
182
198
|
this.value = value;
|
|
183
199
|
this.initialized = true;
|
package/metadata/EntitySchema.js
CHANGED
|
@@ -102,6 +102,8 @@ class EntitySchema {
|
|
|
102
102
|
if (prop.fieldNames && !prop.joinColumns) {
|
|
103
103
|
prop.joinColumns = prop.fieldNames;
|
|
104
104
|
}
|
|
105
|
+
// By default, the foreign key constraint is created on the relation
|
|
106
|
+
utils_1.Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
|
|
105
107
|
this.addProperty(name, type, prop);
|
|
106
108
|
}
|
|
107
109
|
addManyToMany(name, type, options) {
|
|
@@ -111,6 +113,8 @@ class EntitySchema {
|
|
|
111
113
|
}
|
|
112
114
|
if (options.owner) {
|
|
113
115
|
utils_1.Utils.renameKey(options, 'mappedBy', 'inversedBy');
|
|
116
|
+
// By default, the foreign key constraint is created on the relation
|
|
117
|
+
utils_1.Utils.defaultValue(options, 'createForeignKeyConstraint', true);
|
|
114
118
|
}
|
|
115
119
|
const prop = this.createProperty(enums_1.ReferenceKind.MANY_TO_MANY, options);
|
|
116
120
|
this.addProperty(name, type, prop);
|
|
@@ -123,8 +127,12 @@ class EntitySchema {
|
|
|
123
127
|
const prop = this.createProperty(enums_1.ReferenceKind.ONE_TO_ONE, options);
|
|
124
128
|
utils_1.Utils.defaultValue(prop, 'owner', !!prop.inversedBy || !prop.mappedBy);
|
|
125
129
|
utils_1.Utils.defaultValue(prop, 'unique', prop.owner);
|
|
126
|
-
if (prop.owner
|
|
127
|
-
|
|
130
|
+
if (prop.owner) {
|
|
131
|
+
if (options.mappedBy) {
|
|
132
|
+
utils_1.Utils.renameKey(prop, 'mappedBy', 'inversedBy');
|
|
133
|
+
}
|
|
134
|
+
// By default, the foreign key constraint is created on the relation
|
|
135
|
+
utils_1.Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
|
|
128
136
|
}
|
|
129
137
|
if (prop.joinColumns && !prop.fieldNames) {
|
|
130
138
|
prop.fieldNames = prop.joinColumns;
|
|
@@ -657,6 +657,7 @@ class MetadataDiscovery {
|
|
|
657
657
|
autoincrement: false,
|
|
658
658
|
updateRule: prop.updateRule,
|
|
659
659
|
deleteRule: prop.deleteRule,
|
|
660
|
+
createForeignKeyConstraint: prop.createForeignKeyConstraint,
|
|
660
661
|
};
|
|
661
662
|
if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
|
|
662
663
|
ret.updateRule ??= 'no action';
|
|
@@ -1057,7 +1058,7 @@ class MetadataDiscovery {
|
|
|
1057
1058
|
prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
|
|
1058
1059
|
return;
|
|
1059
1060
|
}
|
|
1060
|
-
if (
|
|
1061
|
+
if (Array.isArray(prop.default) && prop.customType) {
|
|
1061
1062
|
val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
|
|
1062
1063
|
}
|
|
1063
1064
|
prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
|
|
@@ -1111,6 +1112,9 @@ class MetadataDiscovery {
|
|
|
1111
1112
|
if (prop.kind === enums_1.ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
|
|
1112
1113
|
prop.customType = new types_1.JsonType();
|
|
1113
1114
|
}
|
|
1115
|
+
if (prop.kind === enums_1.ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
|
|
1116
|
+
prop.customType = new types_1.JsonType();
|
|
1117
|
+
}
|
|
1114
1118
|
if (!prop.customType && prop.array && prop.items) {
|
|
1115
1119
|
prop.customType = new types_1.EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
|
|
1116
1120
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "6.4.17-dev.
|
|
3
|
+
"version": "6.4.17-dev.21",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"esprima": "4.0.1",
|
|
65
65
|
"fs-extra": "11.3.0",
|
|
66
66
|
"globby": "11.1.0",
|
|
67
|
-
"mikro-orm": "6.4.17-dev.
|
|
67
|
+
"mikro-orm": "6.4.17-dev.21",
|
|
68
68
|
"reflect-metadata": "0.2.2"
|
|
69
69
|
}
|
|
70
70
|
}
|
package/typings.d.ts
CHANGED
|
@@ -384,6 +384,7 @@ export interface EntityProperty<Owner = any, Target = any> {
|
|
|
384
384
|
optional?: boolean;
|
|
385
385
|
ignoreSchemaChanges?: ('type' | 'extra' | 'default')[];
|
|
386
386
|
deferMode?: DeferMode;
|
|
387
|
+
createForeignKeyConstraint: boolean;
|
|
387
388
|
foreignKeyName?: string;
|
|
388
389
|
}
|
|
389
390
|
export declare class EntityMetadata<T = any> {
|
|
@@ -144,7 +144,9 @@ class ChangeSetComputer {
|
|
|
144
144
|
if (!target.isDirty() && changeSet.type !== ChangeSet_1.ChangeSetType.CREATE) {
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
-
|
|
147
|
+
if (target.isDirty()) {
|
|
148
|
+
this.collectionUpdates.add(target);
|
|
149
|
+
}
|
|
148
150
|
if (prop.owner && !this.platform.usesPivotTable()) {
|
|
149
151
|
changeSet.payload[prop.name] = target.getItems(false).map((item) => item.__helper.__identifier ?? item.__helper.getPrimaryKey());
|
|
150
152
|
}
|
|
@@ -102,6 +102,7 @@ export declare class UnitOfWork {
|
|
|
102
102
|
private commitDeleteChangeSets;
|
|
103
103
|
private commitExtraUpdates;
|
|
104
104
|
private commitCollectionUpdates;
|
|
105
|
+
private filterCollectionUpdates;
|
|
105
106
|
/**
|
|
106
107
|
* Orders change sets so FK constrains are maintained, ensures stable order (needed for node < 11)
|
|
107
108
|
*/
|
|
@@ -303,6 +303,7 @@ class UnitOfWork {
|
|
|
303
303
|
cs.entity.__helper.__processing = true;
|
|
304
304
|
}
|
|
305
305
|
await this.eventManager.dispatchEvent(enums_1.EventType.onFlush, { em: this.em, uow: this });
|
|
306
|
+
this.filterCollectionUpdates();
|
|
306
307
|
// nothing to do, do not start transaction
|
|
307
308
|
if (this.changeSets.size === 0 && this.collectionUpdates.size === 0 && this.extraUpdates.size === 0) {
|
|
308
309
|
return void await this.eventManager.dispatchEvent(enums_1.EventType.afterFlush, { em: this.em, uow: this });
|
|
@@ -886,23 +887,29 @@ class UnitOfWork {
|
|
|
886
887
|
}
|
|
887
888
|
}
|
|
888
889
|
async commitCollectionUpdates(ctx) {
|
|
889
|
-
|
|
890
|
+
this.filterCollectionUpdates();
|
|
891
|
+
await this.em.getDriver().syncCollections(this.collectionUpdates, { ctx, schema: this.em.schema });
|
|
890
892
|
for (const coll of this.collectionUpdates) {
|
|
893
|
+
coll.takeSnapshot();
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
filterCollectionUpdates() {
|
|
897
|
+
for (const coll of this.collectionUpdates) {
|
|
898
|
+
let skip = true;
|
|
891
899
|
if (coll.property.owner || coll.getItems(false).filter(item => !item.__helper.__initialized).length > 0) {
|
|
892
900
|
if (this.platform.usesPivotTable()) {
|
|
893
|
-
|
|
901
|
+
skip = false;
|
|
894
902
|
}
|
|
895
903
|
}
|
|
896
904
|
else if (coll.property.kind === enums_1.ReferenceKind.ONE_TO_MANY && coll.getSnapshot() === undefined) {
|
|
897
|
-
|
|
905
|
+
skip = false;
|
|
898
906
|
}
|
|
899
907
|
else if (coll.property.kind === enums_1.ReferenceKind.MANY_TO_MANY && !coll.property.owner) {
|
|
900
|
-
|
|
908
|
+
skip = false;
|
|
909
|
+
}
|
|
910
|
+
if (skip) {
|
|
911
|
+
this.collectionUpdates.delete(coll);
|
|
901
912
|
}
|
|
902
|
-
}
|
|
903
|
-
await this.em.getDriver().syncCollections(collectionUpdates, { ctx, schema: this.em.schema });
|
|
904
|
-
for (const coll of this.collectionUpdates) {
|
|
905
|
-
coll.takeSnapshot();
|
|
906
913
|
}
|
|
907
914
|
}
|
|
908
915
|
/**
|
package/utils/QueryHelper.js
CHANGED
|
@@ -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') {
|