func (b *BoltStore) DeleteEntry(id string) error {
	err := b.db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(shortedURLsBucket)
		if bucket.Get([]byte(id)) == nil {
			return errors.New("entry already deleted")
		}
		if err := bucket.Delete([]byte(id)); err != nil {
			return errors.Wrap(err, "could not delete entry")
		}
		if err := tx.DeleteBucket([]byte(id)); err != nil && err != bolt.ErrBucketNotFound && err != bolt.ErrBucketExists {
			return errors.Wrap(err, "could not delte bucket")
		}
		uTsIDsBucket := tx.Bucket(shortedIDsToUserBucket)
		return uTsIDsBucket.ForEach(func(k, v []byte) error {
			if bytes.Equal(k, []byte(id)) {
				return uTsIDsBucket.Delete(k)
			}
			return nil
		})
	})
	return errors.Wrap(err, "could not update db")
}
DeleteEntry deleted an entry by a given ID and returns an error
package boltdb
import (
	"bytes"
	"encoding/json"
	"time"
	"github.com/boltdb/bolt"
	"github.com/mxschmitt/golang-url-shortener/internal/stores/shared"
	"github.com/pkg/errors"
)
var (
	shortedURLsBucket      = []byte("shorted")
	shortedIDsToUserBucket = []byte("shorted2Users")
)
type BoltStore struct {
	db *bolt.DB
}
func New(path string) (*BoltStore, error) {
	db, err := bolt.Open(path, 0644, &bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		return nil, errors.Wrap(err, "could not open bolt DB database")
	}
	err = db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucketIfNotExists(shortedURLsBucket); err != nil {
			return errors.Wrapf(err, "could not create %s bucket", shortedURLsBucket)
		}
		if _, err := tx.CreateBucketIfNotExists(shortedIDsToUserBucket); err != nil {
			return errors.Wrapf(err, "could not create %s bucket", shortedIDsToUserBucket)
		}
		return err
	})
	if err != nil {
		return nil, errors.Wrap(err, "could not create buckets")
	}
	return &BoltStore{
		db: db,
	}, nil
}
func (b *BoltStore) Close() error {
	return b.db.Close()
}
func (b *BoltStore) GetEntryByID(id string) (*shared.Entry, error) {
	var raw []byte
	err := b.db.View(func(tx *bolt.Tx) error {
		raw = tx.Bucket(shortedURLsBucket).Get([]byte(id))
		if raw == nil {
			return shared.ErrNoEntryFound
		}
		return nil
	})
	if err != nil {
		return nil, errors.Wrap(err, "could not view db")
	}
	var entry *shared.Entry
	return entry, json.Unmarshal(raw, &entry)
}
func (b *BoltStore) IncreaseVisitCounter(id string) error {
	entry, err := b.GetEntryByID(id)
	if err != nil {
		return errors.Wrap(err, "could not get entry by ID")
	}
	entry.Public.VisitCount++
	currentTime := time.Now()
	entry.Public.LastVisit = &currentTime
	raw, err := json.Marshal(entry)
	if err != nil {
		return errors.Wrap(err, "could not marshal json")
	}
	err = b.db.Update(func(tx *bolt.Tx) error {
		if err := tx.Bucket(shortedURLsBucket).Put([]byte(id), raw); err != nil {
			return errors.Wrap(err, "could not put updated visitor")
		}
		return nil
	})
	return errors.Wrap(err, "could not update entry")
}
func (b *BoltStore) CreateEntry(entry shared.Entry, id, userIdentifier string) error {
	entryRaw, err := json.Marshal(entry)
	if err != nil {
		return errors.Wrap(err, "could not marshal entry")
	}
	err = b.db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(shortedURLsBucket)
		if raw := bucket.Get([]byte(id)); raw != nil {
			return errors.New("entry already exists")
		}
		if err := bucket.Put([]byte(id), entryRaw); err != nil {
			return errors.Wrap(err, "could not put data into bucket")
		}
		uTsURLsBucket, err := tx.CreateBucketIfNotExists(shortedIDsToUserBucket)
		if err != nil {
			return errors.Wrap(err, "could not create bucket")
		}
		return uTsURLsBucket.Put([]byte(id), []byte(userIdentifier))
	})
	return errors.Wrap(err, "could not update db")
}