metal-orm 1.0.57 → 1.0.58

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.
@@ -1,11 +1,13 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { BelongsToManyRelation, HasManyRelation, HasOneRelation, BelongsToRelation } from '../schema/relation.js';
3
3
  import { SelectQueryBuilder } from '../query-builder/select.js';
4
- import { inList, LiteralNode } from '../core/ast/expression.js';
4
+ import { ExpressionNode, inList, LiteralNode } from '../core/ast/expression.js';
5
5
  import { EntityContext } from './entity-context.js';
6
6
  import type { QueryResult } from '../core/execution/db-executor.js';
7
7
  import { ColumnDef } from '../schema/column-types.js';
8
8
  import { findPrimaryKey } from '../query-builder/hydration-planner.js';
9
+ import { RelationIncludeOptions } from '../query-builder/relation-types.js';
10
+ import { buildDefaultPivotColumns } from '../query-builder/relation-utils.js';
9
11
 
10
12
  /**
11
13
  * An array of database rows, each represented as a record of string keys to unknown values.
@@ -17,16 +19,35 @@ type Rows = Record<string, unknown>[];
17
19
  */
18
20
  type EntityTracker = ReturnType<EntityContext['getEntitiesForTable']>[number];
19
21
 
20
- /**
21
- * Creates a record of all columns from the given table definition.
22
- * @param table - The table definition to select columns from.
23
- * @returns A record mapping column names to their definitions.
24
- */
25
- const selectAllColumns = (table: TableDef): Record<string, ColumnDef> =>
26
- Object.entries(table.columns).reduce((acc, [name, def]) => {
27
- acc[name] = def;
22
+ const hasColumns = (columns?: readonly string[]): columns is readonly string[] =>
23
+ Boolean(columns && columns.length > 0);
24
+
25
+ const buildColumnSelection = (
26
+ table: TableDef,
27
+ columns: string[],
28
+ missingMsg: (col: string) => string
29
+ ): Record<string, ColumnDef> => {
30
+ return columns.reduce((acc, column) => {
31
+ const def = table.columns[column];
32
+ if (!def) {
33
+ throw new Error(missingMsg(column));
34
+ }
35
+ acc[column] = def;
28
36
  return acc;
29
37
  }, {} as Record<string, ColumnDef>);
38
+ };
39
+
40
+ const filterRow = (row: Record<string, unknown>, columns: Set<string>): Record<string, unknown> => {
41
+ const filtered: Record<string, unknown> = {};
42
+ for (const column of columns) {
43
+ if (column in row) {
44
+ filtered[column] = row[column];
45
+ }
46
+ }
47
+ return filtered;
48
+ };
49
+
50
+ const filterRows = (rows: Rows, columns: Set<string>): Rows => rows.map(row => filterRow(row, columns));
30
51
 
31
52
  /**
32
53
  * Extracts rows from query results into a standardized format.
@@ -54,11 +75,11 @@ const rowsFromResults = (results: QueryResult[]): Rows => {
54
75
  * @param qb - The select query builder.
55
76
  * @returns A promise resolving to the rows from the query.
56
77
  */
57
- const executeQuery = async (ctx: EntityContext, qb: SelectQueryBuilder<unknown, TableDef>): Promise<Rows> => {
58
- const compiled = ctx.dialect.compileSelect(qb.getAST());
59
- const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
60
- return rowsFromResults(results);
61
- };
78
+ const executeQuery = async (ctx: EntityContext, qb: SelectQueryBuilder<unknown, TableDef>): Promise<Rows> => {
79
+ const compiled = ctx.dialect.compileSelect(qb.getAST());
80
+ const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
81
+ return rowsFromResults(results);
82
+ };
62
83
 
63
84
  /**
64
85
  * Converts a value to a string key, handling null and undefined as empty string.
@@ -100,16 +121,21 @@ const buildInListValues = (keys: Set<unknown>): (string | number | LiteralNode)[
100
121
  * @param keys - The set of keys to match.
101
122
  * @returns A promise resolving to the matching rows.
102
123
  */
103
- const fetchRowsForKeys = async (
104
- ctx: EntityContext,
105
- table: TableDef,
106
- column: ColumnDef,
107
- keys: Set<unknown>
108
- ): Promise<Rows> => {
109
- const qb = new SelectQueryBuilder(table).select(selectAllColumns(table));
110
- qb.where(inList(column, buildInListValues(keys)));
111
- return executeQuery(ctx, qb);
112
- };
124
+ const fetchRowsForKeys = async (
125
+ ctx: EntityContext,
126
+ table: TableDef,
127
+ column: ColumnDef,
128
+ keys: Set<unknown>,
129
+ selection: Record<string, ColumnDef>,
130
+ filter?: ExpressionNode
131
+ ): Promise<Rows> => {
132
+ let qb = new SelectQueryBuilder(table).select(selection);
133
+ qb = qb.where(inList(column, buildInListValues(keys)));
134
+ if (filter) {
135
+ qb = qb.where(filter);
136
+ }
137
+ return executeQuery(ctx, qb);
138
+ };
113
139
 
114
140
  /**
115
141
  * Groups rows by the value of a key column, allowing multiple rows per key.
@@ -160,8 +186,9 @@ const groupRowsByUnique = (rows: Rows, keyColumn: string): Map<string, Record<st
160
186
  export const loadHasManyRelation = async (
161
187
  ctx: EntityContext,
162
188
  rootTable: TableDef,
163
- _relationName: string,
164
- relation: HasManyRelation
189
+ relationName: string,
190
+ relation: HasManyRelation,
191
+ options?: RelationIncludeOptions
165
192
  ): Promise<Map<string, Rows>> => {
166
193
  const localKey = relation.localKey || findPrimaryKey(rootTable);
167
194
  const roots = ctx.getEntitiesForTable(rootTable);
@@ -174,8 +201,33 @@ export const loadHasManyRelation = async (
174
201
  const fkColumn = relation.target.columns[relation.foreignKey];
175
202
  if (!fkColumn) return new Map();
176
203
 
177
- const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys);
178
- return groupRowsByMany(rows, relation.foreignKey);
204
+ const requestedColumns = hasColumns(options?.columns) ? [...options!.columns] : undefined;
205
+ const targetPrimaryKey = findPrimaryKey(relation.target);
206
+ const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
207
+ if (!selectedColumns.includes(targetPrimaryKey)) {
208
+ selectedColumns.push(targetPrimaryKey);
209
+ }
210
+
211
+ const queryColumns = new Set(selectedColumns);
212
+ queryColumns.add(relation.foreignKey);
213
+
214
+ const selection = buildColumnSelection(
215
+ relation.target,
216
+ Array.from(queryColumns),
217
+ column => `Column '${column}' not found on relation '${relationName}'`
218
+ );
219
+
220
+ const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
221
+ const grouped = groupRowsByMany(rows, relation.foreignKey);
222
+
223
+ if (!requestedColumns) return grouped;
224
+
225
+ const visibleColumns = new Set(selectedColumns);
226
+ const filtered = new Map<string, Rows>();
227
+ for (const [key, bucket] of grouped.entries()) {
228
+ filtered.set(key, filterRows(bucket, visibleColumns));
229
+ }
230
+ return filtered;
179
231
  };
180
232
 
181
233
  /**
@@ -189,8 +241,9 @@ export const loadHasManyRelation = async (
189
241
  export const loadHasOneRelation = async (
190
242
  ctx: EntityContext,
191
243
  rootTable: TableDef,
192
- _relationName: string,
193
- relation: HasOneRelation
244
+ relationName: string,
245
+ relation: HasOneRelation,
246
+ options?: RelationIncludeOptions
194
247
  ): Promise<Map<string, Record<string, unknown>>> => {
195
248
  const localKey = relation.localKey || findPrimaryKey(rootTable);
196
249
  const roots = ctx.getEntitiesForTable(rootTable);
@@ -203,8 +256,33 @@ export const loadHasOneRelation = async (
203
256
  const fkColumn = relation.target.columns[relation.foreignKey];
204
257
  if (!fkColumn) return new Map();
205
258
 
206
- const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys);
207
- return groupRowsByUnique(rows, relation.foreignKey);
259
+ const requestedColumns = hasColumns(options?.columns) ? [...options!.columns] : undefined;
260
+ const targetPrimaryKey = findPrimaryKey(relation.target);
261
+ const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
262
+ if (!selectedColumns.includes(targetPrimaryKey)) {
263
+ selectedColumns.push(targetPrimaryKey);
264
+ }
265
+
266
+ const queryColumns = new Set(selectedColumns);
267
+ queryColumns.add(relation.foreignKey);
268
+
269
+ const selection = buildColumnSelection(
270
+ relation.target,
271
+ Array.from(queryColumns),
272
+ column => `Column '${column}' not found on relation '${relationName}'`
273
+ );
274
+
275
+ const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
276
+ const grouped = groupRowsByUnique(rows, relation.foreignKey);
277
+
278
+ if (!requestedColumns) return grouped;
279
+
280
+ const visibleColumns = new Set(selectedColumns);
281
+ const filtered = new Map<string, Record<string, unknown>>();
282
+ for (const [key, row] of grouped.entries()) {
283
+ filtered.set(key, filterRow(row, visibleColumns));
284
+ }
285
+ return filtered;
208
286
  };
209
287
 
210
288
  /**
@@ -215,25 +293,91 @@ export const loadHasOneRelation = async (
215
293
  * @param relation - The belongs-to relation definition.
216
294
  * @returns A promise resolving to a map of foreign keys to single related rows.
217
295
  */
218
- export const loadBelongsToRelation = async (
219
- ctx: EntityContext,
220
- rootTable: TableDef,
221
- _relationName: string,
222
- relation: BelongsToRelation
223
- ): Promise<Map<string, Record<string, unknown>>> => {
224
- const roots = ctx.getEntitiesForTable(rootTable);
225
- const foreignKeys = collectKeysFromRoots(roots, relation.foreignKey);
226
-
227
- if (!foreignKeys.size) {
228
- return new Map();
229
- }
230
-
231
- const targetKey = relation.localKey || findPrimaryKey(relation.target);
296
+ export const loadBelongsToRelation = async (
297
+ ctx: EntityContext,
298
+ rootTable: TableDef,
299
+ relationName: string,
300
+ relation: BelongsToRelation,
301
+ options?: RelationIncludeOptions
302
+ ): Promise<Map<string, Record<string, unknown>>> => {
303
+ const roots = ctx.getEntitiesForTable(rootTable);
304
+
305
+ const getForeignKeys = (): Set<unknown> => collectKeysFromRoots(roots, relation.foreignKey);
306
+ let foreignKeys = getForeignKeys();
307
+
308
+ if (!foreignKeys.size) {
309
+ const pkName = findPrimaryKey(rootTable);
310
+ const pkColumn = rootTable.columns[pkName];
311
+ const fkColumn = rootTable.columns[relation.foreignKey];
312
+
313
+ if (pkColumn && fkColumn) {
314
+ const missingKeys = new Set<unknown>();
315
+ const entityByPk = new Map<unknown, Record<string, unknown>>();
316
+
317
+ for (const tracked of roots) {
318
+ const entity = tracked.entity as Record<string, unknown>;
319
+ const pkValue = entity[pkName];
320
+ if (pkValue === undefined || pkValue === null) continue;
321
+ const fkValue = entity[relation.foreignKey];
322
+ if (fkValue === undefined || fkValue === null) {
323
+ missingKeys.add(pkValue);
324
+ entityByPk.set(pkValue, entity);
325
+ }
326
+ }
327
+
328
+ if (missingKeys.size) {
329
+ const selection = buildColumnSelection(
330
+ rootTable,
331
+ [pkName, relation.foreignKey],
332
+ column => `Column '${column}' not found on table '${rootTable.name}'`
333
+ );
334
+ const keyRows = await fetchRowsForKeys(ctx, rootTable, pkColumn, missingKeys, selection);
335
+ for (const row of keyRows) {
336
+ const pkValue = row[pkName];
337
+ if (pkValue === undefined || pkValue === null) continue;
338
+ const entity = entityByPk.get(pkValue);
339
+ if (!entity) continue;
340
+ const fkValue = row[relation.foreignKey];
341
+ if (fkValue !== undefined && fkValue !== null) {
342
+ entity[relation.foreignKey] = fkValue;
343
+ }
344
+ }
345
+ foreignKeys = getForeignKeys();
346
+ }
347
+ }
348
+ }
349
+
350
+ if (!foreignKeys.size) {
351
+ return new Map();
352
+ }
353
+
354
+ const targetKey = relation.localKey || findPrimaryKey(relation.target);
232
355
  const pkColumn = relation.target.columns[targetKey];
233
356
  if (!pkColumn) return new Map();
234
357
 
235
- const rows = await fetchRowsForKeys(ctx, relation.target, pkColumn, foreignKeys);
236
- return groupRowsByUnique(rows, targetKey);
358
+ const requestedColumns = hasColumns(options?.columns) ? [...options!.columns] : undefined;
359
+ const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
360
+ if (!selectedColumns.includes(targetKey)) {
361
+ selectedColumns.push(targetKey);
362
+ }
363
+
364
+ const selection = buildColumnSelection(
365
+ relation.target,
366
+ selectedColumns,
367
+ column => `Column '${column}' not found on relation '${relationName}'`
368
+ );
369
+
370
+ const rows = await fetchRowsForKeys(ctx, relation.target, pkColumn, foreignKeys, selection, options?.filter);
371
+ const grouped = groupRowsByUnique(rows, targetKey);
372
+
373
+ if (!requestedColumns) return grouped;
374
+
375
+ const visibleColumns = new Set(selectedColumns);
376
+ const filtered = new Map<string, Record<string, unknown>>();
377
+ for (const [key, row] of grouped.entries()) {
378
+ filtered.set(key, filterRow(row, visibleColumns));
379
+ }
380
+ return filtered;
237
381
  };
238
382
 
239
383
  /**
@@ -247,8 +391,9 @@ export const loadBelongsToRelation = async (
247
391
  export const loadBelongsToManyRelation = async (
248
392
  ctx: EntityContext,
249
393
  rootTable: TableDef,
250
- _relationName: string,
251
- relation: BelongsToManyRelation
394
+ relationName: string,
395
+ relation: BelongsToManyRelation,
396
+ options?: RelationIncludeOptions
252
397
  ): Promise<Map<string, Rows>> => {
253
398
  const rootKey = relation.localKey || findPrimaryKey(rootTable);
254
399
  const roots = ctx.getEntitiesForTable(rootTable);
@@ -261,9 +406,32 @@ export const loadBelongsToManyRelation = async (
261
406
  const pivotColumn = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
262
407
  if (!pivotColumn) return new Map();
263
408
 
264
- const pivotRows = await fetchRowsForKeys(ctx, relation.pivotTable, pivotColumn, rootIds);
409
+ const pivotColumnsRequested = hasColumns(options?.pivot?.columns) ? [...options!.pivot!.columns] : undefined;
410
+ const useIncludeDefaults = options !== undefined;
411
+ let pivotSelectedColumns: string[];
412
+ if (pivotColumnsRequested) {
413
+ pivotSelectedColumns = [...pivotColumnsRequested];
414
+ } else if (useIncludeDefaults) {
415
+ const pivotPk = relation.pivotPrimaryKey || findPrimaryKey(relation.pivotTable);
416
+ pivotSelectedColumns = relation.defaultPivotColumns ?? buildDefaultPivotColumns(relation, pivotPk);
417
+ } else {
418
+ pivotSelectedColumns = Object.keys(relation.pivotTable.columns);
419
+ }
420
+
421
+ const pivotQueryColumns = new Set(pivotSelectedColumns);
422
+ pivotQueryColumns.add(relation.pivotForeignKeyToRoot);
423
+ pivotQueryColumns.add(relation.pivotForeignKeyToTarget);
424
+
425
+ const pivotSelection = buildColumnSelection(
426
+ relation.pivotTable,
427
+ Array.from(pivotQueryColumns),
428
+ column => `Column '${column}' not found on pivot table '${relation.pivotTable.name}'`
429
+ );
430
+
431
+ const pivotRows = await fetchRowsForKeys(ctx, relation.pivotTable, pivotColumn, rootIds, pivotSelection);
265
432
  const rootLookup = new Map<string, { targetId: unknown; pivot: Record<string, unknown> }[]>();
266
433
  const targetIds = new Set<unknown>();
434
+ const pivotVisibleColumns = new Set(pivotSelectedColumns);
267
435
 
268
436
  for (const pivot of pivotRows) {
269
437
  const rootValue = pivot[relation.pivotForeignKeyToRoot];
@@ -274,7 +442,7 @@ export const loadBelongsToManyRelation = async (
274
442
  const bucket = rootLookup.get(toKey(rootValue)) ?? [];
275
443
  bucket.push({
276
444
  targetId: targetValue,
277
- pivot: { ...pivot }
445
+ pivot: pivotVisibleColumns.size ? filterRow(pivot, pivotVisibleColumns) : {}
278
446
  });
279
447
  rootLookup.set(toKey(rootValue), bucket);
280
448
  targetIds.add(targetValue);
@@ -288,8 +456,23 @@ export const loadBelongsToManyRelation = async (
288
456
  const targetPkColumn = relation.target.columns[targetKey];
289
457
  if (!targetPkColumn) return new Map();
290
458
 
291
- const targetRows = await fetchRowsForKeys(ctx, relation.target, targetPkColumn, targetIds);
459
+ const targetRequestedColumns = hasColumns(options?.columns) ? [...options!.columns] : undefined;
460
+ const targetSelectedColumns = targetRequestedColumns
461
+ ? [...targetRequestedColumns]
462
+ : Object.keys(relation.target.columns);
463
+ if (!targetSelectedColumns.includes(targetKey)) {
464
+ targetSelectedColumns.push(targetKey);
465
+ }
466
+
467
+ const targetSelection = buildColumnSelection(
468
+ relation.target,
469
+ targetSelectedColumns,
470
+ column => `Column '${column}' not found on relation '${relationName}'`
471
+ );
472
+
473
+ const targetRows = await fetchRowsForKeys(ctx, relation.target, targetPkColumn, targetIds, targetSelection, options?.filter);
292
474
  const targetMap = groupRowsByUnique(targetRows, targetKey);
475
+ const targetVisibleColumns = new Set(targetSelectedColumns);
293
476
  const result = new Map<string, Rows>();
294
477
 
295
478
  for (const [rootId, entries] of rootLookup.entries()) {
@@ -298,7 +481,7 @@ export const loadBelongsToManyRelation = async (
298
481
  const targetRow = targetMap.get(toKey(entry.targetId));
299
482
  if (!targetRow) continue;
300
483
  bucket.push({
301
- ...targetRow,
484
+ ...(targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : targetRow),
302
485
  _pivot: entry.pivot
303
486
  });
304
487
  }
@@ -1,4 +1,4 @@
1
- import { BelongsToReference } from '../../schema/types.js';
1
+ import { BelongsToReferenceApi } from '../../schema/types.js';
2
2
  import { EntityContext } from '../entity-context.js';
3
3
  import { RelationKey } from '../runtime-types.js';
4
4
  import { BelongsToRelation } from '../../schema/relation.js';
@@ -26,7 +26,7 @@ const hideInternal = (obj: object, keys: string[]): void => {
26
26
  *
27
27
  * @template TParent The type of the parent entity.
28
28
  */
29
- export class DefaultBelongsToReference<TParent> implements BelongsToReference<TParent> {
29
+ export class DefaultBelongsToReference<TParent extends object> implements BelongsToReferenceApi<TParent> {
30
30
  private loaded = false;
31
31
  private current: TParent | null = null;
32
32
 
@@ -69,15 +69,29 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
69
69
  this.items = rows.map(row => this.createEntity(row));
70
70
  this.loaded = true;
71
71
  return this.items;
72
- }
73
-
74
- /**
75
- * Gets the current items in the collection.
76
- * @returns Array of child entities
77
- */
78
- getItems(): TChild[] {
79
- return this.items;
80
- }
72
+ }
73
+
74
+ /**
75
+ * Gets the current items in the collection.
76
+ * @returns Array of child entities
77
+ */
78
+ getItems(): TChild[] {
79
+ return this.items;
80
+ }
81
+
82
+ /**
83
+ * Array-compatible length for testing frameworks.
84
+ */
85
+ get length(): number {
86
+ return this.items.length;
87
+ }
88
+
89
+ /**
90
+ * Enables iteration over the collection like an array.
91
+ */
92
+ [Symbol.iterator](): Iterator<TChild> {
93
+ return this.items[Symbol.iterator]();
94
+ }
81
95
 
82
96
  /**
83
97
  * Adds a new child entity to the collection.
@@ -1,4 +1,4 @@
1
- import { HasOneReference } from '../../schema/types.js';
1
+ import { HasOneReferenceApi } from '../../schema/types.js';
2
2
  import { EntityContext } from '../entity-context.js';
3
3
  import { RelationKey } from '../runtime-types.js';
4
4
  import { HasOneRelation } from '../../schema/relation.js';
@@ -26,7 +26,7 @@ const hideInternal = (obj: object, keys: string[]): void => {
26
26
  *
27
27
  * @template TChild The type of the child entity.
28
28
  */
29
- export class DefaultHasOneReference<TChild> implements HasOneReference<TChild> {
29
+ export class DefaultHasOneReference<TChild extends object> implements HasOneReferenceApi<TChild> {
30
30
  private loaded = false;
31
31
  private current: TChild | null = null;
32
32
 
@@ -78,19 +78,33 @@ export class DefaultManyToManyCollection<TTarget> implements ManyToManyCollectio
78
78
  return this.items;
79
79
  }
80
80
 
81
- /**
82
- * Returns the currently loaded items.
83
- * @returns Array of target entities.
84
- */
85
- getItems(): TTarget[] {
86
- return this.items;
87
- }
88
-
89
- /**
90
- * Attaches an entity to the collection.
91
- * Registers an 'attach' change in the entity context.
92
- * @param target Entity instance or its primary key value.
93
- */
81
+ /**
82
+ * Returns the currently loaded items.
83
+ * @returns Array of target entities.
84
+ */
85
+ getItems(): TTarget[] {
86
+ return this.items;
87
+ }
88
+
89
+ /**
90
+ * Array-compatible length for testing frameworks.
91
+ */
92
+ get length(): number {
93
+ return this.items.length;
94
+ }
95
+
96
+ /**
97
+ * Enables iteration over the collection like an array.
98
+ */
99
+ [Symbol.iterator](): Iterator<TTarget> {
100
+ return this.items[Symbol.iterator]();
101
+ }
102
+
103
+ /**
104
+ * Attaches an entity to the collection.
105
+ * Registers an 'attach' change in the entity context.
106
+ * @param target Entity instance or its primary key value.
107
+ */
94
108
  attach(target: TTarget | number | string): void {
95
109
  const entity = this.ensureEntity(target);
96
110
  const id = this.extractId(entity);
@@ -10,8 +10,8 @@ type AnyFn = (...args: unknown[]) => unknown;
10
10
 
11
11
  type RelationWrapper =
12
12
  | HasManyCollection<unknown>
13
- | HasOneReference<unknown>
14
- | BelongsToReference<unknown>
13
+ | HasOneReference
14
+ | BelongsToReference
15
15
  | ManyToManyCollection<unknown>;
16
16
 
17
17
  type FunctionKeys<T> = {
@@ -184,15 +184,15 @@ const handleHasMany = async (
184
184
  }
185
185
  };
186
186
 
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<unknown>;
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>;
196
196
  if (payload === undefined) return;
197
197
  if (payload === null) {
198
198
  ref.set(null);
@@ -212,15 +212,15 @@ const handleHasOne = async (
212
212
  }
213
213
  };
214
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<unknown>;
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>;
224
224
  if (payload === undefined) return;
225
225
  if (payload === null) {
226
226
  ref.set(null);