Browse Source

fix(nocodb): bt cell copy paste row audit udpate

pull/8901/head
Ramesh Mane 5 months ago
parent
commit
3db9dbc367
  1. 432
      packages/nocodb/src/db/BaseModelSqlv2.ts

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

@ -3703,6 +3703,18 @@ class BaseModelSqlv2 {
await this.prepareNocoData(updateObj, false, cookie); await this.prepareNocoData(updateObj, false, cookie);
const btForeignKeyColumn = columns
.filter((c) => c.uidt === UITypes.ForeignKey)
.find((c) => data[c.column_name] !== undefined);
const btColumn = btForeignKeyColumn
? columns.find(
(c) =>
c.uidt === UITypes.LinkToAnotherRecord &&
c.colOptions?.fk_child_column_id === btForeignKeyColumn.id,
)
: null;
const prevData = await this.readByPk( const prevData = await this.readByPk(
id, id,
false, false,
@ -3730,7 +3742,19 @@ class BaseModelSqlv2 {
{}, {},
{ ignoreView: true, getHiddenColumn: true }, { ignoreView: true, getHiddenColumn: true },
); );
await this.afterUpdate(prevData, newData, trx, cookie, updateObj);
if (btColumn && Object.keys(data || {}).length === 1) {
await this.addChild({
colId: btColumn.id,
rowId: id,
childId: updateObj[btForeignKeyColumn.title],
cookie,
onlyUpdateAuditLogs: true,
prevData,
});
} else {
await this.afterUpdate(prevData, newData, trx, cookie, updateObj);
}
return newData; return newData;
} catch (e) { } catch (e) {
await this.errorUpdate(e, data, trx, cookie); await this.errorUpdate(e, data, trx, cookie);
@ -5386,11 +5410,15 @@ class BaseModelSqlv2 {
rowId, rowId,
childId, childId,
cookie, cookie,
onlyUpdateAuditLogs,
prevData,
}: { }: {
colId: string; colId: string;
rowId: string; rowId: string;
childId: string; childId: string;
cookie?: any; cookie?: any;
onlyUpdateAuditLogs?: boolean;
prevData?: Record<string, any>;
}) { }) {
const columns = await this.model.getColumns(this.context); const columns = await this.model.getColumns(this.context);
const column = columns.find((c) => c.id === colId); const column = columns.find((c) => c.id === colId);
@ -5405,6 +5433,11 @@ class BaseModelSqlv2 {
this.context, this.context,
); );
// return if onlyUpdateAuditLogs is true and is not bt column
if (onlyUpdateAuditLogs && colOptions.type !== RelationTypes.BELONGS_TO) {
return;
}
const childColumn = await colOptions.getChildColumn(this.context); const childColumn = await colOptions.getChildColumn(this.context);
const parentColumn = await colOptions.getParentColumn(this.context); const parentColumn = await colOptions.getParentColumn(this.context);
const parentTable = await parentColumn.getModel(this.context); const parentTable = await parentColumn.getModel(this.context);
@ -5513,8 +5546,11 @@ class BaseModelSqlv2 {
.where(_wherePk(childTable.primaryKeys, childId)) .where(_wherePk(childTable.primaryKeys, childId))
.first(); .first();
const oldRowID = Object.values(linkedHmRowObj)?.[0]; const oldRowId = linkedHmRowObj
if (oldRowID) { ? Object.values(linkedHmRowObj)?.[0]
: null;
if (oldRowId) {
const [parentRelatedPkValue, childRelatedPkValue] = const [parentRelatedPkValue, childRelatedPkValue] =
await Promise.all([ await Promise.all([
await this.dbDriver(childTn) await this.dbDriver(childTn)
@ -5523,14 +5559,14 @@ class BaseModelSqlv2 {
.first(), .first(),
await this.dbDriver(parentTn) await this.dbDriver(parentTn)
.select(parentTable.displayValue.title) .select(parentTable.displayValue.title)
.where(_wherePk(parentTable.primaryKeys, oldRowID)) .where(_wherePk(parentTable.primaryKeys, oldRowId))
.first(), .first(),
]); ]);
auditUpdateObj.push({ auditUpdateObj.push({
model: auditConfig.parentModel, model: auditConfig.parentModel,
childModel: auditConfig.childModel, childModel: auditConfig.childModel,
rowId: oldRowID as string, rowId: oldRowId as string,
childId, childId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD, op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.parentColTitle, columnTitle: auditConfig.parentColTitle,
@ -5542,7 +5578,7 @@ class BaseModelSqlv2 {
model: auditConfig.childModel, model: auditConfig.childModel,
childModel: auditConfig.parentModel, childModel: auditConfig.parentModel,
rowId: childId, rowId: childId,
childId: oldRowID as string, childId: oldRowId as string,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD, op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle, columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue, pkValue: childRelatedPkValue,
@ -5575,78 +5611,332 @@ class BaseModelSqlv2 {
break; break;
case RelationTypes.BELONGS_TO: case RelationTypes.BELONGS_TO:
{ {
const linkedHmRowObj = await this.dbDriver(childTn) auditConfig.parentModel = childTable;
.select(childColumn.column_name) auditConfig.childModel = parentTable;
.where(_wherePk(childTable.primaryKeys, rowId))
.first();
const oldRowID = Object.values(linkedHmRowObj)?.[0]; if (onlyUpdateAuditLogs) {
const oldChildRowId = prevData[column.title]
? getCompositePkValue(
parentTable.primaryKeys,
this._extractPksValues(prevData[column.title]),
)
: null;
if (oldRowID) { if (oldChildRowId) {
const [parentRelatedPkValue, childRelatedPkValue] = auditUpdateObj.push({
await Promise.all([ model: auditConfig.parentModel,
await this.dbDriver(childTn) childModel: auditConfig.childModel,
.select(childTable.displayValue.title) rowId,
.where(_wherePk(childTable.primaryKeys, rowId)) childId: oldChildRowId as string,
.first(), op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
await this.dbDriver(parentTn) columnTitle: auditConfig.parentColTitle,
.select(parentTable.displayValue.title) pkValue: {
.where(_wherePk(parentTable.primaryKeys, oldRowID)) [parentTable.displayValue.title]:
.first(), prevData[column.title]?.[parentTable.displayValue.title] ??
]); null,
},
});
auditUpdateObj.push({ const childRelatedPkValue = await this.dbDriver(childTn)
model: auditConfig.parentModel, .select(childTable.displayValue.title)
childModel: auditConfig.childModel, .where(_wherePk(childTable.primaryKeys, rowId))
rowId: oldRowID as string, .first();
childId: rowId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD, if (parentTable.id !== childTable.id) {
columnTitle: auditConfig.parentColTitle, auditUpdateObj.push({
pkValue: parentRelatedPkValue, model: auditConfig.childModel,
}); childModel: auditConfig.parentModel,
rowId: oldChildRowId as string,
childId: rowId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue,
});
}
}
} else {
const linkedHmRowObj = await this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, rowId))
.first();
const oldChildRowId = linkedHmRowObj
? Object.values(linkedHmRowObj)?.[0]
: null;
if (oldChildRowId) {
const [parentRelatedPkValue, childRelatedPkValue] =
await Promise.all([
await this.dbDriver(parentTn)
.select(parentTable.displayValue.title)
.where(_wherePk(parentTable.primaryKeys, oldChildRowId))
.first(),
await this.dbDriver(childTn)
.select(childTable.displayValue.title)
.where(_wherePk(childTable.primaryKeys, rowId))
.first(),
]);
if (parentTable.id !== childTable.id) {
auditUpdateObj.push({ auditUpdateObj.push({
model: auditConfig.childModel, model: auditConfig.parentModel,
childModel: auditConfig.parentModel, childModel: auditConfig.childModel,
rowId: rowId, rowId,
childId: oldRowID as string, childId: oldChildRowId as string,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD, op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle, columnTitle: auditConfig.parentColTitle,
pkValue: childRelatedPkValue, pkValue: parentRelatedPkValue,
}); });
if (parentTable.id !== childTable.id) {
auditUpdateObj.push({
model: auditConfig.childModel,
childModel: auditConfig.parentModel,
rowId: oldChildRowId as string,
childId: rowId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue,
});
}
} }
await this.execAndParse(
this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, rowId)),
null,
{ raw: true },
);
await this.updateLastModified({
model: parentTable,
rowIds: [childId],
cookie,
});
} }
}
break;
case RelationTypes.ONE_TO_ONE:
{
const isBt = column.meta?.bt;
auditConfig.parentModel = isBt ? childTable : parentTable;
auditConfig.childModel = isBt ? parentTable : childTable;
await this.execAndParse( let linkedOoRowObj;
this.dbDriver(childTn) let linkedCurrentOoRowObj;
.update({ if (isBt) {
// 1. check current row is linked with another child
linkedCurrentOoRowObj = await this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, rowId))
.first();
const oldChildRowId = linkedCurrentOoRowObj
? Object.values(linkedCurrentOoRowObj)?.[0]
: null;
if (oldChildRowId) {
const [parentRelatedPkValue, childRelatedPkValue] =
await Promise.all([
await this.dbDriver(childTn)
.select(childTable.displayValue.title)
.where(_wherePk(childTable.primaryKeys, rowId))
.first(),
await this.dbDriver(parentTn)
.select(parentTable.displayValue.title)
.where(_wherePk(parentTable.primaryKeys, oldChildRowId))
.first(),
]);
auditUpdateObj.push({
model: auditConfig.parentModel,
childModel: auditConfig.childModel,
rowId,
childId: oldChildRowId as string,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.parentColTitle,
pkValue: parentRelatedPkValue,
});
if (parentTable.id !== childTable.id) {
auditUpdateObj.push({
model: auditConfig.childModel,
childModel: auditConfig.parentModel,
rowId: oldChildRowId as string,
childId: rowId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue,
});
}
}
// 2. check current child is linked with another row cell
linkedOoRowObj = await this.dbDriver(childTn)
.where({
[childColumn.column_name]: this.dbDriver.from( [childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn) this.dbDriver(parentTn)
.select(parentColumn.column_name) .select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId)) .where(
_wherePk(parentTable.primaryKeys, isBt ? childId : rowId),
)
.first() .first()
.as('___cn_alias'), .as('___cn_alias'),
), ),
}) })
.where(_wherePk(childTable.primaryKeys, rowId)), .first();
null,
{ raw: true },
);
await this.updateLastModified({ if (linkedOoRowObj) {
model: parentTable, const oldRowId = getCompositePkValue(
rowIds: [childId], childTable.primaryKeys,
cookie, this._extractPksValues(linkedOoRowObj),
}); );
auditConfig.parentModel = childTable; if (oldRowId) {
auditConfig.childModel = parentTable; const [parentRelatedPkValue, childRelatedPkValue] =
} await Promise.all([
break; await this.dbDriver(parentTn)
case RelationTypes.ONE_TO_ONE: .select(parentTable.displayValue.title)
{ .where(_wherePk(parentTable.primaryKeys, childId))
const isBt = column.meta?.bt; .first(),
await this.dbDriver(childTn)
.select(childTable.displayValue.title)
.where(_wherePk(childTable.primaryKeys, oldRowId))
.first(),
]);
auditUpdateObj.push({
model: auditConfig.parentModel,
childModel: auditConfig.childModel,
rowId: oldRowId as string,
childId: childId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.parentColTitle,
pkValue: parentRelatedPkValue,
});
if (parentTable.id !== childTable.id) {
auditUpdateObj.push({
model: auditConfig.childModel,
childModel: auditConfig.parentModel,
rowId: childId,
childId: oldRowId as string,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue,
});
}
}
}
} else {
// 1. check current row is linked with another child
linkedCurrentOoRowObj = await this.dbDriver(childTn)
.where({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, rowId))
.first()
.as('___cn_alias'),
),
})
.first();
if (linkedCurrentOoRowObj) {
const oldChildRowId = getCompositePkValue(
childTable.primaryKeys,
this._extractPksValues(linkedCurrentOoRowObj),
);
if (oldChildRowId) {
const [parentRelatedPkValue, childRelatedPkValue] =
await Promise.all([
await this.dbDriver(childTn)
.select(childTable.displayValue.title)
.where(_wherePk(childTable.primaryKeys, oldChildRowId))
.first(),
await this.dbDriver(parentTn)
.select(parentTable.displayValue.title)
.where(_wherePk(parentTable.primaryKeys, rowId))
.first(),
]);
auditUpdateObj.push({
model: auditConfig.parentModel,
childModel: auditConfig.childModel,
rowId,
childId: oldChildRowId as string,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.parentColTitle,
pkValue: parentRelatedPkValue,
});
if (parentTable.id !== childTable.id) {
auditUpdateObj.push({
model: auditConfig.childModel,
childModel: auditConfig.parentModel,
rowId: oldChildRowId as string,
childId: rowId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue,
});
}
}
}
// 2. check current child is linked with another row cell
linkedOoRowObj = await this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, childId))
.first();
const oldRowId = linkedOoRowObj
? Object.values(linkedOoRowObj)?.[0]
: null;
if (oldRowId) {
const [parentRelatedPkValue, childRelatedPkValue] =
await Promise.all([
await this.dbDriver(childTn)
.select(childTable.displayValue.title)
.where(_wherePk(childTable.primaryKeys, childId))
.first(),
await this.dbDriver(parentTn)
.select(parentTable.displayValue.title)
.where(_wherePk(parentTable.primaryKeys, oldRowId))
.first(),
]);
auditUpdateObj.push({
model: auditConfig.parentModel,
childModel: auditConfig.childModel,
rowId: oldRowId as string,
childId: childId,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.parentColTitle,
pkValue: parentRelatedPkValue,
});
if (parentTable.id !== childTable.id) {
auditUpdateObj.push({
model: auditConfig.childModel,
childModel: auditConfig.parentModel,
rowId: childId,
childId: oldRowId as string,
op_sub_type: AuditOperationSubTypes.UNLINK_RECORD,
columnTitle: auditConfig.childColTitle,
pkValue: childRelatedPkValue,
});
}
}
}
// todo: unlink if it's already mapped // todo: unlink if it's already mapped
// unlink already mapped record if any // unlink already mapped record if any
@ -5691,9 +5981,6 @@ class BaseModelSqlv2 {
rowIds: [childId], rowIds: [childId],
cookie, cookie,
}); });
auditConfig.parentModel = isBt ? childTable : parentTable;
auditConfig.childModel = isBt ? parentTable : childTable;
} }
break; break;
} }
@ -5719,9 +6006,10 @@ class BaseModelSqlv2 {
} }
await Promise.allSettled( await Promise.allSettled(
auditUpdateObj.map(async (updateObj) => { auditUpdateObj
if (updateObj.op_sub_type === AuditOperationSubTypes.LINK_RECORD) { .filter((a) => a.op_sub_type === AuditOperationSubTypes.UNLINK_RECORD)
await this.afterAddChild( .map((updateObj) => {
this.afterRemoveChild(
updateObj.columnTitle, updateObj.columnTitle,
updateObj.rowId, updateObj.rowId,
updateObj.childId, updateObj.childId,
@ -5730,8 +6018,14 @@ class BaseModelSqlv2 {
updateObj.childModel, updateObj.childModel,
updateObj.pkValue, updateObj.pkValue,
); );
} else { }),
await this.afterRemoveChild( );
await Promise.allSettled(
auditUpdateObj
.filter((a) => a.op_sub_type === AuditOperationSubTypes.LINK_RECORD)
.map((updateObj) => {
this.afterAddChild(
updateObj.columnTitle, updateObj.columnTitle,
updateObj.rowId, updateObj.rowId,
updateObj.childId, updateObj.childId,
@ -5740,8 +6034,7 @@ class BaseModelSqlv2 {
updateObj.childModel, updateObj.childModel,
updateObj.pkValue, updateObj.pkValue,
); );
} }),
}),
); );
} }
@ -6862,6 +7155,7 @@ class BaseModelSqlv2 {
colId: string; colId: string;
rowId: string; rowId: string;
}) { }) {
console.log('links');
const columns = await this.model.getColumns(this.context); const columns = await this.model.getColumns(this.context);
const column = columns.find((c) => c.id === colId); const column = columns.find((c) => c.id === colId);

Loading…
Cancel
Save