fix(data-grid): preserve table page size on refresh

This commit is contained in:
zipg authored and GitHub committed 2026-07-17 17:13:09 +08:00
1 parent 7165ec8911
commit 994ae28aef
6 files changed
+138 -14

No files matched your search

@@ -4,9 +4,12 @@ import { useDataGridActions } from "@/composables/useDataGridActions";
import type { QueryTab } from "@/types/database";
const mocks = vi.hoisted(() => ({
buildTableSelectSql: vi.fn(),
buildSortedQuerySql: vi.fn(),
executeTabSql: vi.fn(),
getConfig: vi.fn(),
setExecuting: vi.fn(),
updateSql: vi.fn(),
}));
vi.mock("vue-i18n", () => ({
@@ -17,6 +20,11 @@ vi.mock("@/lib/backend/api", () => ({
buildSortedQuerySql: mocks.buildSortedQuerySql,
}));
vi.mock("@/lib/table/tableSelectSql", () => ({
buildTableSelectSql: mocks.buildTableSelectSql,
quoteTableDataIdentifier: (_databaseType: string, name: string) => `"${name}"`,
}));
vi.mock("@/stores/connectionStore", () => ({
useConnectionStore: () => ({
getConfig: mocks.getConfig,
@@ -26,12 +34,8 @@ vi.mock("@/stores/connectionStore", () => ({
vi.mock("@/stores/queryStore", () => ({
useQueryStore: () => ({
executeTabSql: mocks.executeTabSql,
}),
}));
vi.mock("@/stores/settingsStore", () => ({
useSettingsStore: () => ({
editorSettings: { pageSize: 100 },
setExecuting: mocks.setExecuting,
updateSql: mocks.updateSql,
}),
}));
@@ -39,13 +43,100 @@ vi.mock("@/composables/useToast", () => ({
useToast: () => ({ toast: vi.fn() }),
}));
function tableDataTab(patch: Partial<QueryTab> = {}): QueryTab {
return {
id: "tab-1",
connectionId: "postgres-1",
database: "app",
title: "users",
sql: "SELECT * FROM public.users",
result: { columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
mode: "data",
isDirty: false,
isExecuting: false,
isCancelling: false,
isExplaining: false,
tableMetaUpdatedAt: Date.now(),
tableMeta: {
schema: "public",
tableName: "users",
tableType: "TABLE",
columns: [{ name: "id", data_type: "integer", is_nullable: false, column_default: null, is_primary_key: true, extra: null }],
primaryKeys: ["id"],
},
...patch,
} as QueryTab;
}
describe("useDataGridActions", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.getConfig.mockReturnValue({ id: "postgres-1", db_type: "postgres" });
mocks.buildTableSelectSql.mockResolvedValue("SELECT * FROM public.users LIMIT 100 OFFSET 0");
mocks.buildSortedQuerySql.mockResolvedValue({ ok: true, sql: "SELECT sorted" });
});
it("uses the table-data default when toolbar reload has no saved pagination", async () => {
const tab = tableDataTab();
const actions = useDataGridActions(computed(() => tab));
await actions.onReloadData(tab.sql, "", "", "", undefined, undefined, "refresh");
expect(mocks.buildTableSelectSql).toHaveBeenCalledWith(
expect.objectContaining({
limit: 100,
offset: 0,
}),
);
expect(mocks.executeTabSql).toHaveBeenCalledWith("tab-1", "SELECT * FROM public.users LIMIT 100 OFFSET 0", expect.objectContaining({ pagination: { limit: 100, offset: 0 } }));
expect(mocks.executeTabSql.mock.calls[0]?.[2]).not.toHaveProperty("preserveTotalRowCountDuringExecution");
});
it("preserves the toolbar page segment and offset for table-data refresh", async () => {
const tab = tableDataTab({
resultPageLimit: 25,
resultPageOffset: 50,
});
mocks.buildTableSelectSql.mockResolvedValueOnce("SELECT * FROM public.users LIMIT 25 OFFSET 50");
const actions = useDataGridActions(computed(() => tab));
await actions.onReloadData(tab.sql, "", "", "", 25, 50, "refresh");
expect(mocks.buildTableSelectSql).toHaveBeenCalledWith(expect.objectContaining({ limit: 25, offset: 50 }));
expect(mocks.executeTabSql).toHaveBeenCalledWith("tab-1", "SELECT * FROM public.users LIMIT 25 OFFSET 50", expect.objectContaining({ pagination: { limit: 25, offset: 50 } }));
expect(mocks.executeTabSql.mock.calls[0]?.[2]).not.toHaveProperty("preserveTotalRowCountDuringExecution");
});
it("keeps SQL result toolbar reload free of table pagination defaults", async () => {
const tab = {
id: "tab-1",
connectionId: "postgres-1",
database: "app",
title: "Query",
sql: "SELECT 1",
result: { columns: ["value"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
mode: "query",
isDirty: false,
isExecuting: false,
isCancelling: false,
isExplaining: false,
} as QueryTab;
const actions = useDataGridActions(computed(() => tab));
await actions.onReloadData(tab.sql, "", "", "", undefined, undefined, "refresh");
expect(mocks.buildTableSelectSql).not.toHaveBeenCalled();
expect(mocks.executeTabSql).toHaveBeenCalledWith(
"tab-1",
"SELECT 1",
expect.objectContaining({
resultBaseSql: "SELECT 1",
resultSortedSql: undefined,
preserveResultDuringExecution: true,
}),
);
});
it("excludes hidden primary keys and remaps the selected column for database sorting", async () => {
const tab = {
id: "tab-1",
@@ -2,8 +2,8 @@ import { type ComputedRef } from "vue";
import { useI18n } from "vue-i18n";
import { useConnectionStore } from "@/stores/connectionStore";
import { useQueryStore } from "@/stores/queryStore";
import { useSettingsStore } from "@/stores/settingsStore";
import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql";
import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit";
import { editableRowIdentifierColumns, usesSyntheticRowIdKey } from "@/lib/table/tableEditing";
import { tableMetaForDataTab } from "@/lib/table/tableDataTabMeta";
import * as api from "@/lib/backend/api";
@@ -36,7 +36,6 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
const { toast } = useToast();
const connectionStore = useConnectionStore();
const queryStore = useQueryStore();
const settingsStore = useSettingsStore();
function quoteIdent(tab: QueryTab, name: string): string {
const config = connectionStore.getConfig(tab.connectionId);
@@ -60,7 +59,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
columns: tableMeta?.columns.map((column) => column.name),
primaryKeys,
includeRowId: useRowId,
limit: options.limit ?? settingsStore.editorSettings.pageSize,
limit: options.limit ?? tab.resultPageLimit ?? tableOpenPageLimit(),
...options,
});
}
@@ -120,7 +119,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
const elapsed = () => `${Math.round(performance.now() - startedAt)}ms`;
if (tab.mode === "data" && tableMetaForDataTab(tab)) {
tab.whereInput = whereInput ?? "";
const pageLimit = limit ?? settingsStore.editorSettings.pageSize;
const pageLimit = limit ?? tab.resultPageLimit ?? tableOpenPageLimit();
const pageOffset = offset ?? 0;
console.info("[DBX][reloadData:start]", {
traceId,