@mikro-orm/core 7.0.0-rc.2 → 7.0.0

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.
Files changed (114) hide show
  1. package/EntityManager.d.ts +4 -16
  2. package/EntityManager.js +248 -181
  3. package/MikroORM.d.ts +4 -6
  4. package/MikroORM.js +24 -24
  5. package/README.md +5 -4
  6. package/cache/FileCacheAdapter.d.ts +1 -5
  7. package/cache/FileCacheAdapter.js +22 -24
  8. package/cache/GeneratedCacheAdapter.d.ts +1 -1
  9. package/cache/GeneratedCacheAdapter.js +6 -6
  10. package/cache/MemoryCacheAdapter.d.ts +1 -2
  11. package/cache/MemoryCacheAdapter.js +8 -8
  12. package/cache/index.d.ts +1 -1
  13. package/cache/index.js +0 -1
  14. package/connections/Connection.d.ts +1 -0
  15. package/connections/Connection.js +43 -14
  16. package/drivers/DatabaseDriver.d.ts +0 -2
  17. package/drivers/DatabaseDriver.js +28 -12
  18. package/drivers/IDatabaseDriver.d.ts +43 -0
  19. package/entity/Collection.d.ts +1 -9
  20. package/entity/Collection.js +124 -108
  21. package/entity/EntityAssigner.js +23 -11
  22. package/entity/EntityFactory.d.ts +1 -8
  23. package/entity/EntityFactory.js +79 -59
  24. package/entity/EntityHelper.js +25 -16
  25. package/entity/EntityLoader.d.ts +1 -3
  26. package/entity/EntityLoader.js +90 -60
  27. package/entity/Reference.d.ts +2 -3
  28. package/entity/Reference.js +48 -19
  29. package/entity/WrappedEntity.d.ts +4 -2
  30. package/entity/WrappedEntity.js +5 -1
  31. package/entity/defineEntity.d.ts +42 -85
  32. package/entity/utils.js +28 -26
  33. package/entity/validators.js +2 -1
  34. package/enums.d.ts +2 -1
  35. package/enums.js +13 -17
  36. package/errors.d.ts +11 -11
  37. package/errors.js +8 -8
  38. package/events/EventManager.d.ts +1 -4
  39. package/events/EventManager.js +26 -23
  40. package/events/index.d.ts +1 -1
  41. package/events/index.js +0 -1
  42. package/exceptions.js +9 -2
  43. package/hydration/ObjectHydrator.d.ts +1 -2
  44. package/hydration/ObjectHydrator.js +41 -27
  45. package/index.d.ts +1 -1
  46. package/index.js +1 -1
  47. package/logging/DefaultLogger.js +6 -7
  48. package/logging/Logger.d.ts +2 -1
  49. package/logging/colors.js +2 -5
  50. package/logging/index.d.ts +1 -1
  51. package/logging/index.js +0 -1
  52. package/metadata/EntitySchema.d.ts +3 -3
  53. package/metadata/EntitySchema.js +12 -2
  54. package/metadata/MetadataDiscovery.d.ts +1 -9
  55. package/metadata/MetadataDiscovery.js +251 -179
  56. package/metadata/MetadataProvider.js +26 -1
  57. package/metadata/MetadataStorage.d.ts +1 -5
  58. package/metadata/MetadataStorage.js +37 -39
  59. package/metadata/MetadataValidator.js +20 -5
  60. package/metadata/discover-entities.js +1 -1
  61. package/metadata/index.d.ts +1 -1
  62. package/metadata/index.js +0 -1
  63. package/metadata/types.d.ts +2 -2
  64. package/naming-strategy/AbstractNamingStrategy.js +6 -3
  65. package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
  66. package/naming-strategy/index.d.ts +1 -1
  67. package/naming-strategy/index.js +0 -1
  68. package/not-supported.js +5 -1
  69. package/package.json +38 -38
  70. package/platforms/Platform.d.ts +24 -1
  71. package/platforms/Platform.js +106 -27
  72. package/serialization/EntitySerializer.js +8 -4
  73. package/serialization/EntityTransformer.js +4 -1
  74. package/serialization/SerializationContext.d.ts +4 -8
  75. package/serialization/SerializationContext.js +21 -16
  76. package/types/UuidType.d.ts +2 -0
  77. package/types/UuidType.js +14 -2
  78. package/types/index.d.ts +2 -1
  79. package/typings.d.ts +35 -24
  80. package/typings.js +9 -9
  81. package/unit-of-work/ChangeSet.js +4 -4
  82. package/unit-of-work/ChangeSetComputer.d.ts +1 -6
  83. package/unit-of-work/ChangeSetComputer.js +29 -27
  84. package/unit-of-work/ChangeSetPersister.d.ts +1 -9
  85. package/unit-of-work/ChangeSetPersister.js +63 -58
  86. package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
  87. package/unit-of-work/CommitOrderCalculator.js +17 -15
  88. package/unit-of-work/IdentityMap.d.ts +2 -5
  89. package/unit-of-work/IdentityMap.js +18 -18
  90. package/unit-of-work/UnitOfWork.d.ts +12 -20
  91. package/unit-of-work/UnitOfWork.js +228 -191
  92. package/utils/AbstractMigrator.d.ts +2 -2
  93. package/utils/AbstractMigrator.js +10 -12
  94. package/utils/AbstractSchemaGenerator.js +2 -1
  95. package/utils/AsyncContext.js +1 -1
  96. package/utils/Configuration.d.ts +90 -189
  97. package/utils/Configuration.js +97 -77
  98. package/utils/Cursor.d.ts +3 -3
  99. package/utils/Cursor.js +8 -6
  100. package/utils/DataloaderUtils.js +15 -12
  101. package/utils/EntityComparator.d.ts +8 -15
  102. package/utils/EntityComparator.js +100 -92
  103. package/utils/QueryHelper.d.ts +16 -1
  104. package/utils/QueryHelper.js +108 -50
  105. package/utils/RawQueryFragment.d.ts +4 -4
  106. package/utils/RawQueryFragment.js +3 -2
  107. package/utils/TransactionManager.js +3 -3
  108. package/utils/Utils.d.ts +2 -2
  109. package/utils/Utils.js +39 -32
  110. package/utils/clone.js +5 -0
  111. package/utils/env-vars.js +6 -5
  112. package/utils/fs-utils.d.ts +3 -17
  113. package/utils/fs-utils.js +2 -5
  114. package/utils/upsert-utils.js +7 -4
