@mikro-orm/core 7.0.2-dev.8 → 7.0.2

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 (207) hide show
  1. package/EntityManager.d.ts +883 -579
  2. package/EntityManager.js +1897 -1865
  3. package/MikroORM.d.ts +103 -72
  4. package/MikroORM.js +178 -177
  5. package/README.md +128 -294
  6. package/cache/CacheAdapter.d.ts +38 -36
  7. package/cache/FileCacheAdapter.d.ts +30 -24
  8. package/cache/FileCacheAdapter.js +80 -78
  9. package/cache/GeneratedCacheAdapter.d.ts +19 -20
  10. package/cache/GeneratedCacheAdapter.js +31 -30
  11. package/cache/MemoryCacheAdapter.d.ts +19 -20
  12. package/cache/MemoryCacheAdapter.js +36 -36
  13. package/cache/NullCacheAdapter.d.ts +17 -16
  14. package/cache/NullCacheAdapter.js +25 -24
  15. package/connections/Connection.d.ts +99 -75
  16. package/connections/Connection.js +166 -160
  17. package/drivers/DatabaseDriver.d.ts +187 -69
  18. package/drivers/DatabaseDriver.js +451 -432
  19. package/drivers/IDatabaseDriver.d.ts +464 -281
  20. package/drivers/IDatabaseDriver.js +1 -0
  21. package/entity/BaseEntity.d.ts +121 -73
  22. package/entity/BaseEntity.js +44 -33
  23. package/entity/Collection.d.ts +216 -157
  24. package/entity/Collection.js +728 -707
  25. package/entity/EntityAssigner.d.ts +90 -76
  26. package/entity/EntityAssigner.js +232 -229
  27. package/entity/EntityFactory.d.ts +68 -40
  28. package/entity/EntityFactory.js +427 -366
  29. package/entity/EntityHelper.d.ts +34 -22
  30. package/entity/EntityHelper.js +280 -267
  31. package/entity/EntityIdentifier.d.ts +4 -4
  32. package/entity/EntityIdentifier.js +10 -10
  33. package/entity/EntityLoader.d.ts +105 -56
  34. package/entity/EntityLoader.js +754 -722
  35. package/entity/EntityRepository.d.ts +317 -200
  36. package/entity/EntityRepository.js +214 -212
  37. package/entity/PolymorphicRef.d.ts +5 -5
  38. package/entity/PolymorphicRef.js +10 -10
  39. package/entity/Reference.d.ts +130 -66
  40. package/entity/Reference.js +280 -260
  41. package/entity/WrappedEntity.d.ts +116 -53
  42. package/entity/WrappedEntity.js +169 -147
  43. package/entity/defineEntity.d.ts +1290 -614
  44. package/entity/defineEntity.js +521 -511
  45. package/entity/utils.d.ts +13 -3
  46. package/entity/utils.js +71 -73
  47. package/entity/validators.js +43 -43
  48. package/entity/wrap.js +8 -8
  49. package/enums.d.ts +275 -138
  50. package/enums.js +268 -137
  51. package/errors.d.ts +120 -72
  52. package/errors.js +356 -253
  53. package/events/EventManager.d.ts +27 -10
  54. package/events/EventManager.js +80 -73
  55. package/events/EventSubscriber.d.ts +33 -29
  56. package/events/TransactionEventBroadcaster.d.ts +16 -7
  57. package/events/TransactionEventBroadcaster.js +15 -13
  58. package/exceptions.d.ts +23 -40
  59. package/exceptions.js +35 -52
  60. package/hydration/Hydrator.d.ts +43 -16
  61. package/hydration/Hydrator.js +44 -42
  62. package/hydration/ObjectHydrator.d.ts +51 -17
  63. package/hydration/ObjectHydrator.js +480 -416
  64. package/index.d.ts +116 -2
  65. package/index.js +10 -1
  66. package/logging/DefaultLogger.d.ts +35 -30
  67. package/logging/DefaultLogger.js +87 -84
  68. package/logging/Logger.d.ts +45 -40
  69. package/logging/SimpleLogger.d.ts +13 -11
  70. package/logging/SimpleLogger.js +22 -22
  71. package/logging/colors.d.ts +6 -6
  72. package/logging/colors.js +11 -10
  73. package/logging/inspect.js +7 -7
  74. package/metadata/EntitySchema.d.ts +214 -108
  75. package/metadata/EntitySchema.js +398 -379
  76. package/metadata/MetadataDiscovery.d.ts +115 -111
  77. package/metadata/MetadataDiscovery.js +1948 -1857
  78. package/metadata/MetadataProvider.d.ts +25 -14
  79. package/metadata/MetadataProvider.js +83 -77
  80. package/metadata/MetadataStorage.d.ts +39 -19
  81. package/metadata/MetadataStorage.js +119 -106
  82. package/metadata/MetadataValidator.d.ts +39 -39
  83. package/metadata/MetadataValidator.js +381 -338
  84. package/metadata/discover-entities.d.ts +5 -2
  85. package/metadata/discover-entities.js +27 -27
  86. package/metadata/types.d.ts +615 -531
  87. package/naming-strategy/AbstractNamingStrategy.d.ts +55 -39
  88. package/naming-strategy/AbstractNamingStrategy.js +91 -85
  89. package/naming-strategy/EntityCaseNamingStrategy.d.ts +6 -6
  90. package/naming-strategy/EntityCaseNamingStrategy.js +22 -22
  91. package/naming-strategy/MongoNamingStrategy.d.ts +7 -6
  92. package/naming-strategy/MongoNamingStrategy.js +19 -18
  93. package/naming-strategy/NamingStrategy.d.ts +109 -99
  94. package/naming-strategy/UnderscoreNamingStrategy.d.ts +8 -7
  95. package/naming-strategy/UnderscoreNamingStrategy.js +22 -21
  96. package/not-supported.js +7 -4
  97. package/package.json +1 -1
  98. package/platforms/ExceptionConverter.d.ts +2 -1
  99. package/platforms/ExceptionConverter.js +5 -4
  100. package/platforms/Platform.d.ts +310 -236
  101. package/platforms/Platform.js +661 -573
  102. package/serialization/EntitySerializer.d.ts +49 -25
  103. package/serialization/EntitySerializer.js +224 -216
  104. package/serialization/EntityTransformer.d.ts +11 -5
  105. package/serialization/EntityTransformer.js +220 -216
  106. package/serialization/SerializationContext.d.ts +27 -18
  107. package/serialization/SerializationContext.js +105 -100
  108. package/types/ArrayType.d.ts +9 -8
  109. package/types/ArrayType.js +34 -33
  110. package/types/BigIntType.d.ts +17 -10
  111. package/types/BigIntType.js +37 -37
  112. package/types/BlobType.d.ts +4 -3
  113. package/types/BlobType.js +14 -13
  114. package/types/BooleanType.d.ts +5 -4
  115. package/types/BooleanType.js +13 -12
  116. package/types/CharacterType.d.ts +3 -2
  117. package/types/CharacterType.js +7 -6
  118. package/types/DateTimeType.d.ts +6 -5
  119. package/types/DateTimeType.js +16 -15
  120. package/types/DateType.d.ts +6 -5
  121. package/types/DateType.js +16 -15
  122. package/types/DecimalType.d.ts +7 -7
  123. package/types/DecimalType.js +26 -26
  124. package/types/DoubleType.d.ts +3 -3
  125. package/types/DoubleType.js +12 -12
  126. package/types/EnumArrayType.d.ts +6 -5
  127. package/types/EnumArrayType.js +25 -24
  128. package/types/EnumType.d.ts +4 -3
  129. package/types/EnumType.js +12 -11
  130. package/types/FloatType.d.ts +4 -3
  131. package/types/FloatType.js +10 -9
  132. package/types/IntegerType.d.ts +4 -3
  133. package/types/IntegerType.js +10 -9
  134. package/types/IntervalType.d.ts +5 -4
  135. package/types/IntervalType.js +13 -12
  136. package/types/JsonType.d.ts +9 -8
  137. package/types/JsonType.js +33 -32
  138. package/types/MediumIntType.d.ts +2 -1
  139. package/types/MediumIntType.js +4 -3
  140. package/types/SmallIntType.d.ts +4 -3
  141. package/types/SmallIntType.js +10 -9
  142. package/types/StringType.d.ts +5 -4
  143. package/types/StringType.js +13 -12
  144. package/types/TextType.d.ts +4 -3
  145. package/types/TextType.js +10 -9
  146. package/types/TimeType.d.ts +6 -5
  147. package/types/TimeType.js +18 -17
  148. package/types/TinyIntType.d.ts +4 -3
  149. package/types/TinyIntType.js +11 -10
  150. package/types/Type.d.ts +88 -73
  151. package/types/Type.js +85 -74
  152. package/types/Uint8ArrayType.d.ts +5 -4
  153. package/types/Uint8ArrayType.js +22 -21
  154. package/types/UnknownType.d.ts +5 -4
  155. package/types/UnknownType.js +13 -12
  156. package/types/UuidType.d.ts +6 -5
  157. package/types/UuidType.js +20 -19
  158. package/types/index.d.ts +77 -49
  159. package/types/index.js +64 -26
  160. package/typings.d.ts +1388 -729
  161. package/typings.js +255 -231
  162. package/unit-of-work/ChangeSet.d.ts +28 -24
  163. package/unit-of-work/ChangeSet.js +58 -54
  164. package/unit-of-work/ChangeSetComputer.d.ts +13 -11
  165. package/unit-of-work/ChangeSetComputer.js +180 -159
  166. package/unit-of-work/ChangeSetPersister.d.ts +64 -41
  167. package/unit-of-work/ChangeSetPersister.js +443 -418
  168. package/unit-of-work/CommitOrderCalculator.d.ts +40 -40
  169. package/unit-of-work/CommitOrderCalculator.js +89 -88
  170. package/unit-of-work/IdentityMap.d.ts +32 -25
  171. package/unit-of-work/IdentityMap.js +106 -99
  172. package/unit-of-work/UnitOfWork.d.ts +182 -127
  173. package/unit-of-work/UnitOfWork.js +1201 -1169
  174. package/utils/AbstractMigrator.d.ts +111 -91
  175. package/utils/AbstractMigrator.js +275 -275
  176. package/utils/AbstractSchemaGenerator.d.ts +43 -34
  177. package/utils/AbstractSchemaGenerator.js +121 -122
  178. package/utils/AsyncContext.d.ts +3 -3
  179. package/utils/AsyncContext.js +34 -35
  180. package/utils/Configuration.d.ts +853 -801
  181. package/utils/Configuration.js +360 -337
  182. package/utils/Cursor.d.ts +40 -22
  183. package/utils/Cursor.js +135 -127
  184. package/utils/DataloaderUtils.d.ts +58 -43
  185. package/utils/DataloaderUtils.js +203 -198
  186. package/utils/EntityComparator.d.ts +99 -80
  187. package/utils/EntityComparator.js +825 -727
  188. package/utils/NullHighlighter.d.ts +2 -1
  189. package/utils/NullHighlighter.js +4 -3
  190. package/utils/QueryHelper.d.ts +79 -51
  191. package/utils/QueryHelper.js +372 -361
  192. package/utils/RawQueryFragment.d.ts +54 -28
  193. package/utils/RawQueryFragment.js +110 -99
  194. package/utils/RequestContext.d.ts +33 -32
  195. package/utils/RequestContext.js +52 -53
  196. package/utils/TransactionContext.d.ts +17 -16
  197. package/utils/TransactionContext.js +28 -27
  198. package/utils/TransactionManager.d.ts +58 -58
  199. package/utils/TransactionManager.js +199 -197
  200. package/utils/Utils.d.ts +210 -145
  201. package/utils/Utils.js +820 -813
  202. package/utils/clone.js +104 -113
  203. package/utils/env-vars.js +90 -88
  204. package/utils/fs-utils.d.ts +15 -15
  205. package/utils/fs-utils.js +180 -181
  206. package/utils/upsert-utils.d.ts +20 -5
  207. package/utils/upsert-utils.js +114 -116
