fix(duckdb): save grid batch edits without a transaction

This commit is contained in:
lxk955
2026-10-15 20:27:02 +08:00
committed by GitHub
parent c915ec76c6
commit 3ef9639dbf
3 changed files with 37 additions and 0 deletions
@@ -1725,6 +1725,23 @@ describe("useDataGridEditor saveChanges reload", () => {
expect(mocks.prepareDataGridSave.mock.calls[1]![0].dirtyRows).toEqual([[0, [[3, "new title"]]]]);
});
it("routes multi-statement edits through executeBatch for non-transactional DuckDB (#12306)", async () => {
mocks.prepareDataGridSave.mockResolvedValue({
statements: ["UPDATE users SET name='alpha' WHERE id=1", "UPDATE users SET name='beta' WHERE id=2"],
rollbackStatements: [],
});
mocks.executeBatch.mockResolvedValue({ affected_rows: 2 });
const { editor } = createSaveTestEditor({ databaseType: "duckdb" });
expect(editor.useTransaction.value).toBe(false);
editor.dirtyRows.value.set(0, new Map([[1, "alpha"]]));
editor.dirtyRows.value.set(1, new Map([[1, "beta"]]));
await editor.saveChanges();
expect(mocks.executeInTransaction).not.toHaveBeenCalled();
expect(mocks.executeBatch).toHaveBeenCalledTimes(1);
expect(mocks.executeBatch).toHaveBeenCalledWith("connection-1", "app", ["UPDATE users SET name='alpha' WHERE id=1", "UPDATE users SET name='beta' WHERE id=2"], undefined);
expect(editor.saveError.value).toBe("");
});
it("keeps both joined edits pending if the transaction fails", async () => {
const targets = [
{ tableMeta: { tableName: "users", primaryKeys: ["id"], columns: [] }, sourceColumns: ["id", "name", undefined, undefined] },
@@ -263,4 +263,14 @@ describe("tableEditing", () => {
expect(supportsDataGridTransaction("iris")).toBe(true);
expect(canUseKeylessRowPredicate("iris", [])).toBe(true);
});
it("edits DuckDB table data row by row without a transaction (#12306)", () => {
expect(isTableDataEditable("duckdb", ["id"], "TABLE")).toBe(true);
expect(isTableDataEditable("duckdb", [], "TABLE")).toBe(true);
expect(isTableDataEditable("duckdb", ["id"], "VIEW")).toBe(false);
expect(canInsertTableRows("duckdb")).toBe(true);
expect(canEditExistingTableRows("duckdb")).toBe(true);
expect(supportsDataGridTransaction("duckdb")).toBe(false);
expect(canUseKeylessRowPredicate("duckdb", [])).toBe(true);
});
});
@@ -92,6 +92,16 @@ const NAVICAT_STYLE_TABLE_DATA_TYPES = new Set<DatabaseType>([
]);
const DATABASE_CAPABILITY_OVERRIDES: Partial<Record<DatabaseType, Partial<DatabaseCapability>>> = {
duckdb: {
tableData: {
insert: true,
updateRequiresPrimaryKey: false,
deleteRequiresPrimaryKey: false,
keylessRowPredicate: true,
requiresTransactionalTableForExistingRows: false,
transaction: false,
},
},
kyuubi: {
tableData: {
insert: false,