feat: support emptying multiple selected tables

* Feature: support emptying multiple selected tables

* ci: retrigger checks

* Fix batch empty safety and ClickHouse feedback

---------

Co-authored-by: zipg <4047349+zipg@users.noreply.github.com>
This commit is contained in:
zipgandzipg authored and GitHub committed 2026-07-10 13:36:40 +08:00
1 parent 903ab26c9b
commit 7b2f969356
10 files changed
+204 -3

No files matched your search

@@ -0,0 +1,29 @@
import { describe, expect, it } from "vitest";
import { batchTableEmptyFeedback, runBatchTableEmpty } from "@/lib/sidebar/batchTableEmpty";
describe("batch table empty", () => {
it("continues after a table fails and collects each result", async () => {
const executed: string[] = [];
const result = await runBatchTableEmpty(["orders", "locked", "customers"], async (table) => {
executed.push(table);
if (table === "locked") throw new Error("permission denied");
});
expect(executed).toEqual(["orders", "locked", "customers"]);
expect(result.succeeded).toEqual(["orders", "customers"]);
expect(result.failed.map(({ target }) => target)).toEqual(["locked"]);
});
it("uses submitted feedback for asynchronous mutations", () => {
const succeeded = { succeeded: ["events"], failed: [] };
const partial = { succeeded: ["events"], failed: [{ target: "logs", error: new Error("failed") }] };
const failed = { succeeded: [], failed: [{ target: "logs", error: new Error("failed") }] };
expect(batchTableEmptyFeedback(succeeded, true)).toBe("submitted");
expect(batchTableEmptyFeedback(partial, true)).toBe("submitted-partial");
expect(batchTableEmptyFeedback(failed, true)).toBe("submitted-partial");
expect(batchTableEmptyFeedback(succeeded, false)).toBe("success");
expect(batchTableEmptyFeedback(partial, false)).toBe("partial");
expect(batchTableEmptyFeedback(failed, false)).toBe("partial");
});
});
@@ -0,0 +1,24 @@
export interface BatchTableEmptyResult<T> {
succeeded: T[];
failed: Array<{ target: T; error: unknown }>;
}
export type BatchTableEmptyFeedback = "success" | "partial" | "submitted" | "submitted-partial";
export async function runBatchTableEmpty<T>(targets: readonly T[], execute: (target: T) => Promise<void>): Promise<BatchTableEmptyResult<T>> {
const result: BatchTableEmptyResult<T> = { succeeded: [], failed: [] };
for (const target of targets) {
try {
await execute(target);
result.succeeded.push(target);
} catch (error) {
result.failed.push({ target, error });
}
}
return result;
}
export function batchTableEmptyFeedback(result: BatchTableEmptyResult<unknown>, asynchronousMutation: boolean): BatchTableEmptyFeedback {
if (asynchronousMutation) return result.failed.length > 0 ? "submitted-partial" : "submitted";
return result.failed.length > 0 ? "partial" : "success";
}