redis: complete basic multidatabase browse support

This commit is contained in:
mappu 2024-06-23 14:54:33 +12:00
parent 8cac46e9f2
commit 5992d19906
1 changed files with 66 additions and 33 deletions

View File

@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
@ -10,7 +9,7 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"github.com/ying32/govcl/vcl" "github.com/ying32/govcl/vcl"
// "github.com/ying32/govcl/vcl/types" "github.com/ying32/govcl/vcl/types"
) )
type redisLoadedDatabase struct { type redisLoadedDatabase struct {
@ -42,20 +41,43 @@ func (ld *redisLoadedDatabase) Keepalive(ndata *navData) {
} }
func (ld *redisLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) { func (ld *redisLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) {
ctx := context.Background()
/* if len(ndata.bucketPath) == 0 {
// Load properties // Top-level: Show info() on main Properties tab
infostr, err := ld.db.Info(ctx).Result()
if err != nil {
vcl.ShowMessage(fmt.Sprintf("Retreiving database info: %v", err))
return
}
bucketDisplayName := strings.Join(ndata.bucketPath, `/`) f.propertiesBox.SetText(infostr)
content := fmt.Sprintf("Selected database: %#v\n\n\nSelected bucket: %q\n", ld.db.Stats(), bucketDisplayName)
f.propertiesBox.SetText(content)
// Load data
// Disable data tab
f.contentBox.SetEnabled(false) f.contentBox.SetEnabled(false)
f.contentBox.Clear() f.contentBox.Clear()
// Bolt always uses Key + Value as the columns } else if len(ndata.bucketPath) == 1 {
// One selected database
// Figure out its content
err := ld.db.Do(ctx, "SELECT", ndata.bucketPath[0]).Err()
if err != nil {
vcl.ShowMessage(fmt.Sprintf("Switching to database %q: %v", ndata.bucketPath[0], err))
return
}
allKeys, err := ld.db.Keys(ctx, "*").Result()
if err != nil {
vcl.ShowMessage(fmt.Sprintf("Listing keys in database %q: %v", ndata.bucketPath[0], err))
return
}
f.propertiesBox.SetText(fmt.Sprintf("Database %s\nTotal keys: %d\n", ndata.bucketPath[0], len(allKeys)))
// Redis always uses Key + Value as the columns
f.contentBox.SetEnabled(false)
f.contentBox.Clear()
f.contentBox.Columns().Clear() f.contentBox.Columns().Clear()
colKey := f.contentBox.Columns().Add() colKey := f.contentBox.Columns().Add()
@ -65,37 +87,48 @@ func (ld *redisLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) {
colVal := f.contentBox.Columns().Add() colVal := f.contentBox.Columns().Add()
colVal.SetCaption("Value") colVal.SetCaption("Value")
err := ld.db.View(func(tx *bbolt.Tx) error { for _, key := range allKeys {
b := boltTargetBucket(tx, ndata.bucketPath) val, err := ld.db.Get(ctx, key).Result()
if b == nil {
// no such bucket
return nil
}
// Valid
f.contentBox.Clear()
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
dataEntry := f.contentBox.Items().Add()
dataEntry.SetCaption(formatUtf8(k))
dataEntry.SubItems().Add(formatUtf8(v))
}
return nil
})
if err != nil { if err != nil {
vcl.ShowMessage(fmt.Sprintf("Failed to load data for bucket %q: %s", bucketDisplayName, err.Error())) vcl.ShowMessage(fmt.Sprintf("Listing keys in database %q: %v", ndata.bucketPath[0], err))
return return
} }
dataEntry := f.contentBox.Items().Add()
dataEntry.SetCaption(key) // formatUtf8
dataEntry.SubItems().Add(val) // formatUtf8
}
// Valid // Valid
f.contentBox.SetEnabled(true)*/ f.contentBox.SetEnabled(true)
} else {
vcl.ShowMessage(fmt.Sprintf("Unexpected nav position %q", ndata.bucketPath))
return
}
} }
func (ld *redisLoadedDatabase) NavChildren(ndata *navData) ([]string, error) { func (ld *redisLoadedDatabase) NavChildren(ndata *navData) ([]string, error) {
// In the bolt implementation, the nav is a recursive tree of child buckets // ctx := context.Background()
return nil, errors.New("TODO")
//return boltChildBucketNames(ld.db, ndata.bucketPath) if len(ndata.bucketPath) == 0 {
// Top-level: list of all child databases (usually 16x)
ret := make([]string, 0, ld.maxDb)
for i := 0; i < ld.maxDb; i++ {
ret = append(ret, fmt.Sprintf("%d", i))
}
return ret, nil
} else if len(ndata.bucketPath) == 1 {
// One selected database
// No child keys underneath it
return []string{}, nil
} else {
return nil, fmt.Errorf("Unexpected nav position %q", ndata.bucketPath)
}
} }
func (ld *redisLoadedDatabase) ExecQuery(query string, resultArea *vcl.TListView) { func (ld *redisLoadedDatabase) ExecQuery(query string, resultArea *vcl.TListView) {