package/MikroORM.d.ts CHANGED
@@ -5,7 +5,7 @@ import { Configuration, type Options } from './utils/Configuration.js';
5
5
  import type { EntityManager } from './EntityManager.js';
6
6
  import type { AnyEntity, Constructor, EntityClass, EntityMetadata, EntityName, IEntityGenerator, IMigrator, ISeedManager } from './typings.js';
7
7
  /** @internal */
8
- export declare function loadOptionalDependencies(options: Options): Promise<void>;
8
+ export declare function loadOptionalDependencies(options: Partial<Options>): Promise<void>;
9
9
  /**
10
10
  * The main class used to configure and bootstrap the ORM.
11
11
  *
@@ -35,27 +35,25 @@ export declare function loadOptionalDependencies(options: Options): Promise<void
35
35
  * ```
36
36
  */
37
37
  export declare class MikroORM<Driver extends IDatabaseDriver = IDatabaseDriver, EM extends Driver[typeof EntityManagerType] & EntityManager<Driver> = Driver[typeof EntityManagerType] & EntityManager<Driver>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> {
38
+ #private;
38
39
  /** The global EntityManager instance. If you are using `RequestContext` helper, it will automatically pick the request specific context under the hood */
39
40
  em: EM & {
40
41
  '~entities'?: Entities;
41
42
  };
42
43
  readonly driver: Driver;
43
44
  readonly config: Configuration<Driver>;
44
- private metadata;
45
- private readonly logger;
46
- private readonly discovery;
47
45
  /**
48
46
  * Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
49
47
  * If you omit the `options` parameter, your CLI config will be used.
50
48
  */
51
- static init<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Options<D, EM, Entities>): Promise<MikroORM<D, EM, Entities>>;
49
+ static init<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
52
50
  /**
53
51
  * Synchronous variant of the `init` method with some limitations:
54
52
  * - folder-based discovery not supported
55
53
  * - ORM extensions are not autoloaded
56
54
  * - when metadata cache is enabled, `FileCacheAdapter` needs to be explicitly set in the config
57
55
  */
58
- constructor(options: Options<Driver, EM, Entities>);
56
+ constructor(options: Partial<Options<Driver, EM, Entities>>);
59
57
  /**
60
58
  * Connects to the database.
61
59
  */
