From da5a233cda4b703a9fc7613338df029df4b25700 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 7 Jul 2022 19:44:51 +0800 Subject: [PATCH 1/8] fix: print info message when the deleted row has LTAR data --- .../project/spreadsheet/RowsXcDataTable.vue | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue b/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue index 6385af6908..df53bc0478 100644 --- a/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue +++ b/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue @@ -1127,7 +1127,26 @@ export default { if (!id) { return this.$toast.info("Delete not allowed for table which doesn't have primary Key").goAway(3000); } - await this.$api.dbViewRow.delete('noco', this.projectName, this.meta.id, this.selectedView.id, id); + + const res = await this.$api.dbViewRow.delete( + 'noco', + this.projectName, + this.meta.id, + this.selectedView.id, + id + ); + + if (res?.message) { + this.$toast + .info( + `
Unable to delete tables because of the following. +

${res.message.join('
')}

+ Clear the data first & try again
+ ` + ) + .goAway(5000); + return; + } } this.data.splice(this.rowContextMenu.index, 1); this.syncCount(); From 8a26baf1ccb4f0ff35bfd087187d89b7092b19b3 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 7 Jul 2022 19:45:19 +0800 Subject: [PATCH 2/8] fix: check if the deleted row has LTAR data before deleting --- .../nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts index 9b136dcc99..d86f10602e 100644 --- a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts +++ b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts @@ -76,12 +76,17 @@ async function dataUpdate(req: Request, res: Response) { async function dataDelete(req: Request, res: Response) { const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); const base = await Base.get(model.base_id); + const dbDriver = NcConnectionMgrv2.get(base); const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: NcConnectionMgrv2.get(base), + dbDriver: dbDriver, }); - + const message = await baseModel.hasLTARData(req.params.rowId, model); + if (message.length) { + res.json({ message }); + return; + } res.json(await baseModel.delByPk(req.params.rowId, null, req)); } async function getDataList(model, view: View, req) { From 8b5598ccb93ebc3f5ae14db4c40cb3dcab3b3ac0 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 7 Jul 2022 19:45:35 +0800 Subject: [PATCH 3/8] wip: hasLTARData logic for M2M --- .../sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index bafd578414..652d7a1e60 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1380,6 +1380,46 @@ class BaseModelSqlv2 { } } + async hasLTARData(rowId, model: Model): Promise { + const LTARColumns = (await model.getColumns()).filter( + (c) => c.uidt === UITypes.LinkToAnotherRecord + ); + const res = []; + for (const column of LTARColumns) { + const colOptions = + (await column.getColOptions()) as LinkToAnotherRecordColumn; + const childColumn = await colOptions.getChildColumn(); + const parentColumn = await colOptions.getParentColumn(); + const childModel = await childColumn.getModel(); + await childModel.getColumns(); + const parentModel = await parentColumn.getModel(); + await parentModel.getColumns(); + let i = 0; + if (colOptions.type === RelationTypes.HAS_MANY) { + // TODO: + continue; + } else if (colOptions.type === RelationTypes.BELONGS_TO) { + // TODO: + continue; + } else if (colOptions.type === RelationTypes.MANY_TO_MANY) { + const mmModel = await colOptions.getMMModel(); + const mmChildColumn = await colOptions.getMMChildColumn(); + const selectMmCount = await this.dbDriver(mmModel.table_name) + .where(`${mmModel.table_name}.${mmChildColumn.column_name}`, rowId) + .count(mmChildColumn.column_name, { as: 'cnt' }); + const cnt = (await selectMmCount)[0].cnt; + if (cnt) { + res.push( + `${i++ + 1}. ${model.title}.${ + column.title + } is a LinkToAnotherRecord of ${parentModel.title}` + ); + } + } + } + return res; + } + async updateByPk(id, data, trx?, cookie?) { try { const updateObj = await this.model.mapAliasToColumn(data); From 88935e79bc1a3940de31497a9a6480fe0924031c Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 11:50:33 +0800 Subject: [PATCH 4/8] fix: handle hm case --- .../db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 652d7a1e60..5d0a53e229 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1385,6 +1385,7 @@ class BaseModelSqlv2 { (c) => c.uidt === UITypes.LinkToAnotherRecord ); const res = []; + let i = 0; for (const column of LTARColumns) { const colOptions = (await column.getColOptions()) as LinkToAnotherRecordColumn; @@ -1394,10 +1395,18 @@ class BaseModelSqlv2 { await childModel.getColumns(); const parentModel = await parentColumn.getModel(); await parentModel.getColumns(); - let i = 0; if (colOptions.type === RelationTypes.HAS_MANY) { - // TODO: - continue; + const selectHmCount = await this.dbDriver(childModel.table_name) + .count(childColumn.column_name, { as: 'cnt' }) + .where(childColumn.column_name, rowId); + const cnt = (await selectHmCount)[0].cnt; + if (cnt) { + res.push( + `${i++ + 1}. ${model.title}.${ + column.title + } is a LinkToAnotherRecord of ${childModel.title}` + ); + } } else if (colOptions.type === RelationTypes.BELONGS_TO) { // TODO: continue; From 0d3d38cb8f4919df067d2540d5f0215c8d16f10e Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 12:11:04 +0800 Subject: [PATCH 5/8] fix: handle delete selected rows logic --- .../project/spreadsheet/RowsXcDataTable.vue | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue b/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue index df53bc0478..26e19fa7ea 100644 --- a/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue +++ b/packages/nc-gui/components/project/spreadsheet/RowsXcDataTable.vue @@ -1124,27 +1124,8 @@ export default { .map(c => rowObj[c.title]) .join('___'); - if (!id) { - return this.$toast.info("Delete not allowed for table which doesn't have primary Key").goAway(3000); - } - - const res = await this.$api.dbViewRow.delete( - 'noco', - this.projectName, - this.meta.id, - this.selectedView.id, - id - ); - - if (res?.message) { - this.$toast - .info( - `
Unable to delete tables because of the following. -

${res.message.join('
')}

- Clear the data first & try again
- ` - ) - .goAway(5000); + const successfulDeletion = await this.deleteRowById(id); + if (!successfulDeletion) { return; } } @@ -1157,7 +1138,6 @@ export default { }, async deleteSelectedRows() { let row = this.rowLength; - // let success = 0 while (row--) { try { const { row: rowObj, rowMeta } = this.data[row]; @@ -1170,10 +1150,10 @@ export default { .map(c => rowObj[c.title]) .join('___'); - if (!id) { - return this.$toast.info("Delete not allowed for table which doesn't have primary Key").goAway(3000); + const successfulDeletion = await this.deleteRowById(id); + if (!successfulDeletion) { + continue; } - await this.$api.dbViewRow.delete('noco', this.projectName, this.meta.id, this.selectedView.id, id); } this.data.splice(row, 1); } catch (e) { @@ -1183,6 +1163,32 @@ export default { this.syncCount(); }, + async deleteRowById(id) { + try { + if (!id) { + this.$toast.info("Delete not allowed for table which doesn't have primary Key").goAway(3000); + return false; + } + + const res = await this.$api.dbViewRow.delete('noco', this.projectName, this.meta.id, this.selectedView.id, id); + + if (res?.message) { + this.$toast + .info( + `
Unable to delete row with ID ${id} because of the following: +

${res.message.join('
')}

+ Clear the data first & try again
` + ) + .goAway(5000); + return false; + } + } catch (e) { + this.$toast.error(`Failed to delete row : ${e.message}`).goAway(3000); + return false; + } + return true; + }, + async clearCellValue() { const { col, colIndex, row, index } = this.rowContextMenu; if (row[col.title] === null) { From ff371655ef5076f5e829273bc945d9e1141efcd0 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 12:22:34 +0800 Subject: [PATCH 6/8] chore: remove bt case --- .../src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 5d0a53e229..f4d59d6025 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1407,9 +1407,6 @@ class BaseModelSqlv2 { } is a LinkToAnotherRecord of ${childModel.title}` ); } - } else if (colOptions.type === RelationTypes.BELONGS_TO) { - // TODO: - continue; } else if (colOptions.type === RelationTypes.MANY_TO_MANY) { const mmModel = await colOptions.getMMModel(); const mmChildColumn = await colOptions.getMMChildColumn(); From 7f97f357c4b6c597879312605a6bdd7eb3a703ff Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 12:23:38 +0800 Subject: [PATCH 7/8] chore: rollback to previous code --- packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts index d86f10602e..b982bbc4de 100644 --- a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts +++ b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts @@ -76,11 +76,10 @@ async function dataUpdate(req: Request, res: Response) { async function dataDelete(req: Request, res: Response) { const { model, view } = await getViewAndModelFromRequestByAliasOrId(req); const base = await Base.get(model.base_id); - const dbDriver = NcConnectionMgrv2.get(base); const baseModel = await Model.getBaseModelSQL({ id: model.id, viewId: view?.id, - dbDriver: dbDriver, + dbDriver: NcConnectionMgrv2.get(base), }); const message = await baseModel.hasLTARData(req.params.rowId, model); if (message.length) { From aa6b4177fd89b07cbc787f63047df57b16ab3f68 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 12:28:43 +0800 Subject: [PATCH 8/8] refactor: remove duplicate logic --- .../sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index f4d59d6025..416ffed12f 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1381,10 +1381,10 @@ class BaseModelSqlv2 { } async hasLTARData(rowId, model: Model): Promise { + const res = []; const LTARColumns = (await model.getColumns()).filter( (c) => c.uidt === UITypes.LinkToAnotherRecord ); - const res = []; let i = 0; for (const column of LTARColumns) { const colOptions = @@ -1395,32 +1395,28 @@ class BaseModelSqlv2 { await childModel.getColumns(); const parentModel = await parentColumn.getModel(); await parentModel.getColumns(); + let cnt = 0; if (colOptions.type === RelationTypes.HAS_MANY) { - const selectHmCount = await this.dbDriver(childModel.table_name) - .count(childColumn.column_name, { as: 'cnt' }) - .where(childColumn.column_name, rowId); - const cnt = (await selectHmCount)[0].cnt; - if (cnt) { - res.push( - `${i++ + 1}. ${model.title}.${ - column.title - } is a LinkToAnotherRecord of ${childModel.title}` - ); - } + cnt = +( + await this.dbDriver(childModel.table_name) + .count(childColumn.column_name, { as: 'cnt' }) + .where(childColumn.column_name, rowId) + )[0].cnt; } else if (colOptions.type === RelationTypes.MANY_TO_MANY) { const mmModel = await colOptions.getMMModel(); const mmChildColumn = await colOptions.getMMChildColumn(); - const selectMmCount = await this.dbDriver(mmModel.table_name) - .where(`${mmModel.table_name}.${mmChildColumn.column_name}`, rowId) - .count(mmChildColumn.column_name, { as: 'cnt' }); - const cnt = (await selectMmCount)[0].cnt; - if (cnt) { - res.push( - `${i++ + 1}. ${model.title}.${ - column.title - } is a LinkToAnotherRecord of ${parentModel.title}` - ); - } + cnt = +( + await this.dbDriver(mmModel.table_name) + .where(`${mmModel.table_name}.${mmChildColumn.column_name}`, rowId) + .count(mmChildColumn.column_name, { as: 'cnt' }) + )[0].cnt; + } + if (cnt) { + res.push( + `${i++ + 1}. ${model.title}.${ + column.title + } is a LinkToAnotherRecord of ${childModel.title}` + ); } } return res;