From 297e3d07524b41358d5d7e36e4b5bd147e8c70b6 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 1 Jun 2026 14:18:21 +0800 Subject: [PATCH] fix(grid): preserve table data pagination offset --- apps/desktop/src/components/grid/DataGrid.vue | 1 + .../src/composables/useDataGridActions.ts | 9 ++-- apps/desktop/src/stores/queryStore.ts | 3 +- packages/app-tests/queryStore.test.ts | 52 +++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index 7ccc08064a..23c40e3788 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -1681,6 +1681,7 @@ watch( pageSize.value = normalizedLimit; currentPage.value = Math.floor(offset / normalizedLimit) + 1; }, + { immediate: true }, ); const canGoNextPage = computed(() => props.result.has_more === true || props.result.rows.length >= pageSize.value); const canJumpLastPage = computed(() => canGoNextPage.value && (!!props.tableMeta || !!props.countSql)); diff --git a/apps/desktop/src/composables/useDataGridActions.ts b/apps/desktop/src/composables/useDataGridActions.ts index e1a64b07ea..07e96f90b3 100644 --- a/apps/desktop/src/composables/useDataGridActions.ts +++ b/apps/desktop/src/composables/useDataGridActions.ts @@ -67,8 +67,11 @@ export function useDataGridActions(activeTab: ComputedRef) if (!tab) return; if (tab.mode === "data" && tab.tableMeta) { tab.whereInput = whereInput ?? ""; - queryStore.updateSql(tab.id, await buildTableSql(tab, { whereInput, orderBy, limit, offset })); - await queryStore.executeCurrentTab(); + const pageLimit = limit ?? settingsStore.editorSettings.pageSize; + const pageOffset = offset ?? 0; + const nextSql = await buildTableSql(tab, { whereInput, orderBy, limit: pageLimit, offset: pageOffset }); + queryStore.updateSql(tab.id, nextSql); + await queryStore.executeTabSql(tab.id, nextSql, { pagination: { limit: pageLimit, offset: pageOffset } }); return; } if (tab.resultSortedSql) { @@ -111,7 +114,7 @@ export function useDataGridActions(activeTab: ComputedRef) tab.whereInput = whereInput ?? ""; const sql = await buildTableSql(tab, { limit, offset, whereInput, orderBy }); queryStore.updateSql(tab.id, sql); - await queryStore.executeCurrentTab(); + await queryStore.executeTabSql(tab.id, sql, { pagination: { offset, limit } }); } async function onSort(column: string, columnIndex: number, direction: "asc" | "desc" | null, whereInput?: string) { diff --git a/apps/desktop/src/stores/queryStore.ts b/apps/desktop/src/stores/queryStore.ts index b84b7b9b1e..aa7defc34c 100644 --- a/apps/desktop/src/stores/queryStore.ts +++ b/apps/desktop/src/stores/queryStore.ts @@ -674,7 +674,8 @@ export const useQueryStore = defineStore("query", () => { countSql = plan.countSql; useAgentResultSession = plan.useAgentResultSession; } else if (tab.mode === "data") { - pageLimit = settingsStore.editorSettings.pageSize; + pageLimit = options?.pagination?.limit ?? settingsStore.editorSettings.pageSize; + pageOffset = options?.pagination?.offset ?? 0; } const mongoFind = conn?.db_type === "mongodb" ? parseMongoFindCommand(sql) : null; if (mongoFind) { diff --git a/packages/app-tests/queryStore.test.ts b/packages/app-tests/queryStore.test.ts index 25ff62f322..85494ca9c0 100644 --- a/packages/app-tests/queryStore.test.ts +++ b/packages/app-tests/queryStore.test.ts @@ -300,6 +300,58 @@ test("starting a new query clears the previous result payload immediately", asyn } }); +test("data tab execution preserves pagination offset metadata", async () => { + const restoreStorage = installMemoryStorage(); + setActivePinia(createPinia()); + const connectionStore = useConnectionStore(); + const store = useQueryStore(); + const originalFetch = globalThis.fetch; + let executeBody: any; + let preparedPagination = false; + + connectionStore.addEphemeralConnection(conn("conn-1")); + const tabId = store.createTab("conn-1", "db", "users", "data", "public"); + const tab = store.tabs.find((item) => item.id === tabId); + assert.ok(tab); + + globalThis.fetch = (async (input, init) => { + const url = String(input); + if (url === "/api/query/prepare-pagination-plan") { + preparedPagination = true; + return new Response("unexpected pagination plan request", { status: 500 }); + } + if (url === "/api/query/execute-multi") { + executeBody = JSON.parse(String(init?.body ?? "{}")); + return new Response( + JSON.stringify([{ columns: ["id"], rows: [[101]], affected_rows: 0, execution_time_ms: 1 }]), + { + status: 200, + headers: { "Content-Type": "application/json" }, + }, + ); + } + return new Response("unexpected request", { status: 500 }); + }) as typeof fetch; + + try { + await store.executeTabSql(tabId, 'SELECT * FROM "users" LIMIT 100 OFFSET 100;', { + pagination: { limit: 100, offset: 100 }, + }); + + assert.equal(preparedPagination, false); + assert.equal(executeBody.sql, 'SELECT * FROM "users" LIMIT 100 OFFSET 100;'); + assert.equal(executeBody.maxRows, 100); + assert.equal(executeBody.fetchSize, 100); + assert.equal(executeBody.schema, undefined); + assert.equal(tab.resultPageLimit, 100); + assert.equal(tab.resultPageOffset, 100); + assert.deepEqual(tab.result?.rows, [[101]]); + } finally { + globalThis.fetch = originalFetch; + restoreStorage(); + } +}); + test("query execution finishes without waiting for metadata analysis", async () => { const restoreStorage = installMemoryStorage(); setActivePinia(createPinia());