redis load key refactor

This commit is contained in:
SPRINX0\prochazka
2025-05-14 12:44:53 +02:00
parent b16b02c3f1
commit bb076cce5d
5 changed files with 97 additions and 58 deletions

View File

@@ -19,6 +19,12 @@ export interface DbKeysLeafNodeModel extends DbKeysNodeModelBase {
export interface DbKeysFolderNodeModel extends DbKeysNodeModelBase {
// root: string;
type: 'dir';
// visibleCount?: number;
// isExpanded?: boolean;
}
export interface DbKeysFolderStateMode {
key: string;
visibleCount?: number;
isExpanded?: boolean;
}
@@ -27,6 +33,7 @@ export interface DbKeysTreeModel {
treeKeySeparator: string;
root: DbKeysFolderNodeModel;
dirsByKey: { [key: string]: DbKeysFolderNodeModel };
dirStateByKey: { [key: string]: DbKeysFolderStateMode };
childrenByKey: { [key: string]: DbKeysNodeModel[] };
keyObjectsByKey: { [key: string]: DbKeysNodeModel };
scannedKeys: number;
@@ -54,7 +61,10 @@ export interface DbKeysLoadResult {
// export type DbKeysLoadFunction = (root: string, limit: number) => Promise<DbKeysLoadResult>;
export type DbKeysChangeModelFunction = (func: (model: DbKeysTreeModel) => DbKeysTreeModel) => void;
export type DbKeysChangeModelFunction = (
func: (model: DbKeysTreeModel) => DbKeysTreeModel,
loadNextPage: boolean
) => void;
// function dbKeys_findFolderNode(node: DbKeysNodeModel, root: string) {
// if (node.type != 'dir') {
@@ -174,13 +184,11 @@ export function dbKeys_mergeNextPage(tree: DbKeysTreeModel, nextPage: DbKeysLoad
const newDirKey = newDirPath.join(tree.treeKeySeparator);
if (!dirsByKey[newDirKey]) {
dirsByKey[newDirKey] = {
isExpanded: tree.dirsByKey[newDirKey]?.isExpanded ?? false,
level: keyObj.level - 1,
keyPath: newDirPath,
parentKey: newDirPath.slice(0, -1).join(tree.treeKeySeparator),
type: 'dir',
key: newDirKey,
visibleCount: tree.dirsByKey[newDirKey]?.visibleCount ?? SHOW_INCREMENT,
text: `${newDirPath[newDirPath.length - 1]}${tree.treeKeySeparator}*`,
};
}
@@ -204,6 +212,9 @@ export function dbKeys_mergeNextPage(tree: DbKeysTreeModel, nextPage: DbKeysLoad
childrenByKey[dirObj.parentKey] = [];
}
childrenByKey[dirObj.parentKey].push(dirObj);
// set key count
dirsByKey[dirObj.key].count = childrenByKey[dirObj.key].length;
}
for (const key in childrenByKey) {
@@ -223,14 +234,11 @@ export function dbKeys_mergeNextPage(tree: DbKeysTreeModel, nextPage: DbKeysLoad
}
export function dbKeys_markNodeExpanded(tree: DbKeysTreeModel, root: string, isExpanded: boolean): DbKeysTreeModel {
const node = tree.dirsByKey[root];
if (!node) {
return tree;
}
const node = tree.dirStateByKey[root];
return {
...tree,
dirsByKey: {
...tree.dirsByKey,
dirStateByKey: {
...tree.dirStateByKey,
[root]: {
...node,
isExpanded,
@@ -239,24 +247,28 @@ export function dbKeys_markNodeExpanded(tree: DbKeysTreeModel, root: string, isE
};
}
export function dbKeys_refreshAll(treeKeySeparator: string, tree?: DbKeysTreeModel): DbKeysTreeModel {
export function dbKeys_createNewModel(treeKeySeparator: string): DbKeysTreeModel {
const root: DbKeysFolderNodeModel = {
isExpanded: true,
level: 0,
type: 'dir',
keyPath: [],
parentKey: '',
key: '',
visibleCount: SHOW_INCREMENT,
};
return {
...tree,
treeKeySeparator,
childrenByKey: {},
keyObjectsByKey: {},
dirsByKey: {
'': root,
},
dirStateByKey: {
'': {
key: '',
visibleCount: SHOW_INCREMENT,
isExpanded: true,
},
},
scannedKeys: 0,
dbsize: 0,
loadCount: 2000,
@@ -266,6 +278,21 @@ export function dbKeys_refreshAll(treeKeySeparator: string, tree?: DbKeysTreeMod
};
}
export function dbKeys_clearLoadedData(tree: DbKeysTreeModel): DbKeysTreeModel {
return {
...tree,
childrenByKey: {},
keyObjectsByKey: {},
dirsByKey: {
'': tree.root,
},
scannedKeys: 0,
dbsize: 0,
cursor: '0',
loadedAll: false,
};
}
// export function dbKeys_reloadFolder(tree: DbKeysTreeModel, root: string): DbKeysTreeModel {
// return {
// ...tree,
@@ -282,8 +309,8 @@ export function dbKeys_refreshAll(treeKeySeparator: string, tree?: DbKeysTreeMod
// }
function addFlatItems(tree: DbKeysTreeModel, root: string, res: DbKeysNodeModel[], visitedRoots: string[] = []) {
const item = tree.dirsByKey[root];
if (!item.isExpanded) {
const item = tree.dirStateByKey[root];
if (!item?.isExpanded) {
return false;
}
const children = tree.childrenByKey[root] || [];

View File

@@ -46,7 +46,7 @@
icon="icon dots-horizontal"
expandIcon="icon invisible-box"
on:click={() => {
changeModel(model => dbKeys_markNodeExpanded(model, key, true));
changeModel(model => dbKeys_markNodeExpanded(model, key, true), false);
}}
/>
{/if}

View File

@@ -1,9 +1,10 @@
<script lang="ts">
import {
dbKeys_clearLoadedData,
dbKeys_createNewModel,
dbKeys_getFlatList,
dbKeys_markNodeExpanded,
dbKeys_mergeNextPage,
dbKeys_refreshAll,
findEngineDriver,
} from 'dbgate-tools';
@@ -32,7 +33,6 @@
import AppObjectListHandler from './AppObjectListHandler.svelte';
import { getOpenDetailOnArrowsSettings } from '../settings/settingsTools';
import openNewTab from '../utility/openNewTab';
import clickOutside from '../utility/clickOutside';
export let conid;
export let database;
@@ -43,12 +43,9 @@
let domFilter = null;
let filter;
let isLoading = false;
let model = dbKeys_refreshAll(treeKeySeparator);
function handleRefreshDatabase() {
changeModel(model => dbKeys_refreshAll(treeKeySeparator, model));
}
let model = dbKeys_createNewModel(treeKeySeparator);
function handleAddKey() {
const connection = $currentDatabase?.connection;
@@ -69,7 +66,7 @@
args: [item.keyName, ...type.dbKeyFields.map(fld => item[fld.name])],
});
handleRefreshDatabase();
reloadModel();
},
});
}
@@ -81,11 +78,13 @@
$: connection = useConnectionInfo({ conid });
function changeModel(modelUpdate) {
model = modelUpdate(model);
function changeModel(modelUpdate, loadNext) {
if (modelUpdate) model = modelUpdate(model);
if (loadNext) loadNextPage();
}
async function loadNextPage() {
isLoading = true;
const nextScan = await apiCall('database-connections/scan-keys', {
conid,
database,
@@ -95,11 +94,11 @@
});
model = dbKeys_mergeNextPage(model, nextScan);
isLoading = false;
}
function reloadModel() {
changeModel(model => dbKeys_refreshAll(treeKeySeparator, model));
loadNextPage();
changeModel(model => dbKeys_clearLoadedData(model), true);
}
$: {
@@ -109,7 +108,7 @@
reloadModel();
}
$: console.log('DbKeysTree MODEL', model);
// $: console.log('DbKeysTree MODEL', model);
</script>
<SearchBoxWrapper noMargin>
@@ -126,20 +125,32 @@
<InlineButton on:click={handleAddKey} title="Add new key">
<FontIcon icon="icon plus-thick" />
</InlineButton>
<InlineButton on:click={handleRefreshDatabase} title="Refresh key list">
<InlineButton on:click={reloadModel} title="Refresh key list">
<FontIcon icon="icon refresh" />
</InlineButton>
</SearchBoxWrapper>
<div class="space-between align-items-center ml-1">
{#if model}
<div>
Scanned {Math.min(model?.scannedKeys, model?.dbsize) ?? '???'}/{model?.dbsize ?? '???'}
</div>
{/if}
<InlineButton on:click={loadNextPage} title="Scan more keys">
<FontIcon icon="icon more" /> Scan more
</InlineButton>
</div>
{#if !model?.loadedAll}
<div class="space-between align-items-center ml-1">
{#if model}
<div>
{#if isLoading}
Loading...
{:else}
Scanned {Math.min(model?.scannedKeys, model?.dbsize) ?? '???'}/{model?.dbsize ?? '???'}
{/if}
</div>
{/if}
{#if isLoading}
<div style="margin: 3px; margin-bottom: 2px">
<FontIcon icon="icon loading" />
</div>
{:else}
<InlineButton on:click={loadNextPage} title="Scan more keys">
<FontIcon icon="icon more" /> Scan more
</InlineButton>
{/if}
</div>
{/if}
{#if differentFocusedDb}
<FocusedConnectionInfoWidget {conid} {database} connection={$connection} />
{/if}
@@ -172,11 +183,11 @@
};
}
if (data.key && clickAction == 'keyEnter') {
changeModel(model => dbKeys_markNodeExpanded(model, data.key, !model.dirsByKey[data.key]?.isExpanded));
changeModel(model => dbKeys_markNodeExpanded(model, data.key, !model.dirsByKey[data.key]?.isExpanded), false);
}
}}
handleExpansion={(data, value) => {
changeModel(model => dbKeys_markNodeExpanded(model, data.key, value));
changeModel(model => dbKeys_markNodeExpanded(model, data.key, value), false);
}}
onScrollTop={() => {
domContainer?.scrollTop();

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import {
dbKeys_clearLoadedData,
dbKeys_markNodeExpanded,
dbKeys_reloadFolder,
DbKeysChangeModelFunction,
DbKeysTreeModel,
getIconForRedisType,
@@ -36,7 +36,7 @@
export let model: DbKeysTreeModel;
export let changeModel: DbKeysChangeModelFunction;
$: isExpanded = model.dirsByKey[item.key]?.isExpanded;
$: isExpanded = model.dirStateByKey[item.key]?.isExpanded;
// $: console.log(item.text, indentLevel);
function createMenu() {
@@ -55,7 +55,7 @@
args: [item.key],
});
changeModel(m => dbKeys_reloadFolder(m, key));
changeModel(m => dbKeys_clearLoadedData(m), true);
},
});
},
@@ -76,23 +76,23 @@
args: [item.key, newName],
});
changeModel(m => dbKeys_reloadFolder(m, key));
changeModel(m => dbKeys_clearLoadedData(m), true);
},
});
},
},
item.type == 'dir' &&
!connection?.isReadOnly && {
label: 'Reload',
onClick: () => {
changeModel(m => dbKeys_reloadFolder(m, key));
},
},
// item.type == 'dir' &&
// !connection?.isReadOnly && {
// label: 'Reload',
// onClick: () => {
// changeModel(m => dbKeys_clearLoadedData(m), true);
// },
// },
item.type == 'dir' &&
!connection?.isReadOnly && {
label: 'Delete branch',
onClick: () => {
const branch = `${item.root}:*`;
const branch = `${item.key}:*`;
showModal(ConfirmModal, {
message: `Really delete branch ${branch} with all keys?`,
onConfirm: async () => {
@@ -103,7 +103,7 @@
args: [branch],
});
changeModel(m => dbKeys_reloadFolder(m, key));
changeModel(m => dbKeys_clearLoadedData(m), true);
},
});
},
@@ -141,12 +141,12 @@
expandIcon={item.type == 'dir' ? plusExpandIcon(isExpanded) : 'icon invisible-box'}
on:expand={() => {
if (item.type == 'dir') {
changeModel(tree => dbKeys_markNodeExpanded(tree, item.key, !isExpanded));
changeModel(tree => dbKeys_markNodeExpanded(tree, item.key, !isExpanded), false);
}
}}
on:click={() => {
if (item.type == 'dir') {
changeModel(tree => dbKeys_markNodeExpanded(tree, item.key, !isExpanded));
changeModel(tree => dbKeys_markNodeExpanded(tree, item.key, !isExpanded), false);
} else {
openNewTab({
tabComponent: 'DbKeyDetailTab',

View File

@@ -202,7 +202,8 @@ const driver = {
},
async scanKeys(dbhan, pattern, cursor = 0, count) {
const [nextCursor, keys] = await dbhan.client.scan(cursor, 'MATCH', pattern || '*', 'COUNT', count);
const match = pattern?.match(/[\?\[\{]/) ? pattern : pattern ? `*${pattern}*` : '*';
const [nextCursor, keys] = await dbhan.client.scan(cursor, 'MATCH', match, 'COUNT', count);
const dbsize = await dbhan.client.dbsize();
const keysMapped = keys.map((key) => ({
key,