From 5441bcb4c4b5516290e0724aad79016480698e1e Mon Sep 17 00:00:00 2001 From: mertmit Date: Tue, 30 Apr 2024 17:12:25 +0000 Subject: [PATCH] fix: bulkDelete with composite keys --- packages/nc-gui/composables/useData.ts | 66 ++++++------------- .../nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts | 1 + packages/nocodb/src/db/BaseModelSqlv2.ts | 21 ++++-- .../code/models/xc/ModelXcMetaSnowflake.ts | 1 + 4 files changed, 36 insertions(+), 53 deletions(-) diff --git a/packages/nc-gui/composables/useData.ts b/packages/nc-gui/composables/useData.ts index a287042292..959fc7d813 100644 --- a/packages/nc-gui/composables/useData.ts +++ b/packages/nc-gui/composables/useData.ts @@ -477,8 +477,8 @@ export function useData(args: { try { await $api.dbTableRow.nestedAdd( NOCO, - base.value.title as string, - metaValue?.title as string, + base.value.id as string, + metaValue?.id as string, encodeURIComponent(rowId), type as RelationTypes, column.title as string, @@ -630,23 +630,25 @@ export function useData(args: { async function deleteSelectedRows() { let row = formattedData.value.length - let removedRowsData: Record[] = [] + const removedRowsData: Record[] = [] let compositePrimaryKey = '' while (row--) { - const { row: rowObj, rowMeta } = formattedData.value[row] as Record + const { row: rowData, rowMeta } = formattedData.value[row] as Record if (!rowMeta.selected) { continue } if (!rowMeta.new) { const extractedPk = extractPk(meta?.value?.columns as ColumnType[]) - const compositePkValue = extractPkFromRow(rowObj, meta?.value?.columns as ColumnType[]) + const compositePkValue = extractPkFromRow(rowData, meta?.value?.columns as ColumnType[]) + const pkData = rowPkData(rowData, meta?.value?.columns as ColumnType[]) if (extractedPk && compositePkValue) { if (!compositePrimaryKey) compositePrimaryKey = extractedPk removedRowsData.push({ [compositePrimaryKey]: compositePkValue as string, + pkData, row: clone(formattedData.value[row]) as Row, rowIndex: row as number, }) @@ -670,20 +672,7 @@ export function useData(args: { rowObj.row = clone(fullRecord) } - const removedRowIds: Record[] = await bulkDeleteRows( - removedRowsData.map((row) => ({ [compositePrimaryKey]: row[compositePrimaryKey] as string })), - ) - - if (Array.isArray(removedRowIds)) { - const removedRowsDataSet = new Set(removedRowIds.map((row) => row[compositePrimaryKey])) - - removedRowsData = removedRowsData.filter((row) => removedRowsDataSet.has(row[compositePrimaryKey] as string)) - - const rowIndexesSet = new Set(removedRowsData.map((row) => row.rowIndex)) - formattedData.value = formattedData.value.filter((_, index) => rowIndexesSet.has(index)) - } else { - removedRowsData = [] - } + await bulkDeleteRows(removedRowsData.map((row) => row.pkData)) } catch (e: any) { return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`) } @@ -692,10 +681,8 @@ export function useData(args: { addUndo({ redo: { - fn: async function redo(this: UndoRedoAction, removedRowsData: Record[], compositePrimaryKey: string) { - const removedRowIds = await bulkDeleteRows( - removedRowsData.map((row) => ({ [compositePrimaryKey]: row[compositePrimaryKey] as string })), - ) + fn: async function redo(this: UndoRedoAction, removedRowsData: Record[]) { + const removedRowIds = await bulkDeleteRows(removedRowsData.map((row) => row.pkData)) if (Array.isArray(removedRowIds)) { for (const { row } of removedRowsData) { @@ -708,7 +695,7 @@ export function useData(args: { await callbacks?.syncPagination?.() }, - args: [removedRowsData, compositePrimaryKey], + args: [removedRowsData], }, undo: { fn: async function undo( @@ -764,22 +751,24 @@ export function useData(args: { // plus one because we want to include the end row let row = start + 1 - let removedRowsData: Record[] = [] + const removedRowsData: Record[] = [] let compositePrimaryKey = '' while (row--) { try { - const { row: rowObj, rowMeta } = formattedData.value[row] as Record + const { row: rowData, rowMeta } = formattedData.value[row] as Record if (!rowMeta.new) { const extractedPk = extractPk(meta?.value?.columns as ColumnType[]) - const compositePkValue = extractPkFromRow(rowObj, meta?.value?.columns as ColumnType[]) + const compositePkValue = extractPkFromRow(rowData, meta?.value?.columns as ColumnType[]) + const pkData = rowPkData(rowData, meta?.value?.columns as ColumnType[]) if (extractedPk && compositePkValue) { if (!compositePrimaryKey) compositePrimaryKey = extractedPk removedRowsData.push({ [compositePrimaryKey]: compositePkValue as string, + pkData, row: clone(formattedData.value[row]) as Row, rowIndex: row as number, }) @@ -808,20 +797,7 @@ export function useData(args: { rowObj.row = clone(fullRecord) } - const removedRowIds: Record[] = await bulkDeleteRows( - removedRowsData.map((row) => ({ [compositePrimaryKey]: row[compositePrimaryKey] as string })), - ) - - if (Array.isArray(removedRowIds)) { - const removedRowsDataSet = new Set(removedRowIds.map((row) => row[compositePrimaryKey])) - - removedRowsData = removedRowsData.filter((row) => removedRowsDataSet.has(row[compositePrimaryKey] as string)) - - const rowIndexesSet = new Set(removedRowsData.map((row) => row.rowIndex)) - formattedData.value = formattedData.value.filter((_, index) => rowIndexesSet.has(index)) - } else { - removedRowsData = [] - } + await bulkDeleteRows(removedRowsData.map((row) => row.pkData)) } catch (e: any) { return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`) } @@ -830,10 +806,8 @@ export function useData(args: { addUndo({ redo: { - fn: async function redo(this: UndoRedoAction, removedRowsData: Record[], compositePrimaryKey: string) { - const removedRowIds = await bulkDeleteRows( - removedRowsData.map((row) => ({ [compositePrimaryKey]: row[compositePrimaryKey] as string })), - ) + fn: async function redo(this: UndoRedoAction, removedRowsData: Record[]) { + const removedRowIds = await bulkDeleteRows(removedRowsData.map((row) => row.pkData)) if (Array.isArray(removedRowIds)) { for (const { row } of removedRowsData) { @@ -846,7 +820,7 @@ export function useData(args: { await callbacks?.syncPagination?.() }, - args: [removedRowsData, compositePrimaryKey], + args: [removedRowsData], }, undo: { fn: async function undo( diff --git a/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts b/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts index 348105b25c..533b7de7fc 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts @@ -643,6 +643,7 @@ export class SnowflakeUi { case 'STRING': return 'string'; case 'TEXT': + if (col.dtxp < 1024) return 'string'; return 'text'; case 'BINARY': case 'VARBINARY': diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index 0d2d6c2aa6..d4dd2c5819 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -2107,7 +2107,7 @@ class BaseModelSqlv2 { ] = async function (args): Promise { (listLoader as any).args = args; return listLoader.load( - getCompositePk(self.model.primaryKeys, this), + getCompositePkValue(self.model.primaryKeys, this), ); }; } else if (colOptions.type === 'mm') { @@ -2148,7 +2148,7 @@ class BaseModelSqlv2 { ] = async function (args): Promise { (listLoader as any).args = args; return await listLoader.load( - getCompositePk(self.model.primaryKeys, this), + getCompositePkValue(self.model.primaryKeys, this), ); }; } else if (colOptions.type === 'bt') { @@ -2370,7 +2370,7 @@ class BaseModelSqlv2 { ] = async function (args): Promise { (listLoader as any).args = args; return listLoader.load( - getCompositePk(self.model.primaryKeys, this), + getCompositePkValue(self.model.primaryKeys, this), ); }; } @@ -3738,7 +3738,10 @@ class BaseModelSqlv2 { const pkAndData: { pk: any; data: any }[] = []; const readChunkSize = 100; for (const [i, d] of updateDatas.entries()) { - const pkValues = this._extractPksValues(d); + const pkValues = getCompositePkValue( + this.model.primaryKeys, + this._extractPksValues(d), + ); if (!pkValues) { // throw or skip if no pk provided if (throwExceptionIfNotExist) { @@ -3964,7 +3967,10 @@ class BaseModelSqlv2 { const pkAndData: { pk: any; data: any }[] = []; const readChunkSize = 100; for (const [i, d] of deleteIds.entries()) { - const pkValues = this._extractPksValues(d); + const pkValues = getCompositePkValue( + this.model.primaryKeys, + this._extractPksValues(d), + ); if (!pkValues) { // throw or skip if no pk provided if (throwExceptionIfNotExist) { @@ -6880,8 +6886,9 @@ export function _wherePk(primaryKeys: Column[], id: unknown | unknown[]) { return where; } -function getCompositePk(primaryKeys: Column[], row) { - return primaryKeys.map((c) => row[c.title]).join('___'); +export function getCompositePkValue(primaryKeys: Column[], row) { + if (typeof row !== 'object') return row; + return primaryKeys.map((c) => row[c.title] ?? row[c.column_name]).join('___'); } export function haveFormulaColumn(columns: Column[]) { diff --git a/packages/nocodb/src/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts b/packages/nocodb/src/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts index 9b25a0c352..99094d7a6a 100644 --- a/packages/nocodb/src/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts +++ b/packages/nocodb/src/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts @@ -500,6 +500,7 @@ class ModelXcMetaSnowflake extends BaseModelXcMeta { case 'smgr': return dt; case 'text': + if (col.dtxp < 1024) return 'string'; return 'text'; case 'tid': return dt;