@mikro-orm/core 7.0.0-dev.5 → 7.0.0-dev.51

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 (115) hide show
  1. package/EntityManager.d.ts +81 -27
  2. package/EntityManager.js +287 -175
  3. package/MikroORM.d.ts +6 -6
  4. package/MikroORM.js +31 -74
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +2 -1
  7. package/cache/FileCacheAdapter.js +6 -4
  8. package/connections/Connection.d.ts +9 -5
  9. package/connections/Connection.js +16 -13
  10. package/decorators/Embedded.d.ts +5 -11
  11. package/decorators/Entity.d.ts +18 -3
  12. package/decorators/Indexed.d.ts +2 -2
  13. package/decorators/ManyToMany.d.ts +2 -0
  14. package/decorators/ManyToOne.d.ts +4 -0
  15. package/decorators/OneToOne.d.ts +4 -0
  16. package/decorators/Property.d.ts +53 -9
  17. package/decorators/Transactional.d.ts +1 -0
  18. package/decorators/Transactional.js +3 -3
  19. package/decorators/index.d.ts +1 -1
  20. package/drivers/DatabaseDriver.d.ts +10 -5
  21. package/drivers/DatabaseDriver.js +4 -4
  22. package/drivers/IDatabaseDriver.d.ts +28 -4
  23. package/entity/ArrayCollection.d.ts +6 -4
  24. package/entity/ArrayCollection.js +26 -9
  25. package/entity/BaseEntity.d.ts +0 -1
  26. package/entity/BaseEntity.js +0 -3
  27. package/entity/Collection.d.ts +3 -4
  28. package/entity/Collection.js +37 -17
  29. package/entity/EntityAssigner.d.ts +1 -1
  30. package/entity/EntityAssigner.js +9 -1
  31. package/entity/EntityFactory.d.ts +7 -0
  32. package/entity/EntityFactory.js +29 -11
  33. package/entity/EntityHelper.js +25 -8
  34. package/entity/EntityLoader.d.ts +5 -4
  35. package/entity/EntityLoader.js +69 -36
  36. package/entity/EntityRepository.d.ts +1 -1
  37. package/entity/EntityValidator.js +1 -1
  38. package/entity/Reference.d.ts +9 -7
  39. package/entity/Reference.js +30 -3
  40. package/entity/WrappedEntity.d.ts +0 -2
  41. package/entity/WrappedEntity.js +1 -5
  42. package/entity/defineEntity.d.ts +555 -0
  43. package/entity/defineEntity.js +529 -0
  44. package/entity/index.d.ts +2 -0
  45. package/entity/index.js +2 -0
  46. package/entity/utils.d.ts +7 -0
  47. package/entity/utils.js +15 -3
  48. package/enums.d.ts +16 -3
  49. package/enums.js +13 -0
  50. package/errors.d.ts +6 -1
  51. package/errors.js +14 -4
  52. package/events/EventSubscriber.d.ts +3 -1
  53. package/hydration/ObjectHydrator.d.ts +4 -4
  54. package/hydration/ObjectHydrator.js +35 -24
  55. package/index.d.ts +2 -1
  56. package/index.js +1 -1
  57. package/logging/DefaultLogger.d.ts +1 -1
  58. package/logging/SimpleLogger.d.ts +1 -1
  59. package/metadata/EntitySchema.d.ts +8 -4
  60. package/metadata/EntitySchema.js +39 -19
  61. package/metadata/MetadataDiscovery.d.ts +4 -4
  62. package/metadata/MetadataDiscovery.js +139 -122
  63. package/metadata/MetadataStorage.js +1 -1
  64. package/metadata/MetadataValidator.js +4 -3
  65. package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
  66. package/naming-strategy/AbstractNamingStrategy.js +7 -1
  67. package/naming-strategy/NamingStrategy.d.ts +11 -1
  68. package/package.json +5 -5
  69. package/platforms/Platform.d.ts +5 -3
  70. package/platforms/Platform.js +4 -8
  71. package/serialization/EntitySerializer.d.ts +2 -0
  72. package/serialization/EntitySerializer.js +23 -5
  73. package/serialization/EntityTransformer.js +16 -6
  74. package/serialization/SerializationContext.js +14 -11
  75. package/types/BigIntType.d.ts +9 -6
  76. package/types/BigIntType.js +3 -0
  77. package/types/BooleanType.d.ts +1 -1
  78. package/types/DecimalType.d.ts +6 -4
  79. package/types/DecimalType.js +1 -1
  80. package/types/DoubleType.js +1 -1
  81. package/types/JsonType.d.ts +1 -1
  82. package/types/JsonType.js +7 -2
  83. package/types/Type.d.ts +2 -1
  84. package/types/Type.js +1 -1
  85. package/types/index.d.ts +1 -1
  86. package/typings.d.ts +89 -49
  87. package/typings.js +31 -31
  88. package/unit-of-work/ChangeSetComputer.js +8 -3
  89. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  90. package/unit-of-work/ChangeSetPersister.js +37 -16
  91. package/unit-of-work/UnitOfWork.d.ts +8 -1
  92. package/unit-of-work/UnitOfWork.js +110 -53
  93. package/utils/AbstractSchemaGenerator.js +3 -1
  94. package/utils/Configuration.d.ts +200 -183
  95. package/utils/Configuration.js +137 -144
  96. package/utils/ConfigurationLoader.d.ts +9 -22
  97. package/utils/ConfigurationLoader.js +49 -72
  98. package/utils/Cursor.d.ts +3 -3
  99. package/utils/Cursor.js +3 -0
  100. package/utils/DataloaderUtils.d.ts +7 -2
  101. package/utils/DataloaderUtils.js +38 -7
  102. package/utils/EntityComparator.d.ts +6 -2
  103. package/utils/EntityComparator.js +104 -58
  104. package/utils/QueryHelper.d.ts +9 -1
  105. package/utils/QueryHelper.js +66 -5
  106. package/utils/RawQueryFragment.d.ts +36 -4
  107. package/utils/RawQueryFragment.js +34 -13
  108. package/utils/TransactionManager.d.ts +65 -0
  109. package/utils/TransactionManager.js +223 -0
  110. package/utils/Utils.d.ts +13 -11
  111. package/utils/Utils.js +82 -55
  112. package/utils/index.d.ts +1 -0
  113. package/utils/index.js +1 -0
  114. package/utils/upsert-utils.d.ts +7 -2
  115. package/utils/upsert-utils.js +52 -1