package/MikroORM.js CHANGED
@@ -74,9 +74,9 @@ export class MikroORM {
74
74
  em;
75
75
  driver;
76
76
  config;
77
- metadata;
78
- logger;
79
- discovery;
77
+ #metadata;
78
+ #logger;
79
+ #discovery;
80
80
  /**
81
81
  * Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
82
82
  * If you omit the `options` parameter, your CLI config will be used.
@@ -92,7 +92,7 @@ export class MikroORM {
92
92
  await loadOptionalDependencies(options);
93
93
  const orm = new this(options);
94
94
  const preferTs = orm.config.get('preferTs', Utils.detectTypeScriptSupport());
95
- orm.metadata = await orm.discovery.discover(preferTs);
95
+ orm.#metadata = await orm.#discovery.discover(preferTs);
96
96
  orm.createEntityManager();
97
97
  return orm;
98
98
  }
@@ -104,21 +104,19 @@ export class MikroORM {
104
104
  */
105
105
  constructor(options) {
106
106
  const env = loadEnvironmentVars();
107
- options = options.preferEnvVars
108
- ? Utils.merge(options, env)
109
- : Utils.merge(env, options);
107
+ options = options.preferEnvVars ? Utils.merge(options, env) : Utils.merge(env, options);
110
108
  this.config = new Configuration(options);
111
109
  const discovery = this.config.get('discovery');
112
110
  this.driver = this.config.getDriver();
113
- this.logger = this.config.getLogger();
114
- this.logger.log('info', `MikroORM version: ${colors.green(Utils.getORMVersion())}`);
115
- this.discovery = new MetadataDiscovery(new MetadataStorage(), this.driver.getPlatform(), this.config);
111
+ this.#logger = this.config.getLogger();
112
+ this.#logger.log('info', `MikroORM version: ${colors.green(Utils.getORMVersion())}`);
113
+ this.#discovery = new MetadataDiscovery(new MetadataStorage(), this.driver.getPlatform(), this.config);
116
114
  this.driver.getPlatform().init(this);
117
115
  for (const extension of this.config.get('extensions')) {
118
116
  extension.register(this);
119
117
  }
120
118
  if (!discovery.skipSyncDiscovery) {
121
- this.metadata = this.discovery.discoverSync();
119
+ this.#metadata = this.#discovery.discoverSync();
122
120
  this.createEntityManager();
123
121
  }
124
122
  }
@@ -164,32 +162,32 @@ export class MikroORM {
164
162
  */
165
163
  getMetadata(entityName) {
166
164
  if (entityName) {
167
- return this.metadata.get(entityName);
165
+ return this.#metadata.get(entityName);
168
166
  }
169
- return this.metadata;
167
+ return this.#metadata;
170
168
  }
171
169
  createEntityManager() {
172
- this.driver.setMetadata(this.metadata);
170
+ this.driver.setMetadata(this.#metadata);
173
171
  this.em = this.driver.createEntityManager();
174
172
  this.em.global = true;
175
- this.metadata.decorate(this.em);
176
- this.driver.setMetadata(this.metadata);
173
+ this.#metadata.decorate(this.em);
174
+ this.driver.setMetadata(this.#metadata);
177
175
  }
178
176
  /**
179
177
  * Allows dynamically discovering new entity by reference, handy for testing schema diffing.
180
178
  */
181
179
  discoverEntity(entities, reset) {
182
180
  for (const className of Utils.asArray(reset)) {
183
- this.metadata.reset(className);
184
- this.discovery.reset(className);
181
+ this.#metadata.reset(className);
182
+ this.#discovery.reset(className);
185
183
  }
186
- const tmp = this.discovery.discoverReferences(Utils.asArray(entities));
187
- const metadata = this.discovery.processDiscoveredEntities(tmp);
184
+ const tmp = this.#discovery.discoverReferences(Utils.asArray(entities));
185
+ const metadata = this.#discovery.processDiscoveredEntities(tmp);
188
186
  for (const meta of metadata) {
189
- this.metadata.set(meta.class, meta);
190
- meta.root = this.metadata.get(meta.root.class);
187
+ this.#metadata.set(meta.class, meta);
188
+ meta.root = this.#metadata.get(meta.root.class);
191
189
  }
192
- this.metadata.decorate(this.em);
190
+ this.#metadata.decorate(this.em);
193
191
  }
194
192
  /**
195
193
  * Gets the SchemaGenerator.
@@ -213,6 +211,8 @@ export class MikroORM {
213
211
  * Gets the EntityGenerator.
214
212
  */
215
213
  get entityGenerator() {
216
- return this.driver.getPlatform().getExtension('EntityGenerator', '@mikro-orm/entity-generator', '@mikro-orm/entity-generator', this.em);
214
+ return this.driver
215
+ .getPlatform()
216
+ .getExtension('EntityGenerator', '@mikro-orm/entity-generator', '@mikro-orm/entity-generator', this.em);
217
217
  }
218
218
  }
package/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
  <a href="https://mikro-orm.io"><img src="https://raw.githubusercontent.com/mikro-orm/mikro-orm/master/docs/static/img/logo-readme.svg?sanitize=true" alt="MikroORM" /></a>
3
3
  </h1>
4
4
 
5
- TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite (including libSQL) databases.
5
+ TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL, SQLite (including libSQL), MSSQL and Oracle databases.
6
6
 
7
7
  > Heavily inspired by [Doctrine](https://www.doctrine-project.org/) and [Hibernate](https://hibernate.org/).
8
8
 
9
- [![NPM version](https://img.shields.io/npm/v/@mikro-orm/core.svg)](https://www.npmjs.com/package/@mikro-orm/core)
10
- [![NPM dev version](https://img.shields.io/npm/v/@mikro-orm/core/next.svg)](https://www.npmjs.com/package/@mikro-orm/core)
9
+ [![NPM version](https://img.shields.io/npm/v/@mikro-orm/core.svg)](https://npmx.dev/package/@mikro-orm/core)
10
+ [![NPM dev version](https://img.shields.io/npm/v/@mikro-orm/core/next.svg)](https://npmx.dev/package/@mikro-orm/core)
11
11
  [![Chat on discord](https://img.shields.io/discord/1214904142443839538?label=discord&color=blue)](https://discord.gg/w8bjxFHS7X)
12
- [![Downloads](https://img.shields.io/npm/dm/@mikro-orm/core.svg)](https://www.npmjs.com/package/@mikro-orm/core)
12
+ [![Downloads](https://img.shields.io/npm/dm/@mikro-orm/core.svg)](https://npmx.dev/package/@mikro-orm/core)
13
13
  [![Coverage Status](https://img.shields.io/coveralls/mikro-orm/mikro-orm.svg)](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
14
14
  [![Build Status](https://github.com/mikro-orm/mikro-orm/workflows/tests/badge.svg?branch=master)](https://github.com/mikro-orm/mikro-orm/actions?workflow=tests)
15
15
 
@@ -181,6 +181,7 @@ yarn add @mikro-orm/core @mikro-orm/mysql # for mysql/mariadb
181
181
  yarn add @mikro-orm/core @mikro-orm/mariadb # for mysql/mariadb
182
182
  yarn add @mikro-orm/core @mikro-orm/postgresql # for postgresql
183
183
  yarn add @mikro-orm/core @mikro-orm/mssql # for mssql
184
+ yarn add @mikro-orm/core @mikro-orm/oracledb # for oracle
184
185
  yarn add @mikro-orm/core @mikro-orm/sqlite # for sqlite
185
186
  yarn add @mikro-orm/core @mikro-orm/libsql # for libsql
186
187
  ```
@@ -1,10 +1,6 @@
1
1
  import type { SyncCacheAdapter } from './CacheAdapter.js';
2
2
  export declare class FileCacheAdapter implements SyncCacheAdapter {
3
- private readonly options;
4
- private readonly baseDir;
5
- private readonly pretty;
6
- private readonly VERSION;
7
- private cache;
3
+ #private;
8
4
  constructor(options: {
9
5
  cacheDir: string;
10
6
  combined?: boolean | string;
@@ -2,16 +2,16 @@ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
2
2
  import { fs } from '../utils/fs-utils.js';
3
3
  import { Utils } from '../utils/Utils.js';
4
4
  export class FileCacheAdapter {
5
- options;
6
- baseDir;
7
- pretty;
8
- VERSION = Utils.getORMVersion();
9
- cache = {};
5
+ #VERSION = Utils.getORMVersion();
6
+ #cache = {};
7
+ #options;
8
+ #baseDir;
9
+ #pretty;
10
10
  constructor(options = {}, baseDir, pretty = false) {
11
- this.options = options;
12
- this.baseDir = baseDir;
13
- this.pretty = pretty;
14
- this.options.cacheDir ??= process.cwd() + '/temp';
11
+ this.#options = options;
12
+ this.#baseDir = baseDir;
13
+ this.#pretty = pretty;
14
+ this.#options.cacheDir ??= process.cwd() + '/temp';
15
15
  }
16
16
  /**
17
17
  * @inheritDoc
@@ -32,13 +32,13 @@ export class FileCacheAdapter {
32
32
  * @inheritDoc
33
33
  */
34
34
  set(name, data, origin) {
35
- if (this.options.combined) {
36
- this.cache[name.replace(/\.[jt]s$/, '')] = data;
35
+ if (this.#options.combined) {
36
+ this.#cache[name.replace(/\.[jt]s$/, '')] = data;
37
37
  return;
38
38
  }
39
39
  const path = this.path(name);
40
40
  const hash = this.getHash(origin);
41
- writeFileSync(path, JSON.stringify({ data, origin, hash, version: this.VERSION }, null, this.pretty ? 2 : undefined));
41
+ writeFileSync(path, JSON.stringify({ data, origin, hash, version: this.#VERSION }, null, this.#pretty ? 2 : undefined));
42
42
  }
43
43
  /**
44
44
  * @inheritDoc
@@ -62,30 +62,28 @@ export class FileCacheAdapter {
62
62
  // ignore if file is already gone
63
63
  }
64
64
  }
65
- this.cache = {};
65
+ this.#cache = {};
66
66
  }
67
67
  combine() {
68
- if (!this.options.combined) {
68
+ if (!this.#options.combined) {
69
69
  return;
70
70
  }
71
- let path = typeof this.options.combined === 'string'
72
- ? this.options.combined
73
- : './metadata.json';
74
- path = fs.normalizePath(this.options.cacheDir, path);
75
- this.options.combined = path; // override in the options, so we can log it from the CLI in `cache:generate` command
76
- writeFileSync(path, JSON.stringify(this.cache, null, this.pretty ? 2 : undefined));
71
+ let path = typeof this.#options.combined === 'string' ? this.#options.combined : './metadata.json';
72
+ path = fs.normalizePath(this.#options.cacheDir, path);
73
+ this.#options.combined = path; // override in the options, so we can log it from the CLI in `cache:generate` command
74
+ writeFileSync(path, JSON.stringify(this.#cache, null, this.#pretty ? 2 : undefined));
77
75
  return path;
78
76
  }
79
77
  path(name) {
80
- fs.ensureDir(this.options.cacheDir);
81
- return `${this.options.cacheDir}/${name}.json`;
78
+ fs.ensureDir(this.#options.cacheDir);
79
+ return `${this.#options.cacheDir}/${name}.json`;
82
80
  }
83
81
  getHash(origin) {
84
- origin = fs.absolutePath(origin, this.baseDir);
82
+ origin = fs.absolutePath(origin, this.#baseDir);
85
83
  if (!existsSync(origin)) {
86
84
  return null;
87
85
  }
88
86
  const contents = readFileSync(origin);
89
- return Utils.hash(contents.toString() + this.VERSION);
87
+ return Utils.hash(contents.toString() + this.#VERSION);
90
88
  }
91
89
  }
@@ -1,7 +1,7 @@
1
1
  import type { CacheAdapter } from './CacheAdapter.js';
2
2
  import type { Dictionary } from '../typings.js';
3
3
  export declare class GeneratedCacheAdapter implements CacheAdapter {
4
- private readonly data;
4
+ #private;
5
5
  constructor(options: {
6
6
  data: Dictionary;
7
7
  });
@@ -1,32 +1,32 @@
1
1
  export class GeneratedCacheAdapter {
2
- data = new Map();
2
+ #data;
3
3
  constructor(options) {
4
- this.data = new Map(Object.entries(options.data));
4
+ this.#data = new Map(Object.entries(options.data));
5
5
  }
6
6
  /**
7
7
  * @inheritDoc
8
8
  */
9
9
  get(name) {
10
10
  const key = name.replace(/\.[jt]s$/, '');
11
- const data = this.data.get(key);
11
+ const data = this.#data.get(key);
12
12
  return data;
13
13
  }
14
14
  /**
15
15
  * @inheritDoc
16
16
  */
17
17
  set(name, data, origin) {
18
- this.data.set(name, { data });
18
+ this.#data.set(name, { data });
19
19
  }
20
20
  /**
21
21
  * @inheritDoc
22
22
  */
23
23
  remove(name) {
24
- this.data.delete(name);
24
+ this.#data.delete(name);
25
25
  }
26
26
  /**
27
27
  * @inheritDoc
28
28
  */
29
29
  clear() {
30
- this.data.clear();
30
+ this.#data.clear();
31
31
  }
32
32
  }
@@ -1,7 +1,6 @@
1
1
  import type { CacheAdapter } from './CacheAdapter.js';
2
2
  export declare class MemoryCacheAdapter implements CacheAdapter {
3
- private readonly options;
4
- private readonly data;
3
+ #private;
5
4
  constructor(options: {
6
5
  expiration: number;
7
6
  });
@@ -1,17 +1,17 @@
1
1
  export class MemoryCacheAdapter {
2
- options;
3
- data = new Map();
2
+ #data = new Map();
3
+ #options;
4
4
  constructor(options) {
5
- this.options = options;
5
+ this.#options = options;
6
6
  }
7
7
  /**
8
8
  * @inheritDoc
9
9
  */
10
10
  get(name) {
11
- const data = this.data.get(name);
11
+ const data = this.#data.get(name);
12
12
  if (data) {
13
13
  if (data.expiration < Date.now()) {
14
- this.data.delete(name);
14
+ this.#data.delete(name);
15
15
  }
16
16
  else {
17
17
  return data.data;
@@ -23,18 +23,18 @@ export class MemoryCacheAdapter {
23
23
  * @inheritDoc
24
24
  */
25
25
  set(name, data, origin, expiration) {
26
- this.data.set(name, { data, expiration: Date.now() + (expiration ?? this.options.expiration) });
26
+ this.#data.set(name, { data, expiration: Date.now() + (expiration ?? this.#options.expiration) });
27
27
  }
28
28
  /**
29
29
  * @inheritDoc
30
30
  */
31
31
  remove(name) {
32
- this.data.delete(name);
32
+ this.#data.delete(name);
33
33
  }
34
34
  /**
35
35
  * @inheritDoc
36
36
  */
37
37
  clear() {
38
- this.data.clear();
38
+ this.#data.clear();
39
39
  }
40
40
  }
package/cache/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './CacheAdapter.js';
1
+ export type * from './CacheAdapter.js';
2
2
  export * from './NullCacheAdapter.js';
3
3
  export * from './MemoryCacheAdapter.js';
4
4
  export * from './GeneratedCacheAdapter.js';
package/cache/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export * from './CacheAdapter.js';
2
1
  export * from './NullCacheAdapter.js';
3
2
  export * from './MemoryCacheAdapter.js';
4
3
  export * from './GeneratedCacheAdapter.js';
@@ -6,6 +6,7 @@ import type { Platform } from '../platforms/Platform.js';
6
6
  import type { TransactionEventBroadcaster } from '../events/TransactionEventBroadcaster.js';
7
7
  import type { IsolationLevel } from '../enums.js';
8
8
  export declare abstract class Connection {
9
+ #private;
9
10
  protected readonly config: Configuration;
10
11
  protected readonly type: ConnectionType;
11
12
  protected metadata: MetadataStorage;
@@ -7,6 +7,12 @@ export class Connection {
7
7
  options;
8
8
  logger;
9
9
  connected = false;
10
+ get #connectionLabel() {
11
+ return {
12
+ type: this.type,
13
+ name: this.options.name || this.config.get('name') || this.options.host || this.options.dbName,
14
+ };
15
+ }
10
16
  constructor(config, options, type = 'write') {
11
17
  this.config = config;
12
18
  this.type = type;
@@ -16,7 +22,18 @@ export class Connection {
16
22
  this.options = Utils.copy(options);
17
23
  }
18
24
  else {
19
- const props = ['dbName', 'clientUrl', 'host', 'port', 'user', 'password', 'multipleStatements', 'pool', 'schema', 'driverOptions'];
25
+ const props = [
26
+ 'dbName',
27
+ 'clientUrl',
28
+ 'host',
29
+ 'port',
30
+ 'user',
31
+ 'password',
32
+ 'multipleStatements',
33
+ 'pool',
34
+ 'schema',
35
+ 'driverOptions',
36
+ ];
20
37
  this.options = props.reduce((o, i) => {
21
38
  o[i] = this.config.get(i);
22
39
  return o;
@@ -89,8 +106,10 @@ export class Connection {
89
106
  this.options.host = ret.host = this.options.host ?? this.config.get('host', decodeURIComponent(url.hostname));
90
107
  this.options.port = ret.port = this.options.port ?? this.config.get('port', +url.port);
91
108
  this.options.user = ret.user = this.options.user ?? this.config.get('user', decodeURIComponent(url.username));
92
- this.options.password = ret.password = this.options.password ?? this.config.get('password', decodeURIComponent(url.password));
93
- this.options.dbName = ret.database = this.options.dbName ?? this.config.get('dbName', decodeURIComponent(url.pathname).replace(/^\//, ''));
109
+ this.options.password = ret.password =
110
+ this.options.password ?? this.config.get('password', decodeURIComponent(url.password));
111
+ this.options.dbName = ret.database =
112
+ this.options.dbName ?? this.config.get('dbName', decodeURIComponent(url.pathname).replace(/^\//, ''));
94
113
  }
95
114
  return ret;
96
115
  }
@@ -107,28 +126,38 @@ export class Connection {
107
126
  const now = Date.now();
108
127
  try {
109
128
  const res = await cb();
110
- this.logQuery(query, {
111
- ...context,
112
- took: Date.now() - now,
113
- results: Array.isArray(res) ? res.length : undefined,
114
- affected: Utils.isPlainObject(res) ? res.affectedRows : undefined,
115
- });
129
+ const took = Date.now() - now;
130
+ const results = Array.isArray(res) ? res.length : undefined;
131
+ const affected = Utils.isPlainObject(res) ? res.affectedRows : undefined;
132
+ this.logQuery(query, { ...context, took, results, affected });
116
133
  return res;
117
134
  }
118
135
  catch (e) {
119
- this.logQuery(query, { ...context, took: Date.now() - now, level: 'error' });
136
+ const took = Date.now() - now;
137
+ this.logQuery(query, { ...context, took, level: 'error' });
120
138
  throw e;
121
139
  }
122
140
  }
123
141
  logQuery(query, context = {}) {
142
+ const connection = this.#connectionLabel;
124
143
  this.logger.logQuery({
125
144
  level: 'info',
126
- connection: {
127
- type: this.type,
128
- name: this.options.name || this.config.get('name') || this.options.host,
129
- },
145
+ connection,
130
146
  ...context,
131
147
  query,
132
148
  });
149
+ const threshold = this.config.get('slowQueryThreshold');
150
+ if (threshold != null && (context.took ?? 0) >= threshold) {
151
+ this.config.getSlowQueryLogger().logQuery({
152
+ ...context,
153
+ // `enabled: true` bypasses the debug-mode check in isEnabled(),
154
+ // ensuring slow query logs are always emitted regardless of the `debug` setting.
155
+ enabled: true,
156
+ level: context.level ?? 'warning',
157
+ namespace: 'slow-query',
158
+ connection,
159
+ query,
160
+ });
161
+ }
133
162
  }
134
163
  }
@@ -9,7 +9,6 @@ import type { Platform } from '../platforms/Platform.js';
9
9
  import type { Collection } from '../entity/Collection.js';
10
10
  import { EntityManager } from '../EntityManager.js';
11
11
  import { DriverException } from '../exceptions.js';
12
- import type { Logger } from '../logging/Logger.js';
13
12
  import { MikroORM } from '../MikroORM.js';
14
13
  export declare abstract class DatabaseDriver<C extends Connection> implements IDatabaseDriver<C> {
15
14
  readonly config: Configuration;
@@ -18,7 +17,6 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
18
17
  protected readonly connection: C;
19
18
  protected readonly replicas: C[];
20
19
  protected readonly platform: Platform;
21
- protected readonly logger: Logger;
22
20
  protected comparator: EntityComparator;
23
21
  protected metadata: MetadataStorage;
24
22
  protected constructor(config: Configuration, dependencies: string[]);
@@ -18,13 +18,11 @@ export class DatabaseDriver {
18
18
  connection;
19
19
  replicas = [];
20
20
  platform;
21
- logger;
22
21
  comparator;
23
22
  metadata;
24
23
  constructor(config, dependencies) {
25
24
  this.config = config;
26
25
  this.dependencies = dependencies;
27
- this.logger = this.config.getLogger();
28
26
  }
29
27
  async nativeUpdateMany(entityName, where, data, options) {
30
28
  throw new Error(`Batch updates are not supported by ${this.constructor.name} driver`);
@@ -157,11 +155,11 @@ export class DatabaseDriver {
157
155
  Object.assign(o, createOrderBy(key, direction[key]));
158
156
  return o;
159
157
  }, {});
160
- return ({ [prop]: value });
158
+ return { [prop]: value };
161
159
  }
162
160
  const desc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
163
161
  const dir = Utils.xor(desc, isLast) ? 'desc' : 'asc';
164
- return ({ [prop]: dir });
162
+ return { [prop]: dir };
165
163
  };
166
164
  return {
167
165
  orderBy: definition.map(([prop, direction]) => createOrderBy(prop, direction)),
@@ -256,7 +254,7 @@ export class DatabaseDriver {
256
254
  else {
257
255
  data[prop.fieldNames[0]] = this.mapDataToFieldNames(copy, stringifyJsonArrays, prop.embeddedProps, convertCustomTypes, true);
258
256
  }
259
- if (stringifyJsonArrays && prop.array) {
257
+ if (stringifyJsonArrays && prop.array && !object) {
260
258
  data[prop.fieldNames[0]] = this.platform.convertJsonToDatabaseValue(data[prop.fieldNames[0]]);
261
259
  }
262
260
  return;
@@ -301,16 +299,23 @@ export class DatabaseDriver {
301
299
  if (prop.joinColumns && Array.isArray(data[k])) {
302
300
  const copy = Utils.flatten(data[k]);
303
301
  delete data[k];
304
- prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
302
+ prop.joinColumns.forEach((joinColumn, idx) => (data[joinColumn] = copy[idx]));
305
303
  return;
306
304
  }
307
305
  if (prop.joinColumns?.length > 1 && data[k] == null) {
308
306
  delete data[k];
309
- prop.ownColumns.forEach(joinColumn => data[joinColumn] = null);
307
+ prop.ownColumns.forEach(joinColumn => (data[joinColumn] = null));
310
308
  return;
311
309
  }
312
- if (prop.customType && convertCustomTypes && !(prop.customType instanceof JsonType && object) && !isRaw(data[k])) {
313
- data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query-data' });
310
+ if (prop.customType &&
311
+ convertCustomTypes &&
312
+ !(prop.customType instanceof JsonType && object) &&
313
+ !isRaw(data[k])) {
314
+ data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, {
315
+ fromQuery: true,
316
+ key: k,
317
+ mode: 'query-data',
318
+ });
314
319
  }
315
320
  if (prop.hasConvertToDatabaseValueSQL && !prop.object && !isRaw(data[k])) {
316
321
  const quoted = this.platform.quoteValue(data[k]);
@@ -341,8 +346,8 @@ export class DatabaseDriver {
341
346
  const props = prop.embeddedProps;
342
347
  let unknownProp = false;
343
348
  Object.keys(data[prop.name]).forEach(kk => {
344
- // explicitly allow `$exists`, `$eq` and `$ne` operators here as they can't be misused this way
345
- const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f) && !['$exists', '$ne', '$eq'].includes(f));
349
+ // explicitly allow `$exists`, `$eq`, `$ne` and `$elemMatch` operators here as they can't be misused this way
350
+ const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f) && !['$exists', '$ne', '$eq', '$elemMatch'].includes(f));
346
351
  if (operator) {
347
352
  throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.class, prop.name, data);
348
353
  }
@@ -390,7 +395,18 @@ export class DatabaseDriver {
390
395
  createReplicas(cb) {
391
396
  const replicas = this.config.get('replicas', []);
392
397
  const ret = [];
393
- const props = ['dbName', 'clientUrl', 'host', 'port', 'user', 'password', 'multipleStatements', 'pool', 'name', 'driverOptions'];
398
+ const props = [
399
+ 'dbName',
400
+ 'clientUrl',
401
+ 'host',
402
+ 'port',
403
+ 'user',
404
+ 'password',
405
+ 'multipleStatements',
406
+ 'pool',
407
+ 'name',
408
+ 'driverOptions',
409
+ ];
394
410
  for (const conf of replicas) {
395
411
  const replicaConfig = Utils.copy(conf);
396
412
  for (const prop of props) {