@mikro-orm/core 7.0.0-dev.7 → 7.0.0-dev.71

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 (161) hide show
  1. package/EntityManager.d.ts +85 -42
  2. package/EntityManager.js +282 -194
  3. package/MikroORM.d.ts +11 -29
  4. package/MikroORM.js +33 -127
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.js +1 -2
  7. package/connections/Connection.d.ts +11 -7
  8. package/connections/Connection.js +16 -14
  9. package/drivers/DatabaseDriver.d.ts +11 -5
  10. package/drivers/DatabaseDriver.js +13 -4
  11. package/drivers/IDatabaseDriver.d.ts +27 -5
  12. package/entity/BaseEntity.d.ts +0 -1
  13. package/entity/BaseEntity.js +0 -3
  14. package/entity/Collection.d.ts +98 -30
  15. package/entity/Collection.js +432 -93
  16. package/entity/EntityAssigner.d.ts +1 -1
  17. package/entity/EntityAssigner.js +9 -1
  18. package/entity/EntityFactory.d.ts +7 -0
  19. package/entity/EntityFactory.js +63 -40
  20. package/entity/EntityHelper.js +26 -9
  21. package/entity/EntityLoader.d.ts +5 -4
  22. package/entity/EntityLoader.js +69 -36
  23. package/entity/EntityRepository.d.ts +1 -1
  24. package/entity/EntityValidator.js +4 -4
  25. package/entity/Reference.d.ts +9 -7
  26. package/entity/Reference.js +32 -5
  27. package/entity/WrappedEntity.d.ts +0 -2
  28. package/entity/WrappedEntity.js +1 -5
  29. package/entity/defineEntity.d.ts +549 -0
  30. package/entity/defineEntity.js +529 -0
  31. package/entity/index.d.ts +2 -1
  32. package/entity/index.js +2 -1
  33. package/entity/utils.d.ts +7 -0
  34. package/entity/utils.js +15 -3
  35. package/enums.d.ts +20 -5
  36. package/enums.js +13 -0
  37. package/errors.d.ts +6 -1
  38. package/errors.js +14 -4
  39. package/events/EventSubscriber.d.ts +3 -1
  40. package/hydration/ObjectHydrator.d.ts +4 -4
  41. package/hydration/ObjectHydrator.js +35 -24
  42. package/index.d.ts +2 -2
  43. package/index.js +1 -2
  44. package/logging/DefaultLogger.d.ts +1 -1
  45. package/logging/SimpleLogger.d.ts +1 -1
  46. package/metadata/EntitySchema.d.ts +9 -13
  47. package/metadata/EntitySchema.js +44 -26
  48. package/metadata/MetadataDiscovery.d.ts +6 -7
  49. package/metadata/MetadataDiscovery.js +161 -162
  50. package/metadata/MetadataProvider.d.ts +2 -2
  51. package/metadata/MetadataProvider.js +15 -0
  52. package/metadata/MetadataStorage.d.ts +0 -4
  53. package/metadata/MetadataStorage.js +6 -10
  54. package/metadata/MetadataValidator.d.ts +0 -7
  55. package/metadata/MetadataValidator.js +4 -13
  56. package/metadata/discover-entities.d.ts +5 -0
  57. package/metadata/discover-entities.js +39 -0
  58. package/metadata/index.d.ts +1 -1
  59. package/metadata/index.js +1 -1
  60. package/metadata/types.d.ts +480 -0
  61. package/metadata/types.js +1 -0
  62. package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
  63. package/naming-strategy/AbstractNamingStrategy.js +7 -1
  64. package/naming-strategy/NamingStrategy.d.ts +11 -1
  65. package/package.json +11 -10
  66. package/platforms/Platform.d.ts +6 -10
  67. package/platforms/Platform.js +6 -22
  68. package/serialization/EntitySerializer.d.ts +2 -0
  69. package/serialization/EntitySerializer.js +29 -11
  70. package/serialization/EntityTransformer.js +22 -12
  71. package/serialization/SerializationContext.js +14 -11
  72. package/types/ArrayType.d.ts +1 -1
  73. package/types/ArrayType.js +1 -2
  74. package/types/BigIntType.d.ts +8 -6
  75. package/types/BlobType.d.ts +0 -1
  76. package/types/BlobType.js +0 -3
  77. package/types/BooleanType.d.ts +2 -1
  78. package/types/BooleanType.js +3 -0
  79. package/types/DecimalType.d.ts +6 -4
  80. package/types/DecimalType.js +1 -1
  81. package/types/DoubleType.js +1 -1
  82. package/types/JsonType.d.ts +1 -1
  83. package/types/JsonType.js +7 -2
  84. package/types/Type.d.ts +2 -1
  85. package/types/Type.js +1 -1
  86. package/types/Uint8ArrayType.d.ts +0 -1
  87. package/types/Uint8ArrayType.js +0 -3
  88. package/types/index.d.ts +1 -1
  89. package/typings.d.ts +112 -77
  90. package/typings.js +32 -32
  91. package/unit-of-work/ChangeSetComputer.js +8 -3
  92. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  93. package/unit-of-work/ChangeSetPersister.js +37 -16
  94. package/unit-of-work/UnitOfWork.d.ts +8 -1
  95. package/unit-of-work/UnitOfWork.js +111 -54
  96. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  97. package/utils/AbstractSchemaGenerator.js +10 -8
  98. package/utils/Configuration.d.ts +200 -191
  99. package/utils/Configuration.js +141 -152
  100. package/utils/ConfigurationLoader.d.ts +3 -44
  101. package/utils/ConfigurationLoader.js +26 -239
  102. package/utils/Cursor.d.ts +3 -3
  103. package/utils/Cursor.js +3 -0
  104. package/utils/DataloaderUtils.d.ts +15 -5
  105. package/utils/DataloaderUtils.js +53 -7
  106. package/utils/EntityComparator.d.ts +8 -4
  107. package/utils/EntityComparator.js +107 -60
  108. package/utils/QueryHelper.d.ts +9 -1
  109. package/utils/QueryHelper.js +69 -8
  110. package/utils/RawQueryFragment.d.ts +36 -4
  111. package/utils/RawQueryFragment.js +34 -13
  112. package/utils/TransactionManager.d.ts +65 -0
  113. package/utils/TransactionManager.js +223 -0
  114. package/utils/Utils.d.ts +17 -84
  115. package/utils/Utils.js +132 -252
  116. package/utils/index.d.ts +1 -0
  117. package/utils/index.js +1 -0
  118. package/utils/upsert-utils.d.ts +7 -2
  119. package/utils/upsert-utils.js +52 -1
  120. package/decorators/Check.d.ts +0 -3
  121. package/decorators/Check.js +0 -13
  122. package/decorators/CreateRequestContext.d.ts +0 -3
  123. package/decorators/CreateRequestContext.js +0 -32
  124. package/decorators/Embeddable.d.ts +0 -8
  125. package/decorators/Embeddable.js +0 -11
  126. package/decorators/Embedded.d.ts +0 -18
  127. package/decorators/Embedded.js +0 -18
  128. package/decorators/Entity.d.ts +0 -18
  129. package/decorators/Entity.js +0 -12
  130. package/decorators/Enum.d.ts +0 -9
  131. package/decorators/Enum.js +0 -16
  132. package/decorators/Filter.d.ts +0 -2
  133. package/decorators/Filter.js +0 -8
  134. package/decorators/Formula.d.ts +0 -4
  135. package/decorators/Formula.js +0 -15
  136. package/decorators/Indexed.d.ts +0 -19
  137. package/decorators/Indexed.js +0 -20
  138. package/decorators/ManyToMany.d.ts +0 -40
  139. package/decorators/ManyToMany.js +0 -14
  140. package/decorators/ManyToOne.d.ts +0 -30
  141. package/decorators/ManyToOne.js +0 -14
  142. package/decorators/OneToMany.d.ts +0 -28
  143. package/decorators/OneToMany.js +0 -17
  144. package/decorators/OneToOne.d.ts +0 -24
  145. package/decorators/OneToOne.js +0 -7
  146. package/decorators/PrimaryKey.d.ts +0 -8
  147. package/decorators/PrimaryKey.js +0 -20
  148. package/decorators/Property.d.ts +0 -250
  149. package/decorators/Property.js +0 -32
  150. package/decorators/Transactional.d.ts +0 -13
  151. package/decorators/Transactional.js +0 -28
  152. package/decorators/hooks.d.ts +0 -16
  153. package/decorators/hooks.js +0 -47
  154. package/decorators/index.d.ts +0 -17
  155. package/decorators/index.js +0 -17
  156. package/entity/ArrayCollection.d.ts +0 -116
  157. package/entity/ArrayCollection.js +0 -402
  158. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  159. package/metadata/ReflectMetadataProvider.js +0 -44
  160. package/utils/resolveContextProvider.d.ts +0 -10
  161. package/utils/resolveContextProvider.js +0 -28
