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 (
"context"
"errors"
"fmt"
"strconv"
"strings"
@ -10,7 +9,7 @@ import (
"github.com/redis/go-redis/v9"
"github.com/ying32/govcl/vcl"
// "github.com/ying32/govcl/vcl/types"
"github.com/ying32/govcl/vcl/types"
)
type redisLoadedDatabase struct {
@ -42,20 +41,43 @@ func (ld *redisLoadedDatabase) Keepalive(ndata *navData) {
}
func (ld *redisLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) {
ctx := context.Background()
/*
// Load properties
if len(ndata.bucketPath) == 0 {
// 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, `/`)
content := fmt.Sprintf("Selected database: %#v\n\n\nSelected bucket: %q\n", ld.db.Stats(), bucketDisplayName)
f.propertiesBox.SetText(content)
// Load data
f.propertiesBox.SetText(infostr)
// Disable data tab
f.contentBox.SetEnabled(false)
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()
colKey := f.contentBox.Columns().Add()
@ -65,37 +87,48 @@ func (ld *redisLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) {
colVal := f.contentBox.Columns().Add()
colVal.SetCaption("Value")
err := ld.db.View(func(tx *bbolt.Tx) error {
b := boltTargetBucket(tx, ndata.bucketPath)
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
})
for _, key := range allKeys {
val, err := ld.db.Get(ctx, key).Result()
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
}
dataEntry := f.contentBox.Items().Add()
dataEntry.SetCaption(key) // formatUtf8
dataEntry.SubItems().Add(val) // formatUtf8
}
// 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) {
// In the bolt implementation, the nav is a recursive tree of child buckets
return nil, errors.New("TODO")
//return boltChildBucketNames(ld.db, ndata.bucketPath)
// ctx := context.Background()
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) {