|
1 | 1 | /* eslint-disable sonarjs/cognitive-complexity */ |
2 | 2 | /* eslint-disable sonarjs/no-duplicate-string */ |
3 | | -import { BadRequestException, Injectable } from '@nestjs/common'; |
| 3 | +import { Injectable, Logger } from '@nestjs/common'; |
4 | 4 | import type { ILinkCellValue, ILinkFieldOptions, IRecord } from '@teable/core'; |
5 | 5 | import { FieldType, HttpErrorCode, Relationship } from '@teable/core'; |
6 | 6 | import type { Field } from '@teable/db-main-prisma'; |
@@ -52,6 +52,7 @@ export interface ILinkCellContext { |
52 | 52 |
|
53 | 53 | @Injectable() |
54 | 54 | export class LinkService { |
| 55 | + private logger = new Logger(LinkService.name); |
55 | 56 | constructor( |
56 | 57 | private readonly prismaService: PrismaService, |
57 | 58 | private readonly batchService: BatchService, |
@@ -826,6 +827,7 @@ export class LinkService { |
826 | 827 | ); |
827 | 828 |
|
828 | 829 | const nativeQuery = qb.whereIn('__id', recordIds).toQuery(); |
| 830 | + this.logger.debug(`Fetch records with query: ${nativeQuery}`); |
829 | 831 | const recordRaw = await this.prismaService |
830 | 832 | .txClient() |
831 | 833 | .$queryRawUnsafe<{ [dbTableName: string]: unknown }[]>(nativeQuery); |
@@ -1361,32 +1363,26 @@ export class LinkService { |
1361 | 1363 | ); |
1362 | 1364 | } |
1363 | 1365 | } else { |
1364 | | - // One-many without order column implies one-way using a junction table. |
1365 | | - // To preserve the explicit order provided by the client (e.g., typecast "id1,id2"), |
1366 | | - // delete all existing rows for this source record and re-insert in the new order. |
1367 | | - const oldArr = oldKey ?? []; |
1368 | | - const newArr = newKey ?? []; |
1369 | | - |
1370 | | - const needsReorder = |
1371 | | - oldArr.length !== newArr.length || !oldArr.every((key, i) => key === newArr[i]); |
1372 | | - |
1373 | | - if (needsReorder) { |
1374 | | - // Delete all existing associations for this source record |
1375 | | - const deleteAllQuery = this.knex(fkHostTableName) |
1376 | | - .where(selfKeyName, recordId) |
1377 | | - .delete() |
1378 | | - .toQuery(); |
1379 | | - await this.prismaService.txClient().$executeRawUnsafe(deleteAllQuery); |
1380 | | - |
1381 | | - // Re-insert in the specified order |
1382 | | - if (newArr.length) { |
1383 | | - const insertValues = newArr.map((foreignRecordId) => ({ |
| 1366 | + // One-many without an order column stores the FK directly on the foreign table. |
| 1367 | + // Only update rows where the foreign key actually changes. |
| 1368 | + const toAdd = difference(newKey, oldKey); |
| 1369 | + |
| 1370 | + if (toAdd.length > 0) { |
| 1371 | + const dbFields = [{ dbFieldName: selfKeyName, schemaType: SchemaType.String }]; |
| 1372 | + |
| 1373 | + const addData = toAdd.map((foreignRecordId) => ({ |
| 1374 | + id: foreignRecordId, |
| 1375 | + values: { |
1384 | 1376 | [selfKeyName]: recordId, |
1385 | | - [foreignKeyName]: foreignRecordId, |
1386 | | - })); |
1387 | | - const insertQuery = this.knex(fkHostTableName).insert(insertValues).toQuery(); |
1388 | | - await this.prismaService.txClient().$executeRawUnsafe(insertQuery); |
1389 | | - } |
| 1377 | + }, |
| 1378 | + })); |
| 1379 | + |
| 1380 | + await this.batchService.batchUpdateDB( |
| 1381 | + fkHostTableName, |
| 1382 | + foreignKeyName, |
| 1383 | + dbFields, |
| 1384 | + addData |
| 1385 | + ); |
1390 | 1386 | } |
1391 | 1387 | } |
1392 | 1388 | } |
|
0 commit comments