fix(grid): qualify generated save and copy SQL with database name
This commit is contained in:
32 files changed
+910
-123
No files matched your search
+100
@@ -0,0 +1,100 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { computed, ref } from "vue";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useDataGridEditor } from "@/composables/useDataGridEditor";
|
||||
import type { CellValue } from "@/lib/dataGrid/cellValue";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
getConfig: vi.fn(),
|
||||
prepareDataGridSave: vi.fn(),
|
||||
executeBatch: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/backend/api", () => ({
|
||||
prepareDataGridSave: mocks.prepareDataGridSave,
|
||||
executeBatch: mocks.executeBatch,
|
||||
executeConditionalUpdate: vi.fn(),
|
||||
cancelConditionalUpdate: vi.fn(),
|
||||
executeInTransaction: vi.fn(),
|
||||
executeInManualTransaction: vi.fn(),
|
||||
executeQuery: vi.fn(),
|
||||
unlockConnectionWrites: vi.fn(),
|
||||
lockConnectionWrites: vi.fn(),
|
||||
connectionWriteUnlockState: vi.fn().mockResolvedValue(0),
|
||||
}));
|
||||
vi.mock("@/stores/connectionStore", () => ({
|
||||
useConnectionStore: () => ({ getConfig: mocks.getConfig }),
|
||||
}));
|
||||
vi.mock("@/stores/historyStore", () => ({
|
||||
useHistoryStore: () => ({ add: vi.fn() }),
|
||||
}));
|
||||
vi.mock("@/stores/productionSafetyStore", () => ({
|
||||
useProductionSafetyStore: () => ({}),
|
||||
}));
|
||||
|
||||
function createEditor(includeDatabaseNameInSaveSql: boolean) {
|
||||
const rows = ref<CellValue[][]>([["alpha"]]);
|
||||
let editor: ReturnType<typeof useDataGridEditor>;
|
||||
editor = useDataGridEditor({
|
||||
result: computed(() => ({ columns: ["name"], rows: rows.value })),
|
||||
editable: computed(() => true),
|
||||
databaseType: computed(() => "mysql"),
|
||||
connectionId: computed(() => "connection-1"),
|
||||
database: computed(() => "dbx"),
|
||||
tableMeta: computed(() => ({
|
||||
database: "dbx",
|
||||
tableName: "filter_probe",
|
||||
columns: [{ name: "name", data_type: "varchar(50)" }],
|
||||
primaryKeys: ["id"],
|
||||
})),
|
||||
sourceColumns: computed(() => undefined),
|
||||
includeDatabaseNameInSaveSql: computed(() => includeDatabaseNameInSaveSql),
|
||||
onExecuteSql: computed(() => undefined),
|
||||
sql: computed(() => undefined),
|
||||
searchText: ref(""),
|
||||
whereFilterInput: ref(""),
|
||||
currentWhereInput: computed(() => undefined),
|
||||
orderByInput: ref(""),
|
||||
rowStatusFilter: ref("all"),
|
||||
pageSize: ref(100),
|
||||
currentPage: ref(1),
|
||||
onCellValueChanged: undefined,
|
||||
getRowItem: (rowId) => {
|
||||
if (rowId < 0) return undefined;
|
||||
const row = rows.value[rowId];
|
||||
if (!row) return undefined;
|
||||
const changes = editor.dirtyRows.value.get(rowId);
|
||||
return {
|
||||
id: rowId,
|
||||
sourceIndex: rowId,
|
||||
data: row.map((value, columnIndex) => (changes?.has(columnIndex) ? (changes.get(columnIndex) ?? null) : value)),
|
||||
isNew: false,
|
||||
isDeleted: false,
|
||||
isDirtyCol: row.map((_, columnIndex) => changes?.has(columnIndex) ?? false),
|
||||
status: changes?.size ? "edited" : "normal",
|
||||
};
|
||||
},
|
||||
emit: vi.fn(),
|
||||
});
|
||||
editor.applyCellValue(0, 0, "changed");
|
||||
return editor;
|
||||
}
|
||||
|
||||
describe("useDataGridEditor save SQL database qualification", () => {
|
||||
beforeEach(() => {
|
||||
mocks.prepareDataGridSave.mockReset();
|
||||
mocks.executeBatch.mockReset();
|
||||
mocks.getConfig.mockReset();
|
||||
mocks.getConfig.mockReturnValue(undefined);
|
||||
mocks.prepareDataGridSave.mockResolvedValue({ statements: ["UPDATE x"], rollbackStatements: [] });
|
||||
mocks.executeBatch.mockResolvedValue([]);
|
||||
});
|
||||
|
||||
it("forwards the include-database-name setting to the save statement builder", async () => {
|
||||
await createEditor(true).saveChanges();
|
||||
expect(mocks.prepareDataGridSave.mock.calls[0]![0]).toMatchObject({ includeDatabaseName: true });
|
||||
|
||||
await createEditor(false).saveChanges();
|
||||
expect(mocks.prepareDataGridSave.mock.calls[1]![0]).toMatchObject({ includeDatabaseName: false });
|
||||
});
|
||||
});
|
||||
@@ -119,6 +119,8 @@ export interface UseDataGridEditorOptions {
|
||||
rowStatusFilter: Ref<RowStatusFilter>;
|
||||
dataGridQuickEntryEnabled?: ComputedRef<boolean>;
|
||||
confirmDangerousRowDeletion?: ComputedRef<boolean>;
|
||||
/** `生成 SQL 时包含数据库名` — qualify saved tables with their database. */
|
||||
includeDatabaseNameInSaveSql?: ComputedRef<boolean>;
|
||||
initialEditColumn?: ComputedRef<number>;
|
||||
/** Converts a grid value to the text presented by the cell editor. */
|
||||
cellEditorText?: (value: CellValue, columnIndex: number) => string;
|
||||
@@ -246,6 +248,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
rowStatusFilter,
|
||||
dataGridQuickEntryEnabled = computed(() => false),
|
||||
confirmDangerousRowDeletion = computed(() => true),
|
||||
includeDatabaseNameInSaveSql = computed(() => false),
|
||||
initialEditColumn,
|
||||
cellEditorText,
|
||||
normalizeEditorInput,
|
||||
@@ -1572,6 +1575,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
dirtyRows: [...snapshot.dirtyRows.entries()].map(([rowIndex, changes]) => [rowIndex, [...changes.entries()]] as [number, Array<[number, CellValue]>]),
|
||||
deletedRows: [...snapshot.deletedRows],
|
||||
newRows: snapshot.newRows,
|
||||
includeDatabaseName: includeDatabaseNameInSaveSql.value,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { computed, type ComputedRef, type Ref } from "vue";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import { omitDdlDatabaseQualifier, omitDdlIdentifierQuotes } from "@/lib/sql/ddlDisplay";
|
||||
import { applyDdlDatabaseQualifier, omitDdlIdentifierQuotes } from "@/lib/sql/ddlDisplay";
|
||||
import { sqlFormatDialectForDbType } from "@/lib/sql/sqlFormatter";
|
||||
import { loadObjectDdl } from "@/lib/metadata/objectDdlCache";
|
||||
import { loadObjectMetadataFacet } from "@/lib/metadata/objectMetadataCache";
|
||||
@@ -119,7 +119,7 @@ export function useDataGridTableMetadataLoaders(options: DataGridTableMetadataLo
|
||||
try {
|
||||
const { ddl } = await loadObjectDdl(request, { force });
|
||||
const formatDialect = sqlFormatDialectForDbType(options.resolvedDatabaseType.value);
|
||||
const unqualified = omitDdlDatabaseQualifier(ddl, formatDialect, options.resolvedDatabaseType.value, options.settingsStore.editorSettings.generateSqlIncludeDatabaseName, props.tableMeta?.catalog);
|
||||
const unqualified = applyDdlDatabaseQualifier(ddl, formatDialect, options.resolvedDatabaseType.value, options.settingsStore.editorSettings.generateSqlIncludeDatabaseName, props.tableMeta?.database, props.tableMeta?.catalog);
|
||||
state.ddlContent.value = options.settingsStore.editorSettings.generateSqlQuoteIdentifiers ? unqualified : omitDdlIdentifierQuotes(unqualified, formatDialect);
|
||||
} catch (error: any) {
|
||||
state.ddlContent.value = `-- Error: ${error}`;
|
||||
|
||||
Reference in new issue
Block a user