@@ -1,65 +1,69 @@
1
1
  import { helper } from '../entity/wrap.js';
2
2
  import { Utils } from '../utils/Utils.js';
3
3
  import { inspect } from '../logging/inspect.js';
4
+ /** Represents a pending change (create, update, or delete) for a single entity. */
4
5
  export class ChangeSet {
5
- entity;
6
- type;
7
- payload;
8
- meta;
9
- primaryKey;
10
- serializedPrimaryKey;
11
- constructor(entity, type, payload, meta) {
12
- this.entity = entity;
13
- this.type = type;
14
- this.payload = payload;
15
- this.meta = meta;
16
- this.meta = meta;
17
- this.rootMeta = meta.root;
18
- this.schema = helper(entity).__schema ?? meta.root.schema;
6
+ entity;
7
+ type;
8
+ payload;
9
+ meta;
10
+ primaryKey;
11
+ serializedPrimaryKey;
12
+ constructor(entity, type, payload, meta) {
13
+ this.entity = entity;
14
+ this.type = type;
15
+ this.payload = payload;
16
+ this.meta = meta;
17
+ this.meta = meta;
18
+ this.rootMeta = meta.root;
19
+ this.schema = helper(entity).__schema ?? meta.root.schema;
20
+ }
21
+ /** Returns the primary key of the entity, optionally as an object for composite keys. */
22
+ getPrimaryKey(object = false) {
23
+ if (!this.originalEntity) {
24
+ this.primaryKey ??= helper(this.entity).getPrimaryKey(true);
25
+ } else if (this.meta.compositePK) {
26
+ this.primaryKey = this.meta.primaryKeys.map(pk => this.originalEntity[pk]);
27
+ } else {
28
+ this.primaryKey = this.originalEntity[this.meta.primaryKeys[0]];
19
29
  }
20
- getPrimaryKey(object = false) {
21
- if (!this.originalEntity) {
22
- this.primaryKey ??= helper(this.entity).getPrimaryKey(true);
23
- }
24
- else if (this.meta.compositePK) {
25
- this.primaryKey = this.meta.primaryKeys.map(pk => this.originalEntity[pk]);
26
- }
27
- else {
28
- this.primaryKey = this.originalEntity[this.meta.primaryKeys[0]];
29
- }
30
- if (!this.meta.compositePK &&
31
- this.meta.getPrimaryProp().targetMeta?.compositePK &&
32
- typeof this.primaryKey === 'object' &&
33
- this.primaryKey !== null) {
34
- this.primaryKey = this.meta.getPrimaryProp().targetMeta.primaryKeys.map(childPK => {
35
- return this.primaryKey[childPK];
36
- });
37
- }
38
- if (object && this.primaryKey != null) {
39
- return Utils.primaryKeyToObject(this.meta, this.primaryKey);
40
- }
41
- return this.primaryKey ?? null;
30
+ if (
31
+ !this.meta.compositePK &&
32
+ this.meta.getPrimaryProp().targetMeta?.compositePK &&
33
+ typeof this.primaryKey === 'object' &&
34
+ this.primaryKey !== null
35
+ ) {
36
+ this.primaryKey = this.meta.getPrimaryProp().targetMeta.primaryKeys.map(childPK => {
37
+ return this.primaryKey[childPK];
38
+ });
42
39
  }
43
- getSerializedPrimaryKey() {
44
- this.serializedPrimaryKey ??= helper(this.entity).getSerializedPrimaryKey();
45
- return this.serializedPrimaryKey;
46
- }
47
- /** @ignore */
48
- [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
49
- const object = { ...this };
50
- const hidden = ['meta', 'serializedPrimaryKey'];
51
- hidden.forEach(k => delete object[k]);
52
- const ret = inspect(object, { depth });
53
- const name = `${this.constructor.name}<${this.meta.className}>`;
54
- /* v8 ignore next */
55
- return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
40
+ if (object && this.primaryKey != null) {
41
+ return Utils.primaryKeyToObject(this.meta, this.primaryKey);
56
42
  }
43
+ return this.primaryKey ?? null;
44
+ }
45
+ /** Returns the serialized (string) form of the primary key. */
46
+ getSerializedPrimaryKey() {
47
+ this.serializedPrimaryKey ??= helper(this.entity).getSerializedPrimaryKey();
48
+ return this.serializedPrimaryKey;
49
+ }
50
+ /** @ignore */
51
+ [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
52
+ const object = { ...this };
53
+ const hidden = ['meta', 'serializedPrimaryKey'];
54
+ hidden.forEach(k => delete object[k]);
55
+ const ret = inspect(object, { depth });
56
+ const name = `${this.constructor.name}<${this.meta.className}>`;
57
+ /* v8 ignore next */
58
+ return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
59
+ }
57
60
  }
61
+ /** Enumeration of change set operation types. */
58
62
  export var ChangeSetType;
59
63
  (function (ChangeSetType) {
60
- ChangeSetType["CREATE"] = "create";
61
- ChangeSetType["UPDATE"] = "update";
62
- ChangeSetType["DELETE"] = "delete";
63
- ChangeSetType["UPDATE_EARLY"] = "update_early";
64
- ChangeSetType["DELETE_EARLY"] = "delete_early";
64
+ ChangeSetType['CREATE'] = 'create';
65
+ ChangeSetType['UPDATE'] = 'update';
66
+ ChangeSetType['DELETE'] = 'delete';
67
+ ChangeSetType['UPDATE_EARLY'] = 'update_early';
68
+ ChangeSetType['DELETE_EARLY'] = 'delete_early';
65
69
  })(ChangeSetType || (ChangeSetType = {}));
@@ -2,16 +2,18 @@ import type { AnyEntity } from '../typings.js';
2
2
  import { ChangeSet } from './ChangeSet.js';
3
3
  import { type Collection } from '../entity/Collection.js';
4
4
  import type { EntityManager } from '../EntityManager.js';
5
+ /** @internal Computes change sets by comparing entity state against original snapshots. */
5
6
  export declare class ChangeSetComputer {
6
- #private;
7
- constructor(em: EntityManager, collectionUpdates: Set<Collection<AnyEntity>>);
8
- computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
9
- /**
10
- * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
11
- */
12
- private processPropertyInitializers;
13
- private computePayload;
14
- private processProperty;
15
- private processToOne;
16
- private processToMany;
7
+ #private;
8
+ constructor(em: EntityManager, collectionUpdates: Set<Collection<AnyEntity>>);
9
+ /** Computes a change set for the given entity by diffing against its original state. */
10
+ computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
11
+ /**
12
+ * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
13
+ */
14
+ private processPropertyInitializers;
15
+ private computePayload;
16
+ private processProperty;
17
+ private processToOne;
18
+ private processToMany;
17
19
  }
@@ -6,169 +6,190 @@ import { validateEntity } from '../entity/validators.js';
6
6
  import { Reference } from '../entity/Reference.js';
7
7
  import { PolymorphicRef } from '../entity/PolymorphicRef.js';
8
8
  import { ReferenceKind } from '../enums.js';
9
+ import { isRaw } from '../utils/RawQueryFragment.js';
10
+ /** @internal Computes change sets by comparing entity state against original snapshots. */
9
11
  export class ChangeSetComputer {
10
- #comparator;
11
- #metadata;
12
- #platform;
13
- #config;
14
- #em;
15
- #collectionUpdates;
16
- constructor(em, collectionUpdates) {
17
- this.#em = em;
18
- this.#collectionUpdates = collectionUpdates;
19
- this.#config = this.#em.config;
20
- this.#metadata = this.#em.getMetadata();
21
- this.#platform = this.#em.getPlatform();
22
- this.#comparator = this.#config.getComparator(this.#metadata);
23
- }
24
- computeChangeSet(entity) {
25
- const meta = this.#metadata.get(entity.constructor);
26
- if (meta.readonly) {
27
- return null;
28
- }
29
- const wrapped = helper(entity);
30
- const type = wrapped.__originalEntityData ? ChangeSetType.UPDATE : ChangeSetType.CREATE;
31
- const map = new Map();
32
- // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
33
- // to the `map` as we want to apply those only if something else changed.
34
- if (type === ChangeSetType.CREATE) {
35
- // run update hooks only after we know there are other changes
36
- for (const prop of meta.hydrateProps) {
37
- this.processPropertyInitializers(entity, prop, type, map);
38
- }
39
- }
40
- if (type === ChangeSetType.UPDATE && !wrapped.__initialized) {
41
- const data = this.#comparator.prepareEntity(entity);
42
- if (Utils.equals(data, wrapped.__originalEntityData)) {
43
- return null;
44
- }
45
- }
46
- const changeSet = new ChangeSet(entity, type, this.computePayload(entity), meta);
47
- changeSet.originalEntity = wrapped.__originalEntityData;
48
- for (const prop of meta.relations.filter(prop => prop.persist !== false || prop.userDefined === false)) {
49
- this.processProperty(changeSet, prop);
50
- }
51
- if (changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload)) {
52
- return null;
53
- }
54
- validateEntity(changeSet.entity, meta);
55
- // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
56
- // to the `map` as we want to apply those only if something else changed.
57
- if (type === ChangeSetType.UPDATE) {
58
- for (const prop of meta.hydrateProps) {
59
- this.processPropertyInitializers(entity, prop, type, map);
60
- }
61
- }
62
- if (map.size > 0) {
63
- for (const [entity, pairs] of map) {
64
- for (const [prop, value] of pairs) {
65
- entity[prop] = value;
66
- }
67
- }
68
- // Recompute the changeset, we need to merge this as here we ignore relations.
69
- const diff = this.computePayload(entity, true);
70
- Utils.merge(changeSet.payload, diff);
71
- }
72
- return changeSet;
73
- }
74
- /**
75
- * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
76
- */
77
- processPropertyInitializers(entity, prop, type, map, nested) {
78
- if (prop.onCreate &&
79
- type === ChangeSetType.CREATE &&
80
- (entity[prop.name] == null ||
81
- (Utils.isScalarReference(entity[prop.name]) && entity[prop.name].unwrap() == null))) {
82
- entity[prop.name] = prop.onCreate(entity, this.#em);
83
- }
84
- if (prop.onUpdate && type === ChangeSetType.UPDATE) {
85
- const pairs = map.get(entity) ?? [];
86
- pairs.push([prop.name, prop.onUpdate(entity, this.#em)]);
87
- map.set(entity, pairs);
88
- }
89
- if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
90
- for (const embeddedProp of prop.targetMeta.hydrateProps) {
91
- this.processPropertyInitializers(entity[prop.name], embeddedProp, type, map, nested || prop.object);
92
- }
93
- }
12
+ #comparator;
13
+ #metadata;
14
+ #platform;
15
+ #config;
16
+ #em;
17
+ #collectionUpdates;
18
+ constructor(em, collectionUpdates) {
19
+ this.#em = em;
20
+ this.#collectionUpdates = collectionUpdates;
21
+ this.#config = this.#em.config;
22
+ this.#metadata = this.#em.getMetadata();
23
+ this.#platform = this.#em.getPlatform();
24
+ this.#comparator = this.#config.getComparator(this.#metadata);
25
+ }
26
+ /** Computes a change set for the given entity by diffing against its original state. */
27
+ computeChangeSet(entity) {
28
+ const meta = this.#metadata.get(entity.constructor);
29
+ if (meta.readonly) {
30
+ return null;
94
31
  }
95
- computePayload(entity, ignoreUndefined = false) {
96
- const data = this.#comparator.prepareEntity(entity);
97
- const wrapped = helper(entity);
98
- const entityName = wrapped.__meta.class;
99
- const originalEntityData = wrapped.__originalEntityData;
100
- if (!wrapped.__initialized) {
101
- for (const prop of wrapped.__meta.primaryKeys) {
102
- delete data[prop];
103
- }
104
- return data;
105
- }
106
- if (originalEntityData) {
107
- const comparator = this.#comparator.getEntityComparator(entityName);
108
- const diff = comparator(originalEntityData, data);
109
- if (ignoreUndefined) {
110
- Utils.keys(diff)
111
- .filter(k => diff[k] === undefined)
112
- .forEach(k => delete diff[k]);
113
- }
114
- return diff;
115
- }
116
- return data;
32
+ const wrapped = helper(entity);
33
+ const type = wrapped.__originalEntityData ? ChangeSetType.UPDATE : ChangeSetType.CREATE;
34
+ const map = new Map();
35
+ // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
36
+ // to the `map` as we want to apply those only if something else changed.
37
+ if (type === ChangeSetType.CREATE) {
38
+ // run update hooks only after we know there are other changes
39
+ for (const prop of meta.hydrateProps) {
40
+ this.processPropertyInitializers(entity, prop, type, map);
41
+ }
117
42
  }
118
- processProperty(changeSet, prop, target) {
119
- if (!target) {
120
- const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
121
- targets.forEach(([t]) => this.processProperty(changeSet, prop, t));
122
- return;
123
- }
124
- if (Utils.isCollection(target)) {
125
- // m:n or 1:m
126
- this.processToMany(prop, changeSet);
127
- }
128
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
129
- this.processToOne(prop, changeSet);
130
- }
43
+ if (type === ChangeSetType.UPDATE && !wrapped.__initialized) {
44
+ const data = this.#comparator.prepareEntity(entity);
45
+ if (Utils.equals(data, wrapped.__originalEntityData)) {
46
+ return null;
47
+ }
131
48
  }
132
- processToOne(prop, changeSet) {
133
- const isToOneOwner = prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner);
134
- if (!isToOneOwner || prop.mapToPk) {
135
- return;
136
- }
137
- const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
138
- targets.forEach(([rawTarget, idx]) => {
139
- const target = Reference.unwrapReference(rawTarget);
140
- const needsProcessing = target != null && (prop.targetKey != null || !target.__helper.hasPrimaryKey());
141
- if (needsProcessing) {
142
- let value = prop.targetKey ? target[prop.targetKey] : target.__helper.__identifier;
143
- /* v8 ignore next */
144
- if (prop.targetKey && prop.targetMeta) {
145
- const targetProp = prop.targetMeta.properties[prop.targetKey];
146
- if (targetProp?.customType) {
147
- value = targetProp.customType.convertToDatabaseValue(value, this.#platform, { mode: 'serialization' });
148
- }
149
- }
150
- if (prop.polymorphic) {
151
- const discriminator = QueryHelper.findDiscriminatorValue(prop.discriminatorMap, target.constructor);
152
- Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, new PolymorphicRef(discriminator, value), idx);
153
- }
154
- else {
155
- Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, value, idx);
156
- }
157
- }
158
- });
159
- }
160
- processToMany(prop, changeSet) {
161
- const target = changeSet.entity[prop.name];
162
- if (!target.isDirty() && changeSet.type !== ChangeSetType.CREATE) {
163
- return;
164
- }
165
- if (target.isDirty()) {
166
- this.#collectionUpdates.add(target);
167
- }
168
- if (prop.owner && !this.#platform.usesPivotTable()) {
169
- changeSet.payload[prop.name] = target.getItems(false).map((item) => {
170
- return item.__helper.__identifier ?? item.__helper.getPrimaryKey();
171
- });
49
+ const changeSet = new ChangeSet(entity, type, this.computePayload(entity), meta);
50
+ changeSet.originalEntity = wrapped.__originalEntityData;
51
+ for (const prop of meta.relations.filter(prop => prop.persist !== false || prop.userDefined === false)) {
52
+ this.processProperty(changeSet, prop);
53
+ }
54
+ if (changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload)) {
55
+ return null;
56
+ }
57
+ validateEntity(changeSet.entity, meta);
58
+ // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
59
+ // to the `map` as we want to apply those only if something else changed.
60
+ if (type === ChangeSetType.UPDATE) {
61
+ for (const prop of meta.hydrateProps) {
62
+ this.processPropertyInitializers(entity, prop, type, map);
63
+ }
64
+ }
65
+ if (map.size > 0) {
66
+ for (const [entity, pairs] of map) {
67
+ for (const [prop, value] of pairs) {
68
+ entity[prop] = value;
69
+ }
70
+ }
71
+ // Recompute the changeset, we need to merge this as here we ignore relations.
72
+ const diff = this.computePayload(entity, true);
73
+ Utils.merge(changeSet.payload, diff);
74
+ }
75
+ return changeSet;
76
+ }
77
+ /**
78
+ * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
79
+ */
80
+ processPropertyInitializers(entity, prop, type, map, nested) {
81
+ if (
82
+ prop.onCreate &&
83
+ type === ChangeSetType.CREATE &&
84
+ (entity[prop.name] == null || (Utils.isScalarReference(entity[prop.name]) && entity[prop.name].unwrap() == null))
85
+ ) {
86
+ entity[prop.name] = prop.onCreate(entity, this.#em);
87
+ } else if (
88
+ prop.default != null &&
89
+ !isRaw(prop.default) &&
90
+ ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
91
+ type === ChangeSetType.CREATE &&
92
+ entity[prop.name] === undefined
93
+ ) {
94
+ entity[prop.name] = prop.default;
95
+ }
96
+ if (prop.onUpdate && type === ChangeSetType.UPDATE) {
97
+ const pairs = map.get(entity) ?? [];
98
+ pairs.push([prop.name, prop.onUpdate(entity, this.#em)]);
99
+ map.set(entity, pairs);
100
+ }
101
+ if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
102
+ const items = prop.array ? entity[prop.name] : [entity[prop.name]];
103
+ for (const item of items) {
104
+ for (const embeddedProp of prop.targetMeta.hydrateProps) {
105
+ this.processPropertyInitializers(item, embeddedProp, type, map, nested || prop.object);
172
106
  }
107
+ }
108
+ }
109
+ }
110
+ computePayload(entity, ignoreUndefined = false) {
111
+ const data = this.#comparator.prepareEntity(entity);
112
+ const wrapped = helper(entity);
113
+ const entityName = wrapped.__meta.class;
114
+ const originalEntityData = wrapped.__originalEntityData;
115
+ if (!wrapped.__initialized) {
116
+ for (const prop of wrapped.__meta.primaryKeys) {
117
+ delete data[prop];
118
+ }
119
+ return data;
120
+ }
121
+ if (originalEntityData) {
122
+ const comparator = this.#comparator.getEntityComparator(entityName);
123
+ const diff = comparator(originalEntityData, data);
124
+ if (ignoreUndefined) {
125
+ Utils.keys(diff)
126
+ .filter(k => diff[k] === undefined)
127
+ .forEach(k => delete diff[k]);
128
+ }
129
+ return diff;
130
+ }
131
+ return data;
132
+ }
133
+ processProperty(changeSet, prop, target) {
134
+ if (!target) {
135
+ const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
136
+ targets.forEach(([t]) => this.processProperty(changeSet, prop, t));
137
+ return;
138
+ }
139
+ if (Utils.isCollection(target)) {
140
+ // m:n or 1:m
141
+ this.processToMany(prop, changeSet);
142
+ }
143
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
144
+ this.processToOne(prop, changeSet);
145
+ }
146
+ }
147
+ processToOne(prop, changeSet) {
148
+ const isToOneOwner =
149
+ prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner);
150
+ if (!isToOneOwner || prop.mapToPk) {
151
+ return;
152
+ }
153
+ const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
154
+ targets.forEach(([rawTarget, idx]) => {
155
+ const target = Reference.unwrapReference(rawTarget);
156
+ const needsProcessing = target != null && (prop.targetKey != null || !target.__helper.hasPrimaryKey());
157
+ if (needsProcessing) {
158
+ let value = prop.targetKey ? target[prop.targetKey] : target.__helper.__identifier;
159
+ /* v8 ignore next */
160
+ if (prop.targetKey && prop.targetMeta) {
161
+ const targetProp = prop.targetMeta.properties[prop.targetKey];
162
+ if (targetProp?.customType) {
163
+ value = targetProp.customType.convertToDatabaseValue(value, this.#platform, { mode: 'serialization' });
164
+ }
165
+ }
166
+ if (prop.polymorphic) {
167
+ const discriminator = QueryHelper.findDiscriminatorValue(prop.discriminatorMap, target.constructor);
168
+ Utils.setPayloadProperty(
169
+ changeSet.payload,
170
+ changeSet.meta,
171
+ prop,
172
+ new PolymorphicRef(discriminator, value),
173
+ idx,
174
+ );
175
+ } else {
176
+ Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, value, idx);
177
+ }
178
+ }
179
+ });
180
+ }
181
+ processToMany(prop, changeSet) {
182
+ const target = changeSet.entity[prop.name];
183
+ if (!target.isDirty() && changeSet.type !== ChangeSetType.CREATE) {
184
+ return;
185
+ }
186
+ if (target.isDirty()) {
187
+ this.#collectionUpdates.add(target);
188
+ }
189
+ if (prop.owner && !this.#platform.usesPivotTable()) {
190
+ changeSet.payload[prop.name] = target.getItems(false).map(item => {
191
+ return item.__helper.__identifier ?? item.__helper.getPrimaryKey();
192
+ });
173
193
  }
194
+ }
174
195
  }
@@ -2,46 +2,69 @@ import type { Dictionary, EntityDictionary, EntityMetadata } from '../typings.js
2
2
  import { type ChangeSet } from './ChangeSet.js';
3
3
  import type { DriverMethodOptions } from '../drivers/IDatabaseDriver.js';
4
4
  import type { EntityManager } from '../EntityManager.js';
5
+ /** @internal Executes change sets against the database, handling inserts, updates, and deletes. */
5
6
  export declare class ChangeSetPersister {
6
- #private;
7
- constructor(em: EntityManager);
8
- executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
9
- executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
10
- executeDeletes<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
11
- private runForEachSchema;
12
- private validateRequired;
13
- private processProperties;
14
- private persistNewEntity;
15
- private persistNewEntities;
16
- private prepareOptions;
17
- private persistNewEntitiesBatch;
18
- private persistManagedEntity;
19
- private persistManagedEntities;
20
- private checkConcurrencyKeys;
21
- private persistManagedEntitiesBatch;
22
- private mapPrimaryKey;
23
- /**
24
- * Sets populate flag to new entities so they are serialized like if they were loaded from the db
25
- */
26
- private markAsPopulated;
27
- private updateEntity;
28
- private checkOptimisticLocks;
29
- private checkOptimisticLock;
30
- /**
31
- * This method also handles reloading of database default values for inserts and raw property updates,
32
- * so we use a single query in case of both versioning and default values is used.
33
- */
34
- private reloadVersionValues;
35
- /**
36
- * For TPT child tables, resolve EntityIdentifier values in PK fields.
37
- * The parent table insert assigns the actual PK value, which the child table references.
38
- */
39
- private resolveTPTIdentifiers;
40
- private processProperty;
41
- /**
42
- * Maps values returned via `returning` statement (postgres) or the inserted id (other sql drivers).
43
- * No need to handle composite keys here as they need to be set upfront.
44
- * We do need to map to the change set payload too, as it will be used in the originalEntityData for new entities.
45
- */
46
- mapReturnedValues<T extends object>(entity: T | null | undefined, payload: EntityDictionary<T>, row: Dictionary | undefined, meta: EntityMetadata<T>, upsert?: boolean): void;
7
+ #private;
8
+ constructor(em: EntityManager);
9
+ /** Executes all pending INSERT change sets, using batch inserts when possible. */
10
+ executeInserts<T extends object>(
11
+ changeSets: ChangeSet<T>[],
12
+ options?: DriverMethodOptions,
13
+ withSchema?: boolean,
14
+ ): Promise<void>;
15
+ /** Executes all pending UPDATE change sets, using batch updates when possible. */
16
+ executeUpdates<T extends object>(
17
+ changeSets: ChangeSet<T>[],
18
+ batched: boolean,
19
+ options?: DriverMethodOptions,
20
+ withSchema?: boolean,
21
+ ): Promise<void>;
22
+ /** Executes all pending DELETE change sets in batches. */
23
+ executeDeletes<T extends object>(
24
+ changeSets: ChangeSet<T>[],
25
+ options?: DriverMethodOptions,
26
+ withSchema?: boolean,
27
+ ): Promise<void>;
28
+ private runForEachSchema;
29
+ private validateRequired;
30
+ private processProperties;
31
+ private persistNewEntity;
32
+ private persistNewEntities;
33
+ private prepareOptions;
34
+ private persistNewEntitiesBatch;
35
+ private persistManagedEntity;
36
+ private persistManagedEntities;
37
+ private checkConcurrencyKeys;
38
+ private persistManagedEntitiesBatch;
39
+ private mapPrimaryKey;
40
+ /**
41
+ * Sets populate flag to new entities so they are serialized like if they were loaded from the db
42
+ */
43
+ private markAsPopulated;
44
+ private updateEntity;
45
+ private checkOptimisticLocks;
46
+ private checkOptimisticLock;
47
+ /**
48
+ * This method also handles reloading of database default values for inserts and raw property updates,
49
+ * so we use a single query in case of both versioning and default values is used.
50
+ */
51
+ private reloadVersionValues;
52
+ /**
53
+ * For TPT child tables, resolve EntityIdentifier values in PK fields.
54
+ * The parent table insert assigns the actual PK value, which the child table references.
55
+ */
56
+ private resolveTPTIdentifiers;
57
+ private processProperty;
58
+ /**
59
+ * Maps values returned via `returning` statement (postgres) or the inserted id (other sql drivers).
60
+ * No need to handle composite keys here as they need to be set upfront.
61
+ * We do need to map to the change set payload too, as it will be used in the originalEntityData for new entities.
62
+ */
63
+ mapReturnedValues<T extends object>(
64
+ entity: T | null | undefined,
65
+ payload: EntityDictionary<T>,
66
+ row: Dictionary | undefined,
67
+ meta: EntityMetadata<T>,
68
+ upsert?: boolean,
69
+ ): void;
47
70
  }