@mikro-orm/core 7.0.0-dev.52 → 7.0.0-dev.54

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.
@@ -48,6 +48,7 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
48
48
  setMetadata(metadata: MetadataStorage): void;
49
49
  getMetadata(): MetadataStorage;
50
50
  getDependencies(): string[];
51
+ protected isPopulated<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T>, hint: PopulateOptions<T>, name?: string): boolean;
51
52
  protected processCursorOptions<T extends object, P extends string>(meta: EntityMetadata<T>, options: FindOptions<T, P, any, any>, orderBy: OrderDefinition<T>): {
52
53
  orderBy: OrderDefinition<T>[];
53
54
  where: FilterQuery<T>;
@@ -105,6 +105,15 @@ export class DatabaseDriver {
105
105
  getDependencies() {
106
106
  return this.dependencies;
107
107
  }
108
+ isPopulated(meta, prop, hint, name) {
109
+ if (hint.field === prop.name || hint.field === name || hint.all) {
110
+ return true;
111
+ }
112
+ if (prop.embedded && hint.children && meta.properties[prop.embedded[0]].name === hint.field) {
113
+ return hint.children.some(c => this.isPopulated(meta, prop, c, prop.embedded[1]));
114
+ }
115
+ return false;
116
+ }
108
117
  processCursorOptions(meta, options, orderBy) {
109
118
  const { first, last, before, after, overfetch } = options;
110
119
  const limit = first ?? last;
@@ -45,7 +45,7 @@ export class ArrayCollection {
45
45
  if (items.length === 0) {
46
46
  return [];
47
47
  }
48
- field ??= targetMeta.compositePK ? targetMeta.primaryKeys : targetMeta.serializedPrimaryKey;
48
+ field ??= targetMeta.compositePK ? targetMeta.primaryKeys : (targetMeta.serializedPrimaryKey ?? targetMeta.primaryKeys[0]);
49
49
  const cb = (i, f) => {
50
50
  if (Utils.isEntity(i[f], true)) {
51
51
  return wrap(i[f], true).getPrimaryKey();
@@ -38,8 +38,8 @@ export class EntityFactory {
38
38
  this.hydrate(entity, meta, data, options);
39
39
  return entity;
40
40
  }
41
- if (this.platform.usesDifferentSerializedPrimaryKey()) {
42
- meta.primaryKeys.forEach(pk => this.denormalizePrimaryKey(data, pk, meta.properties[pk]));
41
+ if (meta.serializedPrimaryKey) {
42
+ this.denormalizePrimaryKey(meta, data);
43
43
  }
44
44
  const meta2 = this.processDiscriminatorColumn(meta, data);
45
45
  const exists = this.findEntity(data, meta2, options);
@@ -284,15 +284,15 @@ export class EntityFactory {
284
284
  /**
285
285
  * denormalize PK to value required by driver (e.g. ObjectId)
286
286
  */
287
- denormalizePrimaryKey(data, primaryKey, prop) {
288
- const pk = this.platform.getSerializedPrimaryKeyField(primaryKey);
289
- if (data[pk] != null || data[primaryKey] != null) {
290
- let id = (data[pk] || data[primaryKey]);
291
- if (prop.type.toLowerCase() === 'objectid') {
292
- id = this.platform.denormalizePrimaryKey(id);
293
- }
294
- delete data[pk];
295
- data[primaryKey] = id;
287
+ denormalizePrimaryKey(meta, data) {
288
+ const pk = meta.getPrimaryProp();
289
+ const spk = meta.properties[meta.serializedPrimaryKey];
290
+ if (!spk?.serializedPrimaryKey) {
291
+ return;
292
+ }
293
+ if (pk.type.toLowerCase() === 'objectid' && (data[pk.name] != null || data[spk.name] != null)) {
294
+ data[pk.name] = this.platform.denormalizePrimaryKey((data[spk.name] || data[pk.name]));
295
+ delete data[spk.name];
296
296
  }
297
297
  }
298
298
  /**
@@ -89,7 +89,7 @@ export class EntityValidator {
89
89
  }
90
90
  }
91
91
  validatePrimaryKey(entity, meta) {
92
- const pkExists = meta.primaryKeys.every(pk => entity[pk] != null) || entity[meta.serializedPrimaryKey] != null;
92
+ const pkExists = meta.primaryKeys.every(pk => entity[pk] != null) || (meta.serializedPrimaryKey && entity[meta.serializedPrimaryKey] != null);
93
93
  if (!entity || !pkExists) {
94
94
  throw ValidationError.fromMergeWithoutPK(meta);
95
95
  }
@@ -75,7 +75,7 @@ export class EntitySchema {
75
75
  }
76
76
  addSerializedPrimaryKey(name, type, options = {}) {
77
77
  this._meta.serializedPrimaryKey = name;
78
- this.addProperty(name, type, options);
78
+ this.addProperty(name, type, { serializedPrimaryKey: true, ...options });
79
79
  }
80
80
  addEmbedded(name, options) {
81
81
  this.renameCompositeOptions(name, options);
@@ -497,10 +497,9 @@ export class MetadataDiscovery {
497
497
  }
498
498
  this.initOwnColumns(meta);
499
499
  meta.simplePK = pks.length === 1 && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType && pks[0].runtimeType !== 'Date';
500
- meta.serializedPrimaryKey = this.platform.getSerializedPrimaryKeyField(meta.primaryKeys[0]);
501
- const serializedPKProp = meta.properties[meta.serializedPrimaryKey];
502
- if (serializedPKProp && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
503
- serializedPKProp.persist = false;
500
+ meta.serializedPrimaryKey ??= meta.props.find(prop => prop.serializedPrimaryKey)?.name;
501
+ if (meta.serializedPrimaryKey && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
502
+ meta.properties[meta.serializedPrimaryKey].persist ??= false;
504
503
  }
505
504
  if (this.platform.usesPivotTable()) {
506
505
  return Object.values(meta.properties)
@@ -1110,8 +1109,18 @@ export class MetadataDiscovery {
1110
1109
  }
1111
1110
  // `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
1112
1111
  if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
1113
- prop.customType = new prop.type();
1114
- prop.type = prop.customType.constructor.name;
1112
+ // if the type is an ORM defined mapped type without `ensureComparable: true`,
1113
+ // we use just the type name, to have more performant hydration code
1114
+ const type = Utils.keys(t).find(type => {
1115
+ return !Type.getType(t[type]).ensureComparable(meta, prop) && prop.type === t[type];
1116
+ });
1117
+ if (type) {
1118
+ prop.type = type === 'datetime' ? 'Date' : type;
1119
+ }
1120
+ else {
1121
+ prop.customType = new prop.type();
1122
+ prop.type = prop.customType.constructor.name;
1123
+ }
1115
1124
  }
1116
1125
  if (simple) {
1117
1126
  return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
3
  "type": "module",
4
- "version": "7.0.0-dev.52",
4
+ "version": "7.0.0-dev.54",
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",
@@ -54,7 +54,7 @@
54
54
  "dataloader": "2.2.3",
55
55
  "dotenv": "17.2.3",
56
56
  "esprima": "4.0.1",
57
- "mikro-orm": "7.0.0-dev.52",
57
+ "mikro-orm": "7.0.0-dev.54",
58
58
  "reflect-metadata": "0.2.2",
59
59
  "tinyglobby": "0.2.13"
60
60
  }
@@ -48,11 +48,6 @@ export declare abstract class Platform {
48
48
  * Converts scalar primary key representation to native driver wrapper (e.g. string to mongodb's ObjectId)
49
49
  */
50
50
  denormalizePrimaryKey(data: IPrimaryKey): IPrimaryKey;
51
- /**
52
- * Used when serializing via toObject and toJSON methods, allows to use different PK field name (like `id` instead of `_id`)
53
- */
54
- getSerializedPrimaryKeyField(field: string): string;
55
- usesDifferentSerializedPrimaryKey(): boolean;
56
51
  /**
57
52
  * Returns the SQL specific for the platform to get the current timestamp
58
53
  */
@@ -78,15 +78,6 @@ export class Platform {
78
78
  denormalizePrimaryKey(data) {
79
79
  return data;
80
80
  }
81
- /**
82
- * Used when serializing via toObject and toJSON methods, allows to use different PK field name (like `id` instead of `_id`)
83
- */
84
- getSerializedPrimaryKeyField(field) {
85
- return field;
86
- }
87
- usesDifferentSerializedPrimaryKey() {
88
- return false;
89
- }
90
81
  /**
91
82
  * Returns the SQL specific for the platform to get the current timestamp
92
83
  */
@@ -85,7 +85,7 @@ export class EntitySerializer {
85
85
  }
86
86
  const visible = typeof val !== 'undefined' && !(val === null && options.skipNull);
87
87
  if (visible) {
88
- ret[this.propertyName(meta, prop, wrapped.__platform)] = val;
88
+ ret[this.propertyName(meta, prop)] = val;
89
89
  }
90
90
  }
91
91
  if (contextCreated) {
@@ -99,26 +99,26 @@ export class EntitySerializer {
99
99
  if (prop.getterName != null) {
100
100
  const visible = entity[prop.getterName] instanceof Function && isVisible(meta, prop.name, options);
101
101
  if (visible) {
102
- ret[this.propertyName(meta, prop.name, wrapped.__platform)] = this.processProperty(prop.getterName, entity, options);
102
+ ret[this.propertyName(meta, prop.name)] = this.processProperty(prop.getterName, entity, options);
103
103
  }
104
104
  }
105
105
  else {
106
106
  // decorated getters
107
107
  const visible = typeof entity[prop.name] !== 'undefined' && isVisible(meta, prop.name, options);
108
108
  if (visible) {
109
- ret[this.propertyName(meta, prop.name, wrapped.__platform)] = this.processProperty(prop.name, entity, options);
109
+ ret[this.propertyName(meta, prop.name)] = this.processProperty(prop.name, entity, options);
110
110
  }
111
111
  }
112
112
  }
113
113
  return ret;
114
114
  }
115
- static propertyName(meta, prop, platform) {
115
+ static propertyName(meta, prop) {
116
116
  /* v8 ignore next 3 */
117
117
  if (meta.properties[prop]?.serializedName) {
118
118
  return meta.properties[prop].serializedName;
119
119
  }
120
- if (meta.properties[prop]?.primary && platform) {
121
- return platform.getSerializedPrimaryKeyField(prop);
120
+ if (meta.properties[prop]?.primary && meta.serializedPrimaryKey) {
121
+ return meta.serializedPrimaryKey;
122
122
  }
123
123
  return prop;
124
124
  }
@@ -77,7 +77,7 @@ export class EntityTransformer {
77
77
  if (typeof val === 'undefined') {
78
78
  continue;
79
79
  }
80
- ret[this.propertyName(meta, prop, wrapped.__platform, raw)] = val;
80
+ ret[this.propertyName(meta, prop, raw)] = val;
81
81
  }
82
82
  if (!wrapped.isInitialized() && wrapped.hasPrimaryKey()) {
83
83
  return ret;
@@ -88,7 +88,7 @@ export class EntityTransformer {
88
88
  const visible = !prop.hidden && entity[prop.getterName] instanceof Function;
89
89
  const populated = root.isMarkedAsPopulated(meta.className, prop.name);
90
90
  if (visible) {
91
- ret[this.propertyName(meta, prop.name, wrapped.__platform, raw)] = this.processProperty(prop.getterName, entity, raw, populated);
91
+ ret[this.propertyName(meta, prop.name, raw)] = this.processProperty(prop.getterName, entity, raw, populated);
92
92
  }
93
93
  }
94
94
  else {
@@ -96,7 +96,7 @@ export class EntityTransformer {
96
96
  const visible = !prop.hidden && typeof entity[prop.name] !== 'undefined';
97
97
  const populated = root.isMarkedAsPopulated(meta.className, prop.name);
98
98
  if (visible) {
99
- ret[this.propertyName(meta, prop.name, wrapped.__platform, raw)] = this.processProperty(prop.name, entity, raw, populated);
99
+ ret[this.propertyName(meta, prop.name, raw)] = this.processProperty(prop.name, entity, raw, populated);
100
100
  }
101
101
  }
102
102
  }
@@ -105,15 +105,15 @@ export class EntityTransformer {
105
105
  }
106
106
  return ret;
107
107
  }
108
- static propertyName(meta, prop, platform, raw) {
108
+ static propertyName(meta, prop, raw) {
109
109
  if (raw) {
110
110
  return prop;
111
111
  }
112
112
  if (meta.properties[prop].serializedName) {
113
113
  return meta.properties[prop].serializedName;
114
114
  }
115
- if (meta.properties[prop].primary && platform) {
116
- return platform.getSerializedPrimaryKeyField(prop);
115
+ if (meta.properties[prop].primary && meta.serializedPrimaryKey) {
116
+ return meta.serializedPrimaryKey;
117
117
  }
118
118
  return prop;
119
119
  }
@@ -4,6 +4,5 @@ import type { EntityProperty } from '../typings.js';
4
4
  export declare class BlobType extends Uint8ArrayType {
5
5
  convertToJSValue(value: Buffer): Buffer | null;
6
6
  compareAsType(): string;
7
- ensureComparable(): boolean;
8
7
  getColumnType(prop: EntityProperty, platform: Platform): string;
9
8
  }
package/types/BlobType.js CHANGED
@@ -12,9 +12,6 @@ export class BlobType extends Uint8ArrayType {
12
12
  compareAsType() {
13
13
  return 'Buffer';
14
14
  }
15
- ensureComparable() {
16
- return false;
17
- }
18
15
  getColumnType(prop, platform) {
19
16
  return platform.getBlobDeclarationSQL();
20
17
  }
@@ -4,5 +4,6 @@ import type { EntityProperty } from '../typings.js';
4
4
  export declare class BooleanType extends Type<boolean | null | undefined, boolean | null | undefined> {
5
5
  getColumnType(prop: EntityProperty, platform: Platform): string;
6
6
  compareAsType(): string;
7
+ convertToJSValue(value: boolean | null | undefined): boolean | null | undefined;
7
8
  ensureComparable(): boolean;
8
9
  }
@@ -6,6 +6,9 @@ export class BooleanType extends Type {
6
6
  compareAsType() {
7
7
  return 'boolean';
8
8
  }
9
+ convertToJSValue(value) {
10
+ return Boolean(value);
11
+ }
9
12
  ensureComparable() {
10
13
  return false;
11
14
  }
@@ -5,6 +5,5 @@ export declare class Uint8ArrayType extends Type<Uint8Array | null> {
5
5
  convertToDatabaseValue(value: Uint8Array): Buffer;
6
6
  convertToJSValue(value: Buffer): Uint8Array | null;
7
7
  compareAsType(): string;
8
- ensureComparable(): boolean;
9
8
  getColumnType(prop: EntityProperty, platform: Platform): string;
10
9
  }
@@ -22,9 +22,6 @@ export class Uint8ArrayType extends Type {
22
22
  compareAsType() {
23
23
  return 'Buffer';
24
24
  }
25
- ensureComparable() {
26
- return false;
27
- }
28
25
  getColumnType(prop, platform) {
29
26
  return platform.getBlobDeclarationSQL();
30
27
  }
package/typings.d.ts CHANGED
@@ -462,7 +462,7 @@ export interface EntityMetadata<T = any> {
462
462
  compositePK: boolean;
463
463
  versionProperty: EntityKey<T>;
464
464
  concurrencyCheckKeys: Set<EntityKey<T>>;
465
- serializedPrimaryKey: EntityKey<T>;
465
+ serializedPrimaryKey?: EntityKey<T>;
466
466
  properties: {
467
467
  [K in EntityKey<T>]: EntityProperty<T>;
468
468
  };
@@ -1,4 +1,4 @@
1
- import type { EntityData, EntityDictionary, EntityMetadata, EntityProperty, IMetadataStorage } from '../typings.js';
1
+ import type { EntityData, EntityDictionary, EntityMetadata, EntityName, EntityProperty, IMetadataStorage } from '../typings.js';
2
2
  import type { Platform } from '../platforms/Platform.js';
3
3
  type Comparator<T> = (a: T, b: T, options?: {
4
4
  includeInverseSides?: boolean;
@@ -48,7 +48,7 @@ export declare class EntityComparator {
48
48
  /**
49
49
  * @internal Highly performance-sensitive method.
50
50
  */
51
- getSnapshotGenerator<T>(entityName: string): SnapshotGenerator<T>;
51
+ getSnapshotGenerator<T>(entityName: EntityName<T>): SnapshotGenerator<T>;
52
52
  /**
53
53
  * @internal
54
54
  */
@@ -199,6 +199,7 @@ export class EntityComparator {
199
199
  * @internal Highly performance-sensitive method.
200
200
  */
201
201
  getSnapshotGenerator(entityName) {
202
+ entityName = Utils.className(entityName);
202
203
  const exists = this.snapshotGenerators.get(entityName);
203
204
  if (exists) {
204
205
  return exists;
package/utils/Utils.js CHANGED
@@ -447,7 +447,7 @@ export class Utils {
447
447
  if (meta.compositePK) {
448
448
  return this.getCompositeKeyValue(data, meta);
449
449
  }
450
- return data[meta.primaryKeys[0]] || data[meta.serializedPrimaryKey] || null;
450
+ return data[meta.primaryKeys[0]] ?? data[meta.serializedPrimaryKey] ?? null;
451
451
  }
452
452
  return null;
453
453
  }