fix(grid): treat bulk-edit NULL keyword as SQL NULL
This commit is contained in:
1 parent
7ade5d2b6e
commit
69b43cf401
4 files changed
+84
-5
No files matched your search
@@ -308,7 +308,7 @@ import { uiTuning } from "@/lib/app/uiTuning";
|
||||
import { useDataGridScrollbars, type DataGridScrollbarsRuntime } from "@/composables/useDataGridScrollbars";
|
||||
import { useDataGridSelection } from "@/composables/useDataGridSelection";
|
||||
import { dataGridNavigationOrigin, dataGridPageScrollTop, dataGridRowScrollTop, moveDataGridCell, navigateDataGridCell, type DataGridNavigationDirection, type DataGridScrollAlignment } from "@/lib/dataGrid/dataGridNavigation";
|
||||
import { dataGridInlineBulkEditValue } from "@/lib/dataGrid/dataGridInlineBulkEdit";
|
||||
import { bulkEditInputToSqlValue, dataGridInlineBulkEditValue } from "@/lib/dataGrid/dataGridInlineBulkEdit";
|
||||
import type { CellPosition } from "@/lib/dataGrid/gridSelection";
|
||||
import type { GridSnapshotSource } from "@/lib/gridSnapshot/gridSnapshot";
|
||||
import { createDataGridRuntimeScope } from "@/lib/dataGrid/dataGridRuntime";
|
||||
@@ -8442,7 +8442,8 @@ async function applyBulkEditValue() {
|
||||
toast(t("grid.conditionalBulkEditConditionRequired"), 5000);
|
||||
return;
|
||||
}
|
||||
const value = bulkEditValue.value === "" ? null : coerceCellValue(bulkEditValue.value, undefined, target.columnIndex);
|
||||
const rawValue = bulkEditInputToSqlValue(bulkEditValue.value);
|
||||
const value = rawValue === null ? null : coerceCellValue(rawValue, undefined, target.columnIndex);
|
||||
const statement = await buildDataGridConditionalUpdateSql({
|
||||
databaseType: resolvedDatabaseType.value,
|
||||
identifierQuote: connectionStore.connectionIdentifierQuote?.(props.connectionId),
|
||||
@@ -8464,8 +8465,9 @@ async function applyBulkEditValue() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty input sets the selected cells to SQL NULL (the placeholder hints "Value, or NULL").
|
||||
const value = bulkEditValue.value === "" ? null : bulkEditValue.value;
|
||||
// Empty input or the bare keyword NULL sets the selected cells to SQL NULL
|
||||
// (the placeholder hints "Value, or NULL").
|
||||
const value = bulkEditInputToSqlValue(bulkEditValue.value);
|
||||
if (!fillSelectionWithValue(value)) return;
|
||||
bulkEditDialogOpen.value = false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { dataGridInlineBulkEditValue } from "@/lib/dataGrid/dataGridInlineBulkEdit";
|
||||
import { bulkEditInputToSqlValue, dataGridInlineBulkEditValue } from "@/lib/dataGrid/dataGridInlineBulkEdit";
|
||||
|
||||
const dataGridSource = readFileSync(new URL("../DataGrid.vue", import.meta.url), "utf8");
|
||||
|
||||
@@ -40,3 +40,19 @@ describe("DataGrid inline bulk editing", () => {
|
||||
expect(commit).toContain("cancelEdit()");
|
||||
});
|
||||
});
|
||||
|
||||
describe("bulkEditInputToSqlValue", () => {
|
||||
it.each(["", " ", "NULL", "null", "Null", "nUlL", " NULL "])("maps the NULL sentinel %j to SQL NULL", (input) => {
|
||||
expect(bulkEditInputToSqlValue(input)).toBeNull();
|
||||
});
|
||||
|
||||
it.each(["0", "false", "NULLL", "NULLX", "'NULL'", "nulls", "NUL", " 1 "])("keeps non-sentinel input %j as typed", (input) => {
|
||||
expect(bulkEditInputToSqlValue(input)).toBe(input);
|
||||
});
|
||||
|
||||
it("routes applyBulkEditValue through bulkEditInputToSqlValue for both scopes", () => {
|
||||
const applyBulkEdit = functionBody("applyBulkEditValue", "confirmConditionalBulkEdit");
|
||||
expect(applyBulkEdit).toContain("bulkEditInputToSqlValue(bulkEditValue.value)");
|
||||
expect(applyBulkEdit).not.toContain('bulkEditValue.value === "" ? null');
|
||||
});
|
||||
});
|
||||
@@ -12,3 +12,15 @@ export function dataGridInlineBulkEditValue(event: DataGridInlineBulkEditKeyEven
|
||||
if (event.key === "Enter") return "";
|
||||
return event.key !== "Process" && Array.from(event.key).length === 1 ? event.key : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk-edit dialog contract (placeholder "Value, or NULL"): empty input and the
|
||||
* bare keyword `NULL` stage SQL NULL. Every other input is kept as typed so a
|
||||
* text column can still receive the literal word via quoted/user-specific input
|
||||
* outside this dialog path.
|
||||
*/
|
||||
export function bulkEditInputToSqlValue(input: string): string | null {
|
||||
const trimmed = input.trim();
|
||||
if (trimmed === "" || trimmed.toUpperCase() === "NULL") return null;
|
||||
return input;
|
||||
}
|
||||
Reference in new issue
Block a user