diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index 4aec6b6da6..7e41fa5611 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -17,6 +17,7 @@ import type { ConnectionConfig, DatabaseType, JdbcDriverInfo, JdbcMavenBundleInf import type { MqAdminConfig, MqAuth, MqSystemKind } from "@/types/mq"; import type { NacosAdminConfig, NacosAuthConfig } from "@/types/nacos"; import { useConnectionStore } from "@/stores/connectionStore"; +import { REDIS_SCAN_PAGE_SIZE_DEFAULT, REDIS_SCAN_PAGE_SIZE_MIN, REDIS_SCAN_PAGE_SIZE_MAX, REDIS_SCAN_PAGE_SIZE_OPTIONS } from "@/lib/redisKeyPattern"; import { useSettingsStore } from "@/stores/settingsStore"; import { useToast } from "@/composables/useToast"; import DatabaseIcon from "@/components/icons/DatabaseIcon.vue"; @@ -152,6 +153,7 @@ const defaultForm = (): ConnectionForm => ({ redis_sentinel_tls: false, redis_cluster_nodes: "", redis_key_separator: ":", + redis_scan_page_size: REDIS_SCAN_PAGE_SIZE_DEFAULT, etcd_endpoints: "", gbase_server: "", informix_server: "", @@ -924,6 +926,7 @@ watch( redis_sentinel_tls: config.redis_sentinel_tls || false, redis_cluster_nodes: config.redis_cluster_nodes || "", redis_key_separator: config.redis_key_separator ?? ":", + redis_scan_page_size: config.redis_scan_page_size ?? REDIS_SCAN_PAGE_SIZE_DEFAULT, etcd_endpoints: config.etcd_endpoints || "", informix_server: config.informix_server || "", read_only: config.read_only || false, @@ -1573,6 +1576,7 @@ function connectionConfigForSubmit(id: string): ConnectionConfig { config.redis_sentinel_tls = undefined; config.redis_cluster_nodes = undefined; config.redis_key_separator = undefined; + config.redis_scan_page_size = undefined; } else if (config.redis_connection_mode === "sentinel") { config.redis_sentinel_master = config.redis_sentinel_master?.trim() || ""; config.redis_sentinel_nodes = normalizeRedisSentinelNodes(config.redis_sentinel_nodes || ""); @@ -1606,6 +1610,8 @@ function connectionConfigForSubmit(id: string): ConnectionConfig { } if (config.db_type === "redis") { config.redis_key_separator = config.redis_key_separator?.trim() ?? ":"; + const scanSize = Number(config.redis_scan_page_size); + config.redis_scan_page_size = Number.isFinite(scanSize) && scanSize >= REDIS_SCAN_PAGE_SIZE_MIN && scanSize <= REDIS_SCAN_PAGE_SIZE_MAX ? Math.round(scanSize) : REDIS_SCAN_PAGE_SIZE_DEFAULT; } if (config.db_type === "zookeeper") { const normalizedConnectString = normalizeZooKeeperConnectString(config.connection_string || ""); @@ -3859,6 +3865,22 @@ function openExternalUrl(url: string) { {{ t("connection.readOnlyHint") }} +
+ +
+ +

{{ t("settings.redisScanPageSizeDescription") }}

+
+
diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index ba13d4c762..ac9a994f03 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -206,7 +206,6 @@ const editTableColumnTemplateDatabaseType = ref(TABLE_COLUMN_TEMPL const tableColumnTemplateSectionRef = ref(null); const draggedTableColumnTemplateRowId = ref(null); let tableColumnTemplatePointerDragCleanup: (() => void) | null = null; -const editRedisScanPageSize = ref(settingsStore.editorSettings.redisScanPageSize); const editShortcuts = ref(normalizeShortcutSettings(settingsStore.editorSettings.shortcuts)); const editSqlFormatter = ref(normalizeSqlFormatterSettings(settingsStore.editorSettings.sqlFormatter)); const sqlFormatterConfigValid = ref(true); @@ -226,7 +225,6 @@ const editExportRowLimitEnabled = ref(settingsStore.editorSettings.exportRowLimi const editExportRowLimit = ref(settingsStore.editorSettings.exportRowLimit); const editQueryExportKeysetOptimizationEnabled = ref(settingsStore.editorSettings.queryExportKeysetOptimizationEnabled); const editToolbarItems = ref({ ...settingsStore.editorSettings.toolbarItems }); -const redisScanPageSizeOptions = [200, 1000, 5000, 10000]; const systemFonts = ref([]); const systemFontsLoading = ref(false); const systemFontsLoaded = ref(false); @@ -477,7 +475,6 @@ watch( editInfiniteScroll.value = settingsStore.editorSettings.infiniteScroll; editInfiniteScrollMaxRows.value = settingsStore.editorSettings.infiniteScrollMaxRows; editTableColumnTemplateRows.value = tableColumnTemplateRowsFromSettings(settingsStore.editorSettings.tableColumnTemplateFields); - editRedisScanPageSize.value = settingsStore.editorSettings.redisScanPageSize; editShortcuts.value = normalizeShortcutSettings(settingsStore.editorSettings.shortcuts); editSqlFormatter.value = normalizeSqlFormatterSettings(settingsStore.editorSettings.sqlFormatter); sqlFormatterConfigValid.value = true; @@ -540,7 +537,6 @@ function hasChanges(): boolean { editInfiniteScroll.value !== settingsStore.editorSettings.infiniteScroll || editInfiniteScrollMaxRows.value !== settingsStore.editorSettings.infiniteScrollMaxRows || JSON.stringify(normalizedEditTableColumnTemplateFields.value) !== JSON.stringify(settingsStore.editorSettings.tableColumnTemplateFields) || - editRedisScanPageSize.value !== settingsStore.editorSettings.redisScanPageSize || JSON.stringify(editShortcuts.value) !== JSON.stringify(settingsStore.editorSettings.shortcuts) || JSON.stringify(editSqlFormatter.value) !== JSON.stringify(normalizeSqlFormatterSettings(settingsStore.editorSettings.sqlFormatter)) || editSidebarActivation.value !== settingsStore.editorSettings.sidebarActivation || @@ -584,7 +580,6 @@ async function persistSettings() { infiniteScroll: editInfiniteScroll.value, infiniteScrollMaxRows: editInfiniteScrollMaxRows.value, tableColumnTemplateFields: normalizedEditTableColumnTemplateFields.value, - redisScanPageSize: editRedisScanPageSize.value, shortcuts: editShortcuts.value, sqlFormatter: normalizeSqlFormatterSettings(editSqlFormatter.value), sidebarActivation: editSidebarActivation.value, @@ -674,8 +669,6 @@ function resetDefaultsForTab(tab: SettingsCategory) { editExportRowLimitEnabled.value = DEFAULT_EDITOR_SETTINGS.exportRowLimitEnabled; editExportRowLimit.value = DEFAULT_EDITOR_SETTINGS.exportRowLimit; editQueryExportKeysetOptimizationEnabled.value = DEFAULT_EDITOR_SETTINGS.queryExportKeysetOptimizationEnabled; - } else if (tab === "redis") { - editRedisScanPageSize.value = DEFAULT_EDITOR_SETTINGS.redisScanPageSize; } else if (tab === "shortcuts") { editShortcuts.value = normalizeShortcutSettings(DEFAULT_EDITOR_SETTINGS.shortcuts); } else if (tab === "snippets") { @@ -708,7 +701,6 @@ function resetAllDefaults() { editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll; editInfiniteScrollMaxRows.value = DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows; editTableColumnTemplateRows.value = tableColumnTemplateRowsFromSettings(DEFAULT_EDITOR_SETTINGS.tableColumnTemplateFields); - editRedisScanPageSize.value = DEFAULT_EDITOR_SETTINGS.redisScanPageSize; editShortcuts.value = normalizeShortcutSettings(DEFAULT_EDITOR_SETTINGS.shortcuts); editSqlFormatter.value = normalizeSqlFormatterSettings(DEFAULT_EDITOR_SETTINGS.sqlFormatter); sqlFormatterConfigValid.value = true; @@ -910,11 +902,6 @@ function onLocaleChange(v: any) { if (typeof v === "string") void setLocale(v as Locale); } -function onRedisScanPageSizeChange(v: any) { - const value = Number(v); - if (redisScanPageSizeOptions.includes(value)) editRedisScanPageSize.value = value; -} - function setSidebarObjectDisplay(value: "grouped" | "simple") { editSidebarObjectDisplay.value = value; } @@ -1007,14 +994,13 @@ function setSidebarActivation(value: "single" | "double") { const activeSettingsTab = ref("editor"); const isWeb = !isTauriRuntime(); const displayedAppVersion = computed(() => (props.appVersion ? `v${props.appVersion}` : "")); -type SettingsCategory = "editor" | "formatter" | "appearance" | "navigation" | "data" | "redis" | "shortcuts" | "snippets" | "sync" | "ai" | "mcp" | "security" | "about"; +type SettingsCategory = "editor" | "formatter" | "appearance" | "navigation" | "data" | "shortcuts" | "snippets" | "sync" | "ai" | "mcp" | "security" | "about"; const settingsCategoryNav = computed<{ value: SettingsCategory; label: string }[]>(() => [ { value: "editor", label: t("settings.editorTab") }, { value: "formatter", label: t("settings.sqlFormatterTab") }, { value: "appearance", label: t("settings.appearanceTab") }, { value: "navigation", label: t("settings.navigationTab") }, { value: "data", label: t("settings.dataTab") }, - { value: "redis", label: t("settings.redisTab") }, { value: "shortcuts", label: t("settings.shortcutsTab") }, { value: "snippets", label: t("settings.snippetsTab") }, ...(isWeb ? [] : [{ value: "sync" as const, label: t("settings.syncTab") }]), @@ -1023,7 +1009,7 @@ const settingsCategoryNav = computed<{ value: SettingsCategory; label: string }[ ...(isWeb ? [{ value: "security" as const, label: t("settings.securityTab") }] : []), { value: "about", label: t("settings.aboutTab") }, ]); -const settingsTabsWithApplyFooter = new Set(["editor", "formatter", "appearance", "navigation", "data", "redis", "shortcuts", "snippets"]); +const settingsTabsWithApplyFooter = new Set(["editor", "formatter", "appearance", "navigation", "data", "shortcuts", "snippets"]); function hasSettingsApplyFooter(value: SettingsCategory): boolean { return settingsTabsWithApplyFooter.has(value); @@ -2729,23 +2715,6 @@ watch( -
-
- - -

{{ t("settings.redisScanPageSizeDescription") }}

-
-
-
diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.vue b/apps/desktop/src/components/redis/RedisKeyBrowser.vue index 03aaa03e52..98ba4fa87b 100644 --- a/apps/desktop/src/components/redis/RedisKeyBrowser.vue +++ b/apps/desktop/src/components/redis/RedisKeyBrowser.vue @@ -21,7 +21,6 @@ import * as api from "@/lib/api"; import type { RedisKeyInfo, RedisScanResult, RedisValue, HistoryEntry } from "@/lib/api"; import { uuid } from "@/lib/utils"; import { useConnectionStore } from "@/stores/connectionStore"; -import { useSettingsStore } from "@/stores/settingsStore"; import { buildRedisKeyTree, collectExpandedGroupIds, collectRedisGroupKeyRaws, flattenVisibleRedisKeyTree, mergeKeysIntoRedisKeyTree, redisKeyToFlatTreeRow, type RedisKeyTreeNode } from "@/lib/redisKeyTree"; import { classifyRedisCommandSafety } from "@/lib/redisCommandSafety"; import { isRedisMutatingCommand } from "@/lib/redisCommandTable"; @@ -31,11 +30,11 @@ import { isCancelSearchShortcut } from "@/lib/keyboardShortcuts"; import { useEditorFontFamilyStyle } from "@/composables/useEditorFontFamilyStyle"; import { useToast } from "@/composables/useToast"; import { redisKeySearchPattern } from "@/lib/redisKeyPattern"; +import { REDIS_SCAN_PAGE_SIZE_DEFAULT } from "@/lib/redisKeyPattern"; const { t } = useI18n(); const { toast } = useToast(); const connectionStore = useConnectionStore(); -const settingsStore = useSettingsStore(); const editorFontFamilyStyle = useEditorFontFamilyStyle(); type RedisSearchMode = "key" | "value" | "all"; @@ -115,6 +114,7 @@ const searchPlaceholder = computed(() => { }); const loadingEmptyText = computed(() => (isValueSearchMode.value && valueQuery.value ? t(searchMode.value === "all" ? "redis.searchingAll" : "redis.searchingValues") : t("redis.loadingKeys"))); const redisKeySeparator = computed(() => connectionStore.getConfig(props.connectionId)?.redis_key_separator ?? ":"); +const redisScanPageSize = computed(() => connectionStore.getConfig(props.connectionId)?.redis_scan_page_size ?? REDIS_SCAN_PAGE_SIZE_DEFAULT); watch(redisKeySeparator, () => { if (flatKeys.value.length > 0) rebuildTree(false); }); @@ -202,14 +202,14 @@ function mergeTree(newKeys: RedisKeyInfo[]) { } async function fetchScanPage(): Promise { - const pageSize = settingsStore.editorSettings.redisScanPageSize; + const pageSize = redisScanPageSize.value; return isValueSearchMode.value ? await api.redisScanValues(props.connectionId, props.db, scanCursor.value, "*", valueQuery.value, pageSize, searchMode.value === "all") : await api.redisScanKeysBatch(props.connectionId, props.db, scanCursor.value, effectivePattern.value, pageSize, 1, false); } /// Batch-scan variant that performs multiple SCAN iterations server-side. /// Dramatically reduces frontend↔backend roundtrips for bulk loading. async function fetchScanBatchPage(maxIterations: number, options: { count?: number; includeTypes?: boolean } = {}): Promise { - const pageSize = options.count ?? settingsStore.editorSettings.redisScanPageSize; + const pageSize = options.count ?? redisScanPageSize.value; // Value search cannot be batched because each key requires a GET. if (isValueSearchMode.value) { return api.redisScanValues(props.connectionId, props.db, scanCursor.value, "*", valueQuery.value, pageSize, searchMode.value === "all"); @@ -269,19 +269,19 @@ async function streamValueSearch(requestId: number) { } async function fillInitialKeyBatch(requestId: number) { - const targetCount = Math.max(1, settingsStore.editorSettings.redisScanPageSize); - // Use server-side batching to fill the initial view quickly. - // Each batch iteration does one SCAN round-trip; 5 iterations with - // COUNT=1000 should return enough keys for most cases. - const maxIter = Math.max(1, Math.ceil(targetCount / Math.max(1, settingsStore.editorSettings.redisScanPageSize))); - const result = await fetchScanBatchPage(Math.min(maxIter, 8)); - if (requestId !== searchRequestId) return; - appendScanResult(result); - // If we still need more keys, do one more batch - if (flatKeys.value.length < targetCount && hasMore.value && requestId === searchRequestId) { - const result2 = await fetchScanBatchPage(Math.min(maxIter, 8)); + // Initial batch should fetch a substantial number of keys regardless of + // redisScanPageSize. We scan in batches of at most 8 iterations each and + // keep going until we've done at least 16 total iterations (enough to cover + // most key spaces even with COUNT=200) or hasMore becomes false. + const MAX_TOTAL_ITERATIONS = 16; + const BATCH_ITERATIONS = 8; + let totalIters = 0; + while (requestId === searchRequestId && hasMore.value && totalIters < MAX_TOTAL_ITERATIONS) { + const batchSize = Math.min(BATCH_ITERATIONS, MAX_TOTAL_ITERATIONS - totalIters); + const result = await fetchScanBatchPage(batchSize); if (requestId !== searchRequestId) return; - appendScanResult(result2); + appendScanResult(result); + totalIters += batchSize; } } diff --git a/apps/desktop/src/lib/redisKeyPattern.ts b/apps/desktop/src/lib/redisKeyPattern.ts index 91a9b85d79..32060f7f44 100644 --- a/apps/desktop/src/lib/redisKeyPattern.ts +++ b/apps/desktop/src/lib/redisKeyPattern.ts @@ -10,3 +10,10 @@ export function redisKeySearchPattern(value: string, fuzzy: boolean): string { if (!pattern) return "*"; return fuzzy ? `*${escapeRedisGlobText(pattern, fuzzy)}*` : pattern; } + +// Redis scan page size (COUNT parameter per SCAN round-trip) — shared defaults +// and validation bounds used by the connection form and key browser. +export const REDIS_SCAN_PAGE_SIZE_DEFAULT = 1000; +export const REDIS_SCAN_PAGE_SIZE_MIN = 200; +export const REDIS_SCAN_PAGE_SIZE_MAX = 10_000; +export const REDIS_SCAN_PAGE_SIZE_OPTIONS = [200, 1000, 5000, 10_000] as const; diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts index 814c75eece..57573fee41 100644 --- a/apps/desktop/src/stores/connectionStore.ts +++ b/apps/desktop/src/stores/connectionStore.ts @@ -53,6 +53,7 @@ import { encodeSqlServerLinkedSchema, parseSqlServerLinkedSchema } from "@/lib/s import { inferMongoCompletionFields, type MongoCompletionField } from "@/lib/mongoCompletion"; import { completionSchemasFromTree, completionTablesFromTree } from "@/lib/completionTreeIndex"; import { kvRootNodeLabel } from "@/lib/kvRootPresentation"; +import { REDIS_SCAN_PAGE_SIZE_DEFAULT } from "@/lib/redisKeyPattern"; const PINNED_TREE_NODES_STORAGE_KEY = "dbx-pinned-tree-nodes"; const ACTIVE_CONNECTION_STORAGE_KEY = "dbx-active-connection"; @@ -2792,7 +2793,7 @@ export const useConnectionStore = defineStore("connection", () => { if (cached) return cached; return withCompletionInFlight(`${cacheKey}:redis-keys`, async () => { await ensureConnected(connectionId); - const pageSize = settingsStore.editorSettings.redisScanPageSize; + const pageSize = getConfig(connectionId)?.redis_scan_page_size ?? REDIS_SCAN_PAGE_SIZE_DEFAULT; // Bounded multi-round SCAN: trade coverage for latency/memory safety. const result = await api.redisScanKeysBatch(connectionId, Number(database), 0, "*", pageSize, 6, false); const keys = result.keys.map((key) => key.key_display).slice(0, REDIS_COMPLETION_KEYS_MAX); diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts index cb581e1b79..34eb986b73 100644 --- a/apps/desktop/src/stores/settingsStore.ts +++ b/apps/desktop/src/stores/settingsStore.ts @@ -331,7 +331,6 @@ export interface EditorSettings { pageSize: number; infiniteScroll: boolean; infiniteScrollMaxRows: number; - redisScanPageSize: number; mongoViewMode: "document" | "table"; showColumnCommentsInHeader: boolean; showColumnTypesInHeader: boolean; @@ -435,7 +434,6 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = { pageSize: 100, infiniteScroll: false, infiniteScrollMaxRows: 5000, - redisScanPageSize: 1000, mongoViewMode: "document", showColumnCommentsInHeader: true, showColumnTypesInHeader: true, @@ -606,7 +604,6 @@ export function normalizeEditorSettings(settings: Partial, exist pageSize: normalizeResultPageSize(settings.pageSize), infiniteScroll: settings.infiniteScroll ?? DEFAULT_EDITOR_SETTINGS.infiniteScroll, infiniteScrollMaxRows: typeof settings.infiniteScrollMaxRows === "number" && settings.infiniteScrollMaxRows >= 1000 && settings.infiniteScrollMaxRows <= 50000 ? Math.round(settings.infiniteScrollMaxRows) : DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows, - redisScanPageSize: settings.redisScanPageSize ?? DEFAULT_EDITOR_SETTINGS.redisScanPageSize, mongoViewMode: settings.mongoViewMode === "table" ? "table" : DEFAULT_EDITOR_SETTINGS.mongoViewMode, showColumnCommentsInHeader: settings.showColumnCommentsInHeader ?? DEFAULT_EDITOR_SETTINGS.showColumnCommentsInHeader, showColumnTypesInHeader: settings.showColumnTypesInHeader ?? DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader, @@ -778,7 +775,6 @@ export const useSettingsStore = defineStore("settings", () => { if (partial.infiniteScroll !== undefined) editorSettings.value.infiniteScroll = partial.infiniteScroll; if (partial.infiniteScrollMaxRows !== undefined) editorSettings.value.infiniteScrollMaxRows = typeof partial.infiniteScrollMaxRows === "number" && partial.infiniteScrollMaxRows >= 1000 && partial.infiniteScrollMaxRows <= 50000 ? Math.round(partial.infiniteScrollMaxRows) : DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows; - if (partial.redisScanPageSize !== undefined) editorSettings.value.redisScanPageSize = partial.redisScanPageSize; if (partial.mongoViewMode !== undefined) editorSettings.value.mongoViewMode = partial.mongoViewMode; if (partial.showColumnCommentsInHeader !== undefined) editorSettings.value.showColumnCommentsInHeader = partial.showColumnCommentsInHeader; if (partial.showColumnTypesInHeader !== undefined) editorSettings.value.showColumnTypesInHeader = partial.showColumnTypesInHeader; diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts index 071a75105b..3cf5d76092 100644 --- a/apps/desktop/src/types/database.ts +++ b/apps/desktop/src/types/database.ts @@ -146,6 +146,7 @@ export interface ConnectionConfig { redis_sentinel_tls?: boolean; redis_cluster_nodes?: string; redis_key_separator?: string; + redis_scan_page_size?: number; etcd_endpoints?: string; gbase_server?: string; informix_server?: string; diff --git a/crates/dbx-core/src/agent_connection.rs b/crates/dbx-core/src/agent_connection.rs index 2375093c7a..1de88a64ff 100644 --- a/crates/dbx-core/src/agent_connection.rs +++ b/crates/dbx-core/src/agent_connection.rs @@ -606,6 +606,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/cloud_sync.rs b/crates/dbx-core/src/cloud_sync.rs index e3c28f1b75..7033d5ee83 100644 --- a/crates/dbx-core/src/cloud_sync.rs +++ b/crates/dbx-core/src/cloud_sync.rs @@ -639,6 +639,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/connection.rs b/crates/dbx-core/src/connection.rs index a3844088e4..0c583be45a 100644 --- a/crates/dbx-core/src/connection.rs +++ b/crates/dbx-core/src/connection.rs @@ -2416,6 +2416,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/connection_secrets.rs b/crates/dbx-core/src/connection_secrets.rs index 743ac6edb0..a2b75d33bb 100644 --- a/crates/dbx-core/src/connection_secrets.rs +++ b/crates/dbx-core/src/connection_secrets.rs @@ -728,6 +728,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: crate::models::connection::default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/db/redis_driver.rs b/crates/dbx-core/src/db/redis_driver.rs index 71384038dd..b8455f086f 100644 --- a/crates/dbx-core/src/db/redis_driver.rs +++ b/crates/dbx-core/src/db/redis_driver.rs @@ -2615,6 +2615,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: crate::models::connection::default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/models/connection.rs b/crates/dbx-core/src/models/connection.rs index b6fc4c3524..0ef642f4f5 100644 --- a/crates/dbx-core/src/models/connection.rs +++ b/crates/dbx-core/src/models/connection.rs @@ -67,6 +67,8 @@ pub struct ConnectionConfig { pub redis_cluster_nodes: String, #[serde(default = "default_redis_key_separator", skip_serializing_if = "is_default_redis_separator")] pub redis_key_separator: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub redis_scan_page_size: Option, #[serde(default, skip_serializing_if = "String::is_empty")] pub etcd_endpoints: String, #[serde(default, skip_serializing_if = "String::is_empty")] @@ -397,6 +399,8 @@ struct ConnectionConfigData { #[serde(default = "default_redis_key_separator")] pub redis_key_separator: String, #[serde(default)] + pub redis_scan_page_size: Option, + #[serde(default)] pub etcd_endpoints: String, #[serde(default)] pub gbase_server: String, @@ -452,6 +456,7 @@ impl From for ConnectionConfig { redis_sentinel_tls: data.redis_sentinel_tls, redis_cluster_nodes: data.redis_cluster_nodes, redis_key_separator: data.redis_key_separator, + redis_scan_page_size: data.redis_scan_page_size, etcd_endpoints: data.etcd_endpoints, gbase_server: data.gbase_server, informix_server: data.informix_server, @@ -1582,6 +1587,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/mq/config.rs b/crates/dbx-core/src/mq/config.rs index 1e8a45fba0..4918a67622 100644 --- a/crates/dbx-core/src/mq/config.rs +++ b/crates/dbx-core/src/mq/config.rs @@ -132,6 +132,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: String::new(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/mq/service.rs b/crates/dbx-core/src/mq/service.rs index bdf588e59b..be147ec950 100644 --- a/crates/dbx-core/src/mq/service.rs +++ b/crates/dbx-core/src/mq/service.rs @@ -526,6 +526,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: ":".to_string(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/nacos/config.rs b/crates/dbx-core/src/nacos/config.rs index ec1886956b..76230be3e3 100644 --- a/crates/dbx-core/src/nacos/config.rs +++ b/crates/dbx-core/src/nacos/config.rs @@ -159,6 +159,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: ":".to_string(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/nacos/service.rs b/crates/dbx-core/src/nacos/service.rs index 938a22ec21..d79acc52cf 100644 --- a/crates/dbx-core/src/nacos/service.rs +++ b/crates/dbx-core/src/nacos/service.rs @@ -203,6 +203,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: ":".to_string(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), @@ -266,6 +267,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: ":".to_string(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/query.rs b/crates/dbx-core/src/query.rs index 83120379d3..d782530799 100644 --- a/crates/dbx-core/src/query.rs +++ b/crates/dbx-core/src/query.rs @@ -2468,6 +2468,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/schema.rs b/crates/dbx-core/src/schema.rs index 1a780560e7..122d9af67d 100644 --- a/crates/dbx-core/src/schema.rs +++ b/crates/dbx-core/src/schema.rs @@ -1311,6 +1311,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: crate::models::connection::default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/storage.rs b/crates/dbx-core/src/storage.rs index 04cf4d7f12..03134ed01e 100644 --- a/crates/dbx-core/src/storage.rs +++ b/crates/dbx-core/src/storage.rs @@ -1910,6 +1910,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: ":".to_string(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/crates/dbx-core/src/transfer.rs b/crates/dbx-core/src/transfer.rs index 235da32348..6ff619a99f 100644 --- a/crates/dbx-core/src/transfer.rs +++ b/crates/dbx-core/src/transfer.rs @@ -3742,6 +3742,7 @@ mod tests { redis_sentinel_tls: false, redis_cluster_nodes: String::new(), redis_key_separator: default_redis_key_separator(), + redis_scan_page_size: None, etcd_endpoints: String::new(), gbase_server: String::new(), informix_server: String::new(), diff --git a/packages/app-tests/settingsStore.test.ts b/packages/app-tests/settingsStore.test.ts index fbe0ae1e2b..f3932c7168 100644 --- a/packages/app-tests/settingsStore.test.ts +++ b/packages/app-tests/settingsStore.test.ts @@ -39,15 +39,6 @@ function withMockLocalStorage(initial: Record, run: () => void) } } -test("defaults Redis scan page size to 1000 keys", () => { - assert.equal(DEFAULT_EDITOR_SETTINGS.redisScanPageSize, 1000); - assert.equal(normalizeEditorSettings({}).redisScanPageSize, 1000); -}); - -test("keeps a saved Redis scan page size", () => { - assert.equal(normalizeEditorSettings({ redisScanPageSize: 5000 }).redisScanPageSize, 5000); -}); - test("normalizes saved query result page size", () => { assert.equal(DEFAULT_EDITOR_SETTINGS.pageSize, 100); assert.equal(normalizeEditorSettings({ pageSize: 5000 }).pageSize, 5000);