func (h *HashMap) DelKey(elementid, key string) error {
	if h.name == nil {
		return ErrDoesNotExist
	}
	return (*bbolt.DB)(h.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.Delete([]byte(elementid + ":" + key))
	})
}
DelKey will remove a key for an entry in a hashmap (for instance the email field for a user)
package simplebolt
import (
	"encoding/binary"
	"errors"
	"strconv"
	"strings"
	"time"
	"go.etcd.io/bbolt"
)
const (
	Version = 5.1
)
type (
	Database bbolt.DB
	boltBucket struct {
		db   *Database  
		name []byte     
	}
	List boltBucket
	Set boltBucket
	HashMap boltBucket
	KeyValue boltBucket
)
var (
	ErrBucketNotFound = errors.New("Bucket not found")
	ErrKeyNotFound = errors.New("Key not found")
	ErrDoesNotExist = errors.New("Does not exist")
	ErrExistsInSet = errors.New("Element already exists in set")
	ErrInvalidID = errors.New("Element ID can not contain \":\"")
	errFoundIt = errors.New("Found it")
	errReachedEnd = errors.New("Reached end of data structure")
)
func New(filename string) (*Database, error) {
	db, err := bbolt.Open(filename, 0600, &bbolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		return nil, err
	}
	return (*Database)(db), nil
}
func (db *Database) Close() {
	(*bbolt.DB)(db).Close()
}
func (db *Database) Path() string {
	return (*bbolt.DB)(db).Path()
}
func (db *Database) Ping() error {
	return nil
}
func NewList(db *Database, id string) (*List, error) {
	name := []byte(id)
	if err := (*bbolt.DB)(db).Update(func(tx *bbolt.Tx) error {
		if _, err := tx.CreateBucketIfNotExists(name); err != nil {
			return errors.New("Could not create bucket: " + err.Error())
		}
		return nil  
	}); err != nil {
		return nil, err
	}
	return &List{db, name}, nil
}
func (l *List) Add(value string) error {
	if l.name == nil {
		return ErrDoesNotExist
	}
	return (*bbolt.DB)(l.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(l.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		n, err := bucket.NextSequence()
		if err != nil {
			return err
		}
		return bucket.Put(byteID(n), []byte(value))
	})
}
func (l *List) All() ([]string, error) {
	var results []string
	if l.name == nil {
		return nil, ErrDoesNotExist
	}
	err := (*bbolt.DB)(l.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(l.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.ForEach(func(_, value []byte) error {
			results = append(results, string(value))
			return nil  
		})
	})
	return results, err
}
func (l *List) Last() (string, error) {
	var result string
	if l.name == nil {
		return "", ErrDoesNotExist
	}
	err := (*bbolt.DB)(l.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(l.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		cursor := bucket.Cursor()
		_, value := cursor.Last()
		result = string(value)
		return nil  
	})
	return result, err
}
func (l *List) LastN(n int) ([]string, error) {
	var results []string
	if l.name == nil {
		return nil, ErrDoesNotExist
	}
	err := (*bbolt.DB)(l.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(l.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		c := bucket.Cursor()
		sizeBytes, _ := c.Last()
		size := binary.BigEndian.Uint64(sizeBytes)
		if size < uint64(n) {
			return errors.New("Too few items in list")
		}
		startPos := byteID(size - uint64(n) + 1)
		for key, value := c.Seek(startPos); key != nil; key, value = c.Next() {
			results = append(results, string(value))
		}
		return nil  
	})
	return results, err
}
func (l *List) Remove() error {
	err := (*bbolt.DB)(l.db).Update(func(tx *bbolt.Tx) error {
		return tx.DeleteBucket(l.name)
	})
	l.name = nil
	return err
}
func (l *List) Clear() error {
	if l.name == nil {
		return ErrDoesNotExist
	}
	return (*bbolt.DB)(l.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(l.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.ForEach(func(key, _ []byte) error {
			return bucket.Delete(key)
		})
	})
}
func NewSet(db *Database, id string) (*Set, error) {
	name := []byte(id)
	if err := (*bbolt.DB)(db).Update(func(tx *bbolt.Tx) error {
		if _, err := tx.CreateBucketIfNotExists(name); err != nil {
			return errors.New("Could not create bucket: " + err.Error())
		}
		return nil  
	}); err != nil {
		return nil, err
	}
	return &Set{db, name}, nil
}
func (s *Set) Add(value string) error {
	if s.name == nil {
		return ErrDoesNotExist
	}
	exists, err := s.Has(value)
	if err != nil {
		return err
	}
	if exists {
		return ErrExistsInSet
	}
	return (*bbolt.DB)(s.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(s.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		n, err := bucket.NextSequence()
		if err != nil {
			return err
		}
		return bucket.Put(byteID(n), []byte(value))
	})
}
func (s *Set) Has(value string) (bool, error) {
	var exists bool
	if s.name == nil {
		return false, ErrDoesNotExist
	}
	err := (*bbolt.DB)(s.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(s.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		bucket.ForEach(func(_, byteValue []byte) error {
			if value == string(byteValue) {
				exists = true
				return errFoundIt  
			}
			return nil  
		})
		return nil  
	})
	return exists, err
}
func (s *Set) All() ([]string, error) {
	var values []string
	if s.name == nil {
		return nil, ErrDoesNotExist
	}
	err := (*bbolt.DB)(s.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(s.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.ForEach(func(_, value []byte) error {
			values = append(values, string(value))
			return nil  
		})
	})
	return values, err
}
func (s *Set) Del(value string) error {
	if s.name == nil {
		return ErrDoesNotExist
	}
	return (*bbolt.DB)(s.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(s.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		var foundKey []byte
		bucket.ForEach(func(byteKey, byteValue []byte) error {
			if value == string(byteValue) {
				foundKey = byteKey
				return errFoundIt  
			}
			return nil  
		})
		return bucket.Delete([]byte(foundKey))
	})
}
func (s *Set) Remove() error {
	err := (*bbolt.DB)(s.db).Update(func(tx *bbolt.Tx) error {
		return tx.DeleteBucket(s.name)
	})
	s.name = nil
	return err
}
func (s *Set) Clear() error {
	if s.name == nil {
		return ErrDoesNotExist
	}
	return (*bbolt.DB)(s.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(s.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.ForEach(func(key, _ []byte) error {
			return bucket.Delete(key)
		})
	})
}
func NewHashMap(db *Database, id string) (*HashMap, error) {
	name := []byte(id)
	if err := (*bbolt.DB)(db).Update(func(tx *bbolt.Tx) error {
		if _, err := tx.CreateBucketIfNotExists(name); err != nil {
			return errors.New("Could not create bucket: " + err.Error())
		}
		return nil  
	}); err != nil {
		return nil, err
	}
	return &HashMap{db, name}, nil
}
func (h *HashMap) Set(elementid, key, value string) error {
	if h.name == nil {
		return ErrDoesNotExist
	}
	if strings.Contains(elementid, ":") {
		return ErrInvalidID
	}
	return (*bbolt.DB)(h.db).Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.Put([]byte(elementid+":"+key), []byte(value))
	})
}
func (h *HashMap) All() ([]string, error) {
	var results []string
	if h.name == nil {
		return nil, ErrDoesNotExist
	}
	err := (*bbolt.DB)(h.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.ForEach(func(byteKey, _ []byte) error {
			combinedKey := string(byteKey)
			if strings.Contains(combinedKey, ":") {
				fields := strings.SplitN(combinedKey, ":", 2)
				for _, result := range results {
					if result == fields[0] {
						return nil  
					}
				}
				results = append(results, string(fields[0]))
			}
			return nil  
		})
	})
	return results, err
}
func (h *HashMap) Get(elementid, key string) (string, error) {
	var val string
	if h.name == nil {
		return "", ErrDoesNotExist
	}
	err := (*bbolt.DB)(h.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		byteval := bucket.Get([]byte(elementid + ":" + key))
		if byteval == nil {
			return ErrKeyNotFound
		}
		val = string(byteval)
		return nil  
	})
	return val, err
}
func (h *HashMap) Has(elementid, key string) (bool, error) {
	var found bool
	if h.name == nil {
		return false, ErrDoesNotExist
	}
	err := (*bbolt.DB)(h.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		byteval := bucket.Get([]byte(elementid + ":" + key))
		if byteval != nil {
			found = true
		}
		return nil  
	})
	return found, err
}
func (h *HashMap) Keys(owner string) ([]string, error) {
	var props []string
	err := (*bbolt.DB)(h.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		return bucket.ForEach(func(byteKey, _ []byte) error {
			combinedKey := string(byteKey)
			if strings.HasPrefix(combinedKey, owner+":") {
				fields := strings.SplitN(combinedKey, ":", 2)
				props = append(props, string(fields[1]))
			}
			return nil  
		})
	})
	return props, err
}
func (h *HashMap) Exists(elementid string) (bool, error) {
	var found bool
	if h.name == nil {
		return false, ErrDoesNotExist
	}
	err := (*bbolt.DB)(h.db).View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket(h.name)
		if bucket == nil {
			return ErrBucketNotFound
		}
		bucket.ForEach(func(byteKey, byteValue []byte) error {
			combinedKey := string(byteKey)
			if strings.Contains(combinedKey, ":") {
				fields := strings.SplitN(combinedKey, ":", 2)
				if fields[0] == elementid {
					found = true
					return errFoundIt
				}
			}
			return nil  
		})
		return nil  
	})
	return found, err
}