Browse Source

refactor: use composite key extraction in bulk api implementations

pull/7649/head
Pranav C 7 months ago
parent
commit
0ef551b853
  1. 100
      packages/nocodb/src/db/BaseModelSqlv2.ts

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

@ -2449,7 +2449,11 @@ class BaseModelSqlv2 {
if (ag) { if (ag) {
if (!response) await this.execAndParse(query); if (!response) await this.execAndParse(query);
response = await this.readByPk( response = await this.readByPk(
insertObj[ag.column_name], this.extractCompositePK({
rowId: insertObj[ag.column_name],
insertObj,
ag,
}),
false, false,
{}, {},
{ ignoreView: true, getHiddenColumn: true }, { ignoreView: true, getHiddenColumn: true },
@ -2492,7 +2496,7 @@ class BaseModelSqlv2 {
).id; ).id;
} }
response = await this.readByPk( response = await this.readByPk(
id, this.extractCompositePK({ rowId: id, insertObj, ag }),
false, false,
{}, {},
{ ignoreView: true, getHiddenColumn: true }, { ignoreView: true, getHiddenColumn: true },
@ -2505,7 +2509,7 @@ class BaseModelSqlv2 {
? response?.[0]?.[ai.id] ? response?.[0]?.[ai.id]
: response?.[ai.id]; : response?.[ai.id];
response = await this.readByPk( response = await this.readByPk(
id, this.extractCompositePK({ rowId: id, insertObj, ag }),
false, false,
{}, {},
{ ignoreView: true, getHiddenColumn: true }, { ignoreView: true, getHiddenColumn: true },
@ -2869,22 +2873,7 @@ class BaseModelSqlv2 {
? response?.[0]?.[ai.id] ? response?.[0]?.[ai.id]
: response?.[ai.id]; : response?.[ai.id];
} }
rowId = this.extractCompositePK({ ai, ag, rowId, insertObj });
// handle if composite primary key is used along with ai or ag
if ((ai || ag) && this.model.primaryKeys?.length > 1) {
// generate object with ai column and rest of the primary keys
const pkObj = {};
for (const pk of this.model.primaryKeys) {
if (ai && pk.id === ai.id) {
pkObj[pk.id] = rowId;
} else if (ag && pk.id === ag.id) {
pkObj[pk.id] = rowId;
} else {
pkObj[pk.id] = insertObj[pk.column_name] ?? null;
}
}
rowId = pkObj;
}
await Promise.all(postInsertOps.map((f) => f(rowId))); await Promise.all(postInsertOps.map((f) => f(rowId)));
@ -2905,6 +2894,35 @@ class BaseModelSqlv2 {
} }
} }
private extractCompositePK({
ai,
ag,
rowId,
insertObj,
}: {
ai?: Column<any>;
ag?: Column<any>;
rowId;
insertObj: Record<string, any>;
}) {
// handle if composite primary key is used along with ai or ag
if ((ai || ag) && this.model.primaryKeys?.length > 1) {
// generate object with ai column and rest of the primary keys
const pkObj = {};
for (const pk of this.model.primaryKeys) {
if (ai && pk.id === ai.id) {
pkObj[pk.id] = rowId;
} else if (ag && pk.id === ag.id) {
pkObj[pk.id] = rowId;
} else {
pkObj[pk.id] = insertObj[pk.column_name] ?? null;
}
}
rowId = pkObj;
}
return rowId;
}
private async prepareNestedLinkQb({ private async prepareNestedLinkQb({
nestedCols, nestedCols,
data, data,
@ -3198,27 +3216,43 @@ class BaseModelSqlv2 {
let responses; let responses;
const aiPkCol = this.model.primaryKeys.find((pk) => pk.ai);
const agPkCol = this.model.primaryKeys.find((pk) => pk.meta?.ag);
// insert one by one as fallback to get ids for sqlite and mysql // insert one by one as fallback to get ids for sqlite and mysql
if (insertOneByOneAsFallback && (this.isSqlite || this.isMySQL)) { if (insertOneByOneAsFallback && (this.isSqlite || this.isMySQL)) {
// sqlite and mysql doesn't support returning, so insert one by one and return ids // sqlite and mysql doesn't support returning, so insert one by one and return ids
responses = []; responses = [];
const aiPkCol = this.model.primaryKeys.find((pk) => pk.ai);
for (const insertData of insertDatas) { for (const insertData of insertDatas) {
const query = trx(this.tnPath).insert(insertData); const query = trx(this.tnPath).insert(insertData);
const id = (await query)[0]; let id = (await query)[0];
responses.push(aiPkCol ? { [aiPkCol.title]: id } : id);
if (agPkCol) {
id = insertData[agPkCol.column_name];
}
responses.push(
this.extractCompositePK({
rowId: id,
ai: aiPkCol,
ag: agPkCol,
insertObj: insertData,
}) || insertData,
);
} }
} else { } else {
const returningObj: Record<string, string> = {};
for (const col of this.model.primaryKeys) {
returningObj[col.title] = col.column_name;
}
responses = responses =
!raw && (this.isPg || this.isMssql) !raw && (this.isPg || this.isMssql)
? await trx ? await trx
.batchInsert(this.tnPath, insertDatas, chunkSize) .batchInsert(this.tnPath, insertDatas, chunkSize)
.returning({ .returning(returningObj)
[this.model.primaryKey?.title]:
this.model.primaryKey?.column_name,
})
: await trx.batchInsert(this.tnPath, insertDatas, chunkSize); : await trx.batchInsert(this.tnPath, insertDatas, chunkSize);
} }
@ -3232,7 +3266,17 @@ class BaseModelSqlv2 {
// insert nested link data for single record insertion // insert nested link data for single record insertion
if (isSingleRecordInsertion) { if (isSingleRecordInsertion) {
const rowId = responses[0][this.model.primaryKey?.title]; let rowId = responses[0][this.model.primaryKey?.title];
if (aiPkCol || agPkCol) {
rowId = this.extractCompositePK({
rowId,
ai: aiPkCol,
ag: agPkCol,
insertObj: insertDatas[0],
});
}
await Promise.all(postInsertOps.map((f) => f(rowId, trx))); await Promise.all(postInsertOps.map((f) => f(rowId, trx)));
} }

Loading…
Cancel
Save