diff --git a/packages/nc-gui/composables/useExtensionHelper.ts b/packages/nc-gui/composables/useExtensionHelper.ts index 4e5355a12b..e3a85a1318 100644 --- a/packages/nc-gui/composables/useExtensionHelper.ts +++ b/packages/nc-gui/composables/useExtensionHelper.ts @@ -47,7 +47,7 @@ const [useProvideExtensionHelper, useExtensionHelper] = useInjectionState((exten }) => { const { tableId, viewId, eachPage, done } = params - let page = 0 + let page = 1 const nextPage = async () => { const { list: records, pageInfo } = await $api.dbViewRow.list( @@ -56,8 +56,8 @@ const [useProvideExtensionHelper, useExtensionHelper] = useInjectionState((exten tableId, viewId as string, { - offset: (page - 1) * 25, - limit: 25, + offset: (page - 1) * 100, + limit: 100, } as any, ) @@ -175,14 +175,14 @@ const [useProvideExtensionHelper, useExtensionHelper] = useInjectionState((exten if (insert.length) { insertCounter += insert.length - for (let i = 0; i < insert.length; i += chunkSize) { + while (insert.length) { await $api.dbDataTableRow.create(tableId, insert.splice(0, chunkSize)) } } if (update.length) { updateCounter += update.length - for (let i = 0; i < update.length; i += chunkSize) { + while (update.length) { await $api.dbDataTableRow.update(tableId, update.splice(0, chunkSize)) } } diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index 0c1f84f00f..c1d63f0b7c 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -4,6 +4,7 @@ import DataLoader from 'dataloader'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc.js'; import timezone from 'dayjs/plugin/timezone'; +import equal from 'fast-deep-equal'; import { nocoExecute } from 'nc-help'; import { AuditOperationSubTypes, @@ -260,11 +261,12 @@ class BaseModelSqlv2 { } = {}, validateFormula = false, ): Promise { + const columns = await this.model.getColumns(); const { where, ...rest } = this._getListArgs(args as any); const qb = this.dbDriver(this.tnPath); - await this.selectObject({ ...args, qb, validateFormula }); + await this.selectObject({ ...args, qb, validateFormula, columns }); - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const sorts = extractSortsObject(rest?.sort, aliasColObjMap); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); @@ -296,8 +298,7 @@ class BaseModelSqlv2 { try { data = await this.execAndParse(qb, null, { first: true }); } catch (e) { - if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) - throw e; + if (validateFormula || !haveFormulaColumn(columns)) throw e; logger.log(e); return this.findOne(args, true); } @@ -319,6 +320,7 @@ class BaseModelSqlv2 { sort?: string | string[]; fieldsSet?: Set; limitOverride?: number; + pks?: string; } = {}, options: { ignoreViewFilterAndSort?: boolean; @@ -336,6 +338,8 @@ class BaseModelSqlv2 { limitOverride, } = options; + const columns = await this.model.getColumns(); + const { where, fields, ...rest } = this._getListArgs(args as any); const qb = this.dbDriver(this.tnPath); @@ -345,12 +349,13 @@ class BaseModelSqlv2 { fieldsSet: args.fieldsSet, viewId: this.viewId, validateFormula, + columns, }); if (+rest?.shuffle) { await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); let sorts = extractSortsObject( rest?.sort, aliasColObjMap, @@ -453,8 +458,7 @@ class BaseModelSqlv2 { try { data = await this.execAndParse(qb); } catch (e) { - if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) - throw e; + if (validateFormula || !haveFormulaColumn(columns)) throw e; logger.log(e); return this.list(args, { ignoreViewFilterAndSort, @@ -474,13 +478,13 @@ class BaseModelSqlv2 { ignoreViewFilterAndSort = false, throwErrorIfInvalidParams = false, ): Promise { - await this.model.getColumns(); + const columns = await this.model.getColumns(); const { where } = this._getListArgs(args); const qb = this.dbDriver(this.tnPath); // qb.xwhere(where, await this.model.getAliasColMapping()); - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const filterObj = extractFilterFromXwhere( where, aliasColObjMap, @@ -562,6 +566,8 @@ class BaseModelSqlv2 { widgetFilterArr?: Filter[]; }, ) { + const columns = await this.model.getColumns(); + const { where, ...rest } = this._getListArgs(args as any); const qb = this.dbDriver(this.tnPath); @@ -579,7 +585,7 @@ class BaseModelSqlv2 { await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( @@ -621,7 +627,7 @@ class BaseModelSqlv2 { args.column_name = args.column_name || ''; - const cols = await this.model.getColumns(); + const columns = await this.model.getColumns(); const groupByColumns: Record = {}; const selectors = []; @@ -630,7 +636,9 @@ class BaseModelSqlv2 { await Promise.all( args.column_name.split(',').map(async (col) => { - let column = cols.find((c) => c.column_name === col || c.title === col); + let column = columns.find( + (c) => c.column_name === col || c.title === col, + ); if (!column) { throw NcError.fieldNotFound(col); } @@ -712,7 +720,7 @@ class BaseModelSqlv2 { break; default: { - const columnName = await getColumnName(column, cols); + const columnName = await getColumnName(column, columns); selectors.push( this.dbDriver.raw('?? as ??', [columnName, column.id]), ); @@ -735,7 +743,7 @@ class BaseModelSqlv2 { await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); let sorts = extractSortsObject(rest?.sort, aliasColObjMap); @@ -788,10 +796,7 @@ class BaseModelSqlv2 { column.uidt as UITypes, ) ) { - const columnName = await getColumnName( - column, - await this.model.getColumns(), - ); + const columnName = await getColumnName(column, columns); const baseUsers = await BaseUser.getUsersList({ base_id: column.base_id, @@ -843,112 +848,111 @@ class BaseModelSqlv2 { const groupBySelectors = []; const getAlias = getAliasGenerator('__nc_gb'); + const columns = await this.model.getColumns(); + // todo: refactor and avoid duplicate code - await this.model.getColumns().then((cols) => - Promise.all( - args.column_name.split(',').map(async (col) => { - let column = cols.find( - (c) => c.column_name === col || c.title === col, - ); - if (!column) { - throw NcError.fieldNotFound(col); - } + await Promise.all( + args.column_name.split(',').map(async (col) => { + let column = columns.find( + (c) => c.column_name === col || c.title === col, + ); + if (!column) { + throw NcError.fieldNotFound(col); + } - // if qrCode or Barcode replace it with value column nd keep the alias - if ([UITypes.QrCode, UITypes.Barcode].includes(column.uidt)) - column = new Column({ - ...(await column - .getColOptions() - .then((col) => col.getValueColumn())), - title: column.title, - id: column.id, - }); + // if qrCode or Barcode replace it with value column nd keep the alias + if ([UITypes.QrCode, UITypes.Barcode].includes(column.uidt)) + column = new Column({ + ...(await column + .getColOptions() + .then((col) => col.getValueColumn())), + title: column.title, + id: column.id, + }); - switch (column.uidt) { - case UITypes.Attachment: - NcError.badRequest( - 'Group by using attachment column is not supported', - ); - break; - case UITypes.Rollup: - case UITypes.Links: - selectors.push( - ( - await genRollupSelectv2({ - baseModelSqlv2: this, - // tn: this.title, - knex: this.dbDriver, - // column, - // alias, - columnOptions: - (await column.getColOptions()) as RollupColumn, - }) - ).builder.as(sanitize(column.id)), + switch (column.uidt) { + case UITypes.Attachment: + NcError.badRequest( + 'Group by using attachment column is not supported', + ); + break; + case UITypes.Rollup: + case UITypes.Links: + selectors.push( + ( + await genRollupSelectv2({ + baseModelSqlv2: this, + // tn: this.title, + knex: this.dbDriver, + // column, + // alias, + columnOptions: (await column.getColOptions()) as RollupColumn, + }) + ).builder.as(sanitize(column.id)), + ); + groupBySelectors.push(sanitize(column.id)); + break; + case UITypes.Formula: { + let selectQb; + try { + const _selectQb = await this.getSelectQueryBuilderForFormula( + column, ); - groupBySelectors.push(sanitize(column.id)); - break; - case UITypes.Formula: { - let selectQb; - try { - const _selectQb = await this.getSelectQueryBuilderForFormula( - column, - ); - - selectQb = this.dbDriver.raw(`?? as ??`, [ - _selectQb.builder, - sanitize(column.id), - ]); - } catch (e) { - logger.log(e); - // return dummy select - selectQb = this.dbDriver.raw(`'ERR' as ??`, [ - sanitize(column.id), - ]); - } - selectors.push(selectQb); - groupBySelectors.push(column.id); - break; + selectQb = this.dbDriver.raw(`?? as ??`, [ + _selectQb.builder, + sanitize(column.id), + ]); + } catch (e) { + logger.log(e); + // return dummy select + selectQb = this.dbDriver.raw(`'ERR' as ??`, [ + sanitize(column.id), + ]); } - case UITypes.Lookup: - case UITypes.LinkToAnotherRecord: - { - const _selectQb = await generateLookupSelectQuery({ - baseModelSqlv2: this, - column, - alias: null, - model: this.model, - getAlias, - }); - - const selectQb = this.dbDriver.raw(`?? as ??`, [ - this.dbDriver.raw(_selectQb.builder).wrap('(', ')'), - sanitize(column.id), - ]); - selectors.push(selectQb); - groupBySelectors.push(sanitize(column.id)); - } - break; - default: - { - const columnName = await getColumnName(column, cols); - selectors.push( - this.dbDriver.raw('?? as ??', [columnName, column.id]), - ); - groupBySelectors.push(sanitize(column.id)); - } - break; + selectors.push(selectQb); + groupBySelectors.push(column.id); + break; } - }), - ), + case UITypes.Lookup: + case UITypes.LinkToAnotherRecord: + { + const _selectQb = await generateLookupSelectQuery({ + baseModelSqlv2: this, + column, + alias: null, + model: this.model, + getAlias, + }); + + const selectQb = this.dbDriver.raw(`?? as ??`, [ + this.dbDriver.raw(_selectQb.builder).wrap('(', ')'), + sanitize(column.id), + ]); + + selectors.push(selectQb); + groupBySelectors.push(sanitize(column.id)); + } + break; + default: + { + const columnName = await getColumnName(column, columns); + selectors.push( + this.dbDriver.raw('?? as ??', [columnName, column.id]), + ); + groupBySelectors.push(sanitize(column.id)); + } + break; + } + }), ); const qb = this.dbDriver(this.tnPath); qb.count(`${this.model.primaryKey?.column_name || '*'} as count`); qb.select(...selectors); - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( @@ -2452,7 +2456,7 @@ class BaseModelSqlv2 { // const columns = _columns ?? (await this.model.getColumns()); // for (const column of columns) { viewOrTableColumns = - _columns || viewColumns || (await this.model.getColumns()); + viewColumns || _columns || (await this.model.getColumns()); } for (const viewOrTableColumn of viewOrTableColumns) { const column = @@ -2484,7 +2488,7 @@ class BaseModelSqlv2 { { const columnName = await getColumnName( column, - await this.model.getColumns(), + _columns || (await this.model.getColumns()), ); if (this.isMySQL) { // MySQL stores timestamp in UTC but display in timezone @@ -2651,7 +2655,7 @@ class BaseModelSqlv2 { case UITypes.LastModifiedBy: { const columnName = await getColumnName( column, - await this.model.getColumns(), + _columns || (await this.model.getColumns()), ); res[sanitize(column.id || columnName)] = sanitize( @@ -2705,9 +2709,10 @@ class BaseModelSqlv2 { data, this.clientMeta, this.dbDriver, + columns, ); - await this.validate(insertObj); + await this.validate(insertObj, columns); if ('beforeInsert' in this) { await this.beforeInsert(insertObj, trx, cookie); @@ -2952,13 +2957,16 @@ class BaseModelSqlv2 { async updateByPk(id, data, trx?, cookie?, _disableOptimization = false) { try { + const columns = await this.model.getColumns(); + const updateObj = await this.model.mapAliasToColumn( data, this.clientMeta, this.dbDriver, + columns, ); - await this.validate(data); + await this.validate(data, columns); await this.beforeUpdate(data, trx, cookie); @@ -2973,7 +2981,7 @@ class BaseModelSqlv2 { const query = this.dbDriver(this.tnPath) .update(updateObj) - .where(await this._wherePk(id)); + .where(await this._wherePk(id, true)); await this.execAndParse(query, null, { raw: true }); @@ -2995,11 +3003,15 @@ class BaseModelSqlv2 { } } - async _wherePk(id) { - await this.model.getColumns(); + async _wherePk(id, skipGetColumns = false) { + if (!skipGetColumns) await this.model.getColumns(); return _wherePk(this.model.primaryKeys, id); } + comparePks(pk1, pk2) { + return equal(pk1, pk2); + } + public getTnPath(tb: { table_name: string } | string, alias?: string) { const tn = typeof tb === 'string' ? tb : tb.table_name; const schema = (this.dbDriver as any).searchPath?.(); @@ -3088,23 +3100,25 @@ class BaseModelSqlv2 { try { const source = await Source.get(this.model.source_id); await populatePk(this.model, data); + + const columns = await this.model.getColumns(); + const insertObj = await this.model.mapAliasToColumn( data, this.clientMeta, this.dbDriver, + columns, ); let rowId = null; - const nestedCols = (await this.model.getColumns()).filter((c) => - isLinksOrLTAR(c), - ); + const nestedCols = columns.filter((c) => isLinksOrLTAR(c)); const { postInsertOps, preInsertOps } = await this.prepareNestedLinkQb({ nestedCols, data, insertObj, }); - await this.validate(insertObj); + await this.validate(insertObj, columns); await this.beforeInsert(insertObj, this.dbDriver, cookie); @@ -3402,11 +3416,9 @@ class BaseModelSqlv2 { let agPkCol: Column; if (!raw) { - const nestedCols = (await this.model.getColumns()).filter((c) => - isLinksOrLTAR(c), - ); + const columns = await this.model.getColumns(); - await this.model.getColumns(); + const nestedCols = columns.filter((c) => isLinksOrLTAR(c)); for (const d of datas) { const insertObj = {}; @@ -3687,12 +3699,12 @@ class BaseModelSqlv2 { ) { let transaction; try { - if (raw) await this.model.getColumns(); + const columns = await this.model.getColumns(); // validate update data if (!raw) { for (const d of datas) { - await this.validate(d); + await this.validate(d, columns); } } @@ -3700,7 +3712,12 @@ class BaseModelSqlv2 { ? datas : await Promise.all( datas.map((d) => - this.model.mapAliasToColumn(d, this.clientMeta, this.dbDriver), + this.model.mapAliasToColumn( + d, + this.clientMeta, + this.dbDriver, + columns, + ), ), ); @@ -3708,8 +3725,10 @@ class BaseModelSqlv2 { const newData = []; const updatePkValues = []; const toBeUpdated = []; - for (const d of updateDatas) { - const pkValues = await this._extractPksValues(d); + const pkAndData: { pk: any; data: any }[] = []; + const readChunkSize = 100; + for (const [i, d] of updateDatas.entries()) { + const pkValues = this._extractPksValues(d); if (!pkValues) { // throw or skip if no pk provided if (throwExceptionIfNotExist) { @@ -3720,19 +3739,58 @@ class BaseModelSqlv2 { if (!raw) { await this.prepareNocoData(d, false, cookie); - const oldRecord = await this.readByPk(pkValues); - if (!oldRecord) { - // throw or skip if no record found - if (throwExceptionIfNotExist) { - NcError.recordNotFound(JSON.stringify(pkValues)); + pkAndData.push({ + pk: pkValues, + data: d, + }); + + if ( + pkAndData.length >= readChunkSize || + i === updateDatas.length - 1 + ) { + const tempToRead = pkAndData.splice(0, pkAndData.length); + const oldRecords = await this.list( + { + pks: tempToRead.map((v) => v.pk).join(','), + }, + { + limitOverride: tempToRead.length, + }, + ); + + if (oldRecords.length === tempToRead.length) { + prevData.push(...oldRecords); + } else { + for (const recordPk of tempToRead) { + const oldRecord = oldRecords.find((r) => + this.comparePks(this._extractPksValues(r), recordPk), + ); + + if (!oldRecord) { + // throw or skip if no record found + if (throwExceptionIfNotExist) { + NcError.recordNotFound(JSON.stringify(recordPk)); + } + continue; + } + + prevData.push(oldRecord); + } + } + + for (const { pk, data } of tempToRead) { + const wherePk = await this._wherePk(pk, true); + toBeUpdated.push({ d: data, wherePk }); + updatePkValues.push(pk); } - continue; } - prevData.push(oldRecord); + } else { + const wherePk = await this._wherePk(pkValues, true); + + toBeUpdated.push({ d, wherePk }); + + updatePkValues.push(pkValues); } - const wherePk = await this._wherePk(pkValues); - toBeUpdated.push({ d, wherePk }); - updatePkValues.push(pkValues); } transaction = await this.dbDriver.transaction(); @@ -3744,9 +3802,17 @@ class BaseModelSqlv2 { await transaction.commit(); if (!raw) { - for (const pkValues of updatePkValues) { - const updatedRecord = await this.readByPk(pkValues); - newData.push(updatedRecord); + while (updatePkValues.length) { + const updatedRecords = await this.list( + { + pks: updatePkValues.splice(0, readChunkSize).join(','), + }, + { + limitOverride: readChunkSize, + }, + ); + + newData.push(...updatedRecords); } } @@ -3783,23 +3849,27 @@ class BaseModelSqlv2 { ) { try { let count = 0; + + const columns = await this.model.getColumns(); + const updateData = await this.model.mapAliasToColumn( data, this.clientMeta, this.dbDriver, + columns, ); - if (!args.skipValidationAndHooks) await this.validate(updateData); + if (!args.skipValidationAndHooks) + await this.validate(updateData, columns); await this.prepareNocoData(updateData, false, cookie); - const pkValues = await this._extractPksValues(updateData); + const pkValues = this._extractPksValues(updateData); if (pkValues) { // pk is specified - by pass } else { - await this.model.getColumns(); const { where } = this._getListArgs(args); const qb = this.dbDriver(this.tnPath); - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const filterObj = extractFilterFromXwhere(where, aliasColObjMap, true); const conditionObj = [ @@ -3864,18 +3934,27 @@ class BaseModelSqlv2 { isSingleRecordDeletion?: boolean; } = {}, ) { + const columns = await this.model.getColumns(); + let transaction; try { const deleteIds = await Promise.all( ids.map((d) => - this.model.mapAliasToColumn(d, this.clientMeta, this.dbDriver), + this.model.mapAliasToColumn( + d, + this.clientMeta, + this.dbDriver, + columns, + ), ), ); const deleted = []; const res = []; - for (const d of deleteIds) { - const pkValues = await this._extractPksValues(d); + const pkAndData: { pk: any; data: any }[] = []; + const readChunkSize = 100; + for (const [i, d] of deleteIds.entries()) { + const pkValues = this._extractPksValues(d); if (!pkValues) { // throw or skip if no pk provided if (throwExceptionIfNotExist) { @@ -3884,17 +3963,41 @@ class BaseModelSqlv2 { continue; } - const deletedRecord = await this.readByPk(pkValues); - if (!deletedRecord) { - // throw or skip if no record found - if (throwExceptionIfNotExist) { - NcError.recordNotFound(JSON.stringify(pkValues)); + pkAndData.push({ pk: pkValues, data: d }); + + if (pkAndData.length >= readChunkSize || i === deleteIds.length - 1) { + const tempToRead = pkAndData.splice(0, pkAndData.length); + const oldRecords = await this.list( + { + pks: tempToRead.map((v) => v.pk).join(','), + }, + { + limitOverride: tempToRead.length, + }, + ); + + if (oldRecords.length === tempToRead.length) { + deleted.push(...oldRecords); + res.push(...tempToRead.map((v) => v.data)); + } else { + for (const { pk, data } of tempToRead) { + const oldRecord = oldRecords.find((r) => + this.comparePks(this._extractPksValues(r), pk), + ); + + if (!oldRecord) { + // throw or skip if no record found + if (throwExceptionIfNotExist) { + NcError.recordNotFound(JSON.stringify(pk)); + } + continue; + } + + deleted.push(oldRecord); + res.push(data); + } } - continue; } - deleted.push(deletedRecord); - - res.push(d); } const execQueries: (( @@ -3989,10 +4092,10 @@ class BaseModelSqlv2 { ) { let trx: Knex.Transaction; try { - await this.model.getColumns(); + const columns = await this.model.getColumns(); const { where } = this._getListArgs(args); const qb = this.dbDriver(this.tnPath); - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const filterObj = extractFilterFromXwhere(where, aliasColObjMap, true); await conditionV2( @@ -4336,10 +4439,13 @@ class BaseModelSqlv2 { protected async errorDelete(_e, _id, _trx, _cookie) {} - async validate(data: Record): Promise { - await this.model.getColumns(); + async validate( + data: Record, + columns?: Column[], + ): Promise { + const cols = columns || (await this.model.getColumns()); // let cols = Object.keys(this.columns); - for (let i = 0; i < this.model.columns.length; ++i) { + for (let i = 0; i < cols.length; ++i) { const column = this.model.columns[i]; if ( @@ -4836,9 +4942,8 @@ class BaseModelSqlv2 { > { try { const { where, ...rest } = this._getListArgs(args as any); - const column = await this.model - .getColumns() - .then((cols) => cols?.find((col) => col.id === args.groupColumnId)); + const columns = await this.model.getColumns(); + const column = columns?.find((col) => col.id === args.groupColumnId); if (!column) NcError.fieldNotFound(args.groupColumnId); if (isVirtualCol(column)) @@ -4876,7 +4981,7 @@ class BaseModelSqlv2 { await this.selectObject({ qb, extractPkAndPv: true }); // todo: refactor and move to a method (applyFilterAndSort) - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); let sorts = extractSortsObject(args?.sort, aliasColObjMap); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); // todo: replace with view id @@ -4998,9 +5103,8 @@ class BaseModelSqlv2 { ignoreViewFilterAndSort?: boolean; } & XcFilter, ) { - const column = await this.model - .getColumns() - .then((cols) => cols?.find((col) => col.id === args.groupColumnId)); + const columns = await this.model.getColumns(); + const column = columns?.find((col) => col.id === args.groupColumnId); if (!column) NcError.fieldNotFound(args.groupColumnId); if (isVirtualCol(column)) @@ -5011,7 +5115,7 @@ class BaseModelSqlv2 { .groupBy(column.column_name); // todo: refactor and move to a common method (applyFilterAndSort) - const aliasColObjMap = await this.model.getAliasColObjMap(); + const aliasColObjMap = await this.model.getAliasColObjMap(columns); const filterObj = extractFilterFromXwhere(args.where, aliasColObjMap); // todo: replace with view id @@ -6192,12 +6296,12 @@ class BaseModelSqlv2 { args: { limit?; offset?; fieldSet?: Set } = {}, ) { try { + const columns = await this.model.getColumns(); + const { where, sort } = this._getListArgs(args as any); // todo: get only required fields - const relColumn = (await this.model.getColumns()).find( - (c) => c.id === colId, - ); + const relColumn = columns.find((c) => c.id === colId); const row = await this.execAndParse( this.dbDriver(this.tnPath).where(await this._wherePk(id)), diff --git a/packages/nocodb/src/models/Model.ts b/packages/nocodb/src/models/Model.ts index 5c696fea3a..1148dbe6f5 100644 --- a/packages/nocodb/src/models/Model.ts +++ b/packages/nocodb/src/models/Model.ts @@ -538,9 +538,10 @@ export default class Model implements TableType { isPg: false, }, knex, + columns?: Column[], ) { const insertObj = {}; - for (const col of await this.getColumns()) { + for (const col of columns || (await this.getColumns())) { if (isVirtualCol(col)) continue; let val = data?.[col.column_name] !== undefined @@ -618,9 +619,9 @@ export default class Model implements TableType { return insertObj; } - async mapColumnToAlias(data) { + async mapColumnToAlias(data, columns?: Column[]) { const res = {}; - for (const col of await this.getColumns()) { + for (const col of columns || (await this.getColumns())) { if (isVirtualCol(col)) continue; let val = data?.[col.title] !== undefined @@ -969,8 +970,8 @@ export default class Model implements TableType { )); } - async getAliasColObjMap() { - return (await this.getColumns()).reduce( + async getAliasColObjMap(columns?: Column[]) { + return (columns || (await this.getColumns())).reduce( (sortAgg, c) => ({ ...sortAgg, [c.title]: c }), {}, );