qbolt: do more work in []byte space instead of strings

This commit is contained in:
mappu 2025-04-17 21:25:02 +12:00
parent 09a3e5b90f
commit 7ae6462da0
3 changed files with 41 additions and 22 deletions

30
bolt.go
View File

@ -95,7 +95,7 @@ func Bolt_DeleteBucket(db *bolt.DB, browse []string, delBucket string) error {
}) })
} }
func Bolt_SetItem(db *bolt.DB, browse []string, key, val string) error { func Bolt_SetItem(db *bolt.DB, browse []string, key, val []byte) error {
if len(browse) == 0 { if len(browse) == 0 {
return errors.New("Can't create top-level items") return errors.New("Can't create top-level items")
} }
@ -107,11 +107,11 @@ func Bolt_SetItem(db *bolt.DB, browse []string, key, val string) error {
return err return err
} }
return bucket.Put([]byte(key), []byte(val)) return bucket.Put(key, val)
}) })
} }
func Bolt_DeleteItem(db *bolt.DB, browse []string, key string) error { func Bolt_DeleteItem(db *bolt.DB, browse []string, key []byte) error {
if len(browse) == 0 { if len(browse) == 0 {
return errors.New("Can't create top-level items") return errors.New("Can't create top-level items")
} }
@ -123,7 +123,7 @@ func Bolt_DeleteItem(db *bolt.DB, browse []string, key string) error {
return err return err
} }
return bucket.Delete([]byte(key)) return bucket.Delete(key)
}) })
} }
@ -155,14 +155,13 @@ func Bolt_BucketStats(db *bolt.DB, browse []string) (string, error) {
return string(jBytes), err return string(jBytes), err
} }
func Bolt_ListBuckets(db *bolt.DB, browse []string, cb func(b string)) error { func Bolt_ListBuckets(db *bolt.DB, browse []string, cb func(b string) error) error {
if len(browse) == 0 { if len(browse) == 0 {
// root mode // root mode
return db.View(func(tx *bolt.Tx) error { return db.View(func(tx *bolt.Tx) error {
return tx.ForEach(func(k []byte, _ *bolt.Bucket) error { return tx.ForEach(func(k []byte, _ *bolt.Bucket) error {
cb(string(k)) return cb(string(k))
return nil
}) })
}) })
@ -173,7 +172,7 @@ func Bolt_ListBuckets(db *bolt.DB, browse []string, cb func(b string)) error {
return bucket.ForEach(func(k, v []byte) error { return bucket.ForEach(func(k, v []byte) error {
// non-nil v means it's a data item // non-nil v means it's a data item
if v == nil { if v == nil {
cb(string(k)) return cb(string(k))
} }
return nil return nil
}) })
@ -181,7 +180,7 @@ func Bolt_ListBuckets(db *bolt.DB, browse []string, cb func(b string)) error {
} }
type ListItemInfo struct { type ListItemInfo struct {
Name string Name []byte
DataLen int64 DataLen int64
} }
@ -198,17 +197,22 @@ func Bolt_ListItems(db *bolt.DB, browse []string, cb func(ListItemInfo) error) e
return nil // nil v means it's a bucket, skip return nil // nil v means it's a bucket, skip
} }
return cb(ListItemInfo{string(k), int64(len(v))}) kcopy := make([]byte, len(k))
copy(kcopy, k)
return cb(ListItemInfo{kcopy, int64(len(v))})
}) })
}) })
} }
func Bolt_GetItem(db *bolt.DB, browse []string, key string) (string, error) { func Bolt_GetItem(db *bolt.DB, browse []string, key []byte) ([]byte, error) {
var ret string var ret []byte
err := withBrowse_ReadOnly(db, browse, func(tx *bolt.Tx, bucket *bolt.Bucket) error { err := withBrowse_ReadOnly(db, browse, func(tx *bolt.Tx, bucket *bolt.Bucket) error {
d := bucket.Get([]byte(key)) d := bucket.Get([]byte(key))
ret = string(d)
ret = make([]byte, len(d))
copy(ret, d)
return nil return nil
}) })
return ret, err return ret, err

View File

@ -153,15 +153,17 @@ func (this *MainWindow) refreshBucketTree(itm *qt.QTreeWidgetItem) {
i -= 1 i -= 1
} }
err := Bolt_ListBuckets(ws.bdb, ws.browse, func(qba string) { err := Bolt_ListBuckets(ws.bdb, ws.browse, func(qba string) error {
child := qt.NewQTreeWidgetItem6(itm) // NewQTreeWidgetItem() child := qt.NewQTreeWidgetItem6(itm) // NewQTreeWidgetItem()
child.SetText(0, getDisplayName(qba)) child.SetText(0, getDisplayName([]byte(qba)))
child.SetData(0, BinaryDataRole, qt.NewQVariant12([]byte(qba))) child.SetData(0, BinaryDataRole, qt.NewQVariant12([]byte(qba)))
child.SetIcon(0, qt.NewQIcon4(":/rsrc/table.png")) child.SetIcon(0, qt.NewQIcon4(":/rsrc/table.png"))
itm.AddChild(child) itm.AddChild(child)
this.refreshBucketTree(child) this.refreshBucketTree(child)
return nil
}) })
if err != nil { if err != nil {
this.alert(fmt.Sprintf("Error listing buckets under %s: %s", strings.Join(ws.browse, `/`), err.Error())) this.alert(fmt.Sprintf("Error listing buckets under %s: %s", strings.Join(ws.browse, `/`), err.Error()))
@ -340,7 +342,7 @@ func (this *MainWindow) getSelection(itm *qt.QTreeWidgetItem) windowSelection {
return windowSelection{itm: itm, top: top, browse: browse, bdb: bdb} return windowSelection{itm: itm, top: top, browse: browse, bdb: bdb}
} }
func (this *MainWindow) openEditor(bdb *bolt.DB, saveAs []string, saveAsKey string, currentContent []byte) { func (this *MainWindow) openEditor(bdb *bolt.DB, saveAs []string, saveAsKey []byte, currentContent []byte) {
iw := NewItemWindowUi() iw := NewItemWindowUi()
iw.contentArea.SetPlainText(string(currentContent)) iw.contentArea.SetPlainText(string(currentContent))
@ -349,7 +351,7 @@ func (this *MainWindow) openEditor(bdb *bolt.DB, saveAs []string, saveAsKey stri
iw.ItemWindow.OnFinished(func(exitCode int) { iw.ItemWindow.OnFinished(func(exitCode int) {
if exitCode == int(qt.QDialog__Accepted) { if exitCode == int(qt.QDialog__Accepted) {
err := Bolt_SetItem(bdb, saveAs, saveAsKey, iw.contentArea.ToPlainText()) err := Bolt_SetItem(bdb, saveAs, saveAsKey, []byte(iw.contentArea.ToPlainText()))
if err != nil { if err != nil {
this.alert(fmt.Sprintf("Error saving item content: %s", err.Error())) this.alert(fmt.Sprintf("Error saving item content: %s", err.Error()))
} }
@ -370,7 +372,7 @@ func (this *MainWindow) on_bucketData_doubleClicked(index *qt.QModelIndex) {
// Get item key // Get item key
key := string(index.DataWithRole(BinaryDataRole).ToByteArray()) key := index.DataWithRole(BinaryDataRole).ToByteArray()
// DB lookup // DB lookup
content, err := Bolt_GetItem(ws.bdb, ws.browse, key) content, err := Bolt_GetItem(ws.bdb, ws.browse, key)
@ -414,7 +416,7 @@ func (this *MainWindow) on_actionDelete_bucket_triggered() {
} }
// Prompt for confirmation // Prompt for confirmation
bucketToDelete := string(ws.itm.Data(0, BinaryDataRole).ToByteArray()) bucketToDelete := ws.itm.Data(0, BinaryDataRole).ToByteArray()
if qt.QMessageBox_Question2( if qt.QMessageBox_Question2(
this.Widget(), this.Widget(),
"Delete bucket", "Delete bucket",
@ -433,7 +435,7 @@ func (this *MainWindow) on_actionDelete_bucket_triggered() {
ws.browse = ws.browse[0 : len(ws.browse)-1] ws.browse = ws.browse[0 : len(ws.browse)-1]
} }
err := Bolt_DeleteBucket(ws.bdb, ws.browse, bucketToDelete) err := Bolt_DeleteBucket(ws.bdb, ws.browse, string(bucketToDelete))
if err != nil { if err != nil {
this.alert(fmt.Sprintf("Error removing bucket: %s", err.Error())) this.alert(fmt.Sprintf("Error removing bucket: %s", err.Error()))
return return
@ -458,7 +460,7 @@ func (this *MainWindow) on_AddDataButton_clicked() {
return return
} }
this.openEditor(ws.bdb, ws.browse, name, []byte("")) this.openEditor(ws.bdb, ws.browse, []byte(name), []byte(""))
} }
func (this *MainWindow) on_DeleteDataButton_clicked() { func (this *MainWindow) on_DeleteDataButton_clicked() {
@ -479,7 +481,7 @@ func (this *MainWindow) on_DeleteDataButton_clicked() {
var i int = len(selection) var i int = len(selection)
for i > 0 { for i > 0 {
err := Bolt_DeleteItem(ws.bdb, ws.browse, string(selection[i-1].Data(0, BinaryDataRole).ToByteArray())) err := Bolt_DeleteItem(ws.bdb, ws.browse, selection[i-1].Data(0, BinaryDataRole).ToByteArray())
if err != nil { if err != nil {
this.alert(fmt.Sprintf("Error removing item: %s", err.Error())) this.alert(fmt.Sprintf("Error removing item: %s", err.Error()))
return return

13
util.go
View File

@ -1,5 +1,18 @@
package main package main
import (
"strconv"
)
func getDisplayName(qba []byte) string {
if len(qba) ==0 {
return "<empty>"
}
ret := strconv.Quote(string(qba))
return ret[1 : len(ret)-1]
}
// ReverseSlice reverses a slice. // ReverseSlice reverses a slice.
// @ref https://stackoverflow.com/a/28058324 // @ref https://stackoverflow.com/a/28058324
func ReverseSlice[S ~[]E, E any](s S) { func ReverseSlice[S ~[]E, E any](s S) {