@mikro-orm/core 7.0.0-dev.3 → 7.0.0-dev.31

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 (102) hide show
  1. package/EntityManager.d.ts +50 -7
  2. package/EntityManager.js +141 -97
  3. package/MikroORM.js +0 -1
  4. package/README.md +1 -2
  5. package/cache/FileCacheAdapter.d.ts +2 -1
  6. package/cache/FileCacheAdapter.js +6 -4
  7. package/connections/Connection.d.ts +4 -2
  8. package/connections/Connection.js +2 -2
  9. package/decorators/Check.d.ts +2 -2
  10. package/decorators/Embeddable.d.ts +5 -5
  11. package/decorators/Embeddable.js +1 -1
  12. package/decorators/Embedded.d.ts +6 -12
  13. package/decorators/Entity.d.ts +20 -5
  14. package/decorators/Entity.js +0 -1
  15. package/decorators/Enum.d.ts +1 -1
  16. package/decorators/Formula.d.ts +1 -2
  17. package/decorators/Indexed.d.ts +10 -8
  18. package/decorators/Indexed.js +1 -1
  19. package/decorators/ManyToMany.d.ts +4 -2
  20. package/decorators/ManyToOne.d.ts +6 -2
  21. package/decorators/OneToMany.d.ts +4 -4
  22. package/decorators/OneToOne.d.ts +5 -1
  23. package/decorators/PrimaryKey.d.ts +2 -3
  24. package/decorators/Property.d.ts +1 -1
  25. package/decorators/Transactional.d.ts +1 -0
  26. package/decorators/Transactional.js +3 -3
  27. package/drivers/IDatabaseDriver.d.ts +8 -1
  28. package/entity/ArrayCollection.d.ts +4 -2
  29. package/entity/ArrayCollection.js +18 -6
  30. package/entity/Collection.d.ts +1 -2
  31. package/entity/Collection.js +16 -10
  32. package/entity/EntityAssigner.d.ts +1 -1
  33. package/entity/EntityAssigner.js +9 -1
  34. package/entity/EntityFactory.d.ts +6 -0
  35. package/entity/EntityFactory.js +21 -7
  36. package/entity/EntityHelper.js +8 -1
  37. package/entity/EntityLoader.d.ts +3 -2
  38. package/entity/EntityLoader.js +54 -35
  39. package/entity/EntityRepository.d.ts +1 -1
  40. package/entity/EntityValidator.js +1 -1
  41. package/entity/Reference.d.ts +8 -7
  42. package/entity/Reference.js +22 -1
  43. package/entity/WrappedEntity.js +1 -1
  44. package/entity/defineEntity.d.ts +537 -0
  45. package/entity/defineEntity.js +693 -0
  46. package/entity/index.d.ts +2 -0
  47. package/entity/index.js +2 -0
  48. package/entity/utils.d.ts +7 -0
  49. package/entity/utils.js +15 -3
  50. package/enums.d.ts +16 -3
  51. package/enums.js +13 -0
  52. package/errors.d.ts +6 -0
  53. package/errors.js +14 -0
  54. package/events/EventSubscriber.d.ts +3 -1
  55. package/hydration/ObjectHydrator.js +10 -2
  56. package/index.d.ts +1 -1
  57. package/metadata/EntitySchema.d.ts +6 -4
  58. package/metadata/EntitySchema.js +33 -19
  59. package/metadata/MetadataDiscovery.d.ts +0 -1
  60. package/metadata/MetadataDiscovery.js +51 -29
  61. package/metadata/MetadataStorage.js +1 -1
  62. package/metadata/MetadataValidator.js +4 -3
  63. package/package.json +5 -5
  64. package/platforms/Platform.d.ts +3 -1
  65. package/serialization/EntitySerializer.d.ts +2 -0
  66. package/serialization/EntitySerializer.js +1 -1
  67. package/serialization/SerializationContext.js +13 -10
  68. package/types/BigIntType.d.ts +9 -6
  69. package/types/BigIntType.js +3 -0
  70. package/types/BooleanType.d.ts +1 -1
  71. package/types/DecimalType.d.ts +6 -4
  72. package/types/DecimalType.js +1 -1
  73. package/types/DoubleType.js +1 -1
  74. package/typings.d.ts +72 -35
  75. package/typings.js +24 -4
  76. package/unit-of-work/ChangeSetComputer.js +3 -1
  77. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  78. package/unit-of-work/ChangeSetPersister.js +21 -11
  79. package/unit-of-work/UnitOfWork.d.ts +2 -1
  80. package/unit-of-work/UnitOfWork.js +71 -24
  81. package/utils/AbstractSchemaGenerator.js +5 -2
  82. package/utils/Configuration.d.ts +15 -5
  83. package/utils/Configuration.js +7 -7
  84. package/utils/ConfigurationLoader.d.ts +0 -2
  85. package/utils/ConfigurationLoader.js +2 -24
  86. package/utils/Cursor.d.ts +3 -3
  87. package/utils/Cursor.js +3 -0
  88. package/utils/DataloaderUtils.d.ts +7 -2
  89. package/utils/DataloaderUtils.js +38 -7
  90. package/utils/EntityComparator.d.ts +6 -2
  91. package/utils/EntityComparator.js +98 -59
  92. package/utils/QueryHelper.d.ts +6 -0
  93. package/utils/QueryHelper.js +48 -5
  94. package/utils/RawQueryFragment.d.ts +34 -0
  95. package/utils/RawQueryFragment.js +40 -1
  96. package/utils/TransactionManager.d.ts +65 -0
  97. package/utils/TransactionManager.js +220 -0
  98. package/utils/Utils.d.ts +11 -7
  99. package/utils/Utils.js +67 -33
  100. package/utils/index.d.ts +1 -0
  101. package/utils/index.js +1 -0
  102. package/utils/upsert-utils.js +9 -1