@@ -1,225 +1,11 @@
1
- import dotenv from 'dotenv';
2
1
  import { realpathSync } from 'node:fs';
3
- import { platform } from 'node:os';
4
- import { fileURLToPath } from 'node:url';
5
- import { colors } from '../logging/colors.js';
6
- import { Configuration } from './Configuration.js';
7
2
  import { Utils } from './Utils.js';
3
+ import { colors } from '../logging/colors.js';
8
4
  /**
9
5
  * @internal
10
6
  */
11
7
  export class ConfigurationLoader {
12
- static async getConfiguration(contextName = 'default', paths = ConfigurationLoader.getConfigPaths(), options = {}) {
13
- // Backwards compatibility layer
14
- if (typeof contextName === 'boolean' || !Array.isArray(paths)) {
15
- this.commonJSCompat(options);
16
- this.registerDotenv(options);
17
- const configPathFromArg = ConfigurationLoader.configPathsFromArg();
18
- const configPaths = configPathFromArg ?? (Array.isArray(paths) ? paths : ConfigurationLoader.getConfigPaths());
19
- const config = contextName
20
- ? (await ConfigurationLoader.getConfiguration(process.env.MIKRO_ORM_CONTEXT_NAME ?? 'default', configPaths, Array.isArray(paths) ? {} : paths))
21
- : await (async () => {
22
- const env = await this.loadEnvironmentVars();
23
- const [path, tmp] = await this.getConfigFile(configPaths);
24
- if (!path) {
25
- if (Utils.hasObjectKeys(env)) {
26
- return new Configuration(Utils.mergeConfig({}, options, env), false);
27
- }
28
- throw new Error(`MikroORM config file not found in ['${configPaths.join(`', '`)}']`);
29
- }
30
- return new Configuration(Utils.mergeConfig(tmp, options, env), false);
31
- })();
32
- if (configPathFromArg) {
33
- config.getLogger().warn('deprecated', 'Path for config file was inferred from the command line arguments. Instead, you should set the MIKRO_ORM_CLI_CONFIG environment variable to specify the path, or if you really must use the command line arguments, import the config manually based on them, and pass it to init.', { label: 'D0001' });
34
- }
35
- return config;
36
- }
37
- const env = await this.loadEnvironmentVars();
38
- const configFinder = (cfg) => {
39
- return typeof cfg === 'object' && cfg !== null && ('contextName' in cfg ? cfg.contextName === contextName : (contextName === 'default'));
40
- };
41
- const isValidConfigFactoryResult = (cfg) => {
42
- return typeof cfg === 'object' && cfg !== null && (!('contextName' in cfg) || cfg.contextName === contextName);
43
- };
44
- const result = await this.getConfigFile(paths);
45
- if (!result[0]) {
46
- if (Utils.hasObjectKeys(env)) {
47
- return new Configuration(Utils.mergeConfig({ contextName }, options, env));
48
- }
49
- throw new Error(`MikroORM config file not found in ['${paths.join(`', '`)}']`);
50
- }
51
- const path = result[0];
52
- let tmp = result[1];
53
- if (Array.isArray(tmp)) {
54
- const tmpFirstIndex = tmp.findIndex(configFinder);
55
- if (tmpFirstIndex === -1) {
56
- // Static config not found. Try factory functions
57
- let configCandidate;
58
- for (let i = 0, l = tmp.length; i < l; ++i) {
59
- const f = tmp[i];
60
- if (typeof f !== 'function') {
61
- continue;
62
- }
63
- configCandidate = await f(contextName);
64
- if (!isValidConfigFactoryResult(configCandidate)) {
65
- continue;
66
- }
67
- tmp = configCandidate;
68
- break;
69
- }
70
- if (Array.isArray(tmp)) {
71
- throw new Error(`MikroORM config '${contextName}' was not found within the config file '${path}'. Either add a config with this name to the array, or add a function that when given this name will return a configuration object without a name, or with name set to this name.`);
72
- }
73
- }
74
- else {
75
- const tmpLastIndex = tmp.findLastIndex(configFinder);
76
- if (tmpLastIndex !== tmpFirstIndex) {
77
- throw new Error(`MikroORM config '${contextName}' is not unique within the array exported by '${path}' (first occurrence index: ${tmpFirstIndex}; last occurrence index: ${tmpLastIndex})`);
78
- }
79
- tmp = tmp[tmpFirstIndex];
80
- }
81
- }
82
- else {
83
- if (tmp instanceof Function) {
84
- tmp = await tmp(contextName);
85
- if (!isValidConfigFactoryResult(tmp)) {
86
- throw new Error(`MikroORM config '${contextName}' was not what the function exported from '${path}' provided. Ensure it returns a config object with no name, or name matching the requested one.`);
87
- }
88
- }
89
- else {
90
- if (!configFinder(tmp)) {
91
- throw new Error(`MikroORM config '${contextName}' was not what the default export from '${path}' provided.`);
92
- }
93
- }
94
- }
95
- const esmConfigOptions = this.isESM() ? { entityGenerator: { esmImport: true } } : {};
96
- return new Configuration(Utils.mergeConfig({}, esmConfigOptions, tmp, options, env));
97
- }
98
- static async getConfigFile(paths) {
99
- for (let path of paths) {
100
- path = Utils.absolutePath(path);
101
- path = Utils.normalizePath(path);
102
- if (Utils.pathExistsSync(path)) {
103
- const config = await Utils.dynamicImport(path);
104
- /* v8 ignore next */
105
- return [path, await (config.default ?? config)];
106
- }
107
- }
108
- return [];
109
- }
110
- static getPackageConfig(basePath = process.cwd()) {
111
- if (Utils.pathExistsSync(`${basePath}/package.json`)) {
112
- /* v8 ignore next 5 */
113
- try {
114
- return Utils.readJSONSync(`${basePath}/package.json`);
115
- }
116
- catch {
117
- return {};
118
- }
119
- }
120
- const parentFolder = realpathSync(`${basePath}/..`);
121
- // we reached the root folder
122
- if (basePath === parentFolder) {
123
- return {};
124
- }
125
- return this.getPackageConfig(parentFolder);
126
- }
127
- static getSettings() {
128
- const config = ConfigurationLoader.getPackageConfig();
129
- const settings = { ...config['mikro-orm'] };
130
- const bool = (v) => ['true', 't', '1'].includes(v.toLowerCase());
131
- settings.preferTs = process.env.MIKRO_ORM_CLI_PREFER_TS != null ? bool(process.env.MIKRO_ORM_CLI_PREFER_TS) : settings.preferTs;
132
- settings.tsConfigPath = process.env.MIKRO_ORM_CLI_TS_CONFIG_PATH ?? settings.tsConfigPath;
133
- settings.alwaysAllowTs = process.env.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS != null ? bool(process.env.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS) : settings.alwaysAllowTs;
134
- settings.verbose = process.env.MIKRO_ORM_CLI_VERBOSE != null ? bool(process.env.MIKRO_ORM_CLI_VERBOSE) : settings.verbose;
135
- if (process.env.MIKRO_ORM_CLI_CONFIG?.endsWith('.ts')) {
136
- settings.preferTs = true;
137
- }
138
- return settings;
139
- }
140
- static configPathsFromArg() {
141
- const options = Utils.parseArgs();
142
- const configArgName = process.env.MIKRO_ORM_CONFIG_ARG_NAME ?? 'config';
143
- if (options[configArgName]) {
144
- return [options[configArgName]];
145
- }
146
- return undefined;
147
- }
148
- static getConfigPaths() {
149
- const paths = [];
150
- const settings = ConfigurationLoader.getSettings();
151
- if (process.env.MIKRO_ORM_CLI_CONFIG) {
152
- paths.push(process.env.MIKRO_ORM_CLI_CONFIG);
153
- }
154
- paths.push(...(settings.configPaths || []));
155
- const alwaysAllowTs = settings.alwaysAllowTs ?? process.versions.bun;
156
- if (settings.preferTs !== false || alwaysAllowTs) {
157
- paths.push('./src/mikro-orm.config.ts');
158
- paths.push('./mikro-orm.config.ts');
159
- }
160
- const distDir = Utils.pathExistsSync(process.cwd() + '/dist');
161
- const buildDir = Utils.pathExistsSync(process.cwd() + '/build');
162
- /* v8 ignore next */
163
- const path = distDir ? 'dist' : (buildDir ? 'build' : 'src');
164
- paths.push(`./${path}/mikro-orm.config.js`);
165
- paths.push('./mikro-orm.config.js');
166
- const typeScriptSupport = Utils.detectTypeScriptSupport();
167
- /* v8 ignore next */
168
- return Utils.unique(paths).filter(p => p.endsWith('.js') || typeScriptSupport || alwaysAllowTs);
169
- }
170
- static isESM() {
171
- const config = ConfigurationLoader.getPackageConfig();
172
- const type = config?.type ?? '';
173
- return type === 'module';
174
- }
175
- static async registerTypeScriptSupport(configPath = 'tsconfig.json') {
176
- /* v8 ignore next 3 */
177
- if (process.versions.bun) {
178
- return true;
179
- }
180
- process.env.SWC_NODE_PROJECT ??= configPath;
181
- process.env.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS ??= '1';
182
- const esm = this.isESM();
183
- /* v8 ignore next 2 */
184
- const importMethod = esm ? 'tryImport' : 'tryRequire';
185
- const module = esm ? '@swc-node/register/esm-register' : '@swc-node/register';
186
- const supported = await Utils[importMethod]({
187
- module,
188
- warning: '@swc-node/register and @swc/core are not installed, support for working with TypeScript files might not work',
189
- });
190
- return !!supported;
191
- }
192
- static registerDotenv(options) {
193
- const path = process.env.MIKRO_ORM_ENV ?? ((options?.baseDir ?? process.cwd()) + '/.env');
194
- const env = {};
195
- dotenv.config({ path, processEnv: env });
196
- // only propagate known env vars
197
- for (const key of Object.keys(env)) {
198
- if (key.startsWith('MIKRO_ORM_')) {
199
- process.env[key] ??= env[key]; // respect user provided values
200
- }
201
- }
202
- }
203
- static async loadEnvironmentVars() {
204
- const ret = this.loadEnvironmentVarsSync();
205
- // only to keep some sort of back compatibility with those using env vars only, to support `MIKRO_ORM_TYPE`
206
- const PLATFORMS = {
207
- mongo: { className: 'MongoDriver', module: '@mikro-orm/mongodb' },
208
- mysql: { className: 'MySqlDriver', module: '@mikro-orm/mysql' },
209
- mssql: { className: 'MsSqlDriver', module: '@mikro-orm/mssql' },
210
- mariadb: { className: 'MariaDbDriver', module: '@mikro-orm/mariadb' },
211
- postgresql: { className: 'PostgreSqlDriver', module: '@mikro-orm/postgresql' },
212
- sqlite: { className: 'SqliteDriver', module: '@mikro-orm/sqlite' },
213
- libsql: { className: 'LibSqlDriver', module: '@mikro-orm/libsql' },
214
- };
215
- if (process.env.MIKRO_ORM_TYPE) {
216
- const val = process.env.MIKRO_ORM_TYPE;
217
- const driver = await import(PLATFORMS[val].module);
218
- ret.driver = driver[PLATFORMS[val].className];
219
- }
220
- return ret;
221
- }
222
- static loadEnvironmentVarsSync() {
8
+ static loadEnvironmentVars() {
223
9
  const ret = {};
224
10
  const array = (v) => v.split(',').map(vv => vv.trim());
225
11
  const bool = (v) => ['true', 't', '1'].includes(v.toLowerCase());
@@ -261,9 +47,12 @@ export class ConfigurationLoader {
261
47
  read(ret, 'MIKRO_ORM_COLORS', 'colors', bool);
262
48
  ret.discovery = {};
263
49
  read(ret.discovery, 'MIKRO_ORM_DISCOVERY_WARN_WHEN_NO_ENTITIES', 'warnWhenNoEntities', bool);
264
- read(ret.discovery, 'MIKRO_ORM_DISCOVERY_REQUIRE_ENTITIES_ARRAY', 'requireEntitiesArray', bool);
265
- read(ret.discovery, 'MIKRO_ORM_DISCOVERY_ALWAYS_ANALYSE_PROPERTIES', 'alwaysAnalyseProperties', bool);
266
- read(ret.discovery, 'MIKRO_ORM_DISCOVERY_DISABLE_DYNAMIC_FILE_ACCESS', 'disableDynamicFileAccess', bool);
50
+ read(ret.discovery, 'MIKRO_ORM_DISCOVERY_CHECK_DUPLICATE_TABLE_NAMES', 'checkDuplicateTableNames', bool);
51
+ read(ret.discovery, 'MIKRO_ORM_DISCOVERY_CHECK_DUPLICATE_FIELD_NAMES', 'checkDuplicateFieldNames', bool);
52
+ read(ret.discovery, 'MIKRO_ORM_DISCOVERY_CHECK_DUPLICATE_ENTITIES', 'checkDuplicateEntities', bool);
53
+ read(ret.discovery, 'MIKRO_ORM_DISCOVERY_CHECK_NON_PERSISTENT_COMPOSITE_PROPS', 'checkNonPersistentCompositeProps', bool);
54
+ read(ret.discovery, 'MIKRO_ORM_DISCOVERY_INFER_DEFAULT_VALUES', 'inferDefaultValues', bool);
55
+ read(ret.discovery, 'MIKRO_ORM_DISCOVERY_TS_CONFIG_PATH', 'tsConfigPath');
267
56
  cleanup(ret, 'discovery');
268
57
  ret.migrations = {};
269
58
  read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_TABLE_NAME', 'tableName');
@@ -293,6 +82,23 @@ export class ConfigurationLoader {
293
82
  cleanup(ret, 'seeder');
294
83
  return ret;
295
84
  }
85
+ static getPackageConfig(basePath = process.cwd()) {
86
+ if (Utils.pathExists(`${basePath}/package.json`)) {
87
+ /* v8 ignore next 5 */
88
+ try {
89
+ return Utils.readJSONSync(`${basePath}/package.json`);
90
+ }
91
+ catch {
92
+ return {};
93
+ }
94
+ }
95
+ const parentFolder = realpathSync(`${basePath}/..`);
96
+ // we reached the root folder
97
+ if (basePath === parentFolder) {
98
+ return {};
99
+ }
100
+ return this.getPackageConfig(parentFolder);
101
+ }
296
102
  static getORMPackages() {
297
103
  const pkg = this.getPackageConfig();
298
104
  return new Set([
@@ -300,25 +106,6 @@ export class ConfigurationLoader {
300
106
  ...Object.keys(pkg.devDependencies ?? {}),
301
107
  ]);
302
108
  }
303
- /** @internal */
304
- static commonJSCompat(options) {
305
- if (this.isESM()) {
306
- return;
307
- }
308
- /* v8 ignore next 11 */
309
- options.dynamicImportProvider ??= id => {
310
- if (platform() === 'win32') {
311
- try {
312
- id = fileURLToPath(id);
313
- }
314
- catch {
315
- // ignore
316
- }
317
- }
318
- return Utils.requireFrom(id);
319
- };
320
- Utils.setDynamicImportProvider(options.dynamicImportProvider);
321
- }
322
109
  static getORMPackageVersion(name) {
323
110
  try {
324
111
  const pkg = Utils.requireFrom(`${name}/package.json`);
@@ -332,7 +119,7 @@ export class ConfigurationLoader {
332
119
  // inspired by https://github.com/facebook/docusaurus/pull/3386
333
120
  static checkPackageVersion() {
334
121
  const coreVersion = Utils.getORMVersion();
335
- if (process.env.MIKRO_ORM_ALLOW_VERSION_MISMATCH) {
122
+ if (process.env.MIKRO_ORM_ALLOW_VERSION_MISMATCH || coreVersion === 'N/A') {
336
123
  return coreVersion;
337
124
  }
338
125
  const deps = this.getORMPackages();
package/utils/Cursor.d.ts CHANGED
@@ -49,13 +49,13 @@ import { type QueryOrder } from '../enums.js';
49
49
  * }
50
50
  * ```
51
51
  */
52
- export declare class Cursor<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never> {
52
+ export declare class Cursor<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never, IncludeCount extends boolean = true> {
53
53
  readonly items: Loaded<Entity, Hint, Fields, Excludes>[];
54
- readonly totalCount: number;
54
+ readonly totalCount: IncludeCount extends true ? number : undefined;
55
55
  readonly hasPrevPage: boolean;
56
56
  readonly hasNextPage: boolean;
57
57
  private readonly definition;
58
- constructor(items: Loaded<Entity, Hint, Fields, Excludes>[], totalCount: number, options: FindByCursorOptions<Entity, Hint, Fields, Excludes>, meta: EntityMetadata<Entity>);
58
+ constructor(items: Loaded<Entity, Hint, Fields, Excludes>[], totalCount: IncludeCount extends true ? number : undefined, options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>, meta: EntityMetadata<Entity>);
59
59
  get startCursor(): string | null;
60
60
  get endCursor(): string | null;
61
61
  /**
package/utils/Cursor.js CHANGED
@@ -107,6 +107,9 @@ export class Cursor {
107
107
  if (Utils.isEntity(value, true)) {
108
108
  value = helper(value).getPrimaryKey();
109
109
  }
110
+ if (Utils.isScalarReference(value)) {
111
+ value = value.unwrap();
112
+ }
110
113
  if (object) {
111
114
  return ({ [prop]: value });
112
115
  }
@@ -1,9 +1,10 @@
1
- import type { Primary, Ref } from '../typings.js';
1
+ import type { Constructor, Primary, Ref } from '../typings.js';
2
2
  import { Collection, type InitCollectionOptions } from '../entity/Collection.js';
3
3
  import { type EntityManager } from '../EntityManager.js';
4
- import type DataLoader from 'dataloader';
5
4
  import { type LoadReferenceOptions } from '../entity/Reference.js';
5
+ type BatchLoadFn<K, V> = (keys: readonly K[]) => PromiseLike<ArrayLike<V | Error>>;
6
6
  export declare class DataloaderUtils {
7
+ private static DataLoader?;
7
8
  /**
8
9
  * Groups identified references by entity and returns a Map with the
9
10
  * class name as the index and the corresponding primary keys as the value.
@@ -13,7 +14,7 @@ export declare class DataloaderUtils {
13
14
  * Returns the reference dataloader batchLoadFn, which aggregates references by entity,
14
15
  * makes one query per entity and maps each input reference to the corresponding result.
15
16
  */
16
- static getRefBatchLoadFn(em: EntityManager): DataLoader.BatchLoadFn<[Ref<any>, Omit<LoadReferenceOptions<any, any>, 'dataloader'>?], any>;
17
+ static getRefBatchLoadFn(em: EntityManager): BatchLoadFn<[Ref<any>, Omit<LoadReferenceOptions<any, any>, 'dataloader'>?], any>;
17
18
  /**
18
19
  * Groups collections by entity and returns a Map whose keys are the entity names and whose values are filter Maps
19
20
  * which we can use to narrow down the find query to return just the items of the collections that have been dataloaded.
@@ -34,8 +35,17 @@ export declare class DataloaderUtils {
34
35
  */
35
36
  static getColFilter<T, S extends T>(collection: Collection<any>): (result: T) => result is S;
36
37
  /**
37
- * Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
38
+ * Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
38
39
  * makes one query per entity and maps each input collection to the corresponding result.
39
40
  */
40
- static getColBatchLoadFn(em: EntityManager): DataLoader.BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
41
+ static getColBatchLoadFn(em: EntityManager): BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
42
+ /**
43
+ * Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
44
+ * makes one query per entity and maps each input collection to the corresponding result.
45
+ */
46
+ static getManyToManyColBatchLoadFn(em: EntityManager): BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
47
+ static getDataLoader(): Promise<Constructor<{
48
+ load: (...args: unknown[]) => Promise<unknown>;
49
+ }>>;
41
50
  }
51
+ export {};
@@ -1,8 +1,9 @@
1
1
  import { Collection } from '../entity/Collection.js';
2
2
  import { helper } from '../entity/wrap.js';
3
- import { ReferenceKind } from '../enums.js';
4
3
  import { Reference } from '../entity/Reference.js';
4
+ import { Utils } from './Utils.js';
5
5
  export class DataloaderUtils {
6
+ static DataLoader;
6
7
  /**
7
8
  * Groups identified references by entity and returns a Map with the
8
9
  * class name as the index and the corresponding primary keys as the value.
@@ -118,7 +119,6 @@ export class DataloaderUtils {
118
119
  // We need to populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s)
119
120
  populate: [
120
121
  ...(opts.populate === false ? [] : opts.populate ?? []),
121
- ...(opts.ref ? [':ref'] : []),
122
122
  ...Array.from(filterMap.keys()).filter(
123
123
  // We need to do so only if the inverse side is a collection, because we can already retrieve the PK from a reference without having to load it
124
124
  prop => em.getMetadata(className).properties[prop]?.ref !== true),
@@ -149,15 +149,11 @@ export class DataloaderUtils {
149
149
  else if (target) {
150
150
  return target === collection.owner;
151
151
  }
152
- // FIXME https://github.com/mikro-orm/mikro-orm/issues/6031
153
- if (!target && collection.property.kind === ReferenceKind.MANY_TO_MANY) {
154
- throw new Error(`Inverse side is required for M:N relations with dataloader: ${collection.owner.constructor.name}.${collection.property.name}`);
155
- }
156
152
  return false;
157
153
  };
158
154
  }
159
155
  /**
160
- * Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
156
+ * Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
161
157
  * makes one query per entity and maps each input collection to the corresponding result.
162
158
  */
163
159
  static getColBatchLoadFn(em) {
@@ -179,4 +175,54 @@ export class DataloaderUtils {
179
175
  });
180
176
  };
181
177
  }
178
+ /**
179
+ * Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
180
+ * makes one query per entity and maps each input collection to the corresponding result.
181
+ */
182
+ static getManyToManyColBatchLoadFn(em) {
183
+ return async (collsWithOpts) => {
184
+ const groups = new Map();
185
+ for (const [col, opts] of collsWithOpts) {
186
+ const key = `${col.property.targetMeta.className}.${col.property.name}|${JSON.stringify(opts ?? {})}`;
187
+ const value = groups.get(key) ?? [];
188
+ value.push([col, opts ?? {}]);
189
+ groups.set(key, value);
190
+ }
191
+ const ret = [];
192
+ for (const group of groups.values()) {
193
+ const prop = group[0][0].property;
194
+ const options = {};
195
+ const wrap = (cond) => ({ [prop.name]: cond });
196
+ const orderBy = Utils.asArray(group[0][1]?.orderBy).map(o => wrap(o));
197
+ const populate = wrap(group[0][1]?.populate);
198
+ const owners = group.map(c => c[0].owner);
199
+ const $or = [];
200
+ // a bit of a hack, but we need to prefix the key, since we have only a column name, not a property name
201
+ const alias = em.config.getNamingStrategy().aliasName(prop.pivotEntity, 0);
202
+ const fk = `${alias}.${Utils.getPrimaryKeyHash(prop.joinColumns)}`;
203
+ for (const c of group) {
204
+ $or.push({ $and: [c[1]?.where ?? {}, { [fk]: c[0].owner }] });
205
+ options.refresh ??= c[1]?.refresh;
206
+ }
207
+ options.where = wrap({ $or });
208
+ const r = await em.getEntityLoader().findChildrenFromPivotTable(owners, prop, options, orderBy, populate, group[0][1]?.ref);
209
+ ret.push(...r);
210
+ }
211
+ return ret;
212
+ };
213
+ }
214
+ static async getDataLoader() {
215
+ if (this.DataLoader) {
216
+ return this.DataLoader;
217
+ }
218
+ try {
219
+ const mod = await import('dataloader' + '');
220
+ const DataLoader = mod.default;
221
+ return (this.DataLoader ??= DataLoader);
222
+ }
223
+ catch {
224
+ /* v8 ignore next 2 */
225
+ throw new Error('DataLoader is not found, make sure `dataloader` package is installed in your project\'s dependencies.');
226
+ }
227
+ }
182
228
  }
@@ -1,6 +1,8 @@
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
- type Comparator<T> = (a: T, b: T) => EntityData<T>;
3
+ type Comparator<T> = (a: T, b: T, options?: {
4
+ includeInverseSides?: boolean;
5
+ }) => EntityData<T>;
4
6
  type ResultMapper<T> = (result: EntityData<T>) => EntityData<T> | null;
5
7
  type SnapshotGenerator<T> = (entity: T) => EntityData<T>;
6
8
  type CompositeKeyPart = string | CompositeKeyPart[];
@@ -18,7 +20,9 @@ export declare class EntityComparator {
18
20
  /**
19
21
  * Computes difference between two entities.
20
22
  */
21
- diffEntities<T>(entityName: string, a: EntityData<T>, b: EntityData<T>): EntityData<T>;
23
+ diffEntities<T>(entityName: string, a: EntityData<T>, b: EntityData<T>, options?: {
24
+ includeInverseSides?: boolean;
25
+ }): EntityData<T>;
22
26
  matching<T>(entityName: string, a: EntityData<T>, b: EntityData<T>): boolean;
23
27
  /**
24
28
  * Removes ORM specific code from entities and prepares it for serializing. Used before change set computation.
@@ -44,7 +48,7 @@ export declare class EntityComparator {
44
48
  /**
45
49
  * @internal Highly performance-sensitive method.
46
50
  */
47
- getSnapshotGenerator<T>(entityName: string): SnapshotGenerator<T>;
51
+ getSnapshotGenerator<T>(entityName: EntityName<T>): SnapshotGenerator<T>;
48
52
  /**
49
53
  * @internal
50
54
  */