diff --git a/db_redis.go b/db_redis.go index e7b4591..053799d 100644 --- a/db_redis.go +++ b/db_redis.go @@ -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 + for _, key := range allKeys { + val, err := ld.db.Get(ctx, key).Result() + if err != nil { + vcl.ShowMessage(fmt.Sprintf("Listing keys in database %q: %v", ndata.bucketPath[0], err)) + return } - // 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 { - vcl.ShowMessage(fmt.Sprintf("Failed to load data for bucket %q: %s", bucketDisplayName, err.Error())) - 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) {