@@ -0,0 +1,220 @@
1
+ import { TransactionPropagation } from '../enums.js';
2
+ import { TransactionEventBroadcaster } from '../events/TransactionEventBroadcaster.js';
3
+ import { TransactionContext } from '../utils/TransactionContext.js';
4
+ import { ChangeSetType } from '../unit-of-work/ChangeSet.js';
5
+ import { TransactionStateError } from '../errors.js';
6
+ import { helper } from '../entity/wrap.js';
7
+ /**
8
+ * Manages transaction lifecycle and propagation for EntityManager.
9
+ */
10
+ export class TransactionManager {
11
+ em;
12
+ constructor(em) {
13
+ this.em = em;
14
+ }
15
+ /**
16
+ * Main entry point for handling transactional operations with propagation support.
17
+ */
18
+ async handle(cb, options = {}) {
19
+ const em = this.em.getContext(false);
20
+ // Set NESTED as the default propagation type
21
+ options.propagation ??= TransactionPropagation.NESTED;
22
+ // Set the context to the current transaction context if not already set
23
+ options.ctx ??= em.getTransactionContext();
24
+ const hasExistingTransaction = !!em.getTransactionContext();
25
+ return this.executeWithPropagation(options.propagation, em, cb, options, hasExistingTransaction);
26
+ }
27
+ /**
28
+ * Executes the callback with the specified propagation type.
29
+ */
30
+ async executeWithPropagation(propagation, em, cb, options, hasExistingTransaction) {
31
+ switch (propagation) {
32
+ case TransactionPropagation.NOT_SUPPORTED:
33
+ return this.executeWithoutTransaction(em, cb, options);
34
+ case TransactionPropagation.REQUIRES_NEW:
35
+ return this.executeWithNewTransaction(em, cb, options, hasExistingTransaction);
36
+ case TransactionPropagation.REQUIRED:
37
+ if (hasExistingTransaction) {
38
+ return cb(em);
39
+ }
40
+ return this.createNewTransaction(em, cb, options);
41
+ case TransactionPropagation.NESTED:
42
+ if (hasExistingTransaction) {
43
+ return this.executeNestedTransaction(em, cb, options);
44
+ }
45
+ return this.createNewTransaction(em, cb, options);
46
+ case TransactionPropagation.SUPPORTS:
47
+ if (hasExistingTransaction) {
48
+ return cb(em);
49
+ }
50
+ return this.executeWithoutTransaction(em, cb, options);
51
+ case TransactionPropagation.MANDATORY:
52
+ if (!hasExistingTransaction) {
53
+ throw TransactionStateError.requiredTransactionNotFound(propagation);
54
+ }
55
+ return cb(em);
56
+ case TransactionPropagation.NEVER:
57
+ if (hasExistingTransaction) {
58
+ throw TransactionStateError.transactionNotAllowed(propagation);
59
+ }
60
+ return this.executeWithoutTransaction(em, cb, options);
61
+ default:
62
+ throw TransactionStateError.invalidPropagation(propagation);
63
+ }
64
+ }
65
+ /**
66
+ * Suspends the current transaction and returns the suspended resources.
67
+ */
68
+ suspendTransaction(em) {
69
+ const suspended = em.getTransactionContext();
70
+ em.resetTransactionContext();
71
+ return suspended;
72
+ }
73
+ /**
74
+ * Resumes a previously suspended transaction.
75
+ */
76
+ resumeTransaction(em, suspended) {
77
+ if (suspended != null) {
78
+ em.setTransactionContext(suspended);
79
+ }
80
+ }
81
+ /**
82
+ * Executes operation without transaction context.
83
+ */
84
+ async executeWithoutTransaction(em, cb, options) {
85
+ const suspended = this.suspendTransaction(em);
86
+ const fork = this.createFork(em, { ...options, disableTransactions: true });
87
+ const propagateToUpperContext = this.shouldPropagateToUpperContext(em);
88
+ try {
89
+ return await this.executeTransactionFlow(fork, cb, propagateToUpperContext, em);
90
+ }
91
+ finally {
92
+ this.resumeTransaction(em, suspended);
93
+ }
94
+ }
95
+ /**
96
+ * Creates new independent transaction, suspending any existing one.
97
+ */
98
+ async executeWithNewTransaction(em, cb, options, hasExistingTransaction) {
99
+ const fork = this.createFork(em, options);
100
+ let suspended = null;
101
+ // Suspend existing transaction if present
102
+ if (hasExistingTransaction) {
103
+ suspended = this.suspendTransaction(em);
104
+ }
105
+ const newOptions = { ...options, ctx: undefined };
106
+ try {
107
+ return await this.processTransaction(em, fork, cb, newOptions);
108
+ }
109
+ finally {
110
+ if (suspended != null) {
111
+ this.resumeTransaction(em, suspended);
112
+ }
113
+ }
114
+ }
115
+ /**
116
+ * Creates new transaction context.
117
+ */
118
+ async createNewTransaction(em, cb, options) {
119
+ const fork = this.createFork(em, options);
120
+ return this.processTransaction(em, fork, cb, options);
121
+ }
122
+ /**
123
+ * Executes nested transaction with savepoint.
124
+ */
125
+ async executeNestedTransaction(em, cb, options) {
126
+ const fork = this.createFork(em, options);
127
+ // Pass existing context to create savepoint
128
+ const nestedOptions = { ...options, ctx: em.getTransactionContext() };
129
+ return this.processTransaction(em, fork, cb, nestedOptions);
130
+ }
131
+ /**
132
+ * Creates a fork of the EntityManager with the given options.
133
+ */
134
+ createFork(em, options) {
135
+ return em.fork({
136
+ clear: options.clear ?? false,
137
+ flushMode: options.flushMode,
138
+ cloneEventManager: true,
139
+ disableTransactions: options.ignoreNestedTransactions,
140
+ loggerContext: options.loggerContext,
141
+ });
142
+ }
143
+ /**
144
+ * Determines if changes should be propagated to the upper context.
145
+ */
146
+ shouldPropagateToUpperContext(em) {
147
+ return !em.global || this.em.config.get('allowGlobalContext');
148
+ }
149
+ /**
150
+ * Merges entities from fork to parent EntityManager.
151
+ */
152
+ mergeEntitiesToParent(fork, parent) {
153
+ const parentUoW = parent.getUnitOfWork(false);
154
+ // perf: if parent is empty, we can just move all entities from the fork to skip the `em.merge` overhead
155
+ if (parentUoW.getIdentityMap().keys().length === 0) {
156
+ for (const entity of fork.getUnitOfWork(false).getIdentityMap()) {
157
+ parentUoW.getIdentityMap().store(entity);
158
+ helper(entity).__em = parent;
159
+ }
160
+ return;
161
+ }
162
+ for (const entity of fork.getUnitOfWork(false).getIdentityMap()) {
163
+ const wrapped = helper(entity);
164
+ const meta = wrapped.__meta;
165
+ // eslint-disable-next-line dot-notation
166
+ const parentEntity = parentUoW.getById(meta.className, wrapped.getPrimaryKey(), parent['_schema'], true);
167
+ if (parentEntity && parentEntity !== entity) {
168
+ const parentWrapped = helper(parentEntity);
169
+ parentWrapped.__data = helper(entity).__data;
170
+ parentWrapped.__originalEntityData = helper(entity).__originalEntityData;
171
+ }
172
+ else {
173
+ parentUoW.merge(entity, new Set([entity]));
174
+ }
175
+ }
176
+ }
177
+ /**
178
+ * Registers a deletion handler to unset entity identities after flush.
179
+ */
180
+ registerDeletionHandler(fork, parent) {
181
+ fork.getEventManager().registerSubscriber({
182
+ afterFlush: (args) => {
183
+ const deletionChangeSets = args.uow.getChangeSets()
184
+ .filter(cs => cs.type === ChangeSetType.DELETE || cs.type === ChangeSetType.DELETE_EARLY);
185
+ for (const cs of deletionChangeSets) {
186
+ parent.getUnitOfWork(false).unsetIdentity(cs.entity);
187
+ }
188
+ },
189
+ });
190
+ }
191
+ /**
192
+ * Processes transaction execution.
193
+ */
194
+ async processTransaction(em, fork, cb, options) {
195
+ const propagateToUpperContext = this.shouldPropagateToUpperContext(em);
196
+ const eventBroadcaster = new TransactionEventBroadcaster(fork, undefined);
197
+ return TransactionContext.create(fork, () => fork.getConnection().transactional(async (trx) => {
198
+ fork.setTransactionContext(trx);
199
+ return this.executeTransactionFlow(fork, cb, propagateToUpperContext, em);
200
+ }, { ...options, eventBroadcaster }));
201
+ }
202
+ /**
203
+ * Executes transaction workflow with entity synchronization.
204
+ */
205
+ async executeTransactionFlow(fork, cb, propagateToUpperContext, parentEm) {
206
+ if (!propagateToUpperContext) {
207
+ const ret = await cb(fork);
208
+ await fork.flush();
209
+ return ret;
210
+ }
211
+ // Setup: Register deletion handler before execution
212
+ this.registerDeletionHandler(fork, parentEm);
213
+ // Execute callback and flush
214
+ const ret = await cb(fork);
215
+ await fork.flush();
216
+ // Synchronization: Merge entities back to the parent
217
+ this.mergeEntitiesToParent(fork, parentEm);
218
+ return ret;
219
+ }
220
+ }
package/utils/Utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type GlobbyOptions } from 'globby';
1
+ import { type GlobOptions } from 'tinyglobby';
2
2
  import type { Dictionary, EntityData, EntityDictionary, EntityKey, EntityMetadata, EntityName, EntityProperty, IMetadataStorage, Primary } from '../typings.js';
