Commit and run

This commit is contained in:
Brian Buller 2019-10-24 11:11:09 -05:00
parent 4ab1f201c5
commit 7b683d5c71
6 changed files with 364 additions and 172 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"bytes"
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
) )
@ -16,11 +17,17 @@ type BoltDB struct {
buckets []BoltBucket buckets []BoltBucket
} }
type PathNode struct {
name []byte
dataType Datatype
}
/* /*
BoltBucket is just a struct representation of a Bucket in the Bolt DB BoltBucket is just a struct representation of a Bucket in the Bolt DB
*/ */
type BoltBucket struct { type BoltBucket struct {
name string name []byte
nameDatatype Datatype
pairs []BoltPair pairs []BoltPair
buckets []BoltBucket buckets []BoltBucket
parent *BoltBucket parent *BoltBucket
@ -28,17 +35,52 @@ type BoltBucket struct {
errorFlag bool errorFlag bool
} }
func (b *BoltBucket) SetName(nm []byte) {
b.name = nm
for _, dtk := range dataTypeNameSlice {
if _, err := datatypes[dtk].ToString(nm); err == nil {
b.nameDatatype = datatypes[dtk]
break
}
}
}
/* /*
BoltPair is just a struct representation of a Pair in the Bolt DB BoltPair is just a struct representation of a Pair in the Bolt DB
*/ */
type BoltPair struct { type BoltPair struct {
parent *BoltBucket parent *BoltBucket
key string key []byte
val string val []byte
dataType *Datatype keyDatatype Datatype
valDatatype Datatype
} }
func (bd *BoltDB) getGenericFromPath(path []string) (*BoltBucket, *BoltPair, error) { func NewBoltPair(parent *BoltBucket, key, val []byte) *BoltPair {
tp := BoltPair{
key: key,
val: val,
}
for _, dtk := range dataTypeNameSlice {
if _, err := datatypes[dtk].ToString(key); err == nil {
tp.keyDatatype = datatypes[dtk]
break
}
}
for _, dtk := range dataTypeNameSlice {
if _, err := datatypes[dtk].ToString(val); err == nil {
tp.valDatatype = datatypes[dtk]
break
}
}
return &tp
}
func (bd *BoltDB) getGenericFromStringPath(path []string) (*BoltBucket, *BoltPair, error) {
return bd.getGenericFromPath(stringPathToBytePath(path))
}
func (bd *BoltDB) getGenericFromPath(path []PathNode) (*BoltBucket, *BoltPair, error) {
// Check if 'path' leads to a pair // Check if 'path' leads to a pair
p, err := bd.getPairFromPath(path) p, err := bd.getPairFromPath(path)
if err == nil { if err == nil {
@ -53,19 +95,19 @@ func (bd *BoltDB) getGenericFromPath(path []string) (*BoltBucket, *BoltPair, err
return nil, nil, errors.New("Invalid Path") return nil, nil, errors.New("Invalid Path")
} }
func (bd *BoltDB) getBucketFromPath(path []string) (*BoltBucket, error) { func (bd *BoltDB) getBucketFromPath(path []PathNode) (*BoltBucket, error) {
if len(path) > 0 { if len(path) > 0 {
// Find the BoltBucket with a path == path // Find the BoltBucket with a path == path
var b *BoltBucket var b *BoltBucket
var err error var err error
// Find the root bucket // Find the root bucket
b, err = memBolt.getBucket(path[0]) b, err = memBolt.getBucket(path[0].name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(path) > 1 { if len(path) > 1 {
for p := 1; p < len(path); p++ { for p := 1; p < len(path); p++ {
b, err = b.getBucket(path[p]) b, err = b.getBucket(path[p].name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -76,7 +118,7 @@ func (bd *BoltDB) getBucketFromPath(path []string) (*BoltBucket, error) {
return nil, errors.New("Invalid Path") return nil, errors.New("Invalid Path")
} }
func (bd *BoltDB) getPairFromPath(path []string) (*BoltPair, error) { func (bd *BoltDB) getPairFromPath(path []PathNode) (*BoltPair, error) {
if len(path) <= 0 { if len(path) <= 0 {
return nil, errors.New("No Path") return nil, errors.New("No Path")
} }
@ -85,11 +127,11 @@ func (bd *BoltDB) getPairFromPath(path []string) (*BoltPair, error) {
return nil, err return nil, err
} }
// Found the bucket, pull out the pair // Found the bucket, pull out the pair
p, err := b.getPair(path[len(path)-1]) p, err := b.getPair(path[len(path)-1].name)
return p, err return p, err
} }
func (bd *BoltDB) getVisibleItemCount(path []string) (int, error) { func (bd *BoltDB) getVisibleItemCount(path []PathNode) (int, error) {
vis := 0 vis := 0
var retErr error var retErr error
if len(path) == 0 { if len(path) == 0 {
@ -124,12 +166,12 @@ func (bd *BoltDB) getVisibleItemCount(path []string) (int, error) {
return vis, retErr return vis, retErr
} }
func (bd *BoltDB) buildVisiblePathSlice() ([][]string, error) { func (bd *BoltDB) buildVisiblePathSlice() ([][]PathNode, error) {
var retSlice [][]string var retSlice [][]string
var retErr error var retErr error
// The root path, recurse for root buckets // The root path, recurse for root buckets
for i := range bd.buckets { for i := range bd.buckets {
bktS, bktErr := bd.buckets[i].buildVisiblePathSlice([]string{}) bktS, bktErr := bd.buckets[i].buildVisiblePathSlice([]PathNode{})
if bktErr == nil { if bktErr == nil {
retSlice = append(retSlice, bktS...) retSlice = append(retSlice, bktS...)
} else { } else {
@ -140,7 +182,7 @@ func (bd *BoltDB) buildVisiblePathSlice() ([][]string, error) {
return retSlice, retErr return retSlice, retErr
} }
func (bd *BoltDB) getPrevVisiblePath(path []string) []string { func (bd *BoltDB) getPrevVisiblePath(path []PathNode) []PathNode {
visPaths, err := bd.buildVisiblePathSlice() visPaths, err := bd.buildVisiblePathSlice()
if path == nil { if path == nil {
if len(visPaths) > 0 { if len(visPaths) > 0 {
@ -152,7 +194,7 @@ func (bd *BoltDB) getPrevVisiblePath(path []string) []string {
for idx, pth := range visPaths { for idx, pth := range visPaths {
isCurPath := true isCurPath := true
for i := range path { for i := range path {
if len(pth) <= i || path[i] != pth[i] { if len(pth) <= i || !bytes.Equal(path[i].name, pth[i].name) {
isCurPath = false isCurPath = false
break break
} }
@ -164,7 +206,7 @@ func (bd *BoltDB) getPrevVisiblePath(path []string) []string {
} }
return nil return nil
} }
func (bd *BoltDB) getNextVisiblePath(path []string) []string { func (bd *BoltDB) getNextVisiblePath(path []PathNode) []PathNode {
visPaths, err := bd.buildVisiblePathSlice() visPaths, err := bd.buildVisiblePathSlice()
if path == nil { if path == nil {
if len(visPaths) > 0 { if len(visPaths) > 0 {
@ -176,7 +218,7 @@ func (bd *BoltDB) getNextVisiblePath(path []string) []string {
for idx, pth := range visPaths { for idx, pth := range visPaths {
isCurPath := true isCurPath := true
for i := range path { for i := range path {
if len(pth) <= i || path[i] != pth[i] { if len(pth) <= i || !bytes.Equal(path[i].name, pth[i].name) {
isCurPath = false isCurPath = false
break break
} }
@ -189,7 +231,7 @@ func (bd *BoltDB) getNextVisiblePath(path []string) []string {
return nil return nil
} }
func (bd *BoltDB) toggleOpenBucket(path []string) error { func (bd *BoltDB) toggleOpenBucket(path []PathNode) error {
// Find the BoltBucket with a path == path // Find the BoltBucket with a path == path
b, err := bd.getBucketFromPath(path) b, err := bd.getBucketFromPath(path)
if err == nil { if err == nil {
@ -198,7 +240,7 @@ func (bd *BoltDB) toggleOpenBucket(path []string) error {
return err return err
} }
func (bd *BoltDB) closeBucket(path []string) error { func (bd *BoltDB) closeBucket(path []PathNode) error {
// Find the BoltBucket with a path == path // Find the BoltBucket with a path == path
b, err := bd.getBucketFromPath(path) b, err := bd.getBucketFromPath(path)
if err == nil { if err == nil {
@ -207,7 +249,7 @@ func (bd *BoltDB) closeBucket(path []string) error {
return err return err
} }
func (bd *BoltDB) openBucket(path []string) error { func (bd *BoltDB) openBucket(path []PathNode) error {
// Find the BoltBucket with a path == path // Find the BoltBucket with a path == path
b, err := bd.getBucketFromPath(path) b, err := bd.getBucketFromPath(path)
if err == nil { if err == nil {
@ -216,9 +258,9 @@ func (bd *BoltDB) openBucket(path []string) error {
return err return err
} }
func (bd *BoltDB) getBucket(k string) (*BoltBucket, error) { func (bd *BoltDB) getBucket(k []byte) (*BoltBucket, error) {
for i := range bd.buckets { for i := range bd.buckets {
if bd.buckets[i].name == k { if bytes.Equal(bd.buckets[i].name, k) {
return &bd.buckets[i], nil return &bd.buckets[i], nil
} }
} }
@ -236,7 +278,7 @@ func (bd *BoltDB) syncOpenBuckets(shadow *BoltDB) {
// First test this bucket // First test this bucket
for i := range bd.buckets { for i := range bd.buckets {
for j := range shadow.buckets { for j := range shadow.buckets {
if bd.buckets[i].name == shadow.buckets[j].name { if bytes.Equal(bd.buckets[i].name, shadow.buckets[j].name) {
bd.buckets[i].syncOpenBuckets(&shadow.buckets[j]) bd.buckets[i].syncOpenBuckets(&shadow.buckets[j])
} }
} }
@ -250,7 +292,7 @@ func (bd *BoltDB) refreshDatabase() *BoltDB {
return tx.ForEach(func(nm []byte, b *bolt.Bucket) error { return tx.ForEach(func(nm []byte, b *bolt.Bucket) error {
bb, err := readBucket(b) bb, err := readBucket(b)
if err == nil { if err == nil {
bb.name = string(nm) bb.SetName(nm)
bb.expanded = false bb.expanded = false
memBolt.buckets = append(memBolt.buckets, *bb) memBolt.buckets = append(memBolt.buckets, *bb)
return nil return nil
@ -262,27 +304,40 @@ func (bd *BoltDB) refreshDatabase() *BoltDB {
} }
/* /*
GetPath returns the database path leading to this BoltBucket GetStringName returns the name of the bucket after passing it through it's
Datatype ToString function
*/ */
func (b *BoltBucket) GetPath() []string { func (b *BoltBucket) GetStringName() string {
if b.parent != nil { ret, err := b.nameDatatype.ToString(b.name)
return append(b.parent.GetPath(), b.name) if err != nil {
return stringify(b.name)
} }
return []string{b.name} return ret
} }
/* /*
buildVisiblePathSlice builds a slice of string slices containing all visible paths in this bucket GetPath returns the database path leading to this BoltBucket
*/
func (b *BoltBucket) GetPath() [][]byte {
if b.parent != nil {
return append(b.parent.GetPath(), b.name)
}
return [][]byte{b.name}
}
/*
buildVisiblePathSlice builds a slice of PathNode slices containing all visible paths in this bucket
The passed prefix is the path leading to the current bucket The passed prefix is the path leading to the current bucket
*/ */
func (b *BoltBucket) buildVisiblePathSlice(prefix []string) ([][]string, error) { func (b *BoltBucket) buildVisiblePathSlice(prefix []PathNode) ([][]PathNode, error) {
var retSlice [][]string var retSlice [][]PathNode
var retErr error var retErr error
retSlice = append(retSlice, append(prefix, b.name)) bucketNode := PathNode{b.name, b.nameDatatype}
retSlice = append(retSlice, append(prefix, bucketNode))
if b.expanded { if b.expanded {
// Add subbuckets // Add subbuckets
for i := range b.buckets { for i := range b.buckets {
bktS, bktErr := b.buckets[i].buildVisiblePathSlice(append(prefix, b.name)) bktS, bktErr := b.buckets[i].buildVisiblePathSlice(append(prefix, bucketNode))
if bktErr != nil { if bktErr != nil {
return retSlice, bktErr return retSlice, bktErr
} }
@ -290,7 +345,7 @@ func (b *BoltBucket) buildVisiblePathSlice(prefix []string) ([][]string, error)
} }
// Add pairs // Add pairs
for i := range b.pairs { for i := range b.pairs {
retSlice = append(retSlice, append(append(prefix, b.name), b.pairs[i].key)) retSlice = append(retSlice, append(append(prefix, bucketNode, PathNode{b.pairs[i].key, b.pairs[i].keyDatatype})))
} }
} }
return retSlice, retErr return retSlice, retErr
@ -301,7 +356,7 @@ func (b *BoltBucket) syncOpenBuckets(shadow *BoltBucket) {
b.expanded = shadow.expanded b.expanded = shadow.expanded
for i := range b.buckets { for i := range b.buckets {
for j := range shadow.buckets { for j := range shadow.buckets {
if b.buckets[i].name == shadow.buckets[j].name { if bytes.Equal(b.buckets[i].name, shadow.buckets[j].name) {
b.buckets[i].syncOpenBuckets(&shadow.buckets[j]) b.buckets[i].syncOpenBuckets(&shadow.buckets[j])
} }
} }
@ -315,28 +370,50 @@ func (b *BoltBucket) openAllBuckets() {
} }
} }
func (b *BoltBucket) getBucket(k string) (*BoltBucket, error) { func (b *BoltBucket) getBucket(k []byte) (*BoltBucket, error) {
for i := range b.buckets { for i := range b.buckets {
if b.buckets[i].name == k { if bytes.Equal(b.buckets[i].name, k) {
return &b.buckets[i], nil return &b.buckets[i], nil
} }
} }
return nil, errors.New("Bucket Not Found") return nil, errors.New("Bucket Not Found")
} }
func (b *BoltBucket) getPair(k string) (*BoltPair, error) { func (b *BoltBucket) getPair(k []byte) (*BoltPair, error) {
for i := range b.pairs { for i := range b.pairs {
if b.pairs[i].key == k { if bytes.Equal(b.pairs[i].key, k) {
return &b.pairs[i], nil return &b.pairs[i], nil
} }
} }
return nil, errors.New("Pair Not Found") return nil, errors.New("Pair Not Found")
} }
/*
GetStringKey returns the key of the pair after passing it through it's
Datatype ToString function
*/
func (p *BoltPair) GetStringKey() string {
ret, err := p.keyDatatype.ToString(p.key)
if err != nil {
return stringify(p.key)
}
return ret
}
/*
GetStringVal returns the val of the pair after passing it through it's
Datatype ToString function
*/
func (p *BoltPair) GetStringVal() string {
ret, err := p.valDatatype.ToString(p.val)
if err != nil {
return stringify(p.val)
}
return ret
}
/* /*
GetPath Returns the path of the BoltPair GetPath Returns the path of the BoltPair
*/ */
func (p *BoltPair) GetPath() []string { func (p *BoltPair) GetPath() [][]byte {
return append(p.parent.GetPath(), p.key) return append(p.parent.GetPath(), p.key)
} }
@ -347,7 +424,7 @@ func (p *BoltPair) GetPath() []string {
* Mainly used for moving a bucket from one path to another * Mainly used for moving a bucket from one path to another
* as in the 'renameBucket' function below. * as in the 'renameBucket' function below.
*/ */
func addBucketFromBoltBucket(path []string, bb *BoltBucket) error { func addBucketFromBoltBucket(path [][]byte, bb *BoltBucket) error {
if err := insertBucket(path, bb.name); err == nil { if err := insertBucket(path, bb.name); err == nil {
bucketPath := append(path, bb.name) bucketPath := append(path, bb.name)
for i := range bb.pairs { for i := range bb.pairs {
@ -364,7 +441,7 @@ func addBucketFromBoltBucket(path []string, bb *BoltBucket) error {
return nil return nil
} }
func deleteKey(path []string) error { func deleteKey(path [][]byte) error {
if AppArgs.ReadOnly { if AppArgs.ReadOnly {
return errors.New("DB is in Read-Only Mode") return errors.New("DB is in Read-Only Mode")
} }
@ -373,13 +450,13 @@ func deleteKey(path []string) error {
// the rest are buckets leading to that key // the rest are buckets leading to that key
if len(path) == 1 { if len(path) == 1 {
// Deleting a root bucket // Deleting a root bucket
return tx.DeleteBucket([]byte(path[0])) return tx.DeleteBucket(path[0])
} }
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 1 { if len(path) > 1 {
for i := range path[1 : len(path)-1] { for i := range path[1 : len(path)-1] {
b = b.Bucket([]byte(path[i+1])) b = b.Bucket(path[i+1])
if b == nil { if b == nil {
return errors.New("deleteKey: Invalid Path") return errors.New("deleteKey: Invalid Path")
} }
@ -387,11 +464,11 @@ func deleteKey(path []string) error {
} }
// Now delete the last key in the path // Now delete the last key in the path
var err error var err error
if deleteBkt := b.Bucket([]byte(path[len(path)-1])); deleteBkt == nil { if deleteBkt := b.Bucket(path[len(path)-1]); deleteBkt == nil {
// Must be a pair // Must be a pair
err = b.Delete([]byte(path[len(path)-1])) err = b.Delete(path[len(path)-1])
} else { } else {
err = b.DeleteBucket([]byte(path[len(path)-1])) err = b.DeleteBucket(path[len(path)-1])
} }
return err return err
} }
@ -400,6 +477,8 @@ func deleteKey(path []string) error {
return err return err
} }
// Recursively read a bucket and pairs from the DB
// We assume all datatypes are string
func readBucket(b *bolt.Bucket) (*BoltBucket, error) { func readBucket(b *bolt.Bucket) (*BoltBucket, error) {
bb := new(BoltBucket) bb := new(BoltBucket)
b.ForEach(func(k, v []byte) error { b.ForEach(func(k, v []byte) error {
@ -407,21 +486,19 @@ func readBucket(b *bolt.Bucket) (*BoltBucket, error) {
tb, err := readBucket(b.Bucket(k)) tb, err := readBucket(b.Bucket(k))
tb.parent = bb tb.parent = bb
if err == nil { if err == nil {
tb.name = string(k) tb.SetName(k)
bb.buckets = append(bb.buckets, *tb) bb.buckets = append(bb.buckets, *tb)
} }
} else { } else {
tp := BoltPair{key: string(k), val: string(v)} bb.pairs = append(bb.pairs, *NewBoltPair(bb, k, v))
tp.parent = bb
bb.pairs = append(bb.pairs, tp)
} }
return nil return nil
}) })
return bb, nil return bb, nil
} }
func renameBucket(path []string, name string) error { func renameBucket(path [][]byte, name []byte) error {
if name == path[len(path)-1] { if bytes.Equal(name, path[len(path)-1]) {
// No change requested // No change requested
return nil return nil
} }
@ -429,11 +506,11 @@ func renameBucket(path []string, name string) error {
err := db.View(func(tx *bolt.Tx) error { err := db.View(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key we need to delete, // len(b.path)-1 is the key we need to delete,
// the rest are buckets leading to that key // the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 1 { if len(path) > 1 {
for i := range path[1:len(path)] { for i := range path[1:len(path)] {
b = b.Bucket([]byte(path[i+1])) b = b.Bucket(path[i+1])
if b == nil { if b == nil {
return errors.New("renameBucket: Invalid Path") return errors.New("renameBucket: Invalid Path")
} }
@ -462,7 +539,7 @@ func renameBucket(path []string, name string) error {
return err return err
} }
// Rechristen our cached bucket // Rechristen our cached bucket
bb.name = name bb.SetName(name)
// And re-add it // And re-add it
parentPath := path[:len(path)-1] parentPath := path[:len(path)-1]
@ -472,29 +549,29 @@ func renameBucket(path []string, name string) error {
return nil return nil
} }
func updatePairKey(path []string, k string) error { func updatePairKey(path [][]byte, k []byte) error {
if AppArgs.ReadOnly { if AppArgs.ReadOnly {
return errors.New("DB is in Read-Only Mode") return errors.New("DB is in Read-Only Mode")
} }
err := db.Update(func(tx *bolt.Tx) error { err := db.Update(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key for the pair we're updating, // len(b.path)-1 is the key for the pair we're updating,
// the rest are buckets leading to that key // the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 0 { if len(path) > 0 {
for i := range path[1 : len(path)-1] { for i := range path[1 : len(path)-1] {
b = b.Bucket([]byte(path[i+1])) b = b.Bucket(path[i+1])
if b == nil { if b == nil {
return errors.New("updatePairValue: Invalid Path") return errors.New("updatePairValue: Invalid Path")
} }
} }
} }
bk := []byte(path[len(path)-1]) bk := path[len(path)-1]
v := b.Get(bk) v := b.Get(bk)
err := b.Delete(bk) err := b.Delete(bk)
if err == nil { if err == nil {
// Old pair has been deleted, now add the new one // Old pair has been deleted, now add the new one
err = b.Put([]byte(k), v) err = b.Put(k, v)
} }
// Now update the last key in the path // Now update the last key in the path
return err return err
@ -504,25 +581,25 @@ func updatePairKey(path []string, k string) error {
return err return err
} }
func updatePairValue(path []string, v string) error { func updatePairValue(path [][]byte, v []byte) error {
if AppArgs.ReadOnly { if AppArgs.ReadOnly {
return errors.New("DB is in Read-Only Mode") return errors.New("DB is in Read-Only Mode")
} }
err := db.Update(func(tx *bolt.Tx) error { err := db.Update(func(tx *bolt.Tx) error {
// len(b.GetPath())-1 is the key for the pair we're updating, // len(b.GetPath())-1 is the key for the pair we're updating,
// the rest are buckets leading to that key // the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 0 { if len(path) > 0 {
for i := range path[1 : len(path)-1] { for i := range path[1 : len(path)-1] {
b = b.Bucket([]byte(path[i+1])) b = b.Bucket(path[i+1])
if b == nil { if b == nil {
return errors.New("updatePairValue: Invalid Path") return errors.New("updatePairValue: Invalid Path")
} }
} }
} }
// Now update the last key in the path // Now update the last key in the path
err := b.Put([]byte(path[len(path)-1]), []byte(v)) err := b.Put(path[len(path)-1], v)
return err return err
} }
return errors.New("updatePairValue: Invalid Path") return errors.New("updatePairValue: Invalid Path")
@ -530,7 +607,7 @@ func updatePairValue(path []string, v string) error {
return err return err
} }
func insertBucket(path []string, n string) error { func insertBucket(path [][]byte, n []byte) error {
if AppArgs.ReadOnly { if AppArgs.ReadOnly {
return errors.New("DB is in Read-Only Mode") return errors.New("DB is in Read-Only Mode")
} }
@ -538,18 +615,18 @@ func insertBucket(path []string, n string) error {
err := db.Update(func(tx *bolt.Tx) error { err := db.Update(func(tx *bolt.Tx) error {
if len(path) == 0 { if len(path) == 0 {
// insert at root // insert at root
_, err := tx.CreateBucket([]byte(n)) _, err := tx.CreateBucket(n)
if err != nil { if err != nil {
return fmt.Errorf("insertBucket: %s", err) return fmt.Errorf("insertBucket: %s", err)
} }
} else { } else {
rootBucket, path := path[0], path[1:] rootBucket, path := path[0], path[1:]
b := tx.Bucket([]byte(rootBucket)) b := tx.Bucket(rootBucket)
if b != nil { if b != nil {
for len(path) > 0 { for len(path) > 0 {
tstBucket := "" var tstBucket []byte
tstBucket, path = path[0], path[1:] tstBucket, path = path[0], path[1:]
nB := b.Bucket([]byte(tstBucket)) nB := b.Bucket(tstBucket)
if nB == nil { if nB == nil {
// Not a bucket, if we're out of path, just move on // Not a bucket, if we're out of path, just move on
if len(path) != 0 { if len(path) != 0 {
@ -560,7 +637,7 @@ func insertBucket(path []string, n string) error {
b = nB b = nB
} }
} }
_, err := b.CreateBucket([]byte(n)) _, err := b.CreateBucket(n)
return err return err
} }
return fmt.Errorf("insertBucket: Invalid Path %s", rootBucket) return fmt.Errorf("insertBucket: Invalid Path %s", rootBucket)
@ -570,7 +647,7 @@ func insertBucket(path []string, n string) error {
return err return err
} }
func insertPair(path []string, k string, v string) error { func insertPair(path [][]byte, k []byte, v []byte) error {
if AppArgs.ReadOnly { if AppArgs.ReadOnly {
return errors.New("DB is in Read-Only Mode") return errors.New("DB is in Read-Only Mode")
} }
@ -581,17 +658,17 @@ func insertPair(path []string, k string, v string) error {
return errors.New("insertPair: Cannot insert pair at root") return errors.New("insertPair: Cannot insert pair at root")
} }
var err error var err error
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 0 { if len(path) > 0 {
for i := 1; i < len(path); i++ { for i := 1; i < len(path); i++ {
b = b.Bucket([]byte(path[i])) b = b.Bucket(path[i])
if b == nil { if b == nil {
return fmt.Errorf("insertPair: %s", err) return fmt.Errorf("insertPair: %s", err)
} }
} }
} }
err := b.Put([]byte(k), []byte(v)) err := b.Put(k, v)
if err != nil { if err != nil {
return fmt.Errorf("insertPair: %s", err) return fmt.Errorf("insertPair: %s", err)
} }
@ -601,21 +678,37 @@ func insertPair(path []string, k string, v string) error {
return err return err
} }
func exportValue(path []string, fName string) error { func stringPathToBytePath(path []string) [][]byte {
var ret [][]byte
for _, v := range path {
ret = append(ret, []byte(v))
}
return ret
}
func bytePathToStringPath(path [][]byte) []string {
var ret []string
for _, v := range path {
ret = append(ret, string(v))
}
return ret
}
func exportValue(path [][]byte, fName string) error {
return db.View(func(tx *bolt.Tx) error { return db.View(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key whose value we want to export // len(b.path)-1 is the key whose value we want to export
// the rest are buckets leading to that key // the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 1 { if len(path) > 1 {
for i := range path[1 : len(path)-1] { for i := range path[1 : len(path)-1] {
b = b.Bucket([]byte(path[i+1])) b = b.Bucket(path[i+1])
if b == nil { if b == nil {
return errors.New("exportValue: Invalid Path: " + strings.Join(path, "/")) return errors.New("exportValue: Invalid Path: " + strings.Join(bytePathToStringPath(path), "/"))
} }
} }
} }
bk := []byte(path[len(path)-1]) bk := path[len(path)-1]
v := b.Get(bk) v := b.Get(bk)
return writeToFile(fName, string(v)+"\n", os.O_CREATE|os.O_WRONLY|os.O_TRUNC) return writeToFile(fName, string(v)+"\n", os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
} }
@ -623,21 +716,21 @@ func exportValue(path []string, fName string) error {
}) })
} }
func exportJSON(path []string, fName string) error { func exportJSON(path [][]byte, fName string) error {
return db.View(func(tx *bolt.Tx) error { return db.View(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key whose value we want to export // len(b.path)-1 is the key whose value we want to export
// the rest are buckets leading to that key // the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0])) b := tx.Bucket(path[0])
if b != nil { if b != nil {
if len(path) > 1 { if len(path) > 1 {
for i := range path[1 : len(path)-1] { for i := range path[1 : len(path)-1] {
b = b.Bucket([]byte(path[i+1])) b = b.Bucket(path[i+1])
if b == nil { if b == nil {
return errors.New("exportValue: Invalid Path: " + strings.Join(path, "/")) return errors.New("exportValue: Invalid Path: " + strings.Join(bytePathToStringPath(path), "/"))
} }
} }
} }
bk := []byte(path[len(path)-1]) bk := path[len(path)-1]
if v := b.Get(bk); v != nil { if v := b.Get(bk); v != nil {
return writeToFile(fName, "{\""+string(bk)+"\":\""+string(v)+"\"}", os.O_CREATE|os.O_WRONLY|os.O_TRUNC) return writeToFile(fName, "{\""+string(bk)+"\":\""+string(v)+"\"}", os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
} }

View File

@ -1,37 +1,39 @@
package main package main
import ( import (
"fmt"
"encoding/binary" "encoding/binary"
"errors"
"strconv" "strconv"
) )
// Datatype_Uint64 manages the uint64 data type // Datatype_Int manages the int data type
// All conversions just use the binary package type Datatype_Int64 struct{}
type Datatype_Uint64 struct{}
func (t *Datatype_Uint64) Name() string { func (t *Datatype_Int64) Name() string {
return "uint64" return "int"
} }
func (t *Datatype_Uint64) ToString(data []byte) (string, error) { func (t *Datatype_Int64) ToString(data []byte) (string, error) {
ret, bt := binary.Uvarint(data) return fmt.Sprintf("%d", t.btoi(data)), nil
if bt == 0 {
return "", errors.New("Byte Buffer too small")
} else if bt < 0 {
return "", errors.New("Value larger than 64 bits")
}
return strconv.FormatUint(ret, 10), nil
} }
func (t *Datatype_Uint64) FromString(val string) ([]byte, error) { func (t *Datatype_Int64) FromString(val string) ([]byte, error) {
var err error v, err := strconv.ParseInt(val, 10, 64)
var u uint64
buf := make([]byte, binary.MaxVarintLen64)
u, err = strconv.ParseUint(val, 10, 64)
if err != nil { if err != nil {
return nil, err return []byte{}, err
} }
binary.PutUvarint(buf, u) return t.itob(v), nil
return buf, nil }
func (t *Datatype_Int64) itob(v int64) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(v))
return b
}
func (t *Datatype_Int64) btoi(b []byte) int64 {
if len(b) < 8 {
return 0
}
return int64(binary.BigEndian.Uint64(b))
} }

37
datatype_uint.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"encoding/binary"
"errors"
"strconv"
)
// Datatype_Uint64 manages the uint64 data type
// All conversions just use the binary package
type Datatype_Uint64 struct{}
func (t *Datatype_Uint64) Name() string {
return "uint64"
}
func (t *Datatype_Uint64) ToString(data []byte) (string, error) {
ret, bt := binary.Uvarint(data)
if bt == 0 {
return "", errors.New("Byte Buffer too small")
} else if bt < 0 {
return "", errors.New("Value larger than 64 bits")
}
return strconv.FormatUint(ret, 10), nil
}
func (t *Datatype_Uint64) FromString(val string) ([]byte, error) {
var err error
var u uint64
buf := make([]byte, binary.MaxVarintLen64)
u, err = strconv.ParseUint(val, 10, 64)
if err != nil {
return nil, err
}
binary.PutUvarint(buf, u)
return buf, nil
}

View File

@ -19,6 +19,7 @@ var db *bolt.DB
var memBolt *BoltDB var memBolt *BoltDB
var datatypes map[string]Datatype var datatypes map[string]Datatype
var dataTypeNameSlice []string
var currentFilename string var currentFilename string
@ -142,8 +143,10 @@ func initDataTypes() {
datatypes = make(map[string]Datatype) datatypes = make(map[string]Datatype)
for _, t := range []Datatype{ for _, t := range []Datatype{
&Datatype_String{}, &Datatype_String{},
&Datatype_Int64{},
&Datatype_Uint64{}, &Datatype_Uint64{},
} { } {
dataTypeNameSlice = append(dataTypeNameSlice, t.Name())
datatypes[t.Name()] = t datatypes[t.Name()] = t
} }
} }

View File

@ -28,7 +28,7 @@ type BrowserScreen struct {
leftViewPort ViewPort leftViewPort ViewPort
rightViewPort ViewPort rightViewPort ViewPort
queuedCommand string queuedCommand string
currentPath []string currentPath []PathNode
currentType int currentType int
message string message string
mode BrowserMode mode BrowserMode
@ -39,6 +39,8 @@ type BrowserScreen struct {
leftPaneBuffer []Line leftPaneBuffer []Line
rightPaneBuffer []Line rightPaneBuffer []Line
niceLog []string
} }
/* /*
@ -149,7 +151,7 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int {
screen.startInsertItemAtParent(typeBucket) screen.startInsertItemAtParent(typeBucket)
} else if event.Ch == 'e' { } else if event.Ch == 'e' {
b, p, _ := screen.db.getGenericFromPath(screen.currentPath) b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath)
if b != nil { if b != nil {
screen.setMessage("Cannot edit a bucket, did you mean to (r)ename?") screen.setMessage("Cannot edit a bucket, did you mean to (r)ename?")
} else if p != nil { } else if p != nil {
@ -160,18 +162,18 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int {
screen.startRenameItem() screen.startRenameItem()
} else if event.Key == termbox.KeyEnter { } else if event.Key == termbox.KeyEnter {
b, p, _ := screen.db.getGenericFromPath(screen.currentPath) b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath)
if b != nil { if b != nil {
screen.db.toggleOpenBucket(screen.currentPath) screen.db.toggleOpenBucket(stringPathToBytePath(screen.currentPath))
} else if p != nil { } else if p != nil {
screen.startEditItem() screen.startEditItem()
} }
} else if event.Ch == 'l' || event.Key == termbox.KeyArrowRight { } else if event.Ch == 'l' || event.Key == termbox.KeyArrowRight {
b, p, _ := screen.db.getGenericFromPath(screen.currentPath) b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath)
// Select the current item // Select the current item
if b != nil { if b != nil {
screen.db.toggleOpenBucket(screen.currentPath) screen.db.toggleOpenBucket(stringPathToBytePath(screen.currentPath))
} else if p != nil { } else if p != nil {
screen.startEditItem() screen.startEditItem()
} else { } else {
@ -180,19 +182,19 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int {
} else if event.Ch == 'h' || event.Key == termbox.KeyArrowLeft { } else if event.Ch == 'h' || event.Key == termbox.KeyArrowLeft {
// If we are _on_ a bucket that's open, close it // If we are _on_ a bucket that's open, close it
b, _, e := screen.db.getGenericFromPath(screen.currentPath) b, _, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil && b != nil && b.expanded { if e == nil && b != nil && b.expanded {
screen.db.closeBucket(screen.currentPath) screen.db.closeBucket(stringPathToBytePath(screen.currentPath))
} else { } else {
if len(screen.currentPath) > 1 { if len(screen.currentPath) > 1 {
parentBucket, err := screen.db.getBucketFromPath(screen.currentPath[:len(screen.currentPath)-1]) parentBucket, err := screen.db.getBucketFromPath(stringPathToBytePath(screen.currentPath[:len(screen.currentPath)-1]))
if err == nil { if err == nil {
screen.db.closeBucket(parentBucket.GetPath()) screen.db.closeBucket(parentBucket.GetPath())
// Figure out how far up we need to move the cursor // Figure out how far up we need to move the cursor
screen.currentPath = parentBucket.GetPath() screen.currentPath = bytePathToStringPath(parentBucket.GetPath())
} }
} else { } else {
screen.db.closeBucket(screen.currentPath) screen.db.closeBucket(stringPathToBytePath(screen.currentPath))
} }
} }
@ -207,7 +209,24 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int {
} else if event.Ch == 't' { } else if event.Ch == 't' {
// TODO: change the type of the pair value being viewed // TODO: change the type of the pair value being viewed
p, err := screen.db.getPairFromPath(stringPathToBytePath(screen.currentPath))
if err != nil {
screen.setMessage("Cannot change pair type (did you mean 'T': Change pair key/bucket name type?)")
return BrowserScreenIndex
}
p.valDatatype = findNextDatatype(p.valDatatype.Name())
} else if event.Ch == 'T' {
b, p, err := screen.db.getGenericFromStringPath(screen.currentPath)
if err != nil {
screen.setMessage("Error reading path... Not sure what to do.")
return BrowserScreenIndex
}
if b != nil {
b.nameDatatype = findNextDatatype(b.nameDatatype.Name())
} else if p != nil {
p.keyDatatype = findNextDatatype(p.keyDatatype.Name())
}
} }
return BrowserScreenIndex return BrowserScreenIndex
} }
@ -219,15 +238,15 @@ func (screen *BrowserScreen) handleInputKeyEvent(event termbox.Event) int {
} else { } else {
screen.inputModal.HandleEvent(event) screen.inputModal.HandleEvent(event)
if screen.inputModal.IsDone() { if screen.inputModal.IsDone() {
b, p, _ := screen.db.getGenericFromPath(screen.currentPath) b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath)
if b != nil { if b != nil {
if screen.mode == modeChangeKey { if screen.mode == modeChangeKey {
newName := screen.inputModal.GetValue() newName := screen.inputModal.GetValue()
if renameBucket(screen.currentPath, newName) != nil { if renameBucket(stringPathToBytePath(screen.currentPath), []byte(newName)) != nil {
screen.setMessage("Error renaming bucket.") screen.setMessage("Error renaming bucket.")
} else { } else {
b.name = newName b.name = []byte(newName)
screen.currentPath[len(screen.currentPath)-1] = b.name screen.currentPath[len(screen.currentPath)-1] = newName
screen.setMessage("Bucket Renamed!") screen.setMessage("Bucket Renamed!")
screen.refreshDatabase() screen.refreshDatabase()
} }
@ -235,20 +254,20 @@ func (screen *BrowserScreen) handleInputKeyEvent(event termbox.Event) int {
} else if p != nil { } else if p != nil {
if screen.mode == modeChangeKey { if screen.mode == modeChangeKey {
newKey := screen.inputModal.GetValue() newKey := screen.inputModal.GetValue()
if updatePairKey(screen.currentPath, newKey) != nil { if updatePairKey(stringPathToBytePath(screen.currentPath), []byte(newKey)) != nil {
screen.setMessage("Error occurred updating Pair.") screen.setMessage("Error occurred updating Pair.")
} else { } else {
p.key = newKey p.key = []byte(newKey)
screen.currentPath[len(screen.currentPath)-1] = p.key screen.currentPath[len(screen.currentPath)-1] = newKey
screen.setMessage("Pair updated!") screen.setMessage("Pair updated!")
screen.refreshDatabase() screen.refreshDatabase()
} }
} else if screen.mode == modeChangeVal { } else if screen.mode == modeChangeVal {
newVal := screen.inputModal.GetValue() newVal := screen.inputModal.GetValue()
if updatePairValue(screen.currentPath, newVal) != nil { if updatePairValue(stringPathToBytePath(screen.currentPath), []byte(newVal)) != nil {
screen.setMessage("Error occurred updating Pair.") screen.setMessage("Error occurred updating Pair.")
} else { } else {
p.val = newVal p.val = []byte(newVal)
screen.setMessage("Pair updated!") screen.setMessage("Pair updated!")
screen.refreshDatabase() screen.refreshDatabase()
} }
@ -267,7 +286,7 @@ func (screen *BrowserScreen) handleDeleteKeyEvent(event termbox.Event) int {
if screen.confirmModal.IsAccepted() { if screen.confirmModal.IsAccepted() {
holdNextPath := screen.db.getNextVisiblePath(screen.currentPath) holdNextPath := screen.db.getNextVisiblePath(screen.currentPath)
holdPrevPath := screen.db.getPrevVisiblePath(screen.currentPath) holdPrevPath := screen.db.getPrevVisiblePath(screen.currentPath)
if deleteKey(screen.currentPath) == nil { if deleteKey(stringPathToBytePath(screen.currentPath)) == nil {
screen.refreshDatabase() screen.refreshDatabase()
// Move the current path endpoint appropriately // Move the current path endpoint appropriately
//found_new_path := false //found_new_path := false
@ -312,7 +331,7 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int {
screen.inputModal.Clear() screen.inputModal.Clear()
var insertPath []string var insertPath []string
if len(screen.currentPath) > 0 { if len(screen.currentPath) > 0 {
_, p, e := screen.db.getGenericFromPath(screen.currentPath) _, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e != nil { if e != nil {
screen.setMessage("Error Inserting new item. Invalid Path.") screen.setMessage("Error Inserting new item. Invalid Path.")
} }
@ -331,9 +350,9 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int {
} }
} }
parentB, _, _ := screen.db.getGenericFromPath(insertPath) parentB, _, _ := screen.db.getGenericFromStringPath(insertPath)
if screen.mode&modeInsertBucket == modeInsertBucket { if screen.mode&modeInsertBucket == modeInsertBucket {
err := insertBucket(insertPath, newVal) err := insertBucket(stringPathToBytePath(insertPath), []byte(newVal))
if err != nil { if err != nil {
screen.setMessage(fmt.Sprintf("%s => %s", err, insertPath)) screen.setMessage(fmt.Sprintf("%s => %s", err, insertPath))
} else { } else {
@ -347,7 +366,7 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int {
screen.mode = modeBrowse screen.mode = modeBrowse
screen.inputModal.Clear() screen.inputModal.Clear()
} else if screen.mode&modeInsertPair == modeInsertPair { } else if screen.mode&modeInsertPair == modeInsertPair {
err := insertPair(insertPath, newVal, "") err := insertPair(stringPathToBytePath(insertPath), []byte(newVal), []byte{})
if err != nil { if err != nil {
screen.setMessage(fmt.Sprintf("%s => %s", err, insertPath)) screen.setMessage(fmt.Sprintf("%s => %s", err, insertPath))
screen.refreshDatabase() screen.refreshDatabase()
@ -374,12 +393,12 @@ func (screen *BrowserScreen) handleExportKeyEvent(event termbox.Event) int {
} else { } else {
screen.inputModal.HandleEvent(event) screen.inputModal.HandleEvent(event)
if screen.inputModal.IsDone() { if screen.inputModal.IsDone() {
b, p, _ := screen.db.getGenericFromPath(screen.currentPath) b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath)
fileName := screen.inputModal.GetValue() fileName := screen.inputModal.GetValue()
if screen.mode&modeExportValue == modeExportValue { if screen.mode&modeExportValue == modeExportValue {
// Exporting the value // Exporting the value
if p != nil { if p != nil {
if err := exportValue(screen.currentPath, fileName); err != nil { if err := exportValue(stringPathToBytePath(screen.currentPath), fileName); err != nil {
//screen.setMessage("Error Exporting to file " + fileName + ".") //screen.setMessage("Error Exporting to file " + fileName + ".")
screen.setMessage(err.Error()) screen.setMessage(err.Error())
} else { } else {
@ -388,7 +407,7 @@ func (screen *BrowserScreen) handleExportKeyEvent(event termbox.Event) int {
} }
} else if screen.mode&modeExportJSON == modeExportJSON { } else if screen.mode&modeExportJSON == modeExportJSON {
if b != nil || p != nil { if b != nil || p != nil {
if exportJSON(screen.currentPath, fileName) != nil { if exportJSON(stringPathToBytePath(screen.currentPath), fileName) != nil {
screen.setMessage("Error Exporting to file " + fileName + ".") screen.setMessage("Error Exporting to file " + fileName + ".")
} else { } else {
screen.setMessage("Value exported to file: " + fileName) screen.setMessage("Value exported to file: " + fileName)
@ -583,7 +602,15 @@ func (screen *BrowserScreen) drawLeftPane(style Style) {
func (screen *BrowserScreen) buildRightPane(style Style) { func (screen *BrowserScreen) buildRightPane(style Style) {
screen.rightPaneBuffer = nil screen.rightPaneBuffer = nil
b, p, err := screen.db.getGenericFromPath(screen.currentPath) screen.niceLog = []string{}
var logstr string
for _, v := range screen.currentPath {
logstr = fmt.Sprintf("%s / %s", logstr, stringify([]byte(v)))
}
screen.niceLog = append(screen.niceLog, logstr)
b, p, err := screen.db.getGenericFromStringPath(screen.currentPath)
if err == nil { if err == nil {
if b != nil { if b != nil {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
@ -596,12 +623,12 @@ func (screen *BrowserScreen) buildRightPane(style Style) {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(p.GetPath()), " → ")), style.defaultFg, style.defaultBg}) Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(p.GetPath()), " → ")), style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Key: %s", stringify([]byte(p.key))), style.defaultFg, style.defaultBg}) Line{fmt.Sprintf("Key (%s): %s", p.keyDatatype.Name(), stringify([]byte(p.key))), style.defaultFg, style.defaultBg})
value := strings.Split(string(formatValue([]byte(p.val))), "\n") value := strings.Split(string(formatValue([]byte(p.val))), "\n")
if len(value) == 1 { if len(value) == 1 {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Value: %s", value[0]), style.defaultFg, style.defaultBg}) Line{fmt.Sprintf("Value (%s): %s", p.valDatatype.Name(), value[0]), style.defaultFg, style.defaultBg})
} else { } else {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{"Value:", style.defaultFg, style.defaultBg}) Line{"Value:", style.defaultFg, style.defaultBg})
@ -613,10 +640,18 @@ func (screen *BrowserScreen) buildRightPane(style Style) {
} }
} else { } else {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(screen.currentPath), " → ")), style.defaultFg, style.defaultBg}) Line{fmt.Sprintf("Path: %s", strings.Join(stringifyStringPath(screen.currentPath), " → ")), style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{err.Error(), termbox.ColorRed, termbox.ColorBlack}) Line{err.Error(), termbox.ColorRed, termbox.ColorBlack})
} }
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{"", style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{"== Log ==", style.defaultBg, style.defaultFg})
for _, v := range screen.niceLog {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{v, style.defaultFg, style.defaultBg})
}
} }
func (screen *BrowserScreen) drawRightPane(style Style) { func (screen *BrowserScreen) drawRightPane(style Style) {
@ -673,32 +708,32 @@ func formatValueJSON(val []byte) ([]byte, error) {
func (screen *BrowserScreen) bucketToLines(bkt *BoltBucket, style Style) []Line { func (screen *BrowserScreen) bucketToLines(bkt *BoltBucket, style Style) []Line {
var ret []Line var ret []Line
bfg, bbg := style.defaultFg, style.defaultBg bfg, bbg := style.defaultFg, style.defaultBg
if comparePaths(screen.currentPath, bkt.GetPath()) { if comparePaths(screen.currentPath, bytePathToStringPath(bkt.GetPath())) {
bfg, bbg = style.cursorFg, style.cursorBg bfg, bbg = style.cursorFg, style.cursorBg
} }
bktPrefix := strings.Repeat(" ", len(bkt.GetPath())*2) bktPrefix := strings.Repeat(" ", len(bkt.GetPath())*2)
if bkt.expanded { if bkt.expanded {
ret = append(ret, Line{bktPrefix + "- " + stringify([]byte(bkt.name)), bfg, bbg}) ret = append(ret, Line{bktPrefix + "- " + bkt.GetStringName(), bfg, bbg})
for i := range bkt.buckets { for i := range bkt.buckets {
ret = append(ret, screen.bucketToLines(&bkt.buckets[i], style)...) ret = append(ret, screen.bucketToLines(&bkt.buckets[i], style)...)
} }
for _, bp := range bkt.pairs { for _, bp := range bkt.pairs {
pfg, pbg := style.defaultFg, style.defaultBg pfg, pbg := style.defaultFg, style.defaultBg
if comparePaths(screen.currentPath, bp.GetPath()) { if comparePaths(screen.currentPath, bytePathToStringPath(bp.GetPath())) {
pfg, pbg = style.cursorFg, style.cursorBg pfg, pbg = style.cursorFg, style.cursorBg
} }
prPrefix := strings.Repeat(" ", len(bp.GetPath())*2) prPrefix := strings.Repeat(" ", len(bp.GetPath())*2)
pairString := fmt.Sprintf("%s%s: %s", prPrefix, stringify([]byte(bp.key)), stringify([]byte(bp.val))) pairString := fmt.Sprintf("%s%s: %s", prPrefix, bp.GetStringKey(), bp.GetStringVal())
ret = append(ret, Line{pairString, pfg, pbg}) ret = append(ret, Line{pairString, pfg, pbg})
} }
} else { } else {
ret = append(ret, Line{bktPrefix + "+ " + stringify([]byte(bkt.name)), bfg, bbg}) ret = append(ret, Line{bktPrefix + "+ " + bkt.GetStringName(), bfg, bbg})
} }
return ret return ret
} }
func (screen *BrowserScreen) startDeleteItem() bool { func (screen *BrowserScreen) startDeleteItem() bool {
b, p, e := screen.db.getGenericFromPath(screen.currentPath) b, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil { if e == nil {
w, h := termbox.Size() w, h := termbox.Size()
inpW, inpH := (w / 2), 6 inpW, inpH := (w / 2), 6
@ -719,7 +754,7 @@ func (screen *BrowserScreen) startDeleteItem() bool {
} }
func (screen *BrowserScreen) startEditItem() bool { func (screen *BrowserScreen) startEditItem() bool {
_, p, e := screen.db.getGenericFromPath(screen.currentPath) _, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil { if e == nil {
w, h := termbox.Size() w, h := termbox.Size()
inpW, inpH := (w / 2), 6 inpW, inpH := (w / 2), 6
@ -727,7 +762,7 @@ func (screen *BrowserScreen) startEditItem() bool {
mod := termboxUtil.CreateInputModal("", inpX, inpY, inpW, inpH, termbox.ColorWhite, termbox.ColorBlack) mod := termboxUtil.CreateInputModal("", inpX, inpY, inpW, inpH, termbox.ColorWhite, termbox.ColorBlack)
if p != nil { if p != nil {
mod.SetTitle(termboxUtil.AlignText(fmt.Sprintf("Input new value for '%s'", p.key), inpW, termboxUtil.AlignCenter)) mod.SetTitle(termboxUtil.AlignText(fmt.Sprintf("Input new value for '%s'", p.key), inpW, termboxUtil.AlignCenter))
mod.SetValue(p.val) mod.SetValue(p.GetStringVal())
} }
mod.Show() mod.Show()
screen.inputModal = mod screen.inputModal = mod
@ -738,18 +773,18 @@ func (screen *BrowserScreen) startEditItem() bool {
} }
func (screen *BrowserScreen) startRenameItem() bool { func (screen *BrowserScreen) startRenameItem() bool {
b, p, e := screen.db.getGenericFromPath(screen.currentPath) b, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil { if e == nil {
w, h := termbox.Size() w, h := termbox.Size()
inpW, inpH := (w / 2), 6 inpW, inpH := (w / 2), 6
inpX, inpY := ((w / 2) - (inpW / 2)), ((h / 2) - inpH) inpX, inpY := ((w / 2) - (inpW / 2)), ((h / 2) - inpH)
mod := termboxUtil.CreateInputModal("", inpX, inpY, inpW, inpH, termbox.ColorWhite, termbox.ColorBlack) mod := termboxUtil.CreateInputModal("", inpX, inpY, inpW, inpH, termbox.ColorWhite, termbox.ColorBlack)
if b != nil { if b != nil {
mod.SetTitle(termboxUtil.AlignText(fmt.Sprintf("Rename Bucket '%s' to:", b.name), inpW, termboxUtil.AlignCenter)) mod.SetTitle(termboxUtil.AlignText(fmt.Sprintf("Rename Bucket '%s' to:", b.GetStringName()), inpW, termboxUtil.AlignCenter))
mod.SetValue(b.name) mod.SetValue(b.GetStringName())
} else if p != nil { } else if p != nil {
mod.SetTitle(termboxUtil.AlignText(fmt.Sprintf("Rename Key '%s' to:", p.key), inpW, termboxUtil.AlignCenter)) mod.SetTitle(termboxUtil.AlignText(fmt.Sprintf("Rename Key '%s' to:", p.GetStringKey()), inpW, termboxUtil.AlignCenter))
mod.SetValue(p.key) mod.SetValue(p.GetStringKey())
} }
mod.Show() mod.Show()
screen.inputModal = mod screen.inputModal = mod
@ -778,7 +813,7 @@ func (screen *BrowserScreen) startInsertItemAtParent(tp BoltType) bool {
} }
} else { } else {
var insPath string var insPath string
_, p, e := screen.db.getGenericFromPath(screen.currentPath[:len(screen.currentPath)-1]) _, p, e := screen.db.getGenericFromStringPath(screen.currentPath[:len(screen.currentPath)-1])
if e == nil && p != nil { if e == nil && p != nil {
insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-2], " → ") + " → " insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-2], " → ") + " → "
} else { } else {
@ -821,7 +856,7 @@ func (screen *BrowserScreen) startInsertItem(tp BoltType) bool {
//mod.SetInputWrap(true) //mod.SetInputWrap(true)
screen.inputModal = mod screen.inputModal = mod
var insPath string var insPath string
_, p, e := screen.db.getGenericFromPath(screen.currentPath) _, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil && p != nil { if e == nil && p != nil {
insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-1], " → ") + " → " insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-1], " → ") + " → "
} else { } else {
@ -853,7 +888,7 @@ func (screen *BrowserScreen) startInsertItem(tp BoltType) bool {
} }
func (screen *BrowserScreen) startExportValue() bool { func (screen *BrowserScreen) startExportValue() bool {
_, p, e := screen.db.getGenericFromPath(screen.currentPath) _, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil && p != nil { if e == nil && p != nil {
w, h := termbox.Size() w, h := termbox.Size()
inpW, inpH := (w / 2), 6 inpW, inpH := (w / 2), 6
@ -871,7 +906,7 @@ func (screen *BrowserScreen) startExportValue() bool {
} }
func (screen *BrowserScreen) startExportJSON() bool { func (screen *BrowserScreen) startExportJSON() bool {
b, p, e := screen.db.getGenericFromPath(screen.currentPath) b, p, e := screen.db.getGenericFromStringPath(screen.currentPath)
if e == nil { if e == nil {
w, h := termbox.Size() w, h := termbox.Size()
inpW, inpH := (w / 2), 6 inpW, inpH := (w / 2), 6
@ -918,6 +953,23 @@ func (screen *BrowserScreen) refreshDatabase() {
screen.db.syncOpenBuckets(shadowDB) screen.db.syncOpenBuckets(shadowDB)
} }
func findNextDatatype(curr string) Datatype {
var first Datatype
var found bool
for k, v := range datatypes {
if first == nil {
first = v
}
if found {
return v
}
if k == curr {
found = true
}
}
return first
}
func comparePaths(p1, p2 []string) bool { func comparePaths(p1, p2 []string) bool {
return strings.Join(p1, " → ") == strings.Join(p2, " → ") return strings.Join(p1, " → ") == strings.Join(p2, " → ")
} }

View File

@ -31,9 +31,14 @@ func stringify(v []byte) string {
return fmt.Sprintf("%x", v) return fmt.Sprintf("%x", v)
} }
func stringifyPath(path []string) []string { func stringifyStringPath(path []string) []string {
for k, v := range path { return stringifyPath(stringPathToBytePath(path))
path[k] = stringify([]byte(v)) }
}
return path func stringifyPath(path [][]byte) []string {
var ret []string
for _, v := range path {
ret = append(ret, stringify(v))
}
return ret
} }