fix(sqlserver): keep data results interactive with messages
Closes #5967
This commit is contained in:
1 parent
75df9266cb
commit
be3336c1ec
6 files changed
+142
-10
No files matched your search
@@ -2760,8 +2760,9 @@ const canFetchNextInfiniteScrollSegment = computed(() =>
|
||||
);
|
||||
const canJumpLastPage = computed(() => canGoNextPage.value && (hasKnownPaginationTotalRowCount.value || allRowsLoaded.value || !!props.tableMeta || !!props.countSql || !!props.countTotalRows));
|
||||
const totalRowCountBusy = computed(() => props.totalRowCountLoading === true || manualTotalRowCountLoading.value);
|
||||
/** Full-grid busy state: refresh dispatch, query loading, or on-demand COUNT (e.g. jump to last page). */
|
||||
const gridSurfaceBusy = computed(() => isRefreshingData.value || props.loading === true || totalRowCountBusy.value);
|
||||
/** Automatic background counts keep rows interactive; explicit count navigation still blocks the surface. */
|
||||
const gridSurfaceBusy = computed(() => isRefreshingData.value || props.loading === true || manualTotalRowCountLoading.value);
|
||||
const gridPaginationBusy = computed(() => gridSurfaceBusy.value || totalRowCountBusy.value);
|
||||
const dataGridNativeSelectionBlockOwner = {};
|
||||
watch(
|
||||
gridSurfaceBusy,
|
||||
@@ -2921,7 +2922,7 @@ function nextPage() {
|
||||
}
|
||||
|
||||
function jumpPage(page: number) {
|
||||
if (gridSurfaceBusy.value || infiniteScrollEnabled.value || !Number.isSafeInteger(page) || page < 1) return;
|
||||
if (gridPaginationBusy.value || infiniteScrollEnabled.value || !Number.isSafeInteger(page) || page < 1) return;
|
||||
const targetPage = Math.min(page, maximumPage.value ?? page);
|
||||
if (targetPage === currentPage.value) return;
|
||||
if (allRowsLoaded.value) {
|
||||
@@ -11672,7 +11673,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
:pagination-enabled="paginationEnabled"
|
||||
:selection-summary="selectionSummary"
|
||||
:selection-summary-sum-text="selectionSummarySumText"
|
||||
:loading="gridSurfaceBusy"
|
||||
:loading="gridPaginationBusy"
|
||||
:infinite-scroll-enabled="infiniteScrollEnabled"
|
||||
:infinite-scroll-all-loaded="infiniteScrollAllLoaded"
|
||||
:page-size="pageSize"
|
||||
|
||||
+101
-3
@@ -209,7 +209,7 @@ GO`;
|
||||
expect(activeTab.value?.result?.rows).toEqual([["x"]]);
|
||||
});
|
||||
|
||||
it("selects a trailing SQL Server PRINT result after a data result", async () => {
|
||||
it("keeps a SQL Server data result selected when a trailing message result exists", async () => {
|
||||
const sql = "SELECT 1 AS value; PRINT N'x';";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("dbx_sqlserver_demo"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("sqlserver"));
|
||||
@@ -239,11 +239,109 @@ GO`;
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("result");
|
||||
expect(setActiveResultIndex).not.toHaveBeenCalled();
|
||||
expect(activeTab.value?.activeResultIndex).toBe(0);
|
||||
expect(activeTab.value?.result?.server_message).toBeUndefined();
|
||||
expect(activeTab.value?.result?.rows).toEqual([[1]]);
|
||||
});
|
||||
|
||||
it("selects a SQL Server data result after an earlier message result", async () => {
|
||||
const sql = "PRINT N'x'; SELECT 1 AS value;";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("dbx_sqlserver_demo"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("sqlserver"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart">("result");
|
||||
const queryStore = useQueryStore();
|
||||
const setActiveResultIndex = vi.spyOn(queryStore, "setActiveResultIndex").mockImplementation((_id, index) => {
|
||||
if (!activeTab.value?.results) return;
|
||||
activeTab.value.activeResultIndex = index;
|
||||
activeTab.value.result = activeTab.value.results[index];
|
||||
});
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (!activeTab.value) return;
|
||||
const messageResult = { columns: ["Message"], column_types: ["nvarchar"], rows: [["x"]], affected_rows: 0, execution_time_ms: 1, server_message: true } as const;
|
||||
const dataResult = { columns: ["value"], column_types: ["int"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 };
|
||||
activeTab.value.results = [messageResult, dataResult];
|
||||
activeTab.value.activeResultIndex = 0;
|
||||
activeTab.value.result = messageResult;
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("result");
|
||||
expect(setActiveResultIndex).toHaveBeenCalledWith("tab-1", 1);
|
||||
expect(activeTab.value?.activeResultIndex).toBe(1);
|
||||
expect(activeTab.value?.result?.server_message).toBe(true);
|
||||
expect(activeTab.value?.result?.rows).toEqual([["x"]]);
|
||||
expect(activeTab.value?.result?.rows).toEqual([[1]]);
|
||||
});
|
||||
|
||||
it("keeps a SQL Server execution error selected when a message result also exists", async () => {
|
||||
const sql = "SELECT missing_column FROM demo;";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("dbx_sqlserver_demo"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("sqlserver"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart">("result");
|
||||
const queryStore = useQueryStore();
|
||||
const setActiveResultIndex = vi.spyOn(queryStore, "setActiveResultIndex");
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (!activeTab.value) return;
|
||||
const messageResult = { columns: ["Message"], column_types: ["nvarchar"], rows: [["before error"]], affected_rows: 0, execution_time_ms: 1, server_message: true };
|
||||
const errorResult = { columns: ["Error"], column_types: ["string"], rows: [["Invalid column name"]], affected_rows: 0, execution_time_ms: 1, execution_error: true };
|
||||
activeTab.value.results = [messageResult, errorResult];
|
||||
activeTab.value.activeResultIndex = 1;
|
||||
activeTab.value.result = errorResult;
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(setActiveResultIndex).not.toHaveBeenCalled();
|
||||
expect(activeTab.value?.activeResultIndex).toBe(1);
|
||||
expect(activeTab.value?.result?.execution_error).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps ordinary SQL Server multi-result batches on their summary", async () => {
|
||||
const sql = "SELECT 1 AS first_value; SELECT 2 AS second_value;";
|
||||
const activeTab = ref<QueryTab | undefined>({ ...queryTab("dbx_sqlserver_demo"), sql });
|
||||
const activeConnection = ref<ConnectionConfig | undefined>(connection("sqlserver"));
|
||||
const activeOutputView = ref<"result" | "summary" | "explain" | "chart">("result");
|
||||
const queryStore = useQueryStore();
|
||||
const setActiveResultIndex = vi.spyOn(queryStore, "setActiveResultIndex");
|
||||
vi.spyOn(queryStore, "executeCurrentSql").mockImplementation(async () => {
|
||||
if (!activeTab.value) return;
|
||||
const firstResult = { columns: ["first_value"], column_types: ["int"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 };
|
||||
const secondResult = { columns: ["second_value"], column_types: ["int"], rows: [[2]], affected_rows: 0, execution_time_ms: 1 };
|
||||
activeTab.value.results = [firstResult, secondResult];
|
||||
activeTab.value.activeResultIndex = 0;
|
||||
activeTab.value.result = firstResult;
|
||||
});
|
||||
vi.spyOn(useHistoryStore(), "add").mockResolvedValue(undefined);
|
||||
|
||||
const execution = useSqlExecution({
|
||||
activeTab: computed(() => activeTab.value),
|
||||
activeConnection: computed(() => activeConnection.value),
|
||||
executableSql: computed(() => sql),
|
||||
activeOutputView,
|
||||
});
|
||||
|
||||
await execution.tryExecute();
|
||||
|
||||
expect(activeOutputView.value).toBe("summary");
|
||||
expect(setActiveResultIndex).not.toHaveBeenCalled();
|
||||
expect(activeTab.value?.result?.rows).toEqual([[1]]);
|
||||
});
|
||||
|
||||
it("keeps the summary for ordinary SQL Server data aliased as Message", async () => {
|
||||
|
||||
@@ -274,8 +274,13 @@ export function useSqlExecution(deps: {
|
||||
});
|
||||
if (producedResult === false) return;
|
||||
const sqlServerMessageResultIndex = executionDatabaseType === "sqlserver" ? tab.results?.findIndex((result) => result.server_message === true) : undefined;
|
||||
const activeSqlServerResult = tab.results && tab.activeResultIndex !== undefined ? tab.results[tab.activeResultIndex] : tab.result;
|
||||
if (sqlServerMessageResultIndex !== undefined && sqlServerMessageResultIndex >= 0) {
|
||||
queryStore.setActiveResultIndex(tab.id, sqlServerMessageResultIndex);
|
||||
if (activeSqlServerResult?.server_message === true) {
|
||||
const sqlServerDataResultIndex = tab.results?.findIndex((result) => result.server_message !== true && !isQueryExecutionErrorResult(result) && result.columns.length > 0);
|
||||
if (sqlServerDataResultIndex !== undefined && sqlServerDataResultIndex >= 0) queryStore.setActiveResultIndex(tab.id, sqlServerDataResultIndex);
|
||||
else queryStore.setActiveResultIndex(tab.id, sqlServerMessageResultIndex);
|
||||
}
|
||||
deps.activeOutputView.value = "result";
|
||||
} else if (executionDatabaseType === "sqlserver" && tab.result?.server_message === true) {
|
||||
deps.activeOutputView.value = "result";
|
||||
|
||||
@@ -5332,6 +5332,8 @@ export const useQueryStore = defineStore("query", () => {
|
||||
tab.resultSortDirection = undefined;
|
||||
tab.resultSortMode = undefined;
|
||||
tab.resultSortedSql = undefined;
|
||||
tab.resultTotalRowCount = undefined;
|
||||
tab.resultTotalRowCountLoading = false;
|
||||
// results 数组未变,估算值与当前激活的 result 无关,可直接复用
|
||||
touchResult(tab, Date.now(), { reuseEstimatedBytes: true });
|
||||
tab.queryAnalysis = undefined;
|
||||
|
||||
Reference in new issue
Block a user