3
3
  import type { Collection } from '../entity/Collection.js';
4
4
  import type { Platform } from '../platforms/Platform.js';
@@ -15,7 +15,6 @@ export declare function equals(a: any, b: any): boolean;
15
15
  export declare function parseJsonSafe<T = unknown>(value: unknown): T;
16
16
  export declare class Utils {
17
17
  static readonly PK_SEPARATOR = "~~~";
18
- static dynamicImportProvider: (id: string) => Promise<any>;
19
18
  /**
20
19
  * Checks if the argument is not undefined
21
20
  */
@@ -134,14 +133,14 @@ export declare class Utils {
134
133
  static getCompositeKeyHash<T>(data: EntityData<T>, meta: EntityMetadata<T>, convertCustomTypes?: boolean, platform?: Platform, flat?: boolean): string;
135
134
  static getPrimaryKeyHash(pks: (string | Buffer | Date)[]): string;
136
135
  static splitPrimaryKeys<T extends object>(key: string): EntityKey<T>[];
137
- static getPrimaryKeyValues<T>(entity: T, primaryKeys: string[], allowScalar?: boolean, convertCustomTypes?: boolean): any;
136
+ static getPrimaryKeyValues<T>(entity: T, primaryKeys: string[] | EntityMetadata<T>, allowScalar?: boolean, convertCustomTypes?: boolean): any;
138
137
  static getPrimaryKeyCond<T>(entity: T, primaryKeys: EntityKey<T>[]): Record<string, Primary<T>> | null;
139
138
  /**
140
139
  * Maps nested FKs from `[1, 2, 3]` to `[1, [2, 3]]`.
141
140
  */
142
141
  static mapFlatCompositePrimaryKey(fk: Primary<any>[], prop: EntityProperty, fieldNames?: string[], idx?: number): Primary<any> | Primary<any>[];
143
142
  static getPrimaryKeyCondFromArray<T extends object>(pks: Primary<T>[], meta: EntityMetadata<T>): Record<string, Primary<T>>;
144
- static getOrderedPrimaryKeys<T>(id: Primary<T> | Record<string, Primary<T>>, meta: EntityMetadata<T>, platform?: Platform, convertCustomTypes?: boolean): Primary<T>[];
143
+ static getOrderedPrimaryKeys<T>(id: Primary<T> | Record<string, Primary<T>>, meta: EntityMetadata<T>, platform?: Platform, convertCustomTypes?: boolean, allowScalar?: boolean): Primary<T>[];
145
144
  /**
146
145
  * Checks whether given object is an entity instance.
147
146
  */
@@ -206,13 +205,13 @@ export declare class Utils {
206
205
  * If either `path` or `baseDir` are `file:` URLs, they are converted to local paths.
207
206
  */
208
207
  static absolutePath(path: string, baseDir?: string): string;
209
- static hash(data: string, length?: number): string;
208
+ static hash(data: string, length?: number, algorithm?: 'md5' | 'sha256'): string;
210
209
  static runIfNotEmpty(clause: () => any, data: any): void;
211
210
  static defaultValue<T extends Dictionary>(prop: T, option: keyof T, defaultValue: any): void;
212
211
  static findDuplicates<T>(items: T[]): T[];
213
212
  static removeDuplicates<T>(items: T[]): T[];
214
213
  static randomInt(min: number, max: number): number;
215
- static pathExists(path: string, options?: GlobbyOptions): Promise<boolean>;
214
+ static pathExists(path: string, options?: GlobOptions): Promise<boolean>;
216
215
  /**
217
216
  * Extracts all possible values of a TS enum. Works with both string and numeric enums.
218
217
  */
@@ -230,8 +229,13 @@ export declare class Utils {
230
229
  * @param [from] Location to start the node resolution
231
230
  */
232
231
  static requireFrom<T extends Dictionary>(id: string, from?: string): T;
232
+ /**
233
+ * Resolve path to a module.
234
+ * @param id The module to require
235
+ * @param [from] Location to start the node resolution
236
+ */
237
+ static resolveModulePath(id: string, from?: string): string;
233
238
  static dynamicImport<T = any>(id: string): Promise<T>;
234
- static setDynamicImportProvider(provider: (id: string) => Promise<unknown>): void;
235
239
  static ensureDir(path: string): void;
236
240
  static pathExistsSync(path: string): boolean;
237
241
  static readJSONSync(path: string): Dictionary;
package/utils/Utils.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { createRequire } from 'node:module';
2
- import globby from 'globby';
2
+ import { glob, isDynamicPattern } from 'tinyglobby';
3
3
  import { extname, isAbsolute, join, normalize, relative, resolve } from 'node:path';
4
- import { platform } from 'node:os';
5
4
  import { fileURLToPath, pathToFileURL } from 'node:url';
6
5
  import { existsSync, mkdirSync, readFileSync } from 'node:fs';
7
6
  import { createHash } from 'node:crypto';
@@ -132,8 +131,6 @@ export function parseJsonSafe(value) {
132
131
  }
133
132
  export class Utils {
134
133
  static PK_SEPARATOR = '~~~';
135
- /* v8 ignore next */
136
- static dynamicImportProvider = (id) => import(id);
137
134
  /**
138
135
  * Checks if the argument is not undefined
139
136
  */
@@ -435,7 +432,11 @@ export class Utils {
435
432
  return data;
436
433
  }
437
434
  if (Utils.isEntity(data, true)) {
438
- return helper(data).getPrimaryKey();
435
+ const wrapped = helper(data);
436
+ if (wrapped.__meta.compositePK) {
437
+ return wrapped.getPrimaryKeys();
438
+ }
439
+ return wrapped.getPrimaryKey();
439
440
  }
440
441
  if (strict && meta && Utils.getObjectKeysSize(data) !== meta.primaryKeys.length) {
441
442
  return null;
@@ -483,6 +484,7 @@ export class Utils {
483
484
  static splitPrimaryKeys(key) {
484
485
  return key.split(this.PK_SEPARATOR);
485
486
  }
487
+ // TODO v7: remove support for `primaryKeys: string[]`
486
488
  static getPrimaryKeyValues(entity, primaryKeys, allowScalar = false, convertCustomTypes = false) {
487
489
  /* v8 ignore next 3 */
488
490
  if (entity == null) {
@@ -494,9 +496,24 @@ export class Utils {
494
496
  }
495
497
  return val;
496
498
  }
497
- const pk = Utils.isEntity(entity, true)
498
- ? helper(entity).getPrimaryKey(convertCustomTypes)
499
- : primaryKeys.reduce((o, pk) => { o[pk] = entity[pk]; return o; }, {});
499
+ const meta = Array.isArray(primaryKeys) ? undefined : primaryKeys;
500
+ primaryKeys = Array.isArray(primaryKeys) ? primaryKeys : meta.primaryKeys;
501
+ let pk;
502
+ if (Utils.isEntity(entity, true)) {
503
+ pk = helper(entity).getPrimaryKey(convertCustomTypes);
504
+ }
505
+ else {
506
+ pk = primaryKeys.reduce((o, pk) => {
507
+ const targetMeta = meta?.properties[pk].targetMeta;
508
+ if (targetMeta && Utils.isPlainObject(entity[pk])) {
509
+ o[pk] = Utils.getPrimaryKeyValues(entity[pk], targetMeta, allowScalar, convertCustomTypes);
510
+ }
511
+ else {
512
+ o[pk] = entity[pk];
513
+ }
514
+ return o;
515
+ }, {});
516
+ }
500
517
  if (primaryKeys.length > 1) {
501
518
  return toArray(pk);
502
519
  }
@@ -546,7 +563,7 @@ export class Utils {
546
563
  return o;
547
564
  }, {});
548
565
  }
549
- static getOrderedPrimaryKeys(id, meta, platform, convertCustomTypes = false) {
566
+ static getOrderedPrimaryKeys(id, meta, platform, convertCustomTypes = false, allowScalar = false) {
550
567
  const data = (Utils.isPrimaryKey(id) ? { [meta.primaryKeys[0]]: id } : id);
551
568
  const pks = meta.primaryKeys.map((pk, idx) => {
552
569
  const prop = meta.properties[pk];
@@ -556,11 +573,14 @@ export class Utils {
556
573
  value = prop.customType.convertToJSValue(value, platform);
557
574
  }
558
575
  if (prop.kind !== ReferenceKind.SCALAR && prop.targetMeta) {
559
- const value2 = this.getOrderedPrimaryKeys(value, prop.targetMeta, platform, convertCustomTypes);
576
+ const value2 = this.getOrderedPrimaryKeys(value, prop.targetMeta, platform, convertCustomTypes, allowScalar);
560
577
  value = value2.length > 1 ? value2 : value2[0];
561
578
  }
562
579
  return value;
563
580
  });
581
+ if (allowScalar && pks.length === 1) {
582
+ return pks[0];
583
+ }
564
584
  // we need to flatten the PKs as composite PKs can be build from another composite PKs
565
585
  // and this method is used to get the PK hash in identity map, that expects flat array
566
586
  return Utils.flatten(pks);
@@ -625,8 +645,12 @@ export class Utils {
625
645
  || !!process.env.TS_JEST // check if ts-jest is used (works only with v27.0.4+)
626
646
  || !!process.env.VITEST // check if vitest is used
627
647
  || !!process.versions.bun // check if bun is used
628
- || process.argv.slice(1).some(arg => arg.includes('ts-node')) // registering ts-node runner
629
- || process.execArgv.some(arg => arg === 'ts-node/esm'); // check for ts-node/esm module loader
648
+ || process.argv.slice(1).some(arg => arg.match(/\.([mc]?ts|tsx)$/)) // executing `.ts` file
649
+ || process.execArgv.some(arg => {
650
+ return arg.includes('ts-node') // check for ts-node loader
651
+ || arg.includes('@swc-node/register') // check for swc-node/register loader
652
+ || arg.includes('node_modules/tsx/'); // check for tsx loader
653
+ });
630
654
  }
631
655
  /**
632
656
  * Uses some dark magic to get source path to caller where decorator is used.
@@ -644,7 +668,8 @@ export class Utils {
644
668
  // but those are also present in node, so we need to check this only if they weren't found.
645
669
  if (line === -1) {
646
670
  // here we handle bun which stack is different from nodejs so we search for reflect-metadata
647
- const reflectLine = stack.findIndex(line => Utils.normalizePath(line).includes('node_modules/reflect-metadata/Reflect.js'));
671
+ // Different bun versions might have different stack traces. The "last index" works for both 1.2.6 and 1.2.7.
672
+ const reflectLine = stack.findLastIndex(line => Utils.normalizePath(line).includes('node_modules/reflect-metadata/Reflect.js'));
648
673
  if (reflectLine === -1 || reflectLine + 2 >= stack.length || !stack[reflectLine + 1].includes('bun:wrap')) {
649
674
  return name;
650
675
  }
@@ -761,8 +786,9 @@ export class Utils {
761
786
  }
762
787
  return Utils.normalizePath(path);
763
788
  }
764
- static hash(data, length) {
765
- const hash = createHash('md5').update(data).digest('hex');
789
+ static hash(data, length, algorithm) {
790
+ const hashAlgorithm = algorithm || 'sha256';
791
+ const hash = createHash(hashAlgorithm).update(data).digest('hex');
766
792
  if (length) {
767
793
  return hash.substring(0, length);
768
794
  }
@@ -795,8 +821,8 @@ export class Utils {
795
821
  return Math.round(Math.random() * (max - min)) + min;
796
822
  }
797
823
  static async pathExists(path, options = {}) {
798
- if (globby.hasMagic(path)) {
799
- const found = await globby(path, options);
824
+ if (isDynamicPattern(path)) {
825
+ const found = await glob(path, options);
800
826
  return found.length > 0;
801
827
  }
802
828
  return this.pathExistsSync(path);
@@ -863,22 +889,25 @@ export class Utils {
863
889
  }
864
890
  return createRequire(resolve(from))(id);
865
891
  }
866
- static async dynamicImport(id) {
867
- /* v8 ignore next 7 */
868
- if (platform() === 'win32') {
869
- try {
870
- id = pathToFileURL(id).toString();
871
- }
872
- catch {
873
- // ignore
874
- }
892
+ /**
893
+ * Resolve path to a module.
894
+ * @param id The module to require
895
+ * @param [from] Location to start the node resolution
896
+ */
897
+ static resolveModulePath(id, from = process.cwd()) {
898
+ if (!extname(from)) {
899
+ from = join(from, '__fake.js');
875
900
  }
876
- /* v8 ignore next */
877
- return this.dynamicImportProvider(id);
901
+ const path = Utils.normalizePath(createRequire(resolve(from)).resolve(id));
902
+ const parts = path.split('/');
903
+ const idx = parts.lastIndexOf(id) + 1;
904
+ parts.splice(idx, parts.length - idx);
905
+ return parts.join('/');
878
906
  }
879
- /* v8 ignore next 3 */
880
- static setDynamicImportProvider(provider) {
881
- this.dynamicImportProvider = provider;
907
+ static async dynamicImport(id) {
908
+ /* v8 ignore next */
909
+ const specifier = id.startsWith('file://') ? id : pathToFileURL(id).href;
910
+ return import(specifier);
882
911
  }
883
912
  static ensureDir(path) {
884
913
  if (!existsSync(path)) {
@@ -899,8 +928,13 @@ export class Utils {
899
928
  /* v8 ignore next 5 */
900
929
  }
901
930
  catch {
902
- // this works in production build where we do not have the `src` folder
903
- return this.requireFrom('../package.json', import.meta.dirname).version;
931
+ try {
932
+ // this works in production build where we do not have the `src` folder
933
+ return this.requireFrom('../package.json', import.meta.dirname).version;
934
+ }
935
+ catch {
936
+ return 'N/A';
937
+ }
904
938
  }
905
939
  }
906
940
  static createFunction(context, code) {
package/utils/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from './DataloaderUtils.js';
5
5
  export * from './Utils.js';
6
6
  export * from './RequestContext.js';
7
7
  export * from './TransactionContext.js';
8
+ export * from './TransactionManager.js';
8
9
  export * from './QueryHelper.js';
9
10
  export * from './NullHighlighter.js';
10
11
  export * from './EntityComparator.js';
package/utils/index.js CHANGED
@@ -5,6 +5,7 @@ export * from './DataloaderUtils.js';
5
5
  export * from './Utils.js';
6
6
  export * from './RequestContext.js';
7
7
  export * from './TransactionContext.js';
8
+ export * from './TransactionManager.js';
8
9
  export * from './QueryHelper.js';
9
10
  export * from './NullHighlighter.js';
10
11
  export * from './EntityComparator.js';
@@ -71,7 +71,15 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
71
71
  if (!meta) {
72
72
  return '*';
73
73
  }
74
- const keys = meta.comparableProps.filter(p => !p.lazy && !p.embeddable && Array.isArray(uniqueFields) && !uniqueFields.includes(p.name)).map(p => p.name);
74
+ const keys = meta.comparableProps.filter(p => {
75
+ if (p.lazy || p.embeddable) {
76
+ return false;
77
+ }
78
+ if (p.autoincrement) {
79
+ return true;
80
+ }
81
+ return Array.isArray(uniqueFields) && !uniqueFields.includes(p.name);
82
+ }).map(p => p.name);
75
83
  if (meta.versionProperty) {
76
84
  keys.push(meta.versionProperty);
77
85
  }