@mikro-orm/core 7.0.0-dev.53 → 7.0.0-dev.55

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/MikroORM.d.ts CHANGED
@@ -28,7 +28,7 @@ export declare class MikroORM<Driver extends IDatabaseDriver = IDatabaseDriver,
28
28
  * - no loading of the `config` file, `options` parameter is mandatory
29
29
  * - no support for folder based discovery
30
30
  */
31
- constructor(options: Options<Driver, EM>);
31
+ constructor(options: Options<Driver, EM, Entities>);
32
32
  /**
33
33
  * Connects to the database.
34
34
  */
@@ -36,7 +36,7 @@ export declare class MikroORM<Driver extends IDatabaseDriver = IDatabaseDriver,
36
36
  /**
37
37
  * Reconnects, possibly to a different database.
38
38
  */
39
- reconnect(options?: Options): Promise<void>;
39
+ reconnect(options?: Partial<Options<Driver, EM, Entities>>): Promise<void>;
40
40
  /**
41
41
  * Checks whether the database connection is active.
42
42
  */
@@ -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;
@@ -1,4 +1,4 @@
1
- import { type Constructor, EntityMetadata } from '../typings.js';
1
+ import { type EntityClass, EntityMetadata } from '../typings.js';
2
2
  import type { Configuration } from '../utils/Configuration.js';
3
3
  import { MetadataStorage } from './MetadataStorage.js';
4
4
  import { EntitySchema } from './EntitySchema.js';
@@ -24,8 +24,7 @@ export declare class MetadataDiscovery {
24
24
  private findEntities;
25
25
  private discoverMissingTargets;
26
26
  private tryDiscoverTargets;
27
- private discoverDirectories;
28
- discoverReferences<T>(refs: (Constructor<T> | EntitySchema<T>)[], validate?: boolean): EntityMetadata<T>[];
27
+ discoverReferences<T>(refs: Iterable<EntityClass<T> | EntitySchema<T>>, validate?: boolean): EntityMetadata<T>[];
29
28
  reset(className: string): void;
30
29
  private getSchema;
31
30
  private discoverEntity;
@@ -67,6 +66,5 @@ export declare class MetadataDiscovery {
67
66
  private getPrefix;
68
67
  private initUnsigned;
69
68
  private initIndexes;
70
- private getEntityClassOrSchema;
71
69
  private shouldForceConstructorUsage;
72
70
  }
@@ -1,5 +1,4 @@
1
- import { basename, extname } from 'node:path';
2
- import { glob } from 'tinyglobby';
1
+ import { extname } from 'node:path';
3
2
  import { EntityMetadata } from '../typings.js';
4
3
  import { Utils } from '../utils/Utils.js';
5
4
  import { MetadataValidator } from './MetadataValidator.js';
@@ -32,6 +31,7 @@ export class MetadataDiscovery {
32
31
  this.schemaHelper = this.platform.getSchemaHelper();
33
32
  }
34
33
  async discover(preferTs = true) {
34
+ this.discovered.length = 0;
35
35
  const startTime = Date.now();
36
36
  this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)}`);
37
37
  await this.findEntities(preferTs);
@@ -48,9 +48,11 @@ export class MetadataDiscovery {
48
48
  return storage;
49
49
  }
50
50
  discoverSync() {
51
+ this.discovered.length = 0;
51
52
  const startTime = Date.now();
52
53
  this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)} in sync mode`);
53
- this.findEntities();
54
+ const refs = this.config.get('entities');
55
+ this.discoverReferences(refs);
54
56
  for (const meta of this.discovered) {
55
57
  /* v8 ignore next */
56
58
  void this.config.get('discovery').onMetadata?.(meta, this.platform);
@@ -154,21 +156,23 @@ export class MetadataDiscovery {
154
156
  return meta;
155
157
  });
156
158
  }
