From 62fa05a855205f43b0ef929fc051cd91b0fd8f58 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 13:28:28 +0200 Subject: [PATCH 01/12] Type --- packages/server/src/sdk/app/rows/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index cd1b663f6a..e463397ad9 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -76,7 +76,7 @@ export async function getDatasourceAndQuery( } export function cleanExportRows( - rows: any[], + rows: Row[], schema: TableSchema, format: string, columns?: string[], From fe2b2bb097fb4ee106754630d2419f0f6a8a3cd2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 13:33:20 +0200 Subject: [PATCH 02/12] Don't export couchdb fields --- .../server/src/sdk/app/rows/search/internal.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 46d2cd8c61..f86b041597 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -11,6 +11,7 @@ import { SearchResponse, SortType, Table, + TableSchema, User, } from "@budibase/types" import { getGlobalUsersFromMetadata } from "../../../../utilities/global" @@ -137,6 +138,9 @@ export async function exportRows( let rows: Row[] = [] let schema = table.schema let headers + + result = trimFields(result, schema) + // Filter data to only specified columns if required if (columns && columns.length) { for (let i = 0; i < result.length; i++) { @@ -299,3 +303,13 @@ async function getView(db: Database, viewName: string) { } return viewInfo } + +function trimFields(rows: Row[], schema: TableSchema) { + const allowedFields = ["_id", ...Object.keys(schema)] + const result = rows.map(row => + Object.keys(row) + .filter(key => allowedFields.includes(key)) + .reduce((acc, key) => ({ ...acc, [key]: row[key] }), {} as Row) + ) + return result +} From 543d0e1ce619b7fbaeeb994c0d33c325b2d934eb Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 14:01:38 +0200 Subject: [PATCH 03/12] Add tests --- .../server/src/api/routes/tests/row.spec.ts | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 8871841ee7..96a157893f 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1640,23 +1640,38 @@ describe.each([ table = await config.api.table.save(defaultTable()) }) - it("should allow exporting all columns", async () => { - const existing = await config.api.row.save(table._id!, {}) - const res = await config.api.row.exportRows(table._id!, { - rows: [existing._id!], - }) - const results = JSON.parse(res) - expect(results.length).toEqual(1) - const row = results[0] + isInternal && + it("should not export internal couchdb fields", async () => { + const existing = await config.api.row.save(table._id!, { + name: generator.guid(), + description: generator.paragraph(), + }) + const res = await config.api.row.exportRows(table._id!, { + rows: [existing._id!], + }) + const results = JSON.parse(res) + expect(results.length).toEqual(1) + const row = results[0] - // Ensure all original columns were exported - expect(Object.keys(row).length).toBeGreaterThanOrEqual( - Object.keys(existing).length - ) - Object.keys(existing).forEach(key => { - expect(row[key]).toEqual(existing[key]) + expect(Object.keys(row)).toEqual(["_id", "name", "description"]) + }) + + !isInternal && + it("should allow exporting all columns", async () => { + const existing = await config.api.row.save(table._id!, {}) + const res = await config.api.row.exportRows(table._id!, { + rows: [existing._id!], + }) + const results = JSON.parse(res) + expect(results.length).toEqual(1) + const row = results[0] + + // Ensure all original columns were exported + expect(Object.keys(row).length).toBe(Object.keys(existing).length) + Object.keys(existing).forEach(key => { + expect(row[key]).toEqual(existing[key]) + }) }) - }) it("should allow exporting only certain columns", async () => { const existing = await config.api.row.save(table._id!, {}) From 4f65306c4fdf71deb90fe9283585c446a7b6c318 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 25 Jul 2024 17:20:10 +0200 Subject: [PATCH 04/12] Add basic validateNewTableImport test --- .../server/src/api/routes/tests/table.spec.ts | 33 +++++++++++++++++++ .../server/src/tests/utilities/api/table.ts | 22 ++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index a2cff7b395..b32983b8ad 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -10,6 +10,7 @@ import { Row, SaveTableRequest, Table, + TableSchema, TableSourceType, User, ViewCalculation, @@ -1022,4 +1023,36 @@ describe.each([ }) }) }) + + describe("import validation", () => { + const basicSchema: TableSchema = { + id: { + type: FieldType.NUMBER, + name: "id", + }, + name: { + type: FieldType.STRING, + name: "name", + }, + } + + describe("validateNewTableImport", () => { + it("can validate basic imports", async () => { + const result = await config.api.table.validateNewTableImport( + [{ id: generator.natural(), name: generator.first() }], + basicSchema + ) + + expect(result).toEqual({ + allValid: true, + errors: {}, + invalidColumns: [], + schemaValidation: { + id: true, + name: true, + }, + }) + }) + }) + }) }) diff --git a/packages/server/src/tests/utilities/api/table.ts b/packages/server/src/tests/utilities/api/table.ts index d918ba8b9a..c42247dc59 100644 --- a/packages/server/src/tests/utilities/api/table.ts +++ b/packages/server/src/tests/utilities/api/table.ts @@ -3,9 +3,12 @@ import { BulkImportResponse, MigrateRequest, MigrateResponse, + Row, SaveTableRequest, SaveTableResponse, Table, + TableSchema, + ValidateTableImportResponse, } from "@budibase/types" import { Expectations, TestAPI } from "./base" @@ -61,8 +64,25 @@ export class TableAPI extends TestAPI { revId: string, expectations?: Expectations ): Promise => { - return await this._delete(`/api/tables/${tableId}/${revId}`, { + return await this._delete(`/api/tables/${tableId}/${revId}`, { expectations, }) } + + validateNewTableImport = async ( + rows: Row[], + schema: TableSchema, + expectations?: Expectations + ): Promise => { + return await this._post( + `/api/tables/validateNewTableImport`, + { + body: { + rows, + schema, + }, + expectations, + } + ) + } } From 5896e94e56992964064e5cd43d19b7f7a667c608 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 25 Jul 2024 17:32:53 +0200 Subject: [PATCH 05/12] Add basic validateExistingTableImport test --- .../server/src/api/routes/tests/table.spec.ts | 25 +++++++++++++++++++ .../server/src/tests/utilities/api/table.ts | 14 +++++++++++ 2 files changed, 39 insertions(+) diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index b32983b8ad..67b1d64ae1 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -1054,5 +1054,30 @@ describe.each([ }) }) }) + + describe("validateExistingTableImport", () => { + it("can validate basic imports", async () => { + const table = await config.api.table.save( + tableForDatasource(datasource, { + primary: ["id"], + schema: basicSchema, + }) + ) + const result = await config.api.table.validateExistingTableImport({ + tableId: table._id, + rows: [{ id: generator.natural(), name: generator.first() }], + }) + + expect(result).toEqual({ + allValid: true, + errors: {}, + invalidColumns: [], + schemaValidation: { + id: true, + name: true, + }, + }) + }) + }) }) }) diff --git a/packages/server/src/tests/utilities/api/table.ts b/packages/server/src/tests/utilities/api/table.ts index c42247dc59..9d4a92250a 100644 --- a/packages/server/src/tests/utilities/api/table.ts +++ b/packages/server/src/tests/utilities/api/table.ts @@ -8,6 +8,7 @@ import { SaveTableResponse, Table, TableSchema, + ValidateTableImportRequest, ValidateTableImportResponse, } from "@budibase/types" import { Expectations, TestAPI } from "./base" @@ -85,4 +86,17 @@ export class TableAPI extends TestAPI { } ) } + + validateExistingTableImport = async ( + body: ValidateTableImportRequest, + expectations?: Expectations + ): Promise => { + return await this._post( + `/api/tables/validateExistingTableImport`, + { + body, + expectations, + } + ) + } } From 9d0fdeff68b19d0551498cbc72d2cf53568476bd Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 14:17:51 +0200 Subject: [PATCH 06/12] Add validateExistingTableImport _id support test --- .../server/src/api/routes/tests/table.spec.ts | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index 67b1d64ae1..dd40a2420e 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -1,4 +1,4 @@ -import { context, events } from "@budibase/backend-core" +import { context, docIds, events } from "@budibase/backend-core" import { AutoFieldSubType, BBReferenceFieldSubType, @@ -1078,6 +1078,37 @@ describe.each([ }, }) }) + + isInternal && + it("can reimport _id fields for internal tables", async () => { + const table = await config.api.table.save( + tableForDatasource(datasource, { + primary: ["id"], + schema: basicSchema, + }) + ) + const result = await config.api.table.validateExistingTableImport({ + tableId: table._id, + rows: [ + { + _id: docIds.generateRowID(table._id!), + id: generator.natural(), + name: generator.first(), + }, + ], + }) + + expect(result).toEqual({ + allValid: true, + errors: {}, + invalidColumns: [], + schemaValidation: { + _id: true, + id: true, + name: true, + }, + }) + }) }) }) }) From b28aaa3a936dfc27c9263efc83f6c6e169ad5d3f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 14:22:54 +0200 Subject: [PATCH 07/12] Fix --- packages/server/src/api/controllers/table/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/server/src/api/controllers/table/index.ts b/packages/server/src/api/controllers/table/index.ts index ba861064bb..a02ecc665e 100644 --- a/packages/server/src/api/controllers/table/index.ts +++ b/packages/server/src/api/controllers/table/index.ts @@ -17,6 +17,7 @@ import { CsvToJsonRequest, CsvToJsonResponse, FetchTablesResponse, + FieldType, MigrateRequest, MigrateResponse, SaveTableRequest, @@ -178,9 +179,17 @@ export async function validateExistingTableImport( const { rows, tableId } = ctx.request.body let schema = null + if (tableId) { const table = await sdk.tables.getTable(tableId) schema = table.schema + + if (!isExternalTable(table)) { + schema._id = { + name: "_id", + type: FieldType.STRING, + } + } } else { ctx.status = 422 return From 24cdfb3443b28ab34f80ca9a7e6ed0db119a3fc0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 14:55:25 +0200 Subject: [PATCH 08/12] Fix re-importing --- .../src/api/controllers/table/internal.ts | 23 +++++++-- .../server/src/api/controllers/table/utils.ts | 9 ++-- .../server/src/api/routes/tests/row.spec.ts | 50 +++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/controllers/table/internal.ts b/packages/server/src/api/controllers/table/internal.ts index 4286d51d3e..6d1c67e800 100644 --- a/packages/server/src/api/controllers/table/internal.ts +++ b/packages/server/src/api/controllers/table/internal.ts @@ -3,6 +3,7 @@ import { handleDataImport } from "./utils" import { BulkImportRequest, BulkImportResponse, + FieldType, RenameColumn, SaveTableRequest, SaveTableResponse, @@ -69,10 +70,22 @@ export async function bulkImport( ) { const table = await sdk.tables.getTable(ctx.params.tableId) const { rows, identifierFields } = ctx.request.body - await handleDataImport(table, { - importRows: rows, - identifierFields, - user: ctx.user, - }) + await handleDataImport( + { + ...table, + schema: { + _id: { + name: "_id", + type: FieldType.STRING, + }, + ...table.schema, + }, + }, + { + importRows: rows, + identifierFields, + user: ctx.user, + } + ) return table } diff --git a/packages/server/src/api/controllers/table/utils.ts b/packages/server/src/api/controllers/table/utils.ts index e2036c8115..51f7b0e589 100644 --- a/packages/server/src/api/controllers/table/utils.ts +++ b/packages/server/src/api/controllers/table/utils.ts @@ -124,11 +124,12 @@ export async function importToRows( table: Table, user?: ContextUser ) { - let originalTable = table - let finalData: any = [] + const originalTable = table + const finalData: Row[] = [] + const keepCouchId = "_id" in table.schema for (let i = 0; i < data.length; i++) { let row = data[i] - row._id = generateRowID(table._id!) + row._id = (keepCouchId && row._id) || generateRowID(table._id!) row.type = "row" row.tableId = table._id @@ -180,7 +181,7 @@ export async function handleDataImport( const db = context.getAppDB() const data = parse(importRows, table) - let finalData: any = await importToRows(data, table, user) + const finalData = await importToRows(data, table, user) //Set IDs of finalData to match existing row if an update is expected if (identifierFields.length > 0) { diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 96a157893f..b448d46e6a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1298,6 +1298,56 @@ describe.each([ await assertRowUsage(isInternal ? rowUsage + 2 : rowUsage) }) + isInternal && + it("should be able to update existing rows on bulkImport", async () => { + const table = await config.api.table.save( + saveTableRequest({ + schema: { + name: { + type: FieldType.STRING, + name: "name", + }, + description: { + type: FieldType.STRING, + name: "description", + }, + }, + }) + ) + + const existingRow = await config.api.row.save(table._id!, { + name: "Existing row", + description: "Existing description", + }) + + + await config.api.row.bulkImport(table._id!, { + rows: [ + { + name: "Row 1", + description: "Row 1 description", + }, + { ...existingRow, name: "Updated existing row" }, + { + name: "Row 2", + description: "Row 2 description", + }, + ], + identifierFields: ["_id"], + }) + + const rows = await config.api.row.fetch(table._id!) + expect(rows.length).toEqual(3) + + rows.sort((a, b) => a.name.localeCompare(b.name)) + expect(rows[0].name).toEqual("Row 1") + expect(rows[0].description).toEqual("Row 1 description") + expect(rows[1].name).toEqual("Row 2") + expect(rows[1].description).toEqual("Row 2 description") + expect(rows[2].name).toEqual("Updated existing row") + expect(rows[2].description).toEqual("Existing description") + }) + // Upserting isn't yet supported in MSSQL, see: // https://github.com/knex/knex/pull/6050 !isMSSQL && From f794f84e9035d92817259d63de39f178d3c94b04 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 15:00:30 +0200 Subject: [PATCH 09/12] Fix quote count --- packages/server/src/api/controllers/table/utils.ts | 6 +++++- packages/server/src/api/routes/tests/row.spec.ts | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/table/utils.ts b/packages/server/src/api/controllers/table/utils.ts index 51f7b0e589..417cb22fe3 100644 --- a/packages/server/src/api/controllers/table/utils.ts +++ b/packages/server/src/api/controllers/table/utils.ts @@ -183,6 +183,8 @@ export async function handleDataImport( const finalData = await importToRows(data, table, user) + let newRowCount = finalData.length + //Set IDs of finalData to match existing row if an update is expected if (identifierFields.length > 0) { const allDocs = await db.allDocs( @@ -204,12 +206,14 @@ export async function handleDataImport( if (match) { finalItem._id = doc._id finalItem._rev = doc._rev + + newRowCount-- } }) }) } - await quotas.addRows(finalData.length, () => db.bulkDocs(finalData), { + await quotas.addRows(newRowCount, () => db.bulkDocs(finalData), { tableId: table._id, }) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index b448d46e6a..c4586263f4 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1320,6 +1320,7 @@ describe.each([ description: "Existing description", }) + const rowUsage = await getRowUsage() await config.api.row.bulkImport(table._id!, { rows: [ @@ -1346,6 +1347,8 @@ describe.each([ expect(rows[1].description).toEqual("Row 2 description") expect(rows[2].name).toEqual("Updated existing row") expect(rows[2].description).toEqual("Existing description") + + await assertRowUsage(rowUsage + 2) }) // Upserting isn't yet supported in MSSQL, see: From a6beb0fa82f125cf43896d02c04480f7ffca53eb Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 15:14:29 +0200 Subject: [PATCH 10/12] Support no updating existing rows --- .../server/src/api/controllers/table/utils.ts | 9 ++-- .../server/src/api/routes/tests/row.spec.ts | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/table/utils.ts b/packages/server/src/api/controllers/table/utils.ts index 417cb22fe3..0e0a83e3b3 100644 --- a/packages/server/src/api/controllers/table/utils.ts +++ b/packages/server/src/api/controllers/table/utils.ts @@ -122,11 +122,12 @@ export function makeSureTableUpToDate(table: Table, tableToSave: Table) { export async function importToRows( data: Row[], table: Table, - user?: ContextUser + user?: ContextUser, + opts?: { keepCouchId: boolean } ) { const originalTable = table const finalData: Row[] = [] - const keepCouchId = "_id" in table.schema + const keepCouchId = !!opts?.keepCouchId for (let i = 0; i < data.length; i++) { let row = data[i] row._id = (keepCouchId && row._id) || generateRowID(table._id!) @@ -181,7 +182,9 @@ export async function handleDataImport( const db = context.getAppDB() const data = parse(importRows, table) - const finalData = await importToRows(data, table, user) + const finalData = await importToRows(data, table, user, { + keepCouchId: identifierFields.includes("_id"), + }) let newRowCount = finalData.length diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index c4586263f4..edceb925d6 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1351,6 +1351,60 @@ describe.each([ await assertRowUsage(rowUsage + 2) }) + isInternal && + it("should create new rows if not identifierFields are provided", async () => { + const table = await config.api.table.save( + saveTableRequest({ + schema: { + name: { + type: FieldType.STRING, + name: "name", + }, + description: { + type: FieldType.STRING, + name: "description", + }, + }, + }) + ) + + const existingRow = await config.api.row.save(table._id!, { + name: "Existing row", + description: "Existing description", + }) + + const rowUsage = await getRowUsage() + + await config.api.row.bulkImport(table._id!, { + rows: [ + { + name: "Row 1", + description: "Row 1 description", + }, + { ...existingRow, name: "Updated existing row" }, + { + name: "Row 2", + description: "Row 2 description", + }, + ], + }) + + const rows = await config.api.row.fetch(table._id!) + expect(rows.length).toEqual(4) + + rows.sort((a, b) => a.name.localeCompare(b.name)) + expect(rows[0].name).toEqual("Existing row") + expect(rows[0].description).toEqual("Existing description") + expect(rows[1].name).toEqual("Row 1") + expect(rows[1].description).toEqual("Row 1 description") + expect(rows[2].name).toEqual("Row 2") + expect(rows[2].description).toEqual("Row 2 description") + expect(rows[3].name).toEqual("Updated existing row") + expect(rows[3].description).toEqual("Existing description") + + await assertRowUsage(rowUsage + 3) + }) + // Upserting isn't yet supported in MSSQL, see: // https://github.com/knex/knex/pull/6050 !isMSSQL && From b74841d99da31ea616f34ab1d5741f4478dd354d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jul 2024 15:20:06 +0200 Subject: [PATCH 11/12] Fix --- packages/server/src/db/defaultData/datasource_bb_default.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/db/defaultData/datasource_bb_default.ts b/packages/server/src/db/defaultData/datasource_bb_default.ts index a393888e51..6b553e2d36 100644 --- a/packages/server/src/db/defaultData/datasource_bb_default.ts +++ b/packages/server/src/db/defaultData/datasource_bb_default.ts @@ -651,10 +651,10 @@ export async function buildDefaultDocs() { return new LinkDocument( employeeData.table._id!, "Jobs", - employeeData.rows[index]._id, + employeeData.rows[index]._id!, jobData.table._id!, "Assigned", - jobData.rows[index]._id + jobData.rows[index]._id! ) } ) From 86f59fb71de43245720888126cc7de5b6ee54610 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 1 Aug 2024 11:20:23 +0100 Subject: [PATCH 12/12] Fixes an issue with MS-SQL timeouts, it doesn't respect query timeout value as the client has its own built in timeout by default of 15000ms. --- packages/server/scripts/integrations/mssql/data/Dockerfile | 2 +- packages/server/src/integrations/microsoftSqlServer.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/scripts/integrations/mssql/data/Dockerfile b/packages/server/scripts/integrations/mssql/data/Dockerfile index c26af556a9..2bdca4490c 100644 --- a/packages/server/scripts/integrations/mssql/data/Dockerfile +++ b/packages/server/scripts/integrations/mssql/data/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/mssql/server:2022-latest +FROM mcr.microsoft.com/mssql/server@sha256:c4369c38385eba011c10906dc8892425831275bb035d5ce69656da8e29de50d8 ENV ACCEPT_EULA=Y ENV SA_PASSWORD=Passw0rd diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index af535891cf..88c75891e6 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -29,6 +29,7 @@ import { getReadableErrorMessage } from "./base/errorMapping" import sqlServer from "mssql" import { sql } from "@budibase/backend-core" import { ConfidentialClientApplication } from "@azure/msal-node" +import env from "../environment" import { utils } from "@budibase/shared-core" @@ -246,6 +247,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { options: { encrypt, enableArithAbort: true, + requestTimeout: env.QUERY_THREAD_TIMEOUT, }, } if (encrypt) {