@mikro-orm/core 7.0.0-dev.74 → 7.0.0-dev.76
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 +0 -6
- package/EntityManager.js +21 -34
- package/entity/EntityAssigner.js +4 -4
- package/entity/index.d.ts +1 -1
- package/entity/index.js +1 -1
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +61 -0
- package/enums.d.ts +1 -1
- package/enums.js +1 -1
- package/errors.d.ts +0 -1
- package/errors.js +0 -5
- package/metadata/MetadataDiscovery.js +1 -1
- package/metadata/MetadataStorage.d.ts +1 -2
- package/metadata/MetadataStorage.js +0 -8
- package/not-supported.d.ts +1 -0
- package/not-supported.js +3 -0
- package/package.json +5 -2
- package/typings.d.ts +1 -0
- package/typings.js +6 -0
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +3 -6
- package/unit-of-work/ChangeSetPersister.d.ts +2 -3
- package/unit-of-work/ChangeSetPersister.js +22 -5
- package/unit-of-work/UnitOfWork.js +2 -2
- package/utils/Configuration.d.ts +0 -14
- package/utils/clone.js +1 -2
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
package/EntityManager.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { type Configuration } from './utils/Configuration.js';
|
|
|
3
3
|
import { Cursor } from './utils/Cursor.js';
|
|
4
4
|
import { EntityFactory } from './entity/EntityFactory.js';
|
|
5
5
|
import { type AssignOptions } from './entity/EntityAssigner.js';
|
|
6
|
-
import { EntityValidator } from './entity/EntityValidator.js';
|
|
7
6
|
import { type EntityRepository } from './entity/EntityRepository.js';
|
|
8
7
|
import { EntityLoader, type EntityLoaderOptions } from './entity/EntityLoader.js';
|
|
9
8
|
import { Reference } from './entity/Reference.js';
|
|
@@ -33,7 +32,6 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
|
|
|
33
32
|
readonly global = false;
|
|
34
33
|
readonly name: string;
|
|
35
34
|
private readonly loaders;
|
|
36
|
-
private readonly validator;
|
|
37
35
|
private readonly repositoryMap;
|
|
38
36
|
private readonly entityLoader;
|
|
39
37
|
protected readonly comparator: EntityComparator;
|
|
@@ -72,10 +70,6 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
|
|
|
72
70
|
* Shortcut for `em.getRepository()`.
|
|
73
71
|
*/
|
|
74
72
|
repo<Entity extends object, Repository extends EntityRepository<Entity> = EntityRepository<Entity>>(entityName: EntityName<Entity>): GetRepository<Entity, Repository>;
|
|
75
|
-
/**
|
|
76
|
-
* Gets EntityValidator instance
|
|
77
|
-
*/
|
|
78
|
-
getValidator(): EntityValidator;
|
|
79
73
|
/**
|
|
80
74
|
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
|
81
75
|
*/
|
package/EntityManager.js
CHANGED
|
@@ -8,7 +8,7 @@ import { TransactionContext } from './utils/TransactionContext.js';
|
|
|
8
8
|
import { isRaw, RawQueryFragment } from './utils/RawQueryFragment.js';
|
|
9
9
|
import { EntityFactory } from './entity/EntityFactory.js';
|
|
10
10
|
import { EntityAssigner } from './entity/EntityAssigner.js';
|
|
11
|
-
import {
|
|
11
|
+
import { validateEmptyWhere, validateParams, validatePrimaryKey, validateProperty } from './entity/validators.js';
|
|
12
12
|
import { EntityLoader } from './entity/EntityLoader.js';
|
|
13
13
|
import { Reference } from './entity/Reference.js';
|
|
14
14
|
import { helper } from './entity/wrap.js';
|
|
@@ -36,7 +36,6 @@ export class EntityManager {
|
|
|
36
36
|
global = false;
|
|
37
37
|
name;
|
|
38
38
|
loaders = {};
|
|
39
|
-
validator;
|
|
40
39
|
repositoryMap = {};
|
|
41
40
|
entityLoader;
|
|
42
41
|
comparator;
|
|
@@ -61,7 +60,6 @@ export class EntityManager {
|
|
|
61
60
|
this.eventManager = eventManager;
|
|
62
61
|
this.entityLoader = new EntityLoader(this);
|
|
63
62
|
this.name = this.config.get('contextName');
|
|
64
|
-
this.validator = new EntityValidator(this.config.get('strict'));
|
|
65
63
|
this.comparator = this.config.getComparator(this.metadata);
|
|
66
64
|
this.resultCache = this.config.getResultCacheAdapter();
|
|
67
65
|
this.disableTransactions = this.config.get('disableTransactions');
|
|
@@ -105,12 +103,6 @@ export class EntityManager {
|
|
|
105
103
|
repo(entityName) {
|
|
106
104
|
return this.getRepository(entityName);
|
|
107
105
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Gets EntityValidator instance
|
|
110
|
-
*/
|
|
111
|
-
getValidator() {
|
|
112
|
-
return this.validator;
|
|
113
|
-
}
|
|
114
106
|
/**
|
|
115
107
|
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
|
116
108
|
*/
|
|
@@ -127,7 +119,7 @@ export class EntityManager {
|
|
|
127
119
|
await em.tryFlush(entityName, options);
|
|
128
120
|
entityName = Utils.className(entityName);
|
|
129
121
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
130
|
-
|
|
122
|
+
validateParams(where);
|
|
131
123
|
options.orderBy = options.orderBy || {};
|
|
132
124
|
options.populate = await em.preparePopulate(entityName, options);
|
|
133
125
|
const populate = options.populate;
|
|
@@ -203,7 +195,7 @@ export class EntityManager {
|
|
|
203
195
|
await em.tryFlush(entityName, options);
|
|
204
196
|
entityName = Utils.className(entityName);
|
|
205
197
|
const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
|
|
206
|
-
|
|
198
|
+
validateParams(where);
|
|
207
199
|
options.orderBy = options.orderBy || {};
|
|
208
200
|
options.populate = await em.preparePopulate(entityName, options);
|
|
209
201
|
const meta = this.metadata.get(entityName);
|
|
@@ -625,13 +617,13 @@ export class EntityManager {
|
|
|
625
617
|
await em.tryFlush(entityName, options);
|
|
626
618
|
const meta = em.metadata.get(entityName);
|
|
627
619
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
628
|
-
|
|
620
|
+
validateEmptyWhere(where);
|
|
629
621
|
em.checkLockRequirements(options.lockMode, meta);
|
|
630
622
|
const isOptimisticLocking = options.lockMode == null || options.lockMode === LockMode.OPTIMISTIC;
|
|
631
623
|
if (entity && !em.shouldRefresh(meta, entity, options) && isOptimisticLocking) {
|
|
632
624
|
return em.lockAndPopulate(meta, entity, where, options);
|
|
633
625
|
}
|
|
634
|
-
|
|
626
|
+
validateParams(where);
|
|
635
627
|
options.populate = await em.preparePopulate(entityName, options);
|
|
636
628
|
const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
|
|
637
629
|
const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
|
|
@@ -763,7 +755,7 @@ export class EntityManager {
|
|
|
763
755
|
}
|
|
764
756
|
where = getWhereCondition(meta, options.onConflictFields, data, where).where;
|
|
765
757
|
data = QueryHelper.processObjectParams(data);
|
|
766
|
-
|
|
758
|
+
validateParams(data, 'insert data');
|
|
767
759
|
if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
|
|
768
760
|
await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity: data, em, meta }, meta);
|
|
769
761
|
}
|
|
@@ -915,7 +907,7 @@ export class EntityManager {
|
|
|
915
907
|
platform: this.getPlatform(),
|
|
916
908
|
});
|
|
917
909
|
row = QueryHelper.processObjectParams(row);
|
|
918
|
-
|
|
910
|
+
validateParams(row, 'insert data');
|
|
919
911
|
allData.push(row);
|
|
920
912
|
allWhere.push(where);
|
|
921
913
|
}
|
|
@@ -1144,7 +1136,7 @@ export class EntityManager {
|
|
|
1144
1136
|
return cs.getPrimaryKey();
|
|
1145
1137
|
}
|
|
1146
1138
|
data = QueryHelper.processObjectParams(data);
|
|
1147
|
-
|
|
1139
|
+
validateParams(data, 'insert data');
|
|
1148
1140
|
const res = await em.driver.nativeInsert(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1149
1141
|
return res.insertId;
|
|
1150
1142
|
}
|
|
@@ -1184,7 +1176,7 @@ export class EntityManager {
|
|
|
1184
1176
|
return css.map(cs => cs.getPrimaryKey());
|
|
1185
1177
|
}
|
|
1186
1178
|
data = data.map(row => QueryHelper.processObjectParams(row));
|
|
1187
|
-
data.forEach(row =>
|
|
1179
|
+
data.forEach(row => validateParams(row, 'insert data'));
|
|
1188
1180
|
const res = await em.driver.nativeInsertMany(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1189
1181
|
if (res.insertedIds) {
|
|
1190
1182
|
return res.insertedIds;
|
|
@@ -1200,8 +1192,8 @@ export class EntityManager {
|
|
|
1200
1192
|
entityName = Utils.className(entityName);
|
|
1201
1193
|
data = QueryHelper.processObjectParams(data);
|
|
1202
1194
|
where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
|
|
1203
|
-
|
|
1204
|
-
|
|
1195
|
+
validateParams(data, 'update data');
|
|
1196
|
+
validateParams(where, 'update condition');
|
|
1205
1197
|
const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, ...options });
|
|
1206
1198
|
return res.affectedRows;
|
|
1207
1199
|
}
|
|
@@ -1213,7 +1205,7 @@ export class EntityManager {
|
|
|
1213
1205
|
em.prepareOptions(options);
|
|
1214
1206
|
entityName = Utils.className(entityName);
|
|
1215
1207
|
where = await em.processWhere(entityName, where, options, 'delete');
|
|
1216
|
-
|
|
1208
|
+
validateParams(where, 'delete condition');
|
|
1217
1209
|
const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
|
|
1218
1210
|
return res.affectedRows;
|
|
1219
1211
|
}
|
|
@@ -1224,15 +1216,17 @@ export class EntityManager {
|
|
|
1224
1216
|
entityName = Utils.className(entityName);
|
|
1225
1217
|
const meta = this.metadata.get(entityName);
|
|
1226
1218
|
const data = this.driver.mapResult(result, meta);
|
|
1227
|
-
Object.keys(data)
|
|
1219
|
+
for (const k of Object.keys(data)) {
|
|
1228
1220
|
const prop = meta.properties[k];
|
|
1229
|
-
if (prop
|
|
1230
|
-
|
|
1221
|
+
if (prop?.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && !prop.customType && (prop.setter || !prop.getter)) {
|
|
1222
|
+
validateProperty(prop, data[k], data);
|
|
1231
1223
|
}
|
|
1232
|
-
}
|
|
1224
|
+
}
|
|
1233
1225
|
return this.merge(entityName, data, {
|
|
1234
1226
|
convertCustomTypes: true,
|
|
1235
|
-
refresh: true,
|
|
1227
|
+
refresh: true,
|
|
1228
|
+
validate: false,
|
|
1229
|
+
...options,
|
|
1236
1230
|
});
|
|
1237
1231
|
}
|
|
1238
1232
|
/**
|
|
@@ -1248,15 +1242,11 @@ export class EntityManager {
|
|
|
1248
1242
|
options.validate ??= true;
|
|
1249
1243
|
options.cascade ??= true;
|
|
1250
1244
|
entityName = Utils.className(entityName);
|
|
1251
|
-
|
|
1252
|
-
em.validator.validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1253
|
-
}
|
|
1245
|
+
validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1254
1246
|
let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
|
|
1255
1247
|
if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
|
|
1256
1248
|
return entity;
|
|
1257
1249
|
}
|
|
1258
|
-
const meta = em.metadata.find(entityName);
|
|
1259
|
-
const childMeta = em.metadata.getByDiscriminatorColumn(meta, data);
|
|
1260
1250
|
const dataIsEntity = Utils.isEntity(data);
|
|
1261
1251
|
if (options.keepIdentity && entity && dataIsEntity && entity !== data) {
|
|
1262
1252
|
helper(entity).__data = helper(data).__data;
|
|
@@ -1264,9 +1254,6 @@ export class EntityManager {
|
|
|
1264
1254
|
return entity;
|
|
1265
1255
|
}
|
|
1266
1256
|
entity = dataIsEntity ? data : em.entityFactory.create(entityName, data, { merge: true, ...options });
|
|
1267
|
-
if (options.validate) {
|
|
1268
|
-
em.validator.validate(entity, data, childMeta ?? meta);
|
|
1269
|
-
}
|
|
1270
1257
|
const visited = options.cascade ? undefined : new Set([entity]);
|
|
1271
1258
|
em.unitOfWork.merge(entity, visited);
|
|
1272
1259
|
return entity;
|
|
@@ -1344,7 +1331,7 @@ export class EntityManager {
|
|
|
1344
1331
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
1345
1332
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
1346
1333
|
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
1347
|
-
|
|
1334
|
+
validateParams(where);
|
|
1348
1335
|
delete options.orderBy;
|
|
1349
1336
|
const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
|
|
1350
1337
|
const cached = await em.tryCache(entityName, options.cache, cacheKey);
|
package/entity/EntityAssigner.js
CHANGED
|
@@ -3,10 +3,9 @@ import { Collection } from './Collection.js';
|
|
|
3
3
|
import { Utils } from '../utils/Utils.js';
|
|
4
4
|
import { Reference } from './Reference.js';
|
|
5
5
|
import { ReferenceKind, SCALAR_TYPES } from '../enums.js';
|
|
6
|
-
import {
|
|
6
|
+
import { validateProperty } from './validators.js';
|
|
7
7
|
import { helper, wrap } from './wrap.js';
|
|
8
8
|
import { EntityHelper } from './EntityHelper.js';
|
|
9
|
-
const validator = new EntityValidator(false);
|
|
10
9
|
export class EntityAssigner {
|
|
11
10
|
static assign(entity, data, options = {}) {
|
|
12
11
|
let opts = options;
|
|
@@ -94,8 +93,9 @@ export class EntityAssigner {
|
|
|
94
93
|
}
|
|
95
94
|
return EntityAssigner.assignReference(entity, value, prop, options.em, options);
|
|
96
95
|
}
|
|
97
|
-
if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.
|
|
98
|
-
|
|
96
|
+
if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && (prop.setter || !prop.getter)) {
|
|
97
|
+
validateProperty(prop, value, entity);
|
|
98
|
+
return entity[prop.name] = value;
|
|
99
99
|
}
|
|
100
100
|
if (prop.kind === ReferenceKind.EMBEDDED && EntityAssigner.validateEM(options.em)) {
|
|
101
101
|
return EntityAssigner.assignEmbeddable(entity, value, prop, options.em, options);
|
package/entity/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './EntityRepository.js';
|
|
2
2
|
export * from './EntityIdentifier.js';
|
|
3
|
-
export * from './EntityValidator.js';
|
|
4
3
|
export * from './EntityAssigner.js';
|
|
5
4
|
export * from './EntityHelper.js';
|
|
6
5
|
export * from './EntityFactory.js';
|
|
@@ -9,6 +8,7 @@ export * from './EntityLoader.js';
|
|
|
9
8
|
export * from './Reference.js';
|
|
10
9
|
export * from './BaseEntity.js';
|
|
11
10
|
export * from './WrappedEntity.js';
|
|
11
|
+
export * from './validators.js';
|
|
12
12
|
export * from './wrap.js';
|
|
13
13
|
export * from './defineEntity.js';
|
|
14
14
|
export * from './utils.js';
|
package/entity/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './EntityRepository.js';
|
|
2
2
|
export * from './EntityIdentifier.js';
|
|
3
|
-
export * from './EntityValidator.js';
|
|
4
3
|
export * from './EntityAssigner.js';
|
|
5
4
|
export * from './EntityHelper.js';
|
|
6
5
|
export * from './EntityFactory.js';
|
|
@@ -9,6 +8,7 @@ export * from './EntityLoader.js';
|
|
|
9
8
|
export * from './Reference.js';
|
|
10
9
|
export * from './BaseEntity.js';
|
|
11
10
|
export * from './WrappedEntity.js';
|
|
11
|
+
export * from './validators.js';
|
|
12
12
|
export * from './wrap.js';
|
|
13
13
|
export * from './defineEntity.js';
|
|
14
14
|
export * from './utils.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EntityData, EntityMetadata, EntityProperty, FilterQuery } from '../typings.js';
|
|
2
|
+
/** @internal */
|
|
3
|
+
export declare function validateProperty<T extends object>(prop: EntityProperty, givenValue: any, entity: T): void;
|
|
4
|
+
/** @internal */
|
|
5
|
+
export declare function validateEntity<T extends object>(entity: T, meta: EntityMetadata<T>): void;
|
|
6
|
+
/** @internal */
|
|
7
|
+
export declare function validateParams(params: any, type?: string, field?: string): void;
|
|
8
|
+
/** @internal */
|
|
9
|
+
export declare function validatePrimaryKey<T>(entity: EntityData<T>, meta: EntityMetadata<T>): void;
|
|
10
|
+
/** @internal */
|
|
11
|
+
export declare function validateEmptyWhere<T>(where: FilterQuery<T>): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Utils } from '../utils/Utils.js';
|
|
2
|
+
import { ValidationError } from '../errors.js';
|
|
3
|
+
import { isRaw } from '../utils/RawQueryFragment.js';
|
|
4
|
+
import { SCALAR_TYPES } from '../enums.js';
|
|
5
|
+
/** @internal */
|
|
6
|
+
export function validateProperty(prop, givenValue, entity) {
|
|
7
|
+
if (givenValue == null || isRaw(givenValue)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const expectedType = prop.runtimeType;
|
|
11
|
+
const propName = prop.embedded ? prop.name.replace(/~/g, '.') : prop.name;
|
|
12
|
+
const givenType = Utils.getObjectType(givenValue);
|
|
13
|
+
if (prop.enum && prop.items) {
|
|
14
|
+
/* v8 ignore next 3 */
|
|
15
|
+
if (!prop.items.some(it => it === givenValue)) {
|
|
16
|
+
throw ValidationError.fromWrongPropertyType(entity, propName, expectedType, givenType, givenValue);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
if (givenType !== expectedType && SCALAR_TYPES.has(expectedType)) {
|
|
21
|
+
throw ValidationError.fromWrongPropertyType(entity, propName, expectedType, givenType, givenValue);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function getValue(o, prop) {
|
|
26
|
+
if (prop.embedded && prop.embedded[0] in o) {
|
|
27
|
+
return o[prop.embedded[0]]?.[prop.embedded[1]];
|
|
28
|
+
}
|
|
29
|
+
return o[prop.name];
|
|
30
|
+
}
|
|
31
|
+
/** @internal */
|
|
32
|
+
export function validateEntity(entity, meta) {
|
|
33
|
+
for (const prop of meta.validateProps) {
|
|
34
|
+
validateProperty(prop, getValue(entity, prop), entity);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** @internal */
|
|
38
|
+
export function validateParams(params, type = 'search condition', field) {
|
|
39
|
+
if (Utils.isPrimaryKey(params) || Utils.isEntity(params)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(params)) {
|
|
43
|
+
return params.forEach(item => validateParams(item, type, field));
|
|
44
|
+
}
|
|
45
|
+
if (Utils.isPlainObject(params)) {
|
|
46
|
+
Object.keys(params).forEach(k => validateParams(params[k], type, k));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** @internal */
|
|
50
|
+
export function validatePrimaryKey(entity, meta) {
|
|
51
|
+
const pkExists = meta.primaryKeys.every(pk => entity[pk] != null) || (meta.serializedPrimaryKey && entity[meta.serializedPrimaryKey] != null);
|
|
52
|
+
if (!entity || !pkExists) {
|
|
53
|
+
throw ValidationError.fromMergeWithoutPK(meta);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** @internal */
|
|
57
|
+
export function validateEmptyWhere(where) {
|
|
58
|
+
if (Utils.isEmpty(where)) {
|
|
59
|
+
throw new Error(`You cannot call 'EntityManager.findOne()' with empty 'where' parameter`);
|
|
60
|
+
}
|
|
61
|
+
}
|
package/enums.d.ts
CHANGED
|
@@ -89,7 +89,7 @@ export declare enum QueryFlag {
|
|
|
89
89
|
IDENTITY_INSERT = "IDENTITY_INSERT",// mssql only
|
|
90
90
|
OUTPUT_TABLE = "OUTPUT_TABLE"
|
|
91
91
|
}
|
|
92
|
-
export declare const SCALAR_TYPES: string
|
|
92
|
+
export declare const SCALAR_TYPES: Set<string>;
|
|
93
93
|
export declare enum ReferenceKind {
|
|
94
94
|
SCALAR = "scalar",
|
|
95
95
|
ONE_TO_ONE = "1:1",
|
package/enums.js
CHANGED
|
@@ -99,7 +99,7 @@ export var QueryFlag;
|
|
|
99
99
|
QueryFlag["IDENTITY_INSERT"] = "IDENTITY_INSERT";
|
|
100
100
|
QueryFlag["OUTPUT_TABLE"] = "OUTPUT_TABLE";
|
|
101
101
|
})(QueryFlag || (QueryFlag = {}));
|
|
102
|
-
export const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp'];
|
|
102
|
+
export const SCALAR_TYPES = new Set(['string', 'number', 'boolean', 'bigint', 'Uint8Array', 'Date', 'Buffer', 'RegExp']);
|
|
103
103
|
export var ReferenceKind;
|
|
104
104
|
(function (ReferenceKind) {
|
|
105
105
|
ReferenceKind["SCALAR"] = "scalar";
|
package/errors.d.ts
CHANGED
|
@@ -8,7 +8,6 @@ export declare class ValidationError<T extends AnyEntity = AnyEntity> extends Er
|
|
|
8
8
|
getEntity(): AnyEntity | undefined;
|
|
9
9
|
static fromWrongPropertyType(entity: AnyEntity, property: string, expectedType: string, givenType: string, givenValue: string): ValidationError;
|
|
10
10
|
static fromWrongRepositoryType(entityName: string, repoType: string, method: string): ValidationError;
|
|
11
|
-
static fromCollectionNotInitialized(entity: AnyEntity, prop: EntityProperty): ValidationError;
|
|
12
11
|
static fromMergeWithoutPK(meta: EntityMetadata): ValidationError;
|
|
13
12
|
static transactionRequired(): ValidationError;
|
|
14
13
|
static entityNotManaged(entity: AnyEntity): ValidationError;
|
package/errors.js
CHANGED
|
@@ -23,11 +23,6 @@ export class ValidationError extends Error {
|
|
|
23
23
|
const msg = `Trying to use EntityRepository.${method}() with '${entityName}' entity while the repository is of type '${repoType}'`;
|
|
24
24
|
return new ValidationError(msg);
|
|
25
25
|
}
|
|
26
|
-
static fromCollectionNotInitialized(entity, prop) {
|
|
27
|
-
const entityName = entity.constructor.name;
|
|
28
|
-
const msg = `${entityName}.${prop.name} is not initialized, define it as '${prop.name} = new Collection<${prop.type}>(this);'`;
|
|
29
|
-
return new ValidationError(msg);
|
|
30
|
-
}
|
|
31
26
|
static fromMergeWithoutPK(meta) {
|
|
32
27
|
return new ValidationError(`You cannot merge entity '${meta.className}' without identifier!`);
|
|
33
28
|
}
|
|
@@ -162,7 +162,7 @@ export class MetadataDiscovery {
|
|
|
162
162
|
const processed = [];
|
|
163
163
|
for (const entity of targets) {
|
|
164
164
|
if (typeof entity === 'string') {
|
|
165
|
-
const { discoverEntities } = await import('@mikro-orm/core/file-discovery'
|
|
165
|
+
const { discoverEntities } = await import('@mikro-orm/core/file-discovery');
|
|
166
166
|
processed.push(...await discoverEntities(entity, { baseDir }));
|
|
167
167
|
}
|
|
168
168
|
else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityMetadata, type Dictionary, type
|
|
1
|
+
import { EntityMetadata, type Dictionary, type EntityName } from '../typings.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
3
|
export declare class MetadataStorage {
|
|
4
4
|
static readonly PATH_SYMBOL: unique symbol;
|
|
@@ -10,7 +10,6 @@ export declare class MetadataStorage {
|
|
|
10
10
|
static isKnownEntity(name: string): boolean;
|
|
11
11
|
static clear(): void;
|
|
12
12
|
getAll(): Dictionary<EntityMetadata>;
|
|
13
|
-
getByDiscriminatorColumn<T>(meta: EntityMetadata<T>, data: EntityData<T>): EntityMetadata<T> | undefined;
|
|
14
13
|
get<T = any>(entityName: EntityName<T>, init?: boolean, validate?: boolean): EntityMetadata<T>;
|
|
15
14
|
find<T = any>(entityName: EntityName<T>): EntityMetadata<T> | undefined;
|
|
16
15
|
has(entity: string): boolean;
|
|
@@ -33,14 +33,6 @@ export class MetadataStorage {
|
|
|
33
33
|
getAll() {
|
|
34
34
|
return this.metadata;
|
|
35
35
|
}
|
|
36
|
-
getByDiscriminatorColumn(meta, data) {
|
|
37
|
-
const value = data[meta.root.discriminatorColumn];
|
|
38
|
-
if (!value) {
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
const type = meta.root.discriminatorMap[value];
|
|
42
|
-
return this.metadata[type];
|
|
43
|
-
}
|
|
44
36
|
get(entityName, init = false, validate = true) {
|
|
45
37
|
entityName = Utils.className(entityName);
|
|
46
38
|
if (validate && !init && !this.has(entityName)) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function discoverEntities(): void;
|
package/not-supported.js
ADDED
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.76",
|
|
5
5
|
"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.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
8
8
|
".": "./index.js",
|
|
9
|
-
"./file-discovery":
|
|
9
|
+
"./file-discovery": {
|
|
10
|
+
"node": "./metadata/discover-entities.js",
|
|
11
|
+
"browser": "./not-supported.js"
|
|
12
|
+
}
|
|
10
13
|
},
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
package/typings.d.ts
CHANGED
|
@@ -472,6 +472,7 @@ export interface EntityMetadata<T = any> {
|
|
|
472
472
|
comparableProps: EntityProperty<T>[];
|
|
473
473
|
trackingProps: EntityProperty<T>[];
|
|
474
474
|
hydrateProps: EntityProperty<T>[];
|
|
475
|
+
validateProps: EntityProperty<T>[];
|
|
475
476
|
uniqueProps: EntityProperty<T>[];
|
|
476
477
|
getterProps: EntityProperty<T>[];
|
|
477
478
|
indexes: {
|
package/typings.js
CHANGED
|
@@ -83,6 +83,12 @@ export class EntityMetadata {
|
|
|
83
83
|
this.uniqueProps = this.props.filter(prop => prop.unique);
|
|
84
84
|
this.getterProps = this.props.filter(prop => prop.getter);
|
|
85
85
|
this.comparableProps = this.props.filter(prop => EntityComparator.isComparable(prop, this));
|
|
86
|
+
this.validateProps = this.props.filter(prop => {
|
|
87
|
+
if (prop.inherited || (prop.persist === false && prop.userDefined !== false)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return prop.kind === ReferenceKind.SCALAR && ['string', 'number', 'boolean', 'Date'].includes(prop.type);
|
|
91
|
+
});
|
|
86
92
|
this.hydrateProps = this.props.filter(prop => {
|
|
87
93
|
// `prop.userDefined` is either `undefined` or `false`
|
|
88
94
|
const discriminator = this.root.discriminatorColumn === prop.name && prop.userDefined === false;
|
|
@@ -2,19 +2,17 @@ import { type Configuration } from '../utils/Configuration.js';
|
|
|
2
2
|
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
|
3
3
|
import type { AnyEntity } from '../typings.js';
|
|
4
4
|
import { ChangeSet } from './ChangeSet.js';
|
|
5
|
-
import { type EntityValidator } from '../entity/EntityValidator.js';
|
|
6
5
|
import { type Collection } from '../entity/Collection.js';
|
|
7
6
|
import type { Platform } from '../platforms/Platform.js';
|
|
8
7
|
import type { EntityManager } from '../EntityManager.js';
|
|
9
8
|
export declare class ChangeSetComputer {
|
|
10
|
-
private readonly validator;
|
|
11
9
|
private readonly collectionUpdates;
|
|
12
10
|
private readonly metadata;
|
|
13
11
|
private readonly platform;
|
|
14
12
|
private readonly config;
|
|
15
13
|
private readonly em;
|
|
16
14
|
private readonly comparator;
|
|
17
|
-
constructor(
|
|
15
|
+
constructor(collectionUpdates: Set<Collection<AnyEntity>>, metadata: MetadataStorage, platform: Platform, config: Configuration, em: EntityManager);
|
|
18
16
|
computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
|
|
19
17
|
/**
|
|
20
18
|
* Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { Utils } from '../utils/Utils.js';
|
|
2
2
|
import { ChangeSet, ChangeSetType } from './ChangeSet.js';
|
|
3
3
|
import { helper } from '../entity/wrap.js';
|
|
4
|
+
import { validateEntity } from '../entity/validators.js';
|
|
4
5
|
import { ReferenceKind } from '../enums.js';
|
|
5
6
|
export class ChangeSetComputer {
|
|
6
|
-
validator;
|
|
7
7
|
collectionUpdates;
|
|
8
8
|
metadata;
|
|
9
9
|
platform;
|
|
10
10
|
config;
|
|
11
11
|
em;
|
|
12
12
|
comparator;
|
|
13
|
-
constructor(
|
|
14
|
-
this.validator = validator;
|
|
13
|
+
constructor(collectionUpdates, metadata, platform, config, em) {
|
|
15
14
|
this.collectionUpdates = collectionUpdates;
|
|
16
15
|
this.metadata = metadata;
|
|
17
16
|
this.platform = platform;
|
|
@@ -42,15 +41,13 @@ export class ChangeSetComputer {
|
|
|
42
41
|
}
|
|
43
42
|
const changeSet = new ChangeSet(entity, type, this.computePayload(entity), meta);
|
|
44
43
|
changeSet.originalEntity = wrapped.__originalEntityData;
|
|
45
|
-
if (this.config.get('validate')) {
|
|
46
|
-
this.validator.validate(changeSet.entity, changeSet.payload, meta);
|
|
47
|
-
}
|
|
48
44
|
for (const prop of meta.relations.filter(prop => prop.persist !== false || prop.userDefined === false)) {
|
|
49
45
|
this.processProperty(changeSet, prop);
|
|
50
46
|
}
|
|
51
47
|
if (changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload)) {
|
|
52
48
|
return null;
|
|
53
49
|
}
|
|
50
|
+
validateEntity(changeSet.entity, meta);
|
|
54
51
|
// Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
|
|
55
52
|
// to the `map` as we want to apply those only if something else changed.
|
|
56
53
|
if (type === ChangeSetType.UPDATE) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
|
2
2
|
import type { Dictionary, EntityDictionary, EntityMetadata, IHydrator } from '../typings.js';
|
|
3
3
|
import { type EntityFactory } from '../entity/EntityFactory.js';
|
|
4
|
-
import { type EntityValidator } from '../entity/EntityValidator.js';
|
|
5
4
|
import { type ChangeSet } from './ChangeSet.js';
|
|
6
5
|
import { type Configuration } from '../utils/Configuration.js';
|
|
7
6
|
import type { DriverMethodOptions, IDatabaseDriver } from '../drivers/IDatabaseDriver.js';
|
|
@@ -11,17 +10,17 @@ export declare class ChangeSetPersister {
|
|
|
11
10
|
private readonly metadata;
|
|
12
11
|
private readonly hydrator;
|
|
13
12
|
private readonly factory;
|
|
14
|
-
private readonly validator;
|
|
15
13
|
private readonly config;
|
|
16
14
|
private readonly em;
|
|
17
15
|
private readonly platform;
|
|
18
16
|
private readonly comparator;
|
|
19
17
|
private readonly usesReturningStatement;
|
|
20
|
-
constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory,
|
|
18
|
+
constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, config: Configuration, em: EntityManager);
|
|
21
19
|
executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
22
20
|
executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
23
21
|
executeDeletes<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
24
22
|
private runForEachSchema;
|
|
23
|
+
private validateRequired;
|
|
25
24
|
private processProperties;
|
|
26
25
|
private persistNewEntity;
|
|
27
26
|
private persistNewEntities;
|
|
@@ -3,25 +3,23 @@ import { helper } from '../entity/wrap.js';
|
|
|
3
3
|
import { ChangeSetType } from './ChangeSet.js';
|
|
4
4
|
import { isRaw } from '../utils/RawQueryFragment.js';
|
|
5
5
|
import { Utils } from '../utils/Utils.js';
|
|
6
|
-
import { OptimisticLockError } from '../errors.js';
|
|
6
|
+
import { OptimisticLockError, ValidationError } from '../errors.js';
|
|
7
7
|
import { ReferenceKind } from '../enums.js';
|
|
8
8
|
export class ChangeSetPersister {
|
|
9
9
|
driver;
|
|
10
10
|
metadata;
|
|
11
11
|
hydrator;
|
|
12
12
|
factory;
|
|
13
|
-
validator;
|
|
14
13
|
config;
|
|
15
14
|
em;
|
|
16
15
|
platform;
|
|
17
16
|
comparator;
|
|
18
17
|
usesReturningStatement;
|
|
19
|
-
constructor(driver, metadata, hydrator, factory,
|
|
18
|
+
constructor(driver, metadata, hydrator, factory, config, em) {
|
|
20
19
|
this.driver = driver;
|
|
21
20
|
this.metadata = metadata;
|
|
22
21
|
this.hydrator = hydrator;
|
|
23
22
|
this.factory = factory;
|
|
24
|
-
this.validator = validator;
|
|
25
23
|
this.config = config;
|
|
26
24
|
this.em = em;
|
|
27
25
|
this.platform = this.driver.getPlatform();
|
|
@@ -81,13 +79,32 @@ export class ChangeSetPersister {
|
|
|
81
79
|
await this[method](group, ...args, options, true);
|
|
82
80
|
}
|
|
83
81
|
}
|
|
82
|
+
validateRequired(entity) {
|
|
83
|
+
const wrapped = helper(entity);
|
|
84
|
+
for (const prop of wrapped.__meta.props) {
|
|
85
|
+
if (!prop.nullable &&
|
|
86
|
+
!prop.autoincrement &&
|
|
87
|
+
!prop.default &&
|
|
88
|
+
!prop.defaultRaw &&
|
|
89
|
+
!prop.onCreate &&
|
|
90
|
+
!prop.generated &&
|
|
91
|
+
!prop.embedded &&
|
|
92
|
+
![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
|
|
93
|
+
prop.name !== wrapped.__meta.root.discriminatorColumn &&
|
|
94
|
+
prop.type !== 'ObjectId' &&
|
|
95
|
+
prop.persist !== false &&
|
|
96
|
+
entity[prop.name] == null) {
|
|
97
|
+
throw ValidationError.propertyRequired(entity, prop);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
84
101
|
processProperties(changeSet) {
|
|
85
102
|
const meta = this.metadata.find(changeSet.name);
|
|
86
103
|
for (const prop of meta.relations) {
|
|
87
104
|
this.processProperty(changeSet, prop);
|
|
88
105
|
}
|
|
89
106
|
if (changeSet.type === ChangeSetType.CREATE && this.config.get('validateRequired')) {
|
|
90
|
-
this.
|
|
107
|
+
this.validateRequired(changeSet.entity);
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
async persistNewEntity(meta, changeSet, options) {
|
|
@@ -42,8 +42,8 @@ export class UnitOfWork {
|
|
|
42
42
|
this.identityMap = new IdentityMap(this.platform.getDefaultSchemaName());
|
|
43
43
|
this.eventManager = this.em.getEventManager();
|
|
44
44
|
this.comparator = this.em.getComparator();
|
|
45
|
-
this.changeSetComputer = new ChangeSetComputer(this.
|
|
46
|
-
this.changeSetPersister = new ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.
|
|
45
|
+
this.changeSetComputer = new ChangeSetComputer(this.collectionUpdates, this.metadata, this.platform, this.em.config, this.em);
|
|
46
|
+
this.changeSetPersister = new ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.config, this.em);
|
|
47
47
|
}
|
|
48
48
|
merge(entity, visited) {
|
|
49
49
|
const wrapped = helper(entity);
|
package/utils/Configuration.d.ts
CHANGED
|
@@ -738,20 +738,6 @@ export interface Options<Driver extends IDatabaseDriver = IDatabaseDriver, EM ex
|
|
|
738
738
|
* @see https://mikro-orm.io/docs/read-connections
|
|
739
739
|
*/
|
|
740
740
|
replicas?: ConnectionOptions[];
|
|
741
|
-
/**
|
|
742
|
-
* Enable strict mode which disables automatic data type conversion.
|
|
743
|
-
* In strict mode, the ORM throws errors instead of fixing wrong data types.
|
|
744
|
-
* @default false
|
|
745
|
-
* @see https://mikro-orm.io/docs/property-validation
|
|
746
|
-
*/
|
|
747
|
-
strict?: boolean;
|
|
748
|
-
/**
|
|
749
|
-
* Enable runtime property validation before persisting.
|
|
750
|
-
* Has performance implications and is usually not needed.
|
|
751
|
-
* @default false
|
|
752
|
-
* @see https://mikro-orm.io/docs/property-validation
|
|
753
|
-
*/
|
|
754
|
-
validate?: boolean;
|
|
755
741
|
/**
|
|
756
742
|
* Validate that required properties are set on new entities before insert.
|
|
757
743
|
* @default true
|
package/utils/clone.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* clone `EventEmitter`s to get around https://github.com/mikro-orm/mikro-orm/issues/2748
|
|
4
4
|
* @internal
|
|
5
5
|
*/
|
|
6
|
-
import { EventEmitter } from 'node:events';
|
|
7
6
|
import { RawQueryFragment } from './RawQueryFragment.js';
|
|
8
7
|
/**
|
|
9
8
|
* Get the property descriptor of a property on an object or its prototype chain.
|
|
@@ -34,7 +33,7 @@ export function clone(parent, respectCustomCloneMethod = true) {
|
|
|
34
33
|
if (raw && respectCustomCloneMethod) {
|
|
35
34
|
return raw.clone();
|
|
36
35
|
}
|
|
37
|
-
if (typeof parent !== 'object'
|
|
36
|
+
if (typeof parent !== 'object') {
|
|
38
37
|
return parent;
|
|
39
38
|
}
|
|
40
39
|
if (respectCustomCloneMethod && 'clone' in parent && typeof parent.clone === 'function') {
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { EntityData, EntityMetadata, EntityProperty, FilterQuery } from '../typings.js';
|
|
2
|
-
export declare class EntityValidator {
|
|
3
|
-
private strict;
|
|
4
|
-
KNOWN_TYPES: Set<string>;
|
|
5
|
-
constructor(strict: boolean);
|
|
6
|
-
validate<T extends object>(entity: T, payload: any, meta: EntityMetadata<T>): void;
|
|
7
|
-
validateRequired<T extends object>(entity: T): void;
|
|
8
|
-
validateProperty<T extends object>(prop: EntityProperty, givenValue: any, entity: T): any;
|
|
9
|
-
validateParams(params: any, type?: string, field?: string): void;
|
|
10
|
-
validatePrimaryKey<T>(entity: EntityData<T>, meta: EntityMetadata<T>): void;
|
|
11
|
-
validateEmptyWhere<T>(where: FilterQuery<T>): void;
|
|
12
|
-
private getValue;
|
|
13
|
-
private setValue;
|
|
14
|
-
private validateCollection;
|
|
15
|
-
private fixTypes;
|
|
16
|
-
private fixDateType;
|
|
17
|
-
private fixNumberType;
|
|
18
|
-
private fixBooleanType;
|
|
19
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { ReferenceKind } from '../enums.js';
|
|
2
|
-
import { Utils } from '../utils/Utils.js';
|
|
3
|
-
import { ValidationError } from '../errors.js';
|
|
4
|
-
import { helper } from './wrap.js';
|
|
5
|
-
import { RawQueryFragment } from '../utils/RawQueryFragment.js';
|
|
6
|
-
export class EntityValidator {
|
|
7
|
-
strict;
|
|
8
|
-
KNOWN_TYPES = new Set(['string', 'number', 'boolean', 'bigint', 'Uint8Array', 'Date', 'Buffer', 'RegExp']);
|
|
9
|
-
constructor(strict) {
|
|
10
|
-
this.strict = strict;
|
|
11
|
-
}
|
|
12
|
-
validate(entity, payload, meta) {
|
|
13
|
-
meta.props.forEach(prop => {
|
|
14
|
-
if (prop.inherited || (prop.persist === false && prop.userDefined !== false)) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
18
|
-
this.validateCollection(entity, prop);
|
|
19
|
-
}
|
|
20
|
-
const SCALAR_TYPES = ['string', 'number', 'boolean', 'Date'];
|
|
21
|
-
if (prop.kind !== ReferenceKind.SCALAR || !SCALAR_TYPES.includes(prop.type)) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const newValue = this.validateProperty(prop, this.getValue(payload, prop), entity);
|
|
25
|
-
if (this.getValue(payload, prop) === newValue) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
this.setValue(payload, prop, newValue);
|
|
29
|
-
if (entity[prop.name]) {
|
|
30
|
-
entity[prop.name] = payload[prop.name];
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
validateRequired(entity) {
|
|
35
|
-
const wrapped = helper(entity);
|
|
36
|
-
for (const prop of wrapped.__meta.props) {
|
|
37
|
-
if (!prop.nullable &&
|
|
38
|
-
!prop.autoincrement &&
|
|
39
|
-
!prop.default &&
|
|
40
|
-
!prop.defaultRaw &&
|
|
41
|
-
!prop.onCreate &&
|
|
42
|
-
!prop.generated &&
|
|
43
|
-
!prop.embedded &&
|
|
44
|
-
![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
|
|
45
|
-
prop.name !== wrapped.__meta.root.discriminatorColumn &&
|
|
46
|
-
prop.type !== 'ObjectId' &&
|
|
47
|
-
prop.persist !== false &&
|
|
48
|
-
entity[prop.name] == null) {
|
|
49
|
-
throw ValidationError.propertyRequired(entity, prop);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
validateProperty(prop, givenValue, entity) {
|
|
54
|
-
if (givenValue == null || givenValue instanceof RawQueryFragment) {
|
|
55
|
-
return givenValue;
|
|
56
|
-
}
|
|
57
|
-
const expectedType = prop.runtimeType;
|
|
58
|
-
const propName = prop.embedded ? prop.name.replace(/~/g, '.') : prop.name;
|
|
59
|
-
let givenType = Utils.getObjectType(givenValue);
|
|
60
|
-
let ret = givenValue;
|
|
61
|
-
if (!this.strict) {
|
|
62
|
-
ret = this.fixTypes(expectedType, givenType, givenValue);
|
|
63
|
-
givenType = Utils.getObjectType(ret);
|
|
64
|
-
}
|
|
65
|
-
if (prop.enum && prop.items) {
|
|
66
|
-
/* v8 ignore next 3 */
|
|
67
|
-
if (!prop.items.some(it => it === givenValue)) {
|
|
68
|
-
throw ValidationError.fromWrongPropertyType(entity, propName, expectedType, givenType, givenValue);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
if (givenType !== expectedType && this.KNOWN_TYPES.has(expectedType)) {
|
|
73
|
-
throw ValidationError.fromWrongPropertyType(entity, propName, expectedType, givenType, givenValue);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return ret;
|
|
77
|
-
}
|
|
78
|
-
validateParams(params, type = 'search condition', field) {
|
|
79
|
-
if (Utils.isPrimaryKey(params) || Utils.isEntity(params)) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (Array.isArray(params)) {
|
|
83
|
-
return params.forEach(item => this.validateParams(item, type, field));
|
|
84
|
-
}
|
|
85
|
-
if (Utils.isPlainObject(params)) {
|
|
86
|
-
Object.keys(params).forEach(k => {
|
|
87
|
-
this.validateParams(params[k], type, k);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
validatePrimaryKey(entity, meta) {
|
|
92
|
-
const pkExists = meta.primaryKeys.every(pk => entity[pk] != null) || (meta.serializedPrimaryKey && entity[meta.serializedPrimaryKey] != null);
|
|
93
|
-
if (!entity || !pkExists) {
|
|
94
|
-
throw ValidationError.fromMergeWithoutPK(meta);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
validateEmptyWhere(where) {
|
|
98
|
-
if (Utils.isEmpty(where)) {
|
|
99
|
-
throw new Error(`You cannot call 'EntityManager.findOne()' with empty 'where' parameter`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
getValue(o, prop) {
|
|
103
|
-
if (prop.embedded && prop.embedded[0] in o) {
|
|
104
|
-
return o[prop.embedded[0]]?.[prop.embedded[1]];
|
|
105
|
-
}
|
|
106
|
-
return o[prop.name];
|
|
107
|
-
}
|
|
108
|
-
setValue(o, prop, v) {
|
|
109
|
-
/* v8 ignore next 3 */
|
|
110
|
-
if (prop.embedded && prop.embedded[0] in o) {
|
|
111
|
-
return o[prop.embedded[0]][prop.embedded[1]] = v;
|
|
112
|
-
}
|
|
113
|
-
o[prop.name] = v;
|
|
114
|
-
}
|
|
115
|
-
validateCollection(entity, prop) {
|
|
116
|
-
if (prop.hydrate !== false && helper(entity).__initialized && !entity[prop.name]) {
|
|
117
|
-
throw ValidationError.fromCollectionNotInitialized(entity, prop);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
fixTypes(expectedType, givenType, givenValue) {
|
|
121
|
-
if (expectedType === 'Date' && ['string', 'number'].includes(givenType)) {
|
|
122
|
-
givenValue = this.fixDateType(givenValue);
|
|
123
|
-
}
|
|
124
|
-
if (expectedType === 'number' && givenType === 'string') {
|
|
125
|
-
givenValue = this.fixNumberType(givenValue);
|
|
126
|
-
}
|
|
127
|
-
if (expectedType === 'boolean' && givenType === 'number') {
|
|
128
|
-
givenValue = this.fixBooleanType(givenValue);
|
|
129
|
-
}
|
|
130
|
-
return givenValue;
|
|
131
|
-
}
|
|
132
|
-
fixDateType(givenValue) {
|
|
133
|
-
let date;
|
|
134
|
-
if (typeof givenValue === 'string' && givenValue.match(/^-?\d+(\.\d+)?$/)) {
|
|
135
|
-
date = new Date(+givenValue);
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
date = new Date(givenValue);
|
|
139
|
-
}
|
|
140
|
-
return date.toString() !== 'Invalid Date' ? date : givenValue;
|
|
141
|
-
}
|
|
142
|
-
fixNumberType(givenValue) {
|
|
143
|
-
const num = +givenValue;
|
|
144
|
-
return '' + num === givenValue ? num : givenValue;
|
|
145
|
-
}
|
|
146
|
-
fixBooleanType(givenValue) {
|
|
147
|
-
const bool = !!givenValue;
|
|
148
|
-
return +bool === givenValue ? bool : givenValue;
|
|
149
|
-
}
|
|
150
|
-
}
|