diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index baab008da8..794e2dfddd 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -267,6 +267,8 @@ export async function destroy(ctx: UserCtx) { const datasource = await sdk.datasources.get(datasourceId) // Delete all queries for the datasource + await sdk.rowActions.deleteAllForDatasource(datasourceId) + if (datasource.type === dbCore.BUDIBASE_DATASOURCE_TYPE) { await destroyInternalTablesBySourceId(datasourceId) } else { diff --git a/packages/server/src/api/routes/tests/rowAction.spec.ts b/packages/server/src/api/routes/tests/rowAction.spec.ts index 5cec83fe23..14a1812195 100644 --- a/packages/server/src/api/routes/tests/rowAction.spec.ts +++ b/packages/server/src/api/routes/tests/rowAction.spec.ts @@ -1,17 +1,24 @@ import _ from "lodash" import tk from "timekeeper" +import { + context, + DEFAULT_BB_DATASOURCE_ID, + roles, +} from "@budibase/backend-core" +import { automations } from "@budibase/pro" import { CreateRowActionRequest, DocumentType, PermissionLevel, RowActionResponse, + TableRowActions, } from "@budibase/types" import * as setup from "./utilities" import { generator, mocks } from "@budibase/backend-core/tests" import { Expectations } from "../../../tests/utilities/api/base" -import { roles } from "@budibase/backend-core" -import { automations } from "@budibase/pro" +import { DatabaseName, getDatasource } from "../../../integrations/tests/utils" +import { generateRowActionsID } from "../../../db/utils" const expectAutomationId = () => expect.stringMatching(`^${DocumentType.AUTOMATION}_.+`) @@ -958,9 +965,74 @@ describe("/rowsActions", () => { // document was not being cleaned up. This meant there existed code paths // that would find it and try to reference the tables within it, resulting // in errors. - await config.api.automation.fetchEnriched({ + await config.api.automation.fetch({ status: 200, }) }) + + it.each([ + [ + "internal", + async () => { + await config.newTenant() + await config.api.application.addSampleData(config.getAppId()) + const tables = await config.api.table.fetch() + const table = tables.find( + t => t.sourceId === DEFAULT_BB_DATASOURCE_ID + )! + return table + }, + ], + [ + "external", + async () => { + await config.newTenant() + const ds = await config.createDatasource({ + datasource: await getDatasource(DatabaseName.POSTGRES), + }) + const table = await config.api.table.save( + setup.structures.tableForDatasource(ds) + ) + return table + }, + ], + ])( + "should delete all the row actions (and automations) for its tables when a datasource is deleted", + async (_, getTable) => { + async function getRowActionsFromDb(tableId: string) { + return await context.doInAppContext(config.getAppId(), async () => { + const db = context.getAppDB() + const tableDoc = await db.tryGet( + generateRowActionsID(tableId) + ) + return tableDoc + }) + } + + const table = await getTable() + const tableId = table._id! + + await config.api.rowAction.save(tableId, { + name: generator.guid(), + }) + await config.api.rowAction.save(tableId, { + name: generator.guid(), + }) + + const { actions } = (await getRowActionsFromDb(tableId))! + expect(Object.entries(actions)).toHaveLength(2) + + const { automations } = await config.api.automation.fetch() + expect(automations).toHaveLength(2) + + const datasource = await config.api.datasource.get(table.sourceId) + await config.api.datasource.delete(datasource) + + const automationsResp = await config.api.automation.fetch() + expect(automationsResp.automations).toHaveLength(0) + + expect(await getRowActionsFromDb(tableId)).toBeUndefined() + } + ) }) }) diff --git a/packages/server/src/sdk/app/rowActions.ts b/packages/server/src/sdk/app/rowActions/crud.ts similarity index 96% rename from packages/server/src/sdk/app/rowActions.ts rename to packages/server/src/sdk/app/rowActions/crud.ts index de73969696..1153677685 100644 --- a/packages/server/src/sdk/app/rowActions.ts +++ b/packages/server/src/sdk/app/rowActions/crud.ts @@ -7,11 +7,11 @@ import { User, VirtualDocumentType, } from "@budibase/types" -import { generateRowActionsID } from "../../db/utils" -import automations from "./automations" -import { definitions as TRIGGER_DEFINITIONS } from "../../automations/triggerInfo" -import * as triggers from "../../automations/triggers" -import sdk from ".." +import { generateRowActionsID } from "../../../db/utils" +import automations from "../automations" +import { definitions as TRIGGER_DEFINITIONS } from "../../../automations/triggerInfo" +import * as triggers from "../../../automations/triggers" +import sdk from "../.." async function ensureUniqueAndThrow( doc: TableRowActions, diff --git a/packages/server/src/sdk/app/rowActions/index.ts b/packages/server/src/sdk/app/rowActions/index.ts new file mode 100644 index 0000000000..b0dbd426df --- /dev/null +++ b/packages/server/src/sdk/app/rowActions/index.ts @@ -0,0 +1,2 @@ +export * from "./crud" +export * from "./utils" diff --git a/packages/server/src/sdk/app/rowActions/utils.ts b/packages/server/src/sdk/app/rowActions/utils.ts new file mode 100644 index 0000000000..d4e5a4610d --- /dev/null +++ b/packages/server/src/sdk/app/rowActions/utils.ts @@ -0,0 +1,9 @@ +import sdk from "../../../sdk" + +export async function deleteAllForDatasource(datasourceId: string) { + const allTables = await sdk.tables.getAllTables() + const tables = allTables.filter(t => t.sourceId === datasourceId) + for (const table of Object.values(tables)) { + await sdk.rowActions.deleteAll(table._id!) + } +} diff --git a/packages/server/src/tests/utilities/api/automation.ts b/packages/server/src/tests/utilities/api/automation.ts index 11c041d52b..9d9a27e891 100644 --- a/packages/server/src/tests/utilities/api/automation.ts +++ b/packages/server/src/tests/utilities/api/automation.ts @@ -23,17 +23,6 @@ export class AutomationAPI extends TestAPI { }) } - fetchEnriched = async ( - expectations?: Expectations - ): Promise => { - return await this._get( - `/api/automations?enrich=true`, - { - expectations, - } - ) - } - post = async ( body: Automation, expectations?: Expectations