157
- findEntities(preferTs, sync = false) {
158
- this.discovered.length = 0;
159
- const options = this.config.get('discovery');
160
- const key = (preferTs && this.config.get('entitiesTs').length > 0) ? 'entitiesTs' : 'entities';
161
- const paths = this.config.get(key).filter(item => Utils.isString(item));
162
- const refs = this.config.get(key).filter(item => !Utils.isString(item));
163
- if (paths.length > 0) {
164
- if (sync || options.requireEntitiesArray) {
165
- throw new Error(`[requireEntitiesArray] Explicit list of entities is required, please use the 'entities' option.`);
159
+ async findEntities(preferTs) {
160
+ const { entities, entitiesTs, baseDir } = this.config.getAll();
161
+ const targets = (preferTs && entitiesTs.length > 0) ? entitiesTs : entities;
162
+ const processed = [];
163
+ for (const entity of targets) {
164
+ if (typeof entity === 'string') {
165
+ if (this.config.get('discovery').requireEntitiesArray) {
166
+ throw new Error(`[requireEntitiesArray] Explicit list of entities is required, please use the 'entities' option.`);
167
+ }
168
+ const { discoverEntities } = await Utils.dynamicImport('@mikro-orm/core/file-discovery');
169
+ processed.push(...await discoverEntities(entity, { baseDir }));
170
+ }
171
+ else {
172
+ processed.push(entity);
166
173
  }
167
- return this.discoverDirectories(paths).then(targets => {
168
- return this.discoverReferences([...targets, ...refs]);
169
- });
170
174
  }
171
- return this.discoverReferences(refs);
175
+ return this.discoverReferences(processed);
172
176
  }
173
177
  discoverMissingTargets() {
174
178
  const unwrap = (type) => type
@@ -203,24 +207,12 @@ export class MetadataDiscovery {
203
207
  }
204
208
  }
205
209
  }
206
- async discoverDirectories(paths) {
207
- paths = paths.map(path => Utils.normalizePath(path));
208
- const files = await glob(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
209
- this.logger.log('discovery', `- processing ${colors.cyan('' + files.length)} files`);
210
- const found = new Map();
211
- for (const filepath of files) {
212
- const filename = basename(filepath);
213
- if (!filename.match(/\.[cm]?[jt]s$/) || filename.match(/\.d\.[cm]?ts/)) {
214
- this.logger.log('discovery', `- ignoring file ${filename}`);
215
- continue;
216
- }
217
- await this.getEntityClassOrSchema(filepath, found);
218
- }
219
- return found.keys();
220
- }
221
210
  discoverReferences(refs, validate = true) {
222
211
  const found = [];
223
212
  for (const entity of refs) {
213
+ if (typeof entity === 'string') {
214
+ throw new Error('Folder based discovery requires the async `MikroORM.init()` method.');
215
+ }
224
216
  const schema = this.getSchema(entity);
225
217
  const meta = schema.init().meta;
226
218
  this.metadata.set(meta.className, meta);
@@ -1109,8 +1101,18 @@ export class MetadataDiscovery {
1109
1101
  }
1110
1102
  // `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
1111
1103
  if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
1112
- prop.customType = new prop.type();
1113
- prop.type = prop.customType.constructor.name;
1104
+ // if the type is an ORM defined mapped type without `ensureComparable: true`,
1105
+ // we use just the type name, to have more performant hydration code
1106
+ const type = Utils.keys(t).find(type => {
1107
+ return !Type.getType(t[type]).ensureComparable(meta, prop) && prop.type === t[type];
1108
+ });
1109
+ if (type) {
1110
+ prop.type = type === 'datetime' ? 'Date' : type;
1111
+ }
1112
+ else {
1113
+ prop.customType = new prop.type();
1114
+ prop.type = prop.customType.constructor.name;
1115
+ }
1114
1116
  }
1115
1117
  if (simple) {
1116
1118
  return;
@@ -1320,27 +1322,6 @@ export class MetadataDiscovery {
1320
1322
  prop.index ??= true;
1321
1323
  }
1322
1324
  }
1323
- async getEntityClassOrSchema(filepath, allTargets) {
1324
- const path = Utils.normalizePath(this.config.get('baseDir'), filepath);
1325
- const exports = await Utils.dynamicImport(path);
1326
- const targets = Object.values(exports);
1327
- // ignore class implementations that are linked from an EntitySchema
1328
- for (const item of targets) {
1329
- if (item instanceof EntitySchema) {
1330
- for (const item2 of targets) {
1331
- if (item.meta.class === item2) {
1332
- targets.splice(targets.indexOf(item2), 1);
1333
- }
1334
- }
1335
- }
1336
- }
1337
- for (const item of targets) {
1338
- const validTarget = item instanceof EntitySchema || (item instanceof Function && MetadataStorage.isKnownEntity(item.name));
1339
- if (validTarget && !allTargets.has(item)) {
1340
- allTargets.set(item, path);
1341
- }
1342
- }
1343
- }
1344
1325
  shouldForceConstructorUsage(meta) {
1345
1326
  const forceConstructor = this.config.get('forceEntityConstructor');
1346
1327
  if (Array.isArray(forceConstructor)) {
@@ -0,0 +1,5 @@
1
+ import { type Constructor } from '../typings.js';
2
+ import { EntitySchema } from './EntitySchema.js';
3
+ export declare function discoverEntities(paths: string | string[], options?: {
4
+ baseDir?: string;
5
+ }): Promise<Iterable<EntitySchema | Constructor>>;
@@ -0,0 +1,40 @@
1
+ import { basename } from 'node:path';
2
+ import { glob } from 'tinyglobby';
3
+ import { Utils } from '../utils/Utils.js';
4
+ import { MetadataStorage } from './MetadataStorage.js';
5
+ import { EntitySchema } from './EntitySchema.js';
6
+ async function getEntityClassOrSchema(filepath, allTargets, baseDir) {
7
+ const path = Utils.normalizePath(baseDir, filepath);
8
+ const exports = await Utils.dynamicImport(path);
9
+ const targets = Object.values(exports);
10
+ // ignore class implementations that are linked from an EntitySchema
11
+ for (const item of targets) {
12
+ if (item instanceof EntitySchema) {
13
+ for (const item2 of targets) {
14
+ if (item.meta.class === item2) {
15
+ targets.splice(targets.indexOf(item2), 1);
16
+ }
17
+ }
18
+ }
19
+ }
20
+ for (const item of targets) {
21
+ const validTarget = item instanceof EntitySchema || (item instanceof Function && MetadataStorage.isKnownEntity(item.name));
22
+ if (validTarget && !allTargets.has(item)) {
23
+ allTargets.set(item, path);
24
+ }
25
+ }
26
+ }
27
+ export async function discoverEntities(paths, options) {
28
+ paths = Utils.asArray(paths).map(path => Utils.normalizePath(path));
29
+ const baseDir = options?.baseDir ?? process.cwd();
30
+ const files = await glob(paths, { cwd: Utils.normalizePath(baseDir) });
31
+ const found = new Map();
32
+ for (const filepath of files) {
33
+ const filename = basename(filepath);
34
+ if (!filename.match(/\.[cm]?[jt]s$/) || filename.match(/\.d\.[cm]?ts/)) {
35
+ continue;
36
+ }
37
+ await getEntityClassOrSchema(filepath, found, baseDir);
38
+ }
39
+ return found.keys();
40
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
3
  "type": "module",
4
- "version": "7.0.0-dev.53",
4
+ "version": "7.0.0-dev.55",
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
- ".": "./index.js"
8
+ ".": "./index.js",
9
+ "./file-discovery": "./metadata/discover-entities.js"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
@@ -54,7 +55,7 @@
54
55
  "dataloader": "2.2.3",
55
56
  "dotenv": "17.2.3",
56
57
  "esprima": "4.0.1",
57
- "mikro-orm": "7.0.0-dev.53",
58
+ "mikro-orm": "7.0.0-dev.55",
58
59
  "reflect-metadata": "0.2.2",
59
60
  "tinyglobby": "0.2.13"
60
61
  }
@@ -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
  }
@@ -300,7 +300,7 @@ export interface MetadataDiscoveryOptions {
300
300
  }
301
301
  export interface Options<Driver extends IDatabaseDriver = IDatabaseDriver, EM extends EntityManager<Driver> & Driver[typeof EntityManagerType] = EntityManager<Driver> & Driver[typeof EntityManagerType], Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends ConnectionOptions {
302
302
  entities?: Entities;
303
- entitiesTs?: (string | EntityClass<AnyEntity> | EntitySchema)[];
303
+ entitiesTs?: Entities;
304
304
  extensions?: {
305
305
  register: (orm: MikroORM) => void;
306
306
  }[];
@@ -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;