@@ -11,127 +11,133 @@ import { RequestContext } from './RequestContext.js';
11
11
  import { DataloaderType, FlushMode, LoadStrategy, PopulateHint } from '../enums.js';
12
12
  import { MemoryCacheAdapter } from '../cache/MemoryCacheAdapter.js';
13
13
  import { EntityComparator } from './EntityComparator.js';
14
+ const DEFAULTS = {
15
+ pool: {},
16
+ entities: [],
17
+ entitiesTs: [],
18
+ extensions: [],
19
+ subscribers: [],
20
+ filters: {},
21
+ discovery: {
22
+ warnWhenNoEntities: true,
23
+ requireEntitiesArray: false,
24
+ checkDuplicateTableNames: true,
25
+ checkDuplicateFieldNames: true,
26
+ checkDuplicateEntities: true,
27
+ checkNonPersistentCompositeProps: true,
28
+ alwaysAnalyseProperties: true,
29
+ disableDynamicFileAccess: false,
30
+ inferDefaultValues: true,
31
+ },
32
+ strict: false,
33
+ validate: false,
34
+ validateRequired: true,
35
+ context: (name) => RequestContext.getEntityManager(name),
36
+ contextName: 'default',
37
+ allowGlobalContext: false,
38
+ // eslint-disable-next-line no-console
39
+ logger: console.log.bind(console),
40
+ colors: true,
41
+ findOneOrFailHandler: (entityName, where) => NotFoundError.findOneFailed(entityName, where),
42
+ findExactlyOneOrFailHandler: (entityName, where) => NotFoundError.findExactlyOneFailed(entityName, where),
43
+ baseDir: process.cwd(),
44
+ hydrator: ObjectHydrator,
45
+ flushMode: FlushMode.AUTO,
46
+ loadStrategy: LoadStrategy.BALANCED,
47
+ dataloader: DataloaderType.NONE,
48
+ populateWhere: PopulateHint.ALL,
49
+ ignoreUndefinedInQuery: false,
50
+ onQuery: (sql) => sql,
51
+ autoJoinOneToOneOwner: true,
52
+ autoJoinRefsForFilters: true,
53
+ filtersOnRelations: true,
54
+ propagationOnPrototype: true,
55
+ populateAfterFlush: true,
56
+ serialization: {
57
+ includePrimaryKeys: true,
58
+ },
59
+ assign: {
60
+ updateNestedEntities: true,
61
+ updateByPrimaryKey: true,
62
+ mergeObjectProperties: false,
63
+ mergeEmbeddedProperties: true,
64
+ ignoreUndefined: false,
65
+ },
66
+ persistOnCreate: true,
67
+ upsertManaged: true,
68
+ forceEntityConstructor: false,
69
+ forceUndefined: false,
70
+ processOnCreateHooksEarly: false,
71
+ ensureDatabase: true,
72
+ ensureIndexes: false,
73
+ batchSize: 300,
74
+ hashAlgorithm: 'md5',
75
+ debug: false,
76
+ ignoreDeprecations: false,
77
+ verbose: false,
78
+ driverOptions: {},
79
+ migrations: {
80
+ tableName: 'mikro_orm_migrations',
81
+ path: './migrations',
82
+ glob: '!(*.d).{js,ts,cjs}',
83
+ silent: false,
84
+ transactional: true,
85
+ disableForeignKeys: false,
86
+ allOrNothing: true,
87
+ dropTables: true,
88
+ safe: false,
89
+ snapshot: true,
90
+ emit: 'ts',
91
+ fileName: (timestamp, name) => `Migration${timestamp}${name ? '_' + name : ''}`,
92
+ },
93
+ schemaGenerator: {
94
+ disableForeignKeys: false,
95
+ createForeignKeyConstraints: true,
96
+ ignoreSchema: [],
97
+ skipTables: [],
98
+ skipColumns: {},
99
+ },
100
+ embeddables: {
101
+ prefixMode: 'relative',
102
+ },
103
+ entityGenerator: {
104
+ forceUndefined: true,
105
+ undefinedDefaults: false,
106
+ scalarTypeInDecorator: false,
107
+ bidirectionalRelations: true,
108
+ identifiedReferences: true,
109
+ scalarPropertiesForRelations: 'never',
110
+ entityDefinition: 'defineEntity',
111
+ enumMode: 'dictionary',
112
+ fileName: (className) => className,
113
+ onlyPurePivotTables: false,
114
+ outputPurePivotTables: false,
115
+ readOnlyPivotTables: false,
116
+ useCoreBaseEntity: false,
117
+ },
118
+ metadataCache: {
119
+ pretty: false,
120
+ adapter: FileCacheAdapter,
121
+ options: { cacheDir: process.cwd() + '/temp' },
122
+ },
123
+ resultCache: {
124
+ adapter: MemoryCacheAdapter,
125
+ expiration: 1000, // 1s
126
+ options: {},
127
+ },
128
+ metadataProvider: ReflectMetadataProvider,
129
+ highlighter: new NullHighlighter(),
130
+ seeder: {
131
+ path: './seeders',
132
+ defaultSeeder: 'DatabaseSeeder',
133
+ glob: '!(*.d).{js,ts}',
134
+ emit: 'ts',
135
+ fileName: (className) => className,
136
+ },
137
+ preferReadReplicas: true,
138
+ dynamicImportProvider: /* v8 ignore next */ (id) => import(id),
139
+ };
14
140
  export class Configuration {
15
- static DEFAULTS = {
16
- pool: {},
17
- entities: [],
18
- entitiesTs: [],
19
- extensions: [],
20
- subscribers: [],
21
- filters: {},
22
- discovery: {
23
- warnWhenNoEntities: true,
24
- requireEntitiesArray: false,
25
- checkDuplicateTableNames: true,
26
- checkDuplicateFieldNames: true,
27
- checkDuplicateEntities: true,
28
- checkNonPersistentCompositeProps: true,
29
- alwaysAnalyseProperties: true,
30
- disableDynamicFileAccess: false,
31
- inferDefaultValues: true,
32
- },
33
- strict: false,
34
- validate: false,
35
- validateRequired: true,
36
- context: (name) => RequestContext.getEntityManager(name),
37
- contextName: 'default',
38
- allowGlobalContext: false,
39
- // eslint-disable-next-line no-console
40
- logger: console.log.bind(console),
41
- colors: true,
42
- findOneOrFailHandler: (entityName, where) => NotFoundError.findOneFailed(entityName, where),
43
- findExactlyOneOrFailHandler: (entityName, where) => NotFoundError.findExactlyOneFailed(entityName, where),
44
- baseDir: process.cwd(),
45
- hydrator: ObjectHydrator,
46
- flushMode: FlushMode.AUTO,
47
- loadStrategy: LoadStrategy.JOINED,
48
- dataloader: DataloaderType.NONE,
49
- populateWhere: PopulateHint.ALL,
50
- connect: true,
51
- ignoreUndefinedInQuery: false,
52
- onQuery: sql => sql,
53
- autoJoinOneToOneOwner: true,
54
- autoJoinRefsForFilters: true,
55
- propagationOnPrototype: true,
56
- populateAfterFlush: true,
57
- serialization: {
58
- includePrimaryKeys: true,
59
- },
60
- assign: {
61
- updateNestedEntities: true,
62
- updateByPrimaryKey: true,
63
- mergeObjectProperties: false,
64
- mergeEmbeddedProperties: true,
65
- ignoreUndefined: false,
66
- },
67
- persistOnCreate: true,
68
- upsertManaged: true,
69
- forceEntityConstructor: false,
70
- forceUndefined: false,
71
- ensureDatabase: true,
72
- ensureIndexes: false,
73
- batchSize: 300,
74
- debug: false,
75
- ignoreDeprecations: false,
76
- verbose: false,
77
- driverOptions: {},
78
- migrations: {
79
- tableName: 'mikro_orm_migrations',
80
- path: './migrations',
81
- glob: '!(*.d).{js,ts,cjs}',
82
- silent: false,
83
- transactional: true,
84
- disableForeignKeys: false,
85
- allOrNothing: true,
86
- dropTables: true,
87
- safe: false,
88
- snapshot: true,
89
- emit: 'ts',
90
- fileName: (timestamp, name) => `Migration${timestamp}${name ? '_' + name : ''}`,
91
- },
92
- schemaGenerator: {
93
- disableForeignKeys: false,
94
- createForeignKeyConstraints: true,
95
- ignoreSchema: [],
96
- },
97
- embeddables: {
98
- prefixMode: 'absolute',
99
- },
100
- entityGenerator: {
101
- forceUndefined: true,
102
- undefinedDefaults: false,
103
- bidirectionalRelations: false,
104
- identifiedReferences: false,
105
- scalarTypeInDecorator: false,
106
- scalarPropertiesForRelations: 'never',
107
- fileName: (className) => className,
108
- onlyPurePivotTables: false,
109
- outputPurePivotTables: false,
110
- readOnlyPivotTables: false,
111
- useCoreBaseEntity: false,
112
- },
113
- metadataCache: {
114
- pretty: false,
115
- adapter: FileCacheAdapter,
116
- options: { cacheDir: process.cwd() + '/temp' },
117
- },
118
- resultCache: {
119
- adapter: MemoryCacheAdapter,
120
- expiration: 1000, // 1s
121
- options: {},
122
- },
123
- metadataProvider: ReflectMetadataProvider,
124
- highlighter: new NullHighlighter(),
125
- seeder: {
126
- path: './seeders',
127
- defaultSeeder: 'DatabaseSeeder',
128
- glob: '!(*.d).{js,ts}',
129
- emit: 'ts',
130
- fileName: (className) => className,
131
- },
132
- preferReadReplicas: true,
133
- dynamicImportProvider: /* v8 ignore next */ (id) => import(id),
134
- };
135
141
  options;
136
142
  logger;
137
143
  driver;
@@ -142,9 +148,8 @@ export class Configuration {
142
148
  if (options.dynamicImportProvider) {
143
149
  Utils.setDynamicImportProvider(options.dynamicImportProvider);
144
150
  }
145
- this.options = Utils.mergeConfig({}, Configuration.DEFAULTS, options);
151
+ this.options = Utils.mergeConfig({}, DEFAULTS, options);
146
152
  this.options.baseDir = Utils.absolutePath(this.options.baseDir);
147
- this.options.preferTs ??= options.preferTs;
148
153
  if (validate) {
149
154
  this.validateOptions();
150
155
  }
@@ -190,7 +195,7 @@ export class Configuration {
190
195
  * Resets the configuration to its default value
191
196
  */
192
197
  reset(key) {
193
- this.options[key] = Configuration.DEFAULTS[key];
198
+ this.options[key] = DEFAULTS[key];
194
199
  }
195
200
  /**
196
201
  * Gets Logger instance.
@@ -204,15 +209,6 @@ export class Configuration {
204
209
  }
205
210
  return this.options.dataloader;
206
211
  }
207
- /**
208
- * Gets current client URL (connection string).
209
- */
210
- getClientUrl(hidePassword = false) {
211
- if (hidePassword) {
212
- return this.options.clientUrl.replace(/\/\/([^:]+):(.+)@/, '//$1:*****@');
213
- }
214
- return this.options.clientUrl;
215
- }
216
212
  getSchema(skipDefaultSchema = false) {
217
213
  if (skipDefaultSchema && this.options.schema === this.platform.getDefaultSchemaName()) {
218
214
  return undefined;
@@ -268,7 +264,7 @@ export class Configuration {
268
264
  * Gets instance of metadata CacheAdapter. (cached)
269
265
  */
270
266
  getMetadataCacheAdapter() {
271
- return this.getCachedService(this.options.metadataCache.adapter, this.options.metadataCache.options, this.options.baseDir, this.options.metadataCache.pretty);
267
+ return this.getCachedService(this.options.metadataCache.adapter, this.options.metadataCache.options, this.options.baseDir, this.options.metadataCache.pretty, this.options.hashAlgorithm);
272
268
  }
273
269
  /**
274
270
  * Gets instance of CacheAdapter for result cache. (cached)
@@ -311,17 +307,15 @@ export class Configuration {
311
307
  if (!this.options.clientUrl) {
312
308
  this.options.clientUrl = this.platform.getDefaultClientUrl();
313
309
  }
314
- if (!('implicitTransactions' in this.options)) {
315
- this.options.implicitTransactions = this.platform.usesImplicitTransactions();
316
- }
310
+ this.options.implicitTransactions ??= this.platform.usesImplicitTransactions();
317
311
  try {
318
- const url = new URL(this.getClientUrl());
312
+ const url = new URL(this.options.clientUrl);
319
313
  if (url.pathname) {
320
314
  this.options.dbName = this.get('dbName', decodeURIComponent(url.pathname).substring(1));
321
315
  }
322
316
  }
323
317
  catch {
324
- const url = this.getClientUrl().match(/:\/\/.*\/([^?]+)/);
318
+ const url = this.options.clientUrl.match(/:\/\/.*\/([^?]+)/);
325
319
  if (url) {
326
320
  this.options.dbName = this.get('dbName', decodeURIComponent(url[1]));
327
321
  }
@@ -329,15 +323,14 @@ export class Configuration {
329
323
  if (validate && !this.options.dbName && this.options.clientUrl) {
330
324
  throw new Error("No database specified, `clientUrl` option provided but it's missing the pathname.");
331
325
  }
332
- if (!this.options.schema) {
333
- this.options.schema = this.platform.getDefaultSchemaName();
334
- }
335
- if (!this.options.charset) {
336
- this.options.charset = this.platform.getDefaultCharset();
337
- }
326
+ this.options.schema ??= this.platform.getDefaultSchemaName();
327
+ this.options.charset ??= this.platform.getDefaultCharset();
338
328
  Object.keys(this.options.filters).forEach(key => {
339
329
  this.options.filters[key].default ??= true;
340
330
  });
331
+ if (!this.options.filtersOnRelations) {
332
+ this.options.autoJoinRefsForFilters ??= false;
333
+ }
341
334
  this.options.subscribers = Utils.unique(this.options.subscribers).map(subscriber => {
342
335
  return subscriber.constructor.name === 'Function' ? new subscriber() : subscriber;
343
336
  });
@@ -13,42 +13,29 @@ export declare class ConfigurationLoader {
13
13
  * @param paths Array of possible paths for a configuration file. Files will be checked in order, and the first existing one will be used. Defaults to the output of {@link ConfigurationLoader.getConfigPaths}.
14
14
  * @param options Additional options to augment the final configuration with.
15
15
  */
16
- static getConfiguration<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager = EntityManager>(contextName: string, paths?: string[], options?: Partial<Options>): Promise<Configuration<D, EM>>;
17
- /**
18
- * Gets the default config from the default paths
19
- *
20
- * @deprecated Prefer to explicitly set the `contextName` at the first argument. This signature is available for backwards compatibility, and may be removed in v7.
21
- */
22
- static getConfiguration<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager = EntityManager>(): Promise<Configuration<D, EM>>;
23
- /**
24
- * Gets default configuration out of the default paths, and possibly from `process.argv`
25
- *
26
- * @param validate Whether to validate the final configuration.
27
- * @param options Additional options to augment the final configuration with (just before validation).
28
- *
29
- * @deprecated Use the other overloads of this method. This signature will be removed in v7.
30
- */
31
- static getConfiguration<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager = EntityManager>(validate: boolean, options?: Partial<Options>): Promise<Configuration<D, EM>>;
16
+ static getConfiguration<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>>(contextName?: string, paths?: string[], options?: Partial<Options>): Promise<Configuration<D, EM>>;
32
17
  static getConfigFile(paths: string[]): Promise<[string, unknown] | []>;
33
18
  static getPackageConfig(basePath?: string): Dictionary;
34
19
  static getSettings(): Settings;
35
- static configPathsFromArg(): string[] | undefined;
36
20
  static getConfigPaths(): string[];
37
21
  static isESM(): boolean;
38
- static registerTypeScriptSupport(configPath?: string): Promise<boolean>;
39
- static registerDotenv<D extends IDatabaseDriver>(options?: Options<D>): void;
22
+ /**
23
+ * Tries to register TS support in the following order: swc, tsx, jiti, tsimp
24
+ * Use `MIKRO_ORM_CLI_TS_LOADER` env var to set the loader explicitly.
25
+ * This method is used only in CLI context.
26
+ */
27
+ static registerTypeScriptSupport(configPath?: string, tsLoader?: 'swc' | 'tsx' | 'jiti' | 'tsimp' | 'auto'): Promise<boolean>;
28
+ static registerDotenv<D extends IDatabaseDriver>(options: Options<D>): void;
40
29
  static loadEnvironmentVars<D extends IDatabaseDriver>(): Promise<Partial<Options<D>>>;
41
30
  static loadEnvironmentVarsSync<D extends IDatabaseDriver>(): Partial<Options<D>>;
42
31
  static getORMPackages(): Set<string>;
43
- /** @internal */
44
- static commonJSCompat(options: Partial<Options>): void;
45
32
  static getORMPackageVersion(name: string): string | undefined;
46
33
  static checkPackageVersion(): string;
47
34
  }
48
35
  export interface Settings {
49
- alwaysAllowTs?: boolean;
50
36
  verbose?: boolean;
51
37
  preferTs?: boolean;
38
+ tsLoader?: 'swc' | 'tsx' | 'jiti' | 'tsimp' | 'auto';
52
39
  tsConfigPath?: string;
53
40
  configPaths?: string[];
54
41
  }
@@ -1,7 +1,5 @@
1
1
  import dotenv from 'dotenv';
2
2
  import { realpathSync } from 'node:fs';
3
- import { platform } from 'node:os';
4
- import { fileURLToPath } from 'node:url';
5
3
  import { colors } from '../logging/colors.js';
6
4
  import { Configuration } from './Configuration.js';
7
5
  import { Utils } from './Utils.js';
@@ -9,31 +7,14 @@ import { Utils } from './Utils.js';
9
7
  * @internal
10
8
  */
11
9
  export class ConfigurationLoader {
10
+ /**
11
+ * Gets a named configuration
12
+ *
13
+ * @param contextName Load a config with the given `contextName` value. Used when config file exports array or factory function. Setting it to "default" matches also config objects without `contextName` set.
14
+ * @param paths Array of possible paths for a configuration file. Files will be checked in order, and the first existing one will be used. Defaults to the output of {@link ConfigurationLoader.getConfigPaths}.
15
+ * @param options Additional options to augment the final configuration with.
16
+ */
12
17
  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
18
  const env = await this.loadEnvironmentVars();
38
19
  const configFinder = (cfg) => {
39
20
  return typeof cfg === 'object' && cfg !== null && ('contextName' in cfg ? cfg.contextName === contextName : (contextName === 'default'));
@@ -129,31 +110,23 @@ export class ConfigurationLoader {
129
110
  const settings = { ...config['mikro-orm'] };
130
111
  const bool = (v) => ['true', 't', '1'].includes(v.toLowerCase());
131
112
  settings.preferTs = process.env.MIKRO_ORM_CLI_PREFER_TS != null ? bool(process.env.MIKRO_ORM_CLI_PREFER_TS) : settings.preferTs;
113
+ settings.tsLoader = process.env.MIKRO_ORM_CLI_TS_LOADER ?? settings.tsLoader;
132
114
  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
115
  settings.verbose = process.env.MIKRO_ORM_CLI_VERBOSE != null ? bool(process.env.MIKRO_ORM_CLI_VERBOSE) : settings.verbose;
135
116
  if (process.env.MIKRO_ORM_CLI_CONFIG?.endsWith('.ts')) {
136
117
  settings.preferTs = true;
137
118
  }
138
119
  return settings;
139
120
  }
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
121
  static getConfigPaths() {
149
- const paths = [];
150
122
  const settings = ConfigurationLoader.getSettings();
123
+ const typeScriptSupport = settings.preferTs ?? Utils.detectTypeScriptSupport();
124
+ const paths = [];
151
125
  if (process.env.MIKRO_ORM_CLI_CONFIG) {
152
126
  paths.push(process.env.MIKRO_ORM_CLI_CONFIG);
153
127
  }
154
128
  paths.push(...(settings.configPaths || []));
155
- const alwaysAllowTs = settings.alwaysAllowTs ?? process.versions.bun;
156
- if (settings.preferTs !== false || alwaysAllowTs) {
129
+ if (typeScriptSupport) {
157
130
  paths.push('./src/mikro-orm.config.ts');
158
131
  paths.push('./mikro-orm.config.ts');
159
132
  }
@@ -163,36 +136,59 @@ export class ConfigurationLoader {
163
136
  const path = distDir ? 'dist' : (buildDir ? 'build' : 'src');
164
137
  paths.push(`./${path}/mikro-orm.config.js`);
165
138
  paths.push('./mikro-orm.config.js');
166
- const typeScriptSupport = Utils.detectTypeScriptSupport();
167
139
  /* v8 ignore next */
168
- return Utils.unique(paths).filter(p => p.endsWith('.js') || typeScriptSupport || alwaysAllowTs);
140
+ return Utils.unique(paths).filter(p => !p.match(/\.[mc]?ts$/) || typeScriptSupport);
169
141
  }
170
142
  static isESM() {
171
143
  const config = ConfigurationLoader.getPackageConfig();
172
144
  const type = config?.type ?? '';
173
145
  return type === 'module';
174
146
  }
175
- static async registerTypeScriptSupport(configPath = 'tsconfig.json') {
147
+ /**
148
+ * Tries to register TS support in the following order: swc, tsx, jiti, tsimp
149
+ * Use `MIKRO_ORM_CLI_TS_LOADER` env var to set the loader explicitly.
150
+ * This method is used only in CLI context.
151
+ */
152
+ static async registerTypeScriptSupport(configPath = 'tsconfig.json', tsLoader) {
176
153
  /* v8 ignore next 3 */
177
154
  if (process.versions.bun) {
178
155
  return true;
179
156
  }
180
157
  process.env.SWC_NODE_PROJECT ??= configPath;
158
+ process.env.TSIMP_PROJECT ??= configPath;
181
159
  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;
160
+ const isEsm = this.isESM();
161
+ /* v8 ignore next */
162
+ const importMethod = isEsm ? 'tryImport' : 'tryRequire';
163
+ const explicitLoader = tsLoader ?? process.env.MIKRO_ORM_CLI_TS_LOADER ?? 'auto';
164
+ const loaders = {
165
+ swc: { esm: '@swc-node/register/esm-register', cjs: '@swc-node/register' },
166
+ tsx: { esm: 'tsx/esm/api', cjs: 'tsx/cjs/api', cb: (tsx) => tsx.register({ tsconfig: configPath }) },
167
+ jiti: { esm: 'jiti/register', cjs: 'jiti/register', cb: () => Utils.setDynamicImportProvider(id => import(id).then(mod => mod?.default ?? mod)) },
168
+ tsimp: { esm: 'tsimp/import', cjs: 'tsimp/import' },
169
+ };
170
+ for (const loader of Utils.keys(loaders)) {
171
+ if (explicitLoader !== 'auto' && loader !== explicitLoader) {
172
+ continue;
173
+ }
174
+ const { esm, cjs, cb } = loaders[loader];
175
+ /* v8 ignore next */
176
+ const module = isEsm ? esm : cjs;
177
+ const mod = await Utils[importMethod]({ module });
178
+ if (mod) {
179
+ cb?.(mod);
180
+ process.env.MIKRO_ORM_CLI_TS_LOADER = loader;
181
+ return true;
182
+ }
183
+ }
184
+ // eslint-disable-next-line no-console
185
+ console.warn('Neither `swc`, `tsx`, `jiti` nor `tsimp` found in the project dependencies, support for working with TypeScript files might not work. To use `swc`, you need to install both `@swc-node/register` and `@swc/core`.');
186
+ return false;
191
187
  }
192
188
  static registerDotenv(options) {
193
- const path = process.env.MIKRO_ORM_ENV ?? ((options?.baseDir ?? process.cwd()) + '/.env');
189
+ const path = process.env.MIKRO_ORM_ENV ?? ((options.baseDir ?? process.cwd()) + '/.env');
194
190
  const env = {};
195
- dotenv.config({ path, processEnv: env });
191
+ dotenv.config({ path, processEnv: env, quiet: true });
196
192
  // only propagate known env vars
197
193
  for (const key of Object.keys(env)) {
198
194
  if (key.startsWith('MIKRO_ORM_')) {
@@ -300,25 +296,6 @@ export class ConfigurationLoader {
300
296
  ...Object.keys(pkg.devDependencies ?? {}),
301
297
  ]);
302
298
  }
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
299
  static getORMPackageVersion(name) {
323
300
  try {
324
301
  const pkg = Utils.requireFrom(`${name}/package.json`);
@@ -332,7 +309,7 @@ export class ConfigurationLoader {
332
309
  // inspired by https://github.com/facebook/docusaurus/pull/3386
333
310
  static checkPackageVersion() {
334
311
  const coreVersion = Utils.getORMVersion();
335
- if (process.env.MIKRO_ORM_ALLOW_VERSION_MISMATCH) {
312
+ if (process.env.MIKRO_ORM_ALLOW_VERSION_MISMATCH || coreVersion === 'N/A') {
336
313
  return coreVersion;
337
314
  }
338
315
  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,7 +1,7 @@
1
+ import type DataLoader from 'dataloader';
1
2
  import type { Primary, Ref } from '../typings.js';
2
3
  import { Collection, type InitCollectionOptions } from '../entity/Collection.js';
3
4
  import { type EntityManager } from '../EntityManager.js';
4
- import type DataLoader from 'dataloader';
5
5
  import { type LoadReferenceOptions } from '../entity/Reference.js';
6
6
  export declare class DataloaderUtils {
7
7
  /**
@@ -34,8 +34,13 @@ export declare class DataloaderUtils {
34
34
  */
35
35
  static getColFilter<T, S extends T>(collection: Collection<any>): (result: T) => result is S;
36
36
  /**
37
- * Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
37
+ * Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
38
38
  * makes one query per entity and maps each input collection to the corresponding result.
39
39
  */
40
40
  static getColBatchLoadFn(em: EntityManager): DataLoader.BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
41
+ /**
42
+ * Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
43
+ * makes one query per entity and maps each input collection to the corresponding result.
44
+ */
45
+ static getManyToManyColBatchLoadFn(em: EntityManager): DataLoader.BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
41
46
  }