From 84487c508769b518e57f0cafbd274d13f304dfea Mon Sep 17 00:00:00 2001 From: Pranav C Date: Mon, 6 Nov 2023 13:11:52 +0530 Subject: [PATCH] fix: avoid caching at the data-loader since it may leads to invalid data - in our case we are using it just for making the data processing as batch --- packages/nocodb/src/db/BaseModelSqlv2.ts | 213 +++++++++++++---------- 1 file changed, 121 insertions(+), 92 deletions(-) diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index 79e677b876..21c2604722 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -1711,28 +1711,35 @@ class BaseModelSqlv2 { (await column.getColOptions()) as LinkToAnotherRecordColumn; if (colOptions?.type === 'hm') { - const listLoader = new DataLoader(async (ids: string[]) => { - if (ids.length > 1) { - const data = await this.multipleHmList( - { - colId: column.id, - ids, - }, - (listLoader as any).args, - ); - return ids.map((id: string) => (data[id] ? data[id] : [])); - } else { - return [ - await this.hmList( + const listLoader = new DataLoader( + async (ids: string[]) => { + if (ids.length > 1) { + const data = await this.multipleHmList( { colId: column.id, - id: ids[0], + ids, }, (listLoader as any).args, - ), - ]; - } - }); + ); + return ids.map((id: string) => + data[id] ? data[id] : [], + ); + } else { + return [ + await this.hmList( + { + colId: column.id, + id: ids[0], + }, + (listLoader as any).args, + ), + ]; + } + }, + { + cache: false, + }, + ); const self: BaseModelSqlv2 = this; proto[ @@ -1746,29 +1753,34 @@ class BaseModelSqlv2 { ); }; } else if (colOptions.type === 'mm') { - const listLoader = new DataLoader(async (ids: string[]) => { - if (ids?.length > 1) { - const data = await this.multipleMmList( - { - parentIds: ids, - colId: column.id, - }, - (listLoader as any).args, - ); - - return data; - } else { - return [ - await this.mmList( + const listLoader = new DataLoader( + async (ids: string[]) => { + if (ids?.length > 1) { + const data = await this.multipleMmList( { - parentId: ids[0], + parentIds: ids, colId: column.id, }, (listLoader as any).args, - ), - ]; - } - }); + ); + + return data; + } else { + return [ + await this.mmList( + { + parentId: ids[0], + colId: column.id, + }, + (listLoader as any).args, + ), + ]; + } + }, + { + cache: false, + }, + ); const self: BaseModelSqlv2 = this; proto[ @@ -1796,55 +1808,62 @@ class BaseModelSqlv2 { // it takes individual keys and callback is invoked with an array of values and we can get the // result for all those together and return the value in the same order as in the array // this way all parents data extracted together - const readLoader = new DataLoader(async (_ids: string[]) => { - // handle binary(16) foreign keys - const ids = _ids.map((id) => { - if (pCol.ct !== 'binary(16)') return id; - - // Cast the id to string. - const idAsString = id + ''; - // Check if the id is a UUID and the column is binary(16) - const isUUIDBinary16 = - idAsString.length === 36 || idAsString.length === 32; - // If the id is a UUID and the column is binary(16), convert the id to a Buffer. Otherwise, return null to indicate that the id is not a UUID. - const idAsUUID = isUUIDBinary16 - ? idAsString.length === 32 - ? idAsString.replace( - /(.{8})(.{4})(.{4})(.{4})(.{12})/, - '$1-$2-$3-$4-$5', - ) - : idAsString - : null; - - return idAsUUID - ? Buffer.from(idAsUUID.replace(/-/g, ''), 'hex') - : id; - }); - - const data = await ( - await Model.getBaseModelSQL({ - id: pCol.fk_model_id, - dbDriver: this.dbDriver, - }) - ).list( - { - fieldsSet: (readLoader as any).args?.fieldsSet, - filterArr: [ - new Filter({ - id: null, - fk_column_id: pCol.id, - fk_model_id: pCol.fk_model_id, - value: ids as any[], - comparison_op: 'in', - }), - ], - }, - true, - ); + const readLoader = new DataLoader( + async (_ids: string[]) => { + // handle binary(16) foreign keys + const ids = _ids.map((id) => { + if (pCol.ct !== 'binary(16)') return id; + + // Cast the id to string. + const idAsString = id + ''; + // Check if the id is a UUID and the column is binary(16) + const isUUIDBinary16 = + idAsString.length === 36 || idAsString.length === 32; + // If the id is a UUID and the column is binary(16), convert the id to a Buffer. Otherwise, return null to indicate that the id is not a UUID. + const idAsUUID = isUUIDBinary16 + ? idAsString.length === 32 + ? idAsString.replace( + /(.{8})(.{4})(.{4})(.{4})(.{12})/, + '$1-$2-$3-$4-$5', + ) + : idAsString + : null; + + return idAsUUID + ? Buffer.from(idAsUUID.replace(/-/g, ''), 'hex') + : id; + }); + + const data = await ( + await Model.getBaseModelSQL({ + id: pCol.fk_model_id, + dbDriver: this.dbDriver, + }) + ).list( + { + fieldsSet: (readLoader as any).args?.fieldsSet, + filterArr: [ + new Filter({ + id: null, + fk_column_id: pCol.id, + fk_model_id: pCol.fk_model_id, + value: ids as any[], + comparison_op: 'in', + }), + ], + }, + true, + ); - const groupedList = groupBy(data, pCol.title); - return _ids.map(async (id: string) => groupedList?.[id]?.[0]); - }); + const groupedList = groupBy(data, pCol.title); + return _ids.map( + async (id: string) => groupedList?.[id]?.[0], + ); + }, + { + cache: false, + }, + ); // defining BelongsTo read resolver method proto[column.title] = async function (args?: any) { @@ -4332,7 +4351,7 @@ class BaseModelSqlv2 { } async addLinks({ - cookie: _cookie, + cookie, childIds, colId, rowId, @@ -4348,9 +4367,12 @@ class BaseModelSqlv2 { if (!column || !isLinksOrLTAR(column)) NcError.notFound(`Link column ${colId} not found`); - const row = await this.dbDriver(this.tnPath) - .where(await this._wherePk(rowId)) - .first(); + const row = await this.readByPk( + rowId, + false, + {}, + { ignoreView: true, getHiddenColumn: true }, + ); // validate rowId if (!row) { @@ -4554,9 +4576,16 @@ class BaseModelSqlv2 { break; } - // const response = await this.readByPk(rowId); - // await this.afterInsert(response, this.dbDriver, cookie); - // await this.afterAddChild(rowId, childId, cookie); + const response = await this.readByPk( + rowId, + false, + {}, + { ignoreView: true, getHiddenColumn: true }, + ); + await this.afterUpdate(row, response, this.dbDriver, cookie); + for (const childId of childIds) { + await this.afterAddChild(rowId, childId, cookie); + } } async removeLinks({