From 7ab120c38cc7268fe0d4efc8a8f132b0b9a079fc Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 8 Nov 2023 21:36:05 +0530 Subject: [PATCH] refactor: support nested insert in new insert api v2 - WIP --- packages/nocodb/src/db/BaseModelSqlv2.ts | 160 +++++++++++++---------- 1 file changed, 94 insertions(+), 66 deletions(-) diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index f0fd030ef0..8a919ee6ca 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -2524,75 +2524,15 @@ class BaseModelSqlv2 { ); let rowId = null; - const postInsertOps = []; const nestedCols = (await this.model.getColumns()).filter((c) => isLinksOrLTAR(c), ); - - for (const col of nestedCols) { - if (col.title in data) { - const colOptions = - await col.getColOptions(); - - // parse data if it's JSON string - let nestedData; - try { - nestedData = - typeof data[col.title] === 'string' - ? JSON.parse(data[col.title]) - : data[col.title]; - } catch { - continue; - } - switch (colOptions.type) { - case RelationTypes.BELONGS_TO: - { - const childCol = await colOptions.getChildColumn(); - const parentCol = await colOptions.getParentColumn(); - insertObj[childCol.column_name] = nestedData?.[parentCol.title]; - } - break; - case RelationTypes.HAS_MANY: - { - const childCol = await colOptions.getChildColumn(); - const childModel = await childCol.getModel(); - await childModel.getColumns(); - - postInsertOps.push(async () => { - await this.dbDriver(this.getTnPath(childModel.table_name)) - .update({ - [childCol.column_name]: rowId, - }) - .whereIn( - childModel.primaryKey.column_name, - nestedData?.map((r) => r[childModel.primaryKey.title]), - ); - }); - } - break; - case RelationTypes.MANY_TO_MANY: { - postInsertOps.push(async () => { - const parentModel = await colOptions - .getParentColumn() - .then((c) => c.getModel()); - await parentModel.getColumns(); - const parentMMCol = await colOptions.getMMParentColumn(); - const childMMCol = await colOptions.getMMChildColumn(); - const mmModel = await colOptions.getMMModel(); - - const rows = nestedData.map((r) => ({ - [parentMMCol.column_name]: r[parentModel.primaryKey.title], - [childMMCol.column_name]: rowId, - })); - await this.dbDriver(this.getTnPath(mmModel.table_name)).insert( - rows, - ); - }); - } - } - } - } + const postInsertOps = await this.prepareNestedLinkQb({ + nestedCols, + data, + insertObj, + }); await this.validate(insertObj); @@ -2649,7 +2589,7 @@ class BaseModelSqlv2 { : response?.[ai.title]; } - await Promise.all(postInsertOps.map((f) => f())); + await Promise.all(postInsertOps.map((f) => f(rowId))); response = await this.readByPk( rowId, @@ -2667,6 +2607,81 @@ class BaseModelSqlv2 { } } + private async prepareNestedLinkQb({ + nestedCols, + data, + insertObj, + }: { + nestedCols: Column[]; + data: Record; + insertObj: Record; + }) { + const postInsertOps: ((rowId: any) => Promise)[] = []; + for (const col of nestedCols) { + if (col.title in data) { + const colOptions = await col.getColOptions(); + + // parse data if it's JSON string + let nestedData; + try { + nestedData = + typeof data[col.title] === 'string' + ? JSON.parse(data[col.title]) + : data[col.title]; + } catch { + continue; + } + switch (colOptions.type) { + case RelationTypes.BELONGS_TO: + { + const childCol = await colOptions.getChildColumn(); + const parentCol = await colOptions.getParentColumn(); + insertObj[childCol.column_name] = nestedData?.[parentCol.title]; + } + break; + case RelationTypes.HAS_MANY: + { + const childCol = await colOptions.getChildColumn(); + const childModel = await childCol.getModel(); + await childModel.getColumns(); + + postInsertOps.push(async (rowId) => { + await this.dbDriver(this.getTnPath(childModel.table_name)) + .update({ + [childCol.column_name]: rowId, + }) + .whereIn( + childModel.primaryKey.column_name, + nestedData?.map((r) => r[childModel.primaryKey.title]), + ); + }); + } + break; + case RelationTypes.MANY_TO_MANY: { + postInsertOps.push(async (rowId) => { + const parentModel = await colOptions + .getParentColumn() + .then((c) => c.getModel()); + await parentModel.getColumns(); + const parentMMCol = await colOptions.getMMParentColumn(); + const childMMCol = await colOptions.getMMChildColumn(); + const mmModel = await colOptions.getMMModel(); + + const rows = nestedData.map((r) => ({ + [parentMMCol.column_name]: r[parentModel.primaryKey.title], + [childMMCol.column_name]: rowId, + })); + await this.dbDriver(this.getTnPath(mmModel.table_name)).insert( + rows, + ); + }); + } + } + } + } + return postInsertOps; + } + async bulkInsert( datas: any[], { @@ -2691,8 +2706,13 @@ class BaseModelSqlv2 { try { // TODO: ag column handling for raw bulk insert const insertDatas = raw ? datas : []; + const postInsertOps: ((rowId: any) => Promise)[][] = []; if (!raw) { + const nestedCols = (await this.model.getColumns()).filter((c) => + isLinksOrLTAR(c), + ); + await this.model.getColumns(); for (const d of datas) { @@ -2819,6 +2839,14 @@ class BaseModelSqlv2 { await this.prepareAttachmentData(insertObj); + postInsertOps.push( + await this.prepareNestedLinkQb({ + nestedCols, + d, + insertObj, + }), + ); + insertDatas.push(insertObj); } }