Browse Source

fix: bulkDelete with composite keys

pull/8371/head
mertmit 7 months ago
parent
commit
5441bcb4c4
  1. 66
      packages/nc-gui/composables/useData.ts
  2. 1
      packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts
  3. 21
      packages/nocodb/src/db/BaseModelSqlv2.ts
  4. 1
      packages/nocodb/src/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts

66
packages/nc-gui/composables/useData.ts

@ -477,8 +477,8 @@ export function useData(args: {
try { try {
await $api.dbTableRow.nestedAdd( await $api.dbTableRow.nestedAdd(
NOCO, NOCO,
base.value.title as string, base.value.id as string,
metaValue?.title as string, metaValue?.id as string,
encodeURIComponent(rowId), encodeURIComponent(rowId),
type as RelationTypes, type as RelationTypes,
column.title as string, column.title as string,
@ -630,23 +630,25 @@ export function useData(args: {
async function deleteSelectedRows() { async function deleteSelectedRows() {
let row = formattedData.value.length let row = formattedData.value.length
let removedRowsData: Record<string, any>[] = [] const removedRowsData: Record<string, any>[] = []
let compositePrimaryKey = '' let compositePrimaryKey = ''
while (row--) { while (row--) {
const { row: rowObj, rowMeta } = formattedData.value[row] as Record<string, any> const { row: rowData, rowMeta } = formattedData.value[row] as Record<string, any>
if (!rowMeta.selected) { if (!rowMeta.selected) {
continue continue
} }
if (!rowMeta.new) { if (!rowMeta.new) {
const extractedPk = extractPk(meta?.value?.columns as ColumnType[]) 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 (extractedPk && compositePkValue) {
if (!compositePrimaryKey) compositePrimaryKey = extractedPk if (!compositePrimaryKey) compositePrimaryKey = extractedPk
removedRowsData.push({ removedRowsData.push({
[compositePrimaryKey]: compositePkValue as string, [compositePrimaryKey]: compositePkValue as string,
pkData,
row: clone(formattedData.value[row]) as Row, row: clone(formattedData.value[row]) as Row,
rowIndex: row as number, rowIndex: row as number,
}) })
@ -670,20 +672,7 @@ export function useData(args: {
rowObj.row = clone(fullRecord) rowObj.row = clone(fullRecord)
} }
const removedRowIds: Record<string, any>[] = await bulkDeleteRows( await bulkDeleteRows(removedRowsData.map((row) => row.pkData))
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 = []
}
} catch (e: any) { } catch (e: any) {
return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`) return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`)
} }
@ -692,10 +681,8 @@ export function useData(args: {
addUndo({ addUndo({
redo: { redo: {
fn: async function redo(this: UndoRedoAction, removedRowsData: Record<string, any>[], compositePrimaryKey: string) { fn: async function redo(this: UndoRedoAction, removedRowsData: Record<string, any>[]) {
const removedRowIds = await bulkDeleteRows( const removedRowIds = await bulkDeleteRows(removedRowsData.map((row) => row.pkData))
removedRowsData.map((row) => ({ [compositePrimaryKey]: row[compositePrimaryKey] as string })),
)
if (Array.isArray(removedRowIds)) { if (Array.isArray(removedRowIds)) {
for (const { row } of removedRowsData) { for (const { row } of removedRowsData) {
@ -708,7 +695,7 @@ export function useData(args: {
await callbacks?.syncPagination?.() await callbacks?.syncPagination?.()
}, },
args: [removedRowsData, compositePrimaryKey], args: [removedRowsData],
}, },
undo: { undo: {
fn: async function undo( fn: async function undo(
@ -764,22 +751,24 @@ export function useData(args: {
// plus one because we want to include the end row // plus one because we want to include the end row
let row = start + 1 let row = start + 1
let removedRowsData: Record<string, any>[] = [] const removedRowsData: Record<string, any>[] = []
let compositePrimaryKey = '' let compositePrimaryKey = ''
while (row--) { while (row--) {
try { try {
const { row: rowObj, rowMeta } = formattedData.value[row] as Record<string, any> const { row: rowData, rowMeta } = formattedData.value[row] as Record<string, any>
if (!rowMeta.new) { if (!rowMeta.new) {
const extractedPk = extractPk(meta?.value?.columns as ColumnType[]) 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 (extractedPk && compositePkValue) {
if (!compositePrimaryKey) compositePrimaryKey = extractedPk if (!compositePrimaryKey) compositePrimaryKey = extractedPk
removedRowsData.push({ removedRowsData.push({
[compositePrimaryKey]: compositePkValue as string, [compositePrimaryKey]: compositePkValue as string,
pkData,
row: clone(formattedData.value[row]) as Row, row: clone(formattedData.value[row]) as Row,
rowIndex: row as number, rowIndex: row as number,
}) })
@ -808,20 +797,7 @@ export function useData(args: {
rowObj.row = clone(fullRecord) rowObj.row = clone(fullRecord)
} }
const removedRowIds: Record<string, any>[] = await bulkDeleteRows( await bulkDeleteRows(removedRowsData.map((row) => row.pkData))
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 = []
}
} catch (e: any) { } catch (e: any) {
return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`) return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`)
} }
@ -830,10 +806,8 @@ export function useData(args: {
addUndo({ addUndo({
redo: { redo: {
fn: async function redo(this: UndoRedoAction, removedRowsData: Record<string, any>[], compositePrimaryKey: string) { fn: async function redo(this: UndoRedoAction, removedRowsData: Record<string, any>[]) {
const removedRowIds = await bulkDeleteRows( const removedRowIds = await bulkDeleteRows(removedRowsData.map((row) => row.pkData))
removedRowsData.map((row) => ({ [compositePrimaryKey]: row[compositePrimaryKey] as string })),
)
if (Array.isArray(removedRowIds)) { if (Array.isArray(removedRowIds)) {
for (const { row } of removedRowsData) { for (const { row } of removedRowsData) {
@ -846,7 +820,7 @@ export function useData(args: {
await callbacks?.syncPagination?.() await callbacks?.syncPagination?.()
}, },
args: [removedRowsData, compositePrimaryKey], args: [removedRowsData],
}, },
undo: { undo: {
fn: async function undo( fn: async function undo(

1
packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts

@ -643,6 +643,7 @@ export class SnowflakeUi {
case 'STRING': case 'STRING':
return 'string'; return 'string';
case 'TEXT': case 'TEXT':
if (col.dtxp < 1024) return 'string';
return 'text'; return 'text';
case 'BINARY': case 'BINARY':
case 'VARBINARY': case 'VARBINARY':

21
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -2107,7 +2107,7 @@ class BaseModelSqlv2 {
] = async function (args): Promise<any> { ] = async function (args): Promise<any> {
(listLoader as any).args = args; (listLoader as any).args = args;
return listLoader.load( return listLoader.load(
getCompositePk(self.model.primaryKeys, this), getCompositePkValue(self.model.primaryKeys, this),
); );
}; };
} else if (colOptions.type === 'mm') { } else if (colOptions.type === 'mm') {
@ -2148,7 +2148,7 @@ class BaseModelSqlv2 {
] = async function (args): Promise<any> { ] = async function (args): Promise<any> {
(listLoader as any).args = args; (listLoader as any).args = args;
return await listLoader.load( return await listLoader.load(
getCompositePk(self.model.primaryKeys, this), getCompositePkValue(self.model.primaryKeys, this),
); );
}; };
} else if (colOptions.type === 'bt') { } else if (colOptions.type === 'bt') {
@ -2370,7 +2370,7 @@ class BaseModelSqlv2 {
] = async function (args): Promise<any> { ] = async function (args): Promise<any> {
(listLoader as any).args = args; (listLoader as any).args = args;
return listLoader.load( 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 pkAndData: { pk: any; data: any }[] = [];
const readChunkSize = 100; const readChunkSize = 100;
for (const [i, d] of updateDatas.entries()) { for (const [i, d] of updateDatas.entries()) {
const pkValues = this._extractPksValues(d); const pkValues = getCompositePkValue(
this.model.primaryKeys,
this._extractPksValues(d),
);
if (!pkValues) { if (!pkValues) {
// throw or skip if no pk provided // throw or skip if no pk provided
if (throwExceptionIfNotExist) { if (throwExceptionIfNotExist) {
@ -3964,7 +3967,10 @@ class BaseModelSqlv2 {
const pkAndData: { pk: any; data: any }[] = []; const pkAndData: { pk: any; data: any }[] = [];
const readChunkSize = 100; const readChunkSize = 100;
for (const [i, d] of deleteIds.entries()) { for (const [i, d] of deleteIds.entries()) {
const pkValues = this._extractPksValues(d); const pkValues = getCompositePkValue(
this.model.primaryKeys,
this._extractPksValues(d),
);
if (!pkValues) { if (!pkValues) {
// throw or skip if no pk provided // throw or skip if no pk provided
if (throwExceptionIfNotExist) { if (throwExceptionIfNotExist) {
@ -6880,8 +6886,9 @@ export function _wherePk(primaryKeys: Column[], id: unknown | unknown[]) {
return where; return where;
} }
function getCompositePk(primaryKeys: Column[], row) { export function getCompositePkValue(primaryKeys: Column[], row) {
return primaryKeys.map((c) => row[c.title]).join('___'); if (typeof row !== 'object') return row;
return primaryKeys.map((c) => row[c.title] ?? row[c.column_name]).join('___');
} }
export function haveFormulaColumn(columns: Column[]) { export function haveFormulaColumn(columns: Column[]) {

1
packages/nocodb/src/db/sql-mgr/code/models/xc/ModelXcMetaSnowflake.ts

@ -500,6 +500,7 @@ class ModelXcMetaSnowflake extends BaseModelXcMeta {
case 'smgr': case 'smgr':
return dt; return dt;
case 'text': case 'text':
if (col.dtxp < 1024) return 'string';
return 'text'; return 'text';
case 'tid': case 'tid':
return dt; return dt;

Loading…
Cancel
Save