Viewing buckets is working
This commit is contained in:
		
							
								
								
									
										239
									
								
								bolt_model.go
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								bolt_model.go
									
									
									
									
									
								
							| @@ -1,11 +1,11 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|   "bytes" | ||||
|  | ||||
| 	"github.com/boltdb/bolt" | ||||
| ) | ||||
| @@ -18,8 +18,8 @@ type BoltDB struct { | ||||
| } | ||||
|  | ||||
| type PathNode struct { | ||||
|   name []byte | ||||
|   dataType Datatype | ||||
| 	name     []byte | ||||
| 	dataType Datatype | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -36,13 +36,13 @@ type BoltBucket struct { | ||||
| } | ||||
|  | ||||
| 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 | ||||
|     } | ||||
|   } | ||||
| 	b.name = nm | ||||
| 	for _, dtk := range dataTypeNameSlice { | ||||
| 		if _, err := datatypes[dtk].ToString(nm); err == nil { | ||||
| 			b.nameDatatype = datatypes[dtk] | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -57,27 +57,27 @@ type BoltPair struct { | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	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) getGenericFromStringPath(path []PathNode) (*BoltBucket, *BoltPair, error) { | ||||
| 	return bd.getGenericFromPath(path) | ||||
| } | ||||
|  | ||||
| func (bd *BoltDB) getGenericFromPath(path []PathNode) (*BoltBucket, *BoltPair, error) { | ||||
| @@ -167,7 +167,7 @@ func (bd *BoltDB) getVisibleItemCount(path []PathNode) (int, error) { | ||||
| } | ||||
|  | ||||
| func (bd *BoltDB) buildVisiblePathSlice() ([][]PathNode, error) { | ||||
| 	var retSlice [][]string | ||||
| 	var retSlice [][]PathNode | ||||
| 	var retErr error | ||||
| 	// The root path, recurse for root buckets | ||||
| 	for i := range bd.buckets { | ||||
| @@ -260,7 +260,7 @@ func (bd *BoltDB) openBucket(path []PathNode) error { | ||||
|  | ||||
| func (bd *BoltDB) getBucket(k []byte) (*BoltBucket, error) { | ||||
| 	for i := range bd.buckets { | ||||
|     if bytes.Equal(bd.buckets[i].name, k) { | ||||
| 		if bytes.Equal(bd.buckets[i].name, k) { | ||||
| 			return &bd.buckets[i], nil | ||||
| 		} | ||||
| 	} | ||||
| @@ -278,7 +278,7 @@ func (bd *BoltDB) syncOpenBuckets(shadow *BoltDB) { | ||||
| 	// First test this bucket | ||||
| 	for i := range bd.buckets { | ||||
| 		for j := range shadow.buckets { | ||||
|       if bytes.Equal(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]) | ||||
| 			} | ||||
| 		} | ||||
| @@ -292,7 +292,7 @@ func (bd *BoltDB) refreshDatabase() *BoltDB { | ||||
| 		return tx.ForEach(func(nm []byte, b *bolt.Bucket) error { | ||||
| 			bb, err := readBucket(b) | ||||
| 			if err == nil { | ||||
|         bb.SetName(nm) | ||||
| 				bb.SetName(nm) | ||||
| 				bb.expanded = false | ||||
| 				memBolt.buckets = append(memBolt.buckets, *bb) | ||||
| 				return nil | ||||
| @@ -308,21 +308,22 @@ GetStringName returns the name of the bucket after passing it through it's | ||||
| Datatype ToString function | ||||
| */ | ||||
| func (b *BoltBucket) GetStringName() string { | ||||
|   ret, err := b.nameDatatype.ToString(b.name) | ||||
|   if err != nil { | ||||
|     return stringify(b.name) | ||||
|   } | ||||
|   return ret | ||||
| 	ret, err := b.nameDatatype.ToString(b.name) | ||||
| 	if err != nil { | ||||
| 		return stringify(b.name) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| /* | ||||
| GetPath returns the database path leading to this BoltBucket | ||||
| */ | ||||
| func (b *BoltBucket) GetPath() [][]byte { | ||||
| func (b *BoltBucket) GetPath() []PathNode { | ||||
| 	bktPath := PathNode{name: b.name, dataType: b.nameDatatype} | ||||
| 	if b.parent != nil { | ||||
| 		return append(b.parent.GetPath(), b.name) | ||||
| 		return append(b.parent.GetPath(), bktPath) | ||||
| 	} | ||||
| 	return [][]byte{b.name} | ||||
| 	return []PathNode{bktPath} | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -332,7 +333,7 @@ The passed prefix is the path leading to the current bucket | ||||
| func (b *BoltBucket) buildVisiblePathSlice(prefix []PathNode) ([][]PathNode, error) { | ||||
| 	var retSlice [][]PathNode | ||||
| 	var retErr error | ||||
|   bucketNode := PathNode{b.name, b.nameDatatype} | ||||
| 	bucketNode := PathNode{b.name, b.nameDatatype} | ||||
| 	retSlice = append(retSlice, append(prefix, bucketNode)) | ||||
| 	if b.expanded { | ||||
| 		// Add subbuckets | ||||
| @@ -356,7 +357,7 @@ func (b *BoltBucket) syncOpenBuckets(shadow *BoltBucket) { | ||||
| 	b.expanded = shadow.expanded | ||||
| 	for i := range b.buckets { | ||||
| 		for j := range shadow.buckets { | ||||
|       if bytes.Equal(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]) | ||||
| 			} | ||||
| 		} | ||||
| @@ -393,28 +394,30 @@ 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 | ||||
| 	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 | ||||
| 	ret, err := p.valDatatype.ToString(p.val) | ||||
| 	if err != nil { | ||||
| 		return stringify(p.val) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| /* | ||||
| GetPath Returns the path of the BoltPair | ||||
| */ | ||||
| func (p *BoltPair) GetPath() [][]byte { | ||||
| 	return append(p.parent.GetPath(), p.key) | ||||
| func (p *BoltPair) GetPath() []PathNode { | ||||
| 	return append(p.parent.GetPath(), PathNode{name: p.key, dataType: p.keyDatatype}) | ||||
| } | ||||
|  | ||||
| /* This is a go-between function (between the boltbrowser structs | ||||
| @@ -424,9 +427,9 @@ func (p *BoltPair) GetPath() [][]byte { | ||||
|  * Mainly used for moving a bucket from one path to another | ||||
|  * as in the 'renameBucket' function below. | ||||
|  */ | ||||
| func addBucketFromBoltBucket(path [][]byte, bb *BoltBucket) error { | ||||
| func addBucketFromBoltBucket(path []PathNode, bb *BoltBucket) error { | ||||
| 	if err := insertBucket(path, bb.name); err == nil { | ||||
| 		bucketPath := append(path, bb.name) | ||||
| 		bucketPath := append(path, PathNode{name: bb.name, dataType: bb.nameDatatype}) | ||||
| 		for i := range bb.pairs { | ||||
| 			if err = insertPair(bucketPath, bb.pairs[i].key, bb.pairs[i].val); err != nil { | ||||
| 				return err | ||||
| @@ -441,7 +444,7 @@ func addBucketFromBoltBucket(path [][]byte, bb *BoltBucket) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func deleteKey(path [][]byte) error { | ||||
| func deleteKey(path []PathNode) error { | ||||
| 	if AppArgs.ReadOnly { | ||||
| 		return errors.New("DB is in Read-Only Mode") | ||||
| 	} | ||||
| @@ -450,13 +453,13 @@ func deleteKey(path [][]byte) error { | ||||
| 		// the rest are buckets leading to that key | ||||
| 		if len(path) == 1 { | ||||
| 			// Deleting a root bucket | ||||
| 			return tx.DeleteBucket(path[0]) | ||||
| 			return tx.DeleteBucket(path[0].name) | ||||
| 		} | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 1 { | ||||
| 				for i := range path[1 : len(path)-1] { | ||||
| 					b = b.Bucket(path[i+1]) | ||||
| 					b = b.Bucket(path[i+1].name) | ||||
| 					if b == nil { | ||||
| 						return errors.New("deleteKey: Invalid Path") | ||||
| 					} | ||||
| @@ -464,11 +467,11 @@ func deleteKey(path [][]byte) error { | ||||
| 			} | ||||
| 			// Now delete the last key in the path | ||||
| 			var err error | ||||
| 			if deleteBkt := b.Bucket(path[len(path)-1]); deleteBkt == nil { | ||||
| 			if deleteBkt := b.Bucket(path[len(path)-1].name); deleteBkt == nil { | ||||
| 				// Must be a pair | ||||
| 				err = b.Delete(path[len(path)-1]) | ||||
| 				err = b.Delete(path[len(path)-1].name) | ||||
| 			} else { | ||||
| 				err = b.DeleteBucket(path[len(path)-1]) | ||||
| 				err = b.DeleteBucket(path[len(path)-1].name) | ||||
| 			} | ||||
| 			return err | ||||
| 		} | ||||
| @@ -484,9 +487,9 @@ func readBucket(b *bolt.Bucket) (*BoltBucket, error) { | ||||
| 	b.ForEach(func(k, v []byte) error { | ||||
| 		if v == nil { | ||||
| 			tb, err := readBucket(b.Bucket(k)) | ||||
| 			tb.parent = bb | ||||
| 			if err == nil { | ||||
|         tb.SetName(k) | ||||
| 				tb.parent = bb | ||||
| 				tb.SetName(k) | ||||
| 				bb.buckets = append(bb.buckets, *tb) | ||||
| 			} | ||||
| 		} else { | ||||
| @@ -497,8 +500,8 @@ func readBucket(b *bolt.Bucket) (*BoltBucket, error) { | ||||
| 	return bb, nil | ||||
| } | ||||
|  | ||||
| func renameBucket(path [][]byte, name []byte) error { | ||||
| 	if bytes.Equal(name, path[len(path)-1]) { | ||||
| func renameBucket(path []PathNode, name []byte) error { | ||||
| 	if bytes.Equal(name, path[len(path)-1].name) { | ||||
| 		// No change requested | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -506,11 +509,11 @@ func renameBucket(path [][]byte, name []byte) error { | ||||
| 	err := db.View(func(tx *bolt.Tx) error { | ||||
| 		// len(b.path)-1 is the key we need to delete, | ||||
| 		// the rest are buckets leading to that key | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 1 { | ||||
| 				for i := range path[1:len(path)] { | ||||
| 					b = b.Bucket(path[i+1]) | ||||
| 					b = b.Bucket(path[i+1].name) | ||||
| 					if b == nil { | ||||
| 						return errors.New("renameBucket: Invalid Path") | ||||
| 					} | ||||
| @@ -539,7 +542,7 @@ func renameBucket(path [][]byte, name []byte) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	// Rechristen our cached bucket | ||||
|   bb.SetName(name) | ||||
| 	bb.SetName(name) | ||||
| 	// And re-add it | ||||
|  | ||||
| 	parentPath := path[:len(path)-1] | ||||
| @@ -549,26 +552,26 @@ func renameBucket(path [][]byte, name []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func updatePairKey(path [][]byte, k []byte) error { | ||||
| func updatePairKey(path []PathNode, k []byte) error { | ||||
| 	if AppArgs.ReadOnly { | ||||
| 		return errors.New("DB is in Read-Only Mode") | ||||
| 	} | ||||
| 	err := db.Update(func(tx *bolt.Tx) error { | ||||
| 		// len(b.path)-1 is the key for the pair we're updating, | ||||
| 		// the rest are buckets leading to that key | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 0 { | ||||
| 				for i := range path[1 : len(path)-1] { | ||||
| 					b = b.Bucket(path[i+1]) | ||||
| 					b = b.Bucket(path[i+1].name) | ||||
| 					if b == nil { | ||||
| 						return errors.New("updatePairValue: Invalid Path") | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			bk := path[len(path)-1] | ||||
| 			v := b.Get(bk) | ||||
| 			err := b.Delete(bk) | ||||
| 			v := b.Get(bk.name) | ||||
| 			err := b.Delete(bk.name) | ||||
| 			if err == nil { | ||||
| 				// Old pair has been deleted, now add the new one | ||||
| 				err = b.Put(k, v) | ||||
| @@ -581,25 +584,25 @@ func updatePairKey(path [][]byte, k []byte) error { | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func updatePairValue(path [][]byte, v []byte) error { | ||||
| func updatePairValue(path []PathNode, v []byte) error { | ||||
| 	if AppArgs.ReadOnly { | ||||
| 		return errors.New("DB is in Read-Only Mode") | ||||
| 	} | ||||
| 	err := db.Update(func(tx *bolt.Tx) error { | ||||
| 		// len(b.GetPath())-1 is the key for the pair we're updating, | ||||
| 		// the rest are buckets leading to that key | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 0 { | ||||
| 				for i := range path[1 : len(path)-1] { | ||||
| 					b = b.Bucket(path[i+1]) | ||||
| 					b = b.Bucket(path[i+1].name) | ||||
| 					if b == nil { | ||||
| 						return errors.New("updatePairValue: Invalid Path") | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Now update the last key in the path | ||||
| 			err := b.Put(path[len(path)-1], v) | ||||
| 			err := b.Put(path[len(path)-1].name, v) | ||||
| 			return err | ||||
| 		} | ||||
| 		return errors.New("updatePairValue: Invalid Path") | ||||
| @@ -607,7 +610,7 @@ func updatePairValue(path [][]byte, v []byte) error { | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func insertBucket(path [][]byte, n []byte) error { | ||||
| func insertBucket(path []PathNode, n []byte) error { | ||||
| 	if AppArgs.ReadOnly { | ||||
| 		return errors.New("DB is in Read-Only Mode") | ||||
| 	} | ||||
| @@ -621,12 +624,12 @@ func insertBucket(path [][]byte, n []byte) error { | ||||
| 			} | ||||
| 		} else { | ||||
| 			rootBucket, path := path[0], path[1:] | ||||
| 			b := tx.Bucket(rootBucket) | ||||
| 			b := tx.Bucket(rootBucket.name) | ||||
| 			if b != nil { | ||||
| 				for len(path) > 0 { | ||||
| 					var tstBucket []byte | ||||
| 					var tstBucket PathNode | ||||
| 					tstBucket, path = path[0], path[1:] | ||||
| 					nB := b.Bucket(tstBucket) | ||||
| 					nB := b.Bucket(tstBucket.name) | ||||
| 					if nB == nil { | ||||
| 						// Not a bucket, if we're out of path, just move on | ||||
| 						if len(path) != 0 { | ||||
| @@ -647,7 +650,7 @@ func insertBucket(path [][]byte, n []byte) error { | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func insertPair(path [][]byte, k []byte, v []byte) error { | ||||
| func insertPair(path []PathNode, k []byte, v []byte) error { | ||||
| 	if AppArgs.ReadOnly { | ||||
| 		return errors.New("DB is in Read-Only Mode") | ||||
| 	} | ||||
| @@ -658,11 +661,11 @@ func insertPair(path [][]byte, k []byte, v []byte) error { | ||||
| 			return errors.New("insertPair: Cannot insert pair at root") | ||||
| 		} | ||||
| 		var err error | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 0 { | ||||
| 				for i := 1; i < len(path); i++ { | ||||
| 					b = b.Bucket(path[i]) | ||||
| 					b = b.Bucket(path[i].name) | ||||
| 					if b == nil { | ||||
| 						return fmt.Errorf("insertPair: %s", err) | ||||
| 					} | ||||
| @@ -679,63 +682,79 @@ func insertPair(path [][]byte, k []byte, v []byte) error { | ||||
| } | ||||
|  | ||||
| func stringPathToBytePath(path []string) [][]byte { | ||||
|   var ret [][]byte | ||||
|   for _, v := range path { | ||||
|     ret = append(ret, []byte(v)) | ||||
|   } | ||||
|   return ret | ||||
| 	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 | ||||
| 	var ret []string | ||||
| 	for _, v := range path { | ||||
| 		ret = append(ret, string(v)) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| func exportValue(path [][]byte, fName string) error { | ||||
| func nodePathToStringPath(path []PathNode) []string { | ||||
| 	var ret []string | ||||
| 	for _, v := range path { | ||||
| 		add, err := v.dataType.ToString(v.name) | ||||
| 		if err != nil { | ||||
| 			add = "ERROR" | ||||
| 		} | ||||
| 		ret = append(ret, add) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| func exportValue(path []PathNode, fName string) error { | ||||
| 	return db.View(func(tx *bolt.Tx) error { | ||||
| 		// len(b.path)-1 is the key whose value we want to export | ||||
| 		// the rest are buckets leading to that key | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 1 { | ||||
| 				for i := range path[1 : len(path)-1] { | ||||
| 					b = b.Bucket(path[i+1]) | ||||
| 					b = b.Bucket(path[i+1].name) | ||||
| 					if b == nil { | ||||
| 						return errors.New("exportValue: Invalid Path: " + strings.Join(bytePathToStringPath(path), "/")) | ||||
| 						return errors.New("exportValue: Invalid Path: " + strings.Join(nodePathToStringPath(path), "/")) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			bk := path[len(path)-1] | ||||
| 			v := b.Get(bk) | ||||
| 			v := b.Get(bk.name) | ||||
| 			return writeToFile(fName, string(v)+"\n", os.O_CREATE|os.O_WRONLY|os.O_TRUNC) | ||||
| 		} | ||||
| 		return errors.New("exportValue: Invalid Bucket") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func exportJSON(path [][]byte, fName string) error { | ||||
| func exportJSON(path []PathNode, fName string) error { | ||||
| 	return db.View(func(tx *bolt.Tx) error { | ||||
| 		// len(b.path)-1 is the key whose value we want to export | ||||
| 		// the rest are buckets leading to that key | ||||
| 		b := tx.Bucket(path[0]) | ||||
| 		b := tx.Bucket(path[0].name) | ||||
| 		if b != nil { | ||||
| 			if len(path) > 1 { | ||||
| 				for i := range path[1 : len(path)-1] { | ||||
| 					b = b.Bucket(path[i+1]) | ||||
| 					b = b.Bucket(path[i+1].name) | ||||
| 					if b == nil { | ||||
| 						return errors.New("exportValue: Invalid Path: " + strings.Join(bytePathToStringPath(path), "/")) | ||||
| 						return errors.New("exportValue: Invalid Path: " + strings.Join(nodePathToStringPath(path), "/")) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			bk := path[len(path)-1] | ||||
| 			if v := b.Get(bk); v != nil { | ||||
| 				return writeToFile(fName, "{\""+string(bk)+"\":\""+string(v)+"\"}", os.O_CREATE|os.O_WRONLY|os.O_TRUNC) | ||||
| 			if v := b.Get(bk.name); v != nil { | ||||
| 				str, err := bk.dataType.ToString(bk.name) | ||||
| 				if err != nil { | ||||
| 					str = "ERROR" | ||||
| 				} | ||||
| 				return writeToFile(fName, "{\""+str+"\":\""+string(v)+"\"}", os.O_CREATE|os.O_WRONLY|os.O_TRUNC) | ||||
| 			} | ||||
| 			if b.Bucket(bk) != nil { | ||||
| 				return writeToFile(fName, genJSONString(b.Bucket(bk)), os.O_CREATE|os.O_WRONLY|os.O_TRUNC) | ||||
| 			if b.Bucket(bk.name) != nil { | ||||
| 				return writeToFile(fName, genJSONString(b.Bucket(bk.name)), os.O_CREATE|os.O_WRONLY|os.O_TRUNC) | ||||
| 			} | ||||
| 			return writeToFile(fName, genJSONString(b), os.O_CREATE|os.O_WRONLY|os.O_TRUNC) | ||||
| 		} | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| @@ -40,7 +41,7 @@ type BrowserScreen struct { | ||||
| 	leftPaneBuffer  []Line | ||||
| 	rightPaneBuffer []Line | ||||
|  | ||||
|   niceLog []string | ||||
| 	niceLog []string | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -164,7 +165,7 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int { | ||||
| 	} else if event.Key == termbox.KeyEnter { | ||||
| 		b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath) | ||||
| 		if b != nil { | ||||
| 			screen.db.toggleOpenBucket(stringPathToBytePath(screen.currentPath)) | ||||
| 			screen.db.toggleOpenBucket(screen.currentPath) | ||||
| 		} else if p != nil { | ||||
| 			screen.startEditItem() | ||||
| 		} | ||||
| @@ -173,7 +174,7 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int { | ||||
| 		b, p, _ := screen.db.getGenericFromStringPath(screen.currentPath) | ||||
| 		// Select the current item | ||||
| 		if b != nil { | ||||
| 			screen.db.toggleOpenBucket(stringPathToBytePath(screen.currentPath)) | ||||
| 			screen.db.toggleOpenBucket(screen.currentPath) | ||||
| 		} else if p != nil { | ||||
| 			screen.startEditItem() | ||||
| 		} else { | ||||
| @@ -184,17 +185,17 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int { | ||||
| 		// If we are _on_ a bucket that's open, close it | ||||
| 		b, _, e := screen.db.getGenericFromStringPath(screen.currentPath) | ||||
| 		if e == nil && b != nil && b.expanded { | ||||
| 			screen.db.closeBucket(stringPathToBytePath(screen.currentPath)) | ||||
| 			screen.db.closeBucket(screen.currentPath) | ||||
| 		} else { | ||||
| 			if len(screen.currentPath) > 1 { | ||||
| 				parentBucket, err := screen.db.getBucketFromPath(stringPathToBytePath(screen.currentPath[:len(screen.currentPath)-1])) | ||||
| 				parentBucket, err := screen.db.getBucketFromPath(screen.currentPath[:len(screen.currentPath)-1]) | ||||
| 				if err == nil { | ||||
| 					screen.db.closeBucket(parentBucket.GetPath()) | ||||
| 					// Figure out how far up we need to move the cursor | ||||
| 					screen.currentPath = bytePathToStringPath(parentBucket.GetPath()) | ||||
| 					screen.currentPath = parentBucket.GetPath() | ||||
| 				} | ||||
| 			} else { | ||||
| 				screen.db.closeBucket(stringPathToBytePath(screen.currentPath)) | ||||
| 				screen.db.closeBucket(screen.currentPath) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -209,24 +210,24 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int { | ||||
|  | ||||
| 	} else if event.Ch == 't' { | ||||
| 		// 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()) | ||||
| 		p, err := screen.db.getPairFromPath(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()) | ||||
|     } | ||||
| 	} 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 | ||||
| } | ||||
| @@ -242,11 +243,11 @@ func (screen *BrowserScreen) handleInputKeyEvent(event termbox.Event) int { | ||||
| 			if b != nil { | ||||
| 				if screen.mode == modeChangeKey { | ||||
| 					newName := screen.inputModal.GetValue() | ||||
| 					if renameBucket(stringPathToBytePath(screen.currentPath), []byte(newName)) != nil { | ||||
| 					if renameBucket(screen.currentPath, []byte(newName)) != nil { | ||||
| 						screen.setMessage("Error renaming bucket.") | ||||
| 					} else { | ||||
| 						b.name = []byte(newName) | ||||
| 						screen.currentPath[len(screen.currentPath)-1] = newName | ||||
| 						screen.currentPath[len(screen.currentPath)-1].name = b.name | ||||
| 						screen.setMessage("Bucket Renamed!") | ||||
| 						screen.refreshDatabase() | ||||
| 					} | ||||
| @@ -254,17 +255,17 @@ func (screen *BrowserScreen) handleInputKeyEvent(event termbox.Event) int { | ||||
| 			} else if p != nil { | ||||
| 				if screen.mode == modeChangeKey { | ||||
| 					newKey := screen.inputModal.GetValue() | ||||
| 					if updatePairKey(stringPathToBytePath(screen.currentPath), []byte(newKey)) != nil { | ||||
| 					if updatePairKey(screen.currentPath, []byte(newKey)) != nil { | ||||
| 						screen.setMessage("Error occurred updating Pair.") | ||||
| 					} else { | ||||
| 						p.key = []byte(newKey) | ||||
| 						screen.currentPath[len(screen.currentPath)-1] = newKey | ||||
| 						screen.currentPath[len(screen.currentPath)-1].name = p.key | ||||
| 						screen.setMessage("Pair updated!") | ||||
| 						screen.refreshDatabase() | ||||
| 					} | ||||
| 				} else if screen.mode == modeChangeVal { | ||||
| 					newVal := screen.inputModal.GetValue() | ||||
| 					if updatePairValue(stringPathToBytePath(screen.currentPath), []byte(newVal)) != nil { | ||||
| 					if updatePairValue(screen.currentPath, []byte(newVal)) != nil { | ||||
| 						screen.setMessage("Error occurred updating Pair.") | ||||
| 					} else { | ||||
| 						p.val = []byte(newVal) | ||||
| @@ -286,13 +287,13 @@ func (screen *BrowserScreen) handleDeleteKeyEvent(event termbox.Event) int { | ||||
| 		if screen.confirmModal.IsAccepted() { | ||||
| 			holdNextPath := screen.db.getNextVisiblePath(screen.currentPath) | ||||
| 			holdPrevPath := screen.db.getPrevVisiblePath(screen.currentPath) | ||||
| 			if deleteKey(stringPathToBytePath(screen.currentPath)) == nil { | ||||
| 			if deleteKey(screen.currentPath) == nil { | ||||
| 				screen.refreshDatabase() | ||||
| 				// Move the current path endpoint appropriately | ||||
| 				//found_new_path := false | ||||
| 				if holdNextPath != nil { | ||||
| 					if len(holdNextPath) > 2 { | ||||
| 						if holdNextPath[len(holdNextPath)-2] == screen.currentPath[len(screen.currentPath)-2] { | ||||
| 						if bytes.Equal(holdNextPath[len(holdNextPath)-2].name, screen.currentPath[len(screen.currentPath)-2].name) { | ||||
| 							screen.currentPath = holdNextPath | ||||
| 						} else if holdPrevPath != nil { | ||||
| 							screen.currentPath = holdPrevPath | ||||
| @@ -328,12 +329,21 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int { | ||||
| 		screen.inputModal.HandleEvent(event) | ||||
| 		if screen.inputModal.IsDone() { | ||||
| 			newVal := screen.inputModal.GetValue() | ||||
| 			// TODO: Just default datatype to string? Or should we infer it somehow? | ||||
| 			useType := datatypes["string"] | ||||
| 			nodeName, err := useType.FromString(newVal) | ||||
| 			if err != nil { | ||||
| 				screen.setMessage("Error Inserting new item. Data did not match datatype.") | ||||
| 				return BrowserScreenIndex | ||||
| 			} | ||||
| 			newNode := PathNode{name: nodeName, dataType: useType} | ||||
| 			screen.inputModal.Clear() | ||||
| 			var insertPath []string | ||||
| 			var insertPath []PathNode | ||||
| 			if len(screen.currentPath) > 0 { | ||||
| 				_, p, e := screen.db.getGenericFromStringPath(screen.currentPath) | ||||
| 				if e != nil { | ||||
| 					screen.setMessage("Error Inserting new item. Invalid Path.") | ||||
| 					return BrowserScreenIndex | ||||
| 				} | ||||
| 				insertPath = screen.currentPath | ||||
| 				// where are we inserting? | ||||
| @@ -345,14 +355,14 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int { | ||||
| 					if len(screen.currentPath) > 1 { | ||||
| 						insertPath = screen.currentPath[:len(screen.currentPath)-1] | ||||
| 					} else { | ||||
| 						insertPath = make([]string, 0) | ||||
| 						insertPath = make([]PathNode, 0) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			parentB, _, _ := screen.db.getGenericFromStringPath(insertPath) | ||||
| 			if screen.mode&modeInsertBucket == modeInsertBucket { | ||||
| 				err := insertBucket(stringPathToBytePath(insertPath), []byte(newVal)) | ||||
| 				err := insertBucket(insertPath, newNode.name) | ||||
| 				if err != nil { | ||||
| 					screen.setMessage(fmt.Sprintf("%s => %s", err, insertPath)) | ||||
| 				} else { | ||||
| @@ -360,13 +370,13 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int { | ||||
| 						parentB.expanded = true | ||||
| 					} | ||||
| 				} | ||||
| 				screen.currentPath = append(insertPath, newVal) | ||||
| 				screen.currentPath = append(insertPath, newNode) | ||||
|  | ||||
| 				screen.refreshDatabase() | ||||
| 				screen.mode = modeBrowse | ||||
| 				screen.inputModal.Clear() | ||||
| 			} else if screen.mode&modeInsertPair == modeInsertPair { | ||||
| 				err := insertPair(stringPathToBytePath(insertPath), []byte(newVal), []byte{}) | ||||
| 				err := insertPair(insertPath, []byte(newVal), []byte{}) | ||||
| 				if err != nil { | ||||
| 					screen.setMessage(fmt.Sprintf("%s => %s", err, insertPath)) | ||||
| 					screen.refreshDatabase() | ||||
| @@ -376,7 +386,7 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int { | ||||
| 					if parentB != nil { | ||||
| 						parentB.expanded = true | ||||
| 					} | ||||
| 					screen.currentPath = append(insertPath, newVal) | ||||
| 					screen.currentPath = append(insertPath, newNode) | ||||
| 					screen.refreshDatabase() | ||||
| 					screen.startEditItem() | ||||
| 				} | ||||
| @@ -398,7 +408,7 @@ func (screen *BrowserScreen) handleExportKeyEvent(event termbox.Event) int { | ||||
| 			if screen.mode&modeExportValue == modeExportValue { | ||||
| 				// Exporting the value | ||||
| 				if p != nil { | ||||
| 					if err := exportValue(stringPathToBytePath(screen.currentPath), fileName); err != nil { | ||||
| 					if err := exportValue(screen.currentPath, fileName); err != nil { | ||||
| 						//screen.setMessage("Error Exporting to file " + fileName + ".") | ||||
| 						screen.setMessage(err.Error()) | ||||
| 					} else { | ||||
| @@ -407,7 +417,7 @@ func (screen *BrowserScreen) handleExportKeyEvent(event termbox.Event) int { | ||||
| 				} | ||||
| 			} else if screen.mode&modeExportJSON == modeExportJSON { | ||||
| 				if b != nil || p != nil { | ||||
| 					if exportJSON(stringPathToBytePath(screen.currentPath), fileName) != nil { | ||||
| 					if exportJSON(screen.currentPath, fileName) != nil { | ||||
| 						screen.setMessage("Error Exporting to file " + fileName + ".") | ||||
| 					} else { | ||||
| 						screen.setMessage("Value exported to file: " + fileName) | ||||
| @@ -429,7 +439,7 @@ func (screen *BrowserScreen) jumpCursorUp(distance int) bool { | ||||
| 		for idx, pth := range visPaths { | ||||
| 			startJump := true | ||||
| 			for i := range pth { | ||||
| 				if len(screen.currentPath) > i && pth[i] != screen.currentPath[i] { | ||||
| 				if len(screen.currentPath) > i && !bytes.Equal(pth[i].name, screen.currentPath[i].name) { | ||||
| 					startJump = false | ||||
| 				} | ||||
| 			} | ||||
| @@ -443,7 +453,7 @@ func (screen *BrowserScreen) jumpCursorUp(distance int) bool { | ||||
| 		} | ||||
| 		isCurPath := true | ||||
| 		for i := range screen.currentPath { | ||||
| 			if screen.currentPath[i] != findPath[i] { | ||||
| 			if !bytes.Equal(screen.currentPath[i].name, findPath[i].name) { | ||||
| 				isCurPath = false | ||||
| 				break | ||||
| 			} | ||||
| @@ -462,7 +472,7 @@ func (screen *BrowserScreen) jumpCursorDown(distance int) bool { | ||||
| 			startJump := true | ||||
|  | ||||
| 			for i := range pth { | ||||
| 				if len(screen.currentPath) > i && pth[i] != screen.currentPath[i] { | ||||
| 				if len(screen.currentPath) > i && !bytes.Equal(pth[i].name, screen.currentPath[i].name) { | ||||
| 					startJump = false | ||||
| 				} | ||||
| 			} | ||||
| @@ -476,7 +486,7 @@ func (screen *BrowserScreen) jumpCursorDown(distance int) bool { | ||||
| 		} | ||||
| 		isCurPath := true | ||||
| 		for i := range screen.currentPath { | ||||
| 			if screen.currentPath[i] != findPath[i] { | ||||
| 			if !bytes.Equal(screen.currentPath[i].name, findPath[i].name) { | ||||
| 				isCurPath = false | ||||
| 				break | ||||
| 			} | ||||
| @@ -602,26 +612,30 @@ func (screen *BrowserScreen) drawLeftPane(style Style) { | ||||
|  | ||||
| func (screen *BrowserScreen) buildRightPane(style Style) { | ||||
| 	screen.rightPaneBuffer = nil | ||||
|   screen.niceLog = []string{} | ||||
| 	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) | ||||
| 	var logstr string | ||||
| 	for _, v := range screen.currentPath { | ||||
| 		vStr, err := v.dataType.ToString(v.name) | ||||
| 		if err != nil { | ||||
| 			vStr = "ERROR" | ||||
| 		} | ||||
| 		logstr = fmt.Sprintf("%s / %s", logstr, vStr) | ||||
| 	} | ||||
| 	screen.niceLog = append(screen.niceLog, logstr) | ||||
|  | ||||
| 	b, p, err := screen.db.getGenericFromStringPath(screen.currentPath) | ||||
| 	if err == nil { | ||||
| 		if b != nil { | ||||
| 			screen.rightPaneBuffer = append(screen.rightPaneBuffer, | ||||
| 				Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(b.GetPath()), " → ")), style.defaultFg, style.defaultBg}) | ||||
| 				Line{fmt.Sprintf("Path: %s", strings.Join(nodePathToStringPath(b.GetPath()), " → ")), style.defaultFg, style.defaultBg}) | ||||
| 			screen.rightPaneBuffer = append(screen.rightPaneBuffer, | ||||
| 				Line{fmt.Sprintf("Buckets: %d", len(b.buckets)), style.defaultFg, style.defaultBg}) | ||||
| 			screen.rightPaneBuffer = append(screen.rightPaneBuffer, | ||||
| 				Line{fmt.Sprintf("Pairs: %d", len(b.pairs)), style.defaultFg, style.defaultBg}) | ||||
| 		} else if p != nil { | ||||
| 			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(nodePathToStringPath(p.GetPath()), " → ")), style.defaultFg, style.defaultBg}) | ||||
| 			screen.rightPaneBuffer = append(screen.rightPaneBuffer, | ||||
| 				Line{fmt.Sprintf("Key (%s): %s", p.keyDatatype.Name(), stringify([]byte(p.key))), style.defaultFg, style.defaultBg}) | ||||
|  | ||||
| @@ -640,18 +654,18 @@ func (screen *BrowserScreen) buildRightPane(style Style) { | ||||
| 		} | ||||
| 	} else { | ||||
| 		screen.rightPaneBuffer = append(screen.rightPaneBuffer, | ||||
| 			Line{fmt.Sprintf("Path: %s", strings.Join(stringifyStringPath(screen.currentPath), " → ")), style.defaultFg, style.defaultBg}) | ||||
| 			Line{fmt.Sprintf("Path: %s", strings.Join(nodePathToStringPath(screen.currentPath), " → ")), style.defaultFg, style.defaultBg}) | ||||
| 		screen.rightPaneBuffer = append(screen.rightPaneBuffer, | ||||
| 			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}) | ||||
|   } | ||||
| 	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) { | ||||
| @@ -708,7 +722,7 @@ func formatValueJSON(val []byte) ([]byte, error) { | ||||
| func (screen *BrowserScreen) bucketToLines(bkt *BoltBucket, style Style) []Line { | ||||
| 	var ret []Line | ||||
| 	bfg, bbg := style.defaultFg, style.defaultBg | ||||
| 	if comparePaths(screen.currentPath, bytePathToStringPath(bkt.GetPath())) { | ||||
| 	if comparePaths(screen.currentPath, bkt.GetPath()) { | ||||
| 		bfg, bbg = style.cursorFg, style.cursorBg | ||||
| 	} | ||||
| 	bktPrefix := strings.Repeat(" ", len(bkt.GetPath())*2) | ||||
| @@ -719,7 +733,7 @@ func (screen *BrowserScreen) bucketToLines(bkt *BoltBucket, style Style) []Line | ||||
| 		} | ||||
| 		for _, bp := range bkt.pairs { | ||||
| 			pfg, pbg := style.defaultFg, style.defaultBg | ||||
| 			if comparePaths(screen.currentPath, bytePathToStringPath(bp.GetPath())) { | ||||
| 			if comparePaths(screen.currentPath, bp.GetPath()) { | ||||
| 				pfg, pbg = style.cursorFg, style.cursorBg | ||||
| 			} | ||||
| 			prPrefix := strings.Repeat(" ", len(bp.GetPath())*2) | ||||
| @@ -814,10 +828,11 @@ func (screen *BrowserScreen) startInsertItemAtParent(tp BoltType) bool { | ||||
| 	} else { | ||||
| 		var insPath string | ||||
| 		_, p, e := screen.db.getGenericFromStringPath(screen.currentPath[:len(screen.currentPath)-1]) | ||||
| 		stringPath := nodePathToStringPath(screen.currentPath) | ||||
| 		if e == nil && p != nil { | ||||
| 			insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-2], " → ") + " → " | ||||
| 			insPath = strings.Join(stringPath[:len(stringPath)-2], " → ") + " → " | ||||
| 		} else { | ||||
| 			insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-1], " → ") + " → " | ||||
| 			insPath = strings.Join(stringPath[:len(stringPath)-1], " → ") + " → " | ||||
| 		} | ||||
| 		titlePrfx := "" | ||||
| 		if tp == typeBucket { | ||||
| @@ -857,10 +872,11 @@ func (screen *BrowserScreen) startInsertItem(tp BoltType) bool { | ||||
| 	screen.inputModal = mod | ||||
| 	var insPath string | ||||
| 	_, p, e := screen.db.getGenericFromStringPath(screen.currentPath) | ||||
| 	strPath := nodePathToStringPath(screen.currentPath) | ||||
| 	if e == nil && p != nil { | ||||
| 		insPath = strings.Join(screen.currentPath[:len(screen.currentPath)-1], " → ") + " → " | ||||
| 		insPath = strings.Join(strPath[:len(strPath)-1], " → ") + " → " | ||||
| 	} else { | ||||
| 		insPath = strings.Join(screen.currentPath, " → ") + " → " | ||||
| 		insPath = strings.Join(strPath, " → ") + " → " | ||||
| 	} | ||||
| 	titlePrfx := "" | ||||
| 	if tp == typeBucket { | ||||
| @@ -901,7 +917,12 @@ func (screen *BrowserScreen) startExportValue() bool { | ||||
| 		screen.mode = modeExportValue | ||||
| 		return true | ||||
| 	} | ||||
| 	screen.setMessage("Couldn't do string export on " + screen.currentPath[len(screen.currentPath)-1] + "(did you mean 'X'?)") | ||||
| 	expNode := screen.currentPath[len(screen.currentPath)-1] | ||||
| 	strVal, err := expNode.dataType.ToString(expNode.name) | ||||
| 	if err != nil { | ||||
| 		strVal = "ERROR" | ||||
| 	} | ||||
| 	screen.setMessage("Couldn't do string export on " + strVal + " (did you mean 'X'?)") | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| @@ -954,22 +975,30 @@ func (screen *BrowserScreen) refreshDatabase() { | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	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 { | ||||
| 	return strings.Join(p1, " → ") == strings.Join(p2, " → ") | ||||
| func comparePaths(p1, p2 []PathNode) bool { | ||||
| 	if len(p1) != len(p2) { | ||||
| 		return false | ||||
| 	} | ||||
| 	for k := range p1 { | ||||
| 		if !bytes.Equal(p1[k].name, p2[k].name) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|   | ||||
| @@ -32,11 +32,11 @@ func stringify(v []byte) string { | ||||
| } | ||||
|  | ||||
| func stringifyStringPath(path []string) []string { | ||||
|   return stringifyPath(stringPathToBytePath(path)) | ||||
| 	return stringifyPath(stringPathToBytePath(path)) | ||||
| } | ||||
|  | ||||
| func stringifyPath(path [][]byte) []string { | ||||
|   var ret []string | ||||
| 	var ret []string | ||||
| 	for _, v := range path { | ||||
| 		ret = append(ret, stringify(v)) | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user