metal-orm 1.0.64 → 1.0.66

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.
@@ -18,7 +18,7 @@ import { RelationChangeProcessor } from './relation-change-processor.js';
18
18
  import { createQueryLoggingExecutor, QueryLogger } from './query-logger.js';
19
19
  import { ExecutionContext } from './execution-context.js';
20
20
  import type { HydrationContext } from './hydration-context.js';
21
- import type { EntityContext } from './entity-context.js';
21
+ import type { EntityContext, PrimaryKey } from './entity-context.js';
22
22
  import {
23
23
  DomainEvent,
24
24
  OrmDomainEvent,
@@ -27,10 +27,10 @@ import {
27
27
  RelationKey,
28
28
  TrackedEntity
29
29
  } from './runtime-types.js';
30
- import { executeHydrated } from './execute.js';
31
- import { runInTransaction } from './transaction-runner.js';
32
- import { saveGraphInternal, SaveGraphOptions } from './save-graph.js';
33
- import type { SaveGraphInputPayload } from './save-graph-types.js';
30
+ import { executeHydrated } from './execute.js';
31
+ import { runInTransaction } from './transaction-runner.js';
32
+ import { saveGraphInternal, SaveGraphOptions } from './save-graph.js';
33
+ import type { SaveGraphInputPayload } from './save-graph-types.js';
34
34
 
35
35
  /**
36
36
  * Interface for ORM interceptors that allow hooking into the flush lifecycle.
@@ -142,9 +142,9 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
142
142
  * @param pk - The primary key value
143
143
  * @returns The entity or undefined if not found
144
144
  */
145
- getEntity(table: TableDef, pk: unknown): unknown | undefined {
146
- return this.unitOfWork.getEntity(table, pk as string | number);
147
- }
145
+ getEntity(table: TableDef, pk: PrimaryKey): object | undefined {
146
+ return this.unitOfWork.getEntity(table, pk);
147
+ }
148
148
 
149
149
  /**
150
150
  * Sets an entity in the identity map.
@@ -152,9 +152,9 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
152
152
  * @param pk - The primary key value
153
153
  * @param entity - The entity instance
154
154
  */
155
- setEntity(table: TableDef, pk: unknown, entity: unknown): void {
156
- this.unitOfWork.setEntity(table, pk as string | number, entity);
157
- }
155
+ setEntity(table: TableDef, pk: PrimaryKey, entity: object): void {
156
+ this.unitOfWork.setEntity(table, pk, entity);
157
+ }
158
158
 
159
159
  /**
160
160
  * Tracks a new entity.
@@ -162,9 +162,9 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
162
162
  * @param entity - The entity instance
163
163
  * @param pk - Optional primary key value
164
164
  */
165
- trackNew(table: TableDef, entity: unknown, pk?: unknown): void {
166
- this.unitOfWork.trackNew(table, entity, pk as string | number);
167
- }
165
+ trackNew(table: TableDef, entity: object, pk?: PrimaryKey): void {
166
+ this.unitOfWork.trackNew(table, entity, pk);
167
+ }
168
168
 
169
169
  /**
170
170
  * Tracks a managed entity.
@@ -172,25 +172,25 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
172
172
  * @param pk - The primary key value
173
173
  * @param entity - The entity instance
174
174
  */
175
- trackManaged(table: TableDef, pk: unknown, entity: unknown): void {
176
- this.unitOfWork.trackManaged(table, pk as string | number, entity);
177
- }
175
+ trackManaged(table: TableDef, pk: PrimaryKey, entity: object): void {
176
+ this.unitOfWork.trackManaged(table, pk, entity);
177
+ }
178
178
 
179
179
  /**
180
180
  * Marks an entity as dirty (modified).
181
181
  * @param entity - The entity to mark as dirty
182
182
  */
183
- markDirty(entity: unknown): void {
184
- this.unitOfWork.markDirty(entity);
185
- }
183
+ markDirty(entity: object): void {
184
+ this.unitOfWork.markDirty(entity);
185
+ }
186
186
 
187
187
  /**
188
188
  * Marks an entity as removed.
189
189
  * @param entity - The entity to mark as removed
190
190
  */
191
- markRemoved(entity: unknown): void {
192
- this.unitOfWork.markRemoved(entity);
193
- }
191
+ markRemoved(entity: object): void {
192
+ this.unitOfWork.markRemoved(entity);
193
+ }
194
194
 
195
195
  /**
196
196
  * Registers a relation change.
@@ -298,30 +298,30 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
298
298
  return executeHydrated(this, qb);
299
299
  }
300
300
 
301
- /**
302
- * Saves an entity graph (root + nested relations) based on a DTO-like payload.
303
- * @param entityClass - Root entity constructor
304
- * @param payload - DTO payload containing column values and nested relations
305
- * @param options - Graph save options
306
- * @returns The root entity instance
307
- */
308
- async saveGraph<TCtor extends EntityConstructor<object>>(
309
- entityClass: TCtor,
310
- payload: SaveGraphInputPayload<InstanceType<TCtor>>,
311
- options?: SaveGraphOptions & { transactional?: boolean }
312
- ): Promise<InstanceType<TCtor>>;
313
- async saveGraph<TCtor extends EntityConstructor<object>>(
314
- entityClass: TCtor,
315
- payload: Record<string, unknown>,
316
- options?: SaveGraphOptions & { transactional?: boolean }
317
- ): Promise<InstanceType<TCtor>> {
318
- const { transactional = true, ...graphOptions } = options ?? {};
319
- const execute = () => saveGraphInternal(this, entityClass, payload, graphOptions);
320
- if (!transactional) {
321
- return execute();
322
- }
323
- return this.transaction(() => execute());
324
- }
301
+ /**
302
+ * Saves an entity graph (root + nested relations) based on a DTO-like payload.
303
+ * @param entityClass - Root entity constructor
304
+ * @param payload - DTO payload containing column values and nested relations
305
+ * @param options - Graph save options
306
+ * @returns The root entity instance
307
+ */
308
+ async saveGraph<TCtor extends EntityConstructor<object>>(
309
+ entityClass: TCtor,
310
+ payload: SaveGraphInputPayload<InstanceType<TCtor>>,
311
+ options?: SaveGraphOptions & { transactional?: boolean }
312
+ ): Promise<InstanceType<TCtor>>;
313
+ async saveGraph<TCtor extends EntityConstructor<object>>(
314
+ entityClass: TCtor,
315
+ payload: Record<string, unknown>,
316
+ options?: SaveGraphOptions & { transactional?: boolean }
317
+ ): Promise<InstanceType<TCtor>> {
318
+ const { transactional = true, ...graphOptions } = options ?? {};
319
+ const execute = () => saveGraphInternal(this, entityClass, payload, graphOptions);
320
+ if (!transactional) {
321
+ return execute();
322
+ }
323
+ return this.transaction(() => execute());
324
+ }
325
325
 
326
326
  /**
327
327
  * Persists an entity (either inserts or updates).
@@ -340,7 +340,7 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
340
340
  const primaryKey = findPrimaryKey(table);
341
341
  const pkValue = (entity as Record<string, unknown>)[primaryKey];
342
342
  if (pkValue !== undefined && pkValue !== null) {
343
- this.trackManaged(table, pkValue, entity);
343
+ this.trackManaged(table, pkValue as PrimaryKey, entity);
344
344
  } else {
345
345
  this.trackNew(table, entity);
346
346
  }
@@ -354,12 +354,12 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
354
354
  this.markRemoved(entity);
355
355
  }
356
356
 
357
- /**
358
- * Flushes pending changes to the database without session hooks, relation processing, or domain events.
359
- */
360
- async flush(): Promise<void> {
361
- await this.unitOfWork.flush();
362
- }
357
+ /**
358
+ * Flushes pending changes to the database without session hooks, relation processing, or domain events.
359
+ */
360
+ async flush(): Promise<void> {
361
+ await this.unitOfWork.flush();
362
+ }
363
363
 
364
364
  /**
365
365
  * Flushes pending changes with interceptors and relation processing.
@@ -78,7 +78,7 @@ export class RelationChangeProcessor {
78
78
  const target = entry.change.entity;
79
79
  if (!target) return;
80
80
 
81
- const tracked = this.unitOfWork.findTracked(target);
81
+ const tracked = this.unitOfWork.findTracked(target as object);
82
82
  if (!tracked) return;
83
83
 
84
84
  const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
@@ -105,7 +105,7 @@ export class RelationChangeProcessor {
105
105
  const target = entry.change.entity;
106
106
  if (!target) return;
107
107
 
108
- const tracked = this.unitOfWork.findTracked(target);
108
+ const tracked = this.unitOfWork.findTracked(target as object);
109
109
  if (!tracked) return;
110
110
 
111
111
  const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
@@ -154,7 +154,7 @@ export class RelationChangeProcessor {
154
154
  await this.deletePivotRow(relation, rootId, targetId);
155
155
 
156
156
  if (relation.cascade === 'all' || relation.cascade === 'remove') {
157
- this.unitOfWork.markRemoved(entry.change.entity);
157
+ this.unitOfWork.markRemoved(entry.change.entity as object);
158
158
  }
159
159
  }
160
160
  }
@@ -125,7 +125,7 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
125
125
  attach(entity: TChild): void {
126
126
  const keyValue = this.root[this.localKey];
127
127
  (entity as Record<string, unknown>)[this.relation.foreignKey] = keyValue;
128
- this.ctx.markDirty(entity);
128
+ this.ctx.markDirty(entity as object);
129
129
  this.items.push(entity);
130
130
  this.ctx.registerRelationChange(
131
131
  this.root,
@@ -20,11 +20,11 @@ export enum EntityStatus {
20
20
  /**
21
21
  * Represents an entity being tracked by the ORM
22
22
  */
23
- export interface TrackedEntity {
24
- /** The table definition this entity belongs to */
25
- table: TableDef;
26
- /** The actual entity instance */
27
- entity: unknown;
23
+ export interface TrackedEntity {
24
+ /** The table definition this entity belongs to */
25
+ table: TableDef;
26
+ /** The actual entity instance */
27
+ entity: object;
28
28
  /** Primary key value of the entity */
29
29
  pk: string | number | null;
30
30
  /** Current status of the entity */
@@ -1,16 +1,16 @@
1
- import type {
2
- EntityInstance,
3
- HasManyCollection,
4
- HasOneReference,
5
- BelongsToReference,
6
- ManyToManyCollection
7
- } from '../schema/types.js';
8
- import { normalizeColumnType, type ColumnDef } from '../schema/column-types.js';
9
- import {
10
- RelationKinds,
11
- type BelongsToManyRelation,
12
- type BelongsToRelation,
13
- type HasManyRelation,
1
+ import type {
2
+ EntityInstance,
3
+ HasManyCollection,
4
+ HasOneReference,
5
+ BelongsToReference,
6
+ ManyToManyCollection
7
+ } from '../schema/types.js';
8
+ import { normalizeColumnType, type ColumnDef } from '../schema/column-types.js';
9
+ import {
10
+ RelationKinds,
11
+ type BelongsToManyRelation,
12
+ type BelongsToRelation,
13
+ type HasManyRelation,
14
14
  type HasOneRelation,
15
15
  type RelationDef
16
16
  } from '../schema/relation.js';
@@ -20,25 +20,23 @@ import { createEntityFromRow } from './entity.js';
20
20
  import type { EntityConstructor } from './entity-metadata.js';
21
21
  import { getTableDefFromEntity } from '../decorators/bootstrap.js';
22
22
  import type { OrmSession } from './orm-session.js';
23
+ import type { PrimaryKey } from './entity-context.js';
23
24
 
24
25
  /**
25
26
  * Options for controlling the behavior of save graph operations.
26
27
  */
27
- export interface SaveGraphOptions {
28
- /** Remove existing collection members that are not present in the payload */
29
- pruneMissing?: boolean;
30
- /**
31
- * Coerce JSON-friendly input values into DB-friendly primitives.
32
- * Currently:
33
- * - Date -> ISO string (for DATE/DATETIME/TIMESTAMP/TIMESTAMPTZ columns)
34
- */
35
- coerce?: 'json';
36
- }
28
+ export interface SaveGraphOptions {
29
+ /** Remove existing collection members that are not present in the payload */
30
+ pruneMissing?: boolean;
31
+ /**
32
+ * Coerce JSON-friendly input values into DB-friendly primitives.
33
+ * Currently:
34
+ * - Date -> ISO string (for DATE/DATETIME/TIMESTAMP/TIMESTAMPTZ columns)
35
+ */
36
+ coerce?: 'json';
37
+ }
37
38
 
38
39
  /** Represents an entity object with arbitrary properties. */
39
-
40
- /** Represents an entity object with arbitrary properties. */
41
-
42
40
  type AnyEntity = Record<string, unknown>;
43
41
 
44
42
  /**
@@ -51,58 +49,58 @@ type AnyEntity = Record<string, unknown>;
51
49
 
52
50
  */
53
51
 
54
- const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
55
-
56
- const coerceColumnValue = (
57
- table: TableDef,
58
- columnName: string,
59
- value: unknown,
60
- options: SaveGraphOptions
61
- ): unknown => {
62
- if (options.coerce !== 'json') return value;
63
- if (value === null || value === undefined) return value;
64
-
65
- const column = table.columns[columnName] as unknown as ColumnDef | undefined;
66
- if (!column) return value;
67
-
68
- const normalized = normalizeColumnType(column.type);
69
-
70
- const isDateLikeColumn =
71
- normalized === 'date' ||
72
- normalized === 'datetime' ||
73
- normalized === 'timestamp' ||
74
- normalized === 'timestamptz';
75
-
76
- if (isDateLikeColumn && value instanceof Date) {
77
- return value.toISOString();
78
- }
79
-
80
- // Future coercions can be added here based on `normalized`.
81
- return value;
82
- };
83
-
84
- const pickColumns = (table: TableDef, payload: AnyEntity, options: SaveGraphOptions): Record<string, unknown> => {
85
- const columns: Record<string, unknown> = {};
86
- for (const key of Object.keys(table.columns)) {
87
- if (payload[key] !== undefined) {
88
- columns[key] = coerceColumnValue(table, key, payload[key], options);
89
- }
90
- }
91
- return columns;
92
- };
93
-
94
- const ensureEntity = <TTable extends TableDef>(
95
- session: OrmSession,
96
- table: TTable,
97
- payload: AnyEntity,
98
- options: SaveGraphOptions
99
- ): EntityInstance<TTable> => {
100
- const pk = findPrimaryKey(table);
101
- const row = pickColumns(table, payload, options);
102
- const pkValue = payload[pk];
52
+ const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
53
+
54
+ const coerceColumnValue = (
55
+ table: TableDef,
56
+ columnName: string,
57
+ value: unknown,
58
+ options: SaveGraphOptions
59
+ ): unknown => {
60
+ if (options.coerce !== 'json') return value;
61
+ if (value === null || value === undefined) return value;
62
+
63
+ const column = table.columns[columnName] as unknown as ColumnDef | undefined;
64
+ if (!column) return value;
65
+
66
+ const normalized = normalizeColumnType(column.type);
67
+
68
+ const isDateLikeColumn =
69
+ normalized === 'date' ||
70
+ normalized === 'datetime' ||
71
+ normalized === 'timestamp' ||
72
+ normalized === 'timestamptz';
73
+
74
+ if (isDateLikeColumn && value instanceof Date) {
75
+ return value.toISOString();
76
+ }
77
+
78
+ // Future coercions can be added here based on `normalized`.
79
+ return value;
80
+ };
81
+
82
+ const pickColumns = (table: TableDef, payload: AnyEntity, options: SaveGraphOptions): Record<string, unknown> => {
83
+ const columns: Record<string, unknown> = {};
84
+ for (const key of Object.keys(table.columns)) {
85
+ if (payload[key] !== undefined) {
86
+ columns[key] = coerceColumnValue(table, key, payload[key], options);
87
+ }
88
+ }
89
+ return columns;
90
+ };
91
+
92
+ const ensureEntity = <TTable extends TableDef>(
93
+ session: OrmSession,
94
+ table: TTable,
95
+ payload: AnyEntity,
96
+ options: SaveGraphOptions
97
+ ): EntityInstance<TTable> => {
98
+ const pk = findPrimaryKey(table);
99
+ const row = pickColumns(table, payload, options);
100
+ const pkValue = payload[pk];
103
101
 
104
102
  if (pkValue !== undefined && pkValue !== null) {
105
- const tracked = session.getEntity(table, pkValue);
103
+ const tracked = session.getEntity(table, pkValue as PrimaryKey);
106
104
  if (tracked) {
107
105
  return tracked as EntityInstance<TTable>;
108
106
  }
@@ -112,16 +110,16 @@ const ensureEntity = <TTable extends TableDef>(
112
110
  }
113
111
  }
114
112
 
115
- return createEntityFromRow(session, table, row) as EntityInstance<TTable>;
116
- };
117
-
118
- const assignColumns = (table: TableDef, entity: AnyEntity, payload: AnyEntity, options: SaveGraphOptions): void => {
119
- for (const key of Object.keys(table.columns)) {
120
- if (payload[key] !== undefined) {
121
- entity[key] = coerceColumnValue(table, key, payload[key], options);
122
- }
123
- }
124
- };
113
+ return createEntityFromRow(session, table, row) as EntityInstance<TTable>;
114
+ };
115
+
116
+ const assignColumns = (table: TableDef, entity: AnyEntity, payload: AnyEntity, options: SaveGraphOptions): void => {
117
+ for (const key of Object.keys(table.columns)) {
118
+ if (payload[key] !== undefined) {
119
+ entity[key] = coerceColumnValue(table, key, payload[key], options);
120
+ }
121
+ }
122
+ };
125
123
 
126
124
  const isEntityInCollection = (items: AnyEntity[], pkName: string, entity: AnyEntity): boolean => {
127
125
  if (items.includes(entity)) return true;
@@ -157,13 +155,13 @@ const handleHasMany = async (
157
155
  const asObj = typeof item === 'object' ? (item as AnyEntity) : { [targetPk]: item };
158
156
  const pkValue = asObj[targetPk];
159
157
 
160
- const current =
161
- findInCollectionByPk(existing, targetPk, pkValue) ??
162
- (pkValue !== undefined && pkValue !== null ? session.getEntity(targetTable, pkValue) : undefined);
163
-
164
- const entity = current ?? ensureEntity(session, targetTable, asObj, options);
165
- assignColumns(targetTable, entity as AnyEntity, asObj, options);
166
- await applyGraphToEntity(session, targetTable, entity as AnyEntity, asObj, options);
158
+ const current =
159
+ findInCollectionByPk(existing, targetPk, pkValue) ??
160
+ (pkValue !== undefined && pkValue !== null ? session.getEntity(targetTable, pkValue as PrimaryKey) : undefined);
161
+
162
+ const entity = current ?? ensureEntity(session, targetTable, asObj, options);
163
+ assignColumns(targetTable, entity as AnyEntity, asObj, options);
164
+ await applyGraphToEntity(session, targetTable, entity as AnyEntity, asObj, options);
167
165
 
168
166
  if (!isEntityInCollection(collection.getItems() as unknown as AnyEntity[], targetPk, entity as unknown as AnyEntity)) {
169
167
  collection.attach(entity);
@@ -184,15 +182,15 @@ const handleHasMany = async (
184
182
  }
185
183
  };
186
184
 
187
- const handleHasOne = async (
188
- session: OrmSession,
189
- root: AnyEntity,
190
- relationName: string,
191
- relation: HasOneRelation,
192
- payload: unknown,
193
- options: SaveGraphOptions
194
- ): Promise<void> => {
195
- const ref = root[relationName] as unknown as HasOneReference<object>;
185
+ const handleHasOne = async (
186
+ session: OrmSession,
187
+ root: AnyEntity,
188
+ relationName: string,
189
+ relation: HasOneRelation,
190
+ payload: unknown,
191
+ options: SaveGraphOptions
192
+ ): Promise<void> => {
193
+ const ref = root[relationName] as unknown as HasOneReference<object>;
196
194
  if (payload === undefined) return;
197
195
  if (payload === null) {
198
196
  ref.set(null);
@@ -202,25 +200,25 @@ const handleHasOne = async (
202
200
  if (typeof payload === 'number' || typeof payload === 'string') {
203
201
  const entity = ref.set({ [pk]: payload });
204
202
  if (entity) {
205
- await applyGraphToEntity(session, relation.target, entity as AnyEntity, { [pk]: payload }, options);
203
+ await applyGraphToEntity(session, relation.target, entity as AnyEntity, { [pk]: payload as PrimaryKey }, options);
206
204
  }
207
205
  return;
208
206
  }
209
- const attached = ref.set(payload as AnyEntity);
210
- if (attached) {
211
- await applyGraphToEntity(session, relation.target, attached as AnyEntity, payload as AnyEntity, options);
212
- }
213
- };
214
-
215
- const handleBelongsTo = async (
216
- session: OrmSession,
217
- root: AnyEntity,
218
- relationName: string,
219
- relation: BelongsToRelation,
220
- payload: unknown,
221
- options: SaveGraphOptions
222
- ): Promise<void> => {
223
- const ref = root[relationName] as unknown as BelongsToReference<object>;
207
+ const attached = ref.set(payload as AnyEntity);
208
+ if (attached) {
209
+ await applyGraphToEntity(session, relation.target, attached as AnyEntity, payload as AnyEntity, options);
210
+ }
211
+ };
212
+
213
+ const handleBelongsTo = async (
214
+ session: OrmSession,
215
+ root: AnyEntity,
216
+ relationName: string,
217
+ relation: BelongsToRelation,
218
+ payload: unknown,
219
+ options: SaveGraphOptions
220
+ ): Promise<void> => {
221
+ const ref = root[relationName] as unknown as BelongsToReference<object>;
224
222
  if (payload === undefined) return;
225
223
  if (payload === null) {
226
224
  ref.set(null);
@@ -230,15 +228,15 @@ const handleBelongsTo = async (
230
228
  if (typeof payload === 'number' || typeof payload === 'string') {
231
229
  const entity = ref.set({ [pk]: payload });
232
230
  if (entity) {
233
- await applyGraphToEntity(session, relation.target, entity as AnyEntity, { [pk]: payload }, options);
231
+ await applyGraphToEntity(session, relation.target, entity as AnyEntity, { [pk]: payload as PrimaryKey }, options);
234
232
  }
235
233
  return;
236
234
  }
237
- const attached = ref.set(payload as AnyEntity);
238
- if (attached) {
239
- await applyGraphToEntity(session, relation.target, attached as AnyEntity, payload as AnyEntity, options);
240
- }
241
- };
235
+ const attached = ref.set(payload as AnyEntity);
236
+ if (attached) {
237
+ await applyGraphToEntity(session, relation.target, attached as AnyEntity, payload as AnyEntity, options);
238
+ }
239
+ };
242
240
 
243
241
  const handleBelongsToMany = async (
244
242
  session: OrmSession,
@@ -265,14 +263,14 @@ const handleBelongsToMany = async (
265
263
  continue;
266
264
  }
267
265
 
268
- const asObj = item as AnyEntity;
269
- const pkValue = asObj[targetPk];
270
- const entity = pkValue !== undefined && pkValue !== null
271
- ? session.getEntity(targetTable, pkValue) ?? ensureEntity(session, targetTable, asObj, options)
272
- : ensureEntity(session, targetTable, asObj, options);
273
-
274
- assignColumns(targetTable, entity as AnyEntity, asObj, options);
275
- await applyGraphToEntity(session, targetTable, entity as AnyEntity, asObj, options);
266
+ const asObj = item as AnyEntity;
267
+ const pkValue = asObj[targetPk];
268
+ const entity = pkValue !== undefined && pkValue !== null
269
+ ? session.getEntity(targetTable, pkValue as PrimaryKey) ?? ensureEntity(session, targetTable, asObj, options)
270
+ : ensureEntity(session, targetTable, asObj, options);
271
+
272
+ assignColumns(targetTable, entity as AnyEntity, asObj, options);
273
+ await applyGraphToEntity(session, targetTable, entity as AnyEntity, asObj, options);
276
274
 
277
275
  if (!isEntityInCollection(collection.getItems() as unknown as AnyEntity[], targetPk, entity as unknown as AnyEntity)) {
278
276
  collection.attach(entity);
@@ -314,36 +312,36 @@ const applyRelation = async (
314
312
  }
315
313
  };
316
314
 
317
- const applyGraphToEntity = async (
318
- session: OrmSession,
319
- table: TableDef,
320
- entity: AnyEntity,
321
- payload: AnyEntity,
322
- options: SaveGraphOptions
323
- ): Promise<void> => {
324
- assignColumns(table, entity, payload, options);
325
-
326
- for (const [relationName, relation] of Object.entries(table.relations)) {
327
- if (!(relationName in payload)) continue;
328
- await applyRelation(session, table, entity, relationName, relation as RelationDef, payload[relationName], options);
329
- }
330
- };
331
-
332
- export const saveGraph = async <TTable extends TableDef>(
333
- session: OrmSession,
334
- entityClass: EntityConstructor,
335
- payload: AnyEntity,
336
- options: SaveGraphOptions = {}
337
- ): Promise<EntityInstance<TTable>> => {
315
+ const applyGraphToEntity = async (
316
+ session: OrmSession,
317
+ table: TableDef,
318
+ entity: AnyEntity,
319
+ payload: AnyEntity,
320
+ options: SaveGraphOptions
321
+ ): Promise<void> => {
322
+ assignColumns(table, entity, payload, options);
323
+
324
+ for (const [relationName, relation] of Object.entries(table.relations)) {
325
+ if (!(relationName in payload)) continue;
326
+ await applyRelation(session, table, entity, relationName, relation as RelationDef, payload[relationName], options);
327
+ }
328
+ };
329
+
330
+ export const saveGraph = async <TTable extends TableDef>(
331
+ session: OrmSession,
332
+ entityClass: EntityConstructor,
333
+ payload: AnyEntity,
334
+ options: SaveGraphOptions = {}
335
+ ): Promise<EntityInstance<TTable>> => {
338
336
  const table = getTableDefFromEntity(entityClass);
339
337
  if (!table) {
340
338
  throw new Error('Entity metadata has not been bootstrapped');
341
339
  }
342
340
 
343
- const root = ensureEntity<TTable>(session, table as TTable, payload, options);
344
- await applyGraphToEntity(session, table, root as AnyEntity, payload, options);
345
- return root;
346
- };
341
+ const root = ensureEntity<TTable>(session, table as TTable, payload, options);
342
+ await applyGraphToEntity(session, table, root as AnyEntity, payload, options);
343
+ return root;
344
+ };
347
345
 
348
346
  /**
349
347
 
@@ -361,7 +359,7 @@ export const saveGraph = async <TTable extends TableDef>(
361
359
 
362
360
  */
363
361
 
364
- export const saveGraphInternal = async <TCtor extends EntityConstructor>(
362
+ export const saveGraphInternal = async <TCtor extends EntityConstructor>(
365
363
 
366
364
  session: OrmSession,
367
365
 
@@ -373,7 +371,7 @@ export const saveGraphInternal = async <TCtor extends EntityConstructor>(
373
371
 
374
372
  ): Promise<InstanceType<TCtor>> => {
375
373
 
376
- const table = getTableDefFromEntity(entityClass);
374
+ const table = getTableDefFromEntity(entityClass);
377
375
 
378
376
  if (!table) {
379
377
 
@@ -381,10 +379,10 @@ export const saveGraphInternal = async <TCtor extends EntityConstructor>(
381
379
 
382
380
  }
383
381
 
384
- const root = ensureEntity(session, table, payload, options);
385
-
386
- await applyGraphToEntity(session, table, root as AnyEntity, payload, options);
387
-
388
- return root as unknown as InstanceType<TCtor>;
389
-
390
- };
382
+ const root = ensureEntity(session, table, payload, options);
383
+
384
+ await applyGraphToEntity(session, table, root as AnyEntity, payload, options);
385
+
386
+ return root as unknown as InstanceType<TCtor>;
387
+
388
+ };