Plan stuff. Log stuff.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

197 lines
3.8 KiB

package bolt
import (
"context"
"github.com/gisle/stufflog/database/repositories"
"github.com/gisle/stufflog/models"
"github.com/gisle/stufflog/slerrors"
"github.com/vmihailenco/msgpack/v4"
"go.etcd.io/bbolt"
)
var bnItems = []byte("Item")
type itemRepository struct {
db *bbolt.DB
userIdIdx *index
}
func (r *itemRepository) FindID(ctx context.Context, id string) (*models.Item, error) {
item := new(models.Item)
err := r.db.View(func(tx *bbolt.Tx) error {
value := tx.Bucket(bnItems).Get(unsafeStringToBytes(id))
if value == nil {
return slerrors.NotFound("Period")
}
err := msgpack.Unmarshal(value, item)
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return item, nil
}
func (r *itemRepository) List(ctx context.Context) ([]*models.Item, error) {
items := make([]*models.Item, 0, 16)
err := r.db.View(func(tx *bbolt.Tx) error {
cursor := tx.Bucket(bnItems).Cursor()
for key, value := cursor.First(); key != nil; key, value = cursor.Next() {
item := new(models.Item)
err := msgpack.Unmarshal(value, item)
if err != nil {
return err
}
items = append(items, item)
}
return nil
})
if err != nil {
return nil, err
}
return items, nil
}
func (r *itemRepository) ListUser(ctx context.Context, user models.User) ([]*models.Item, error) {
items := make([]*models.Item, 0, 16)
err := r.db.View(func(tx *bbolt.Tx) error {
bucket := tx.Bucket(bnItems)
ids, err := r.userIdIdx.WithTx(tx).Get(user.ID)
if err != nil {
return err
}
for _, id := range ids {
value := bucket.Get(id)
if value == nil {
continue
}
item := new(models.Item)
err := msgpack.Unmarshal(value, item)
if err != nil {
return err
}
items = append(items, item)
}
return nil
})
if err != nil {
return nil, err
}
return items, nil
}
func (r *itemRepository) Insert(ctx context.Context, item models.Item) error {
value, err := msgpack.Marshal(&item)
if err != nil {
return err
}
return r.db.Update(func(tx *bbolt.Tx) error {
err := tx.Bucket(bnItems).Put(unsafeStringToBytes(item.ID), value)
if err != nil {
return err
}
err = r.index(tx, &item)
if err != nil {
return err
}
return nil
})
}
func (r *itemRepository) Update(ctx context.Context, item models.Item, updates []*models.ItemUpdate) (*models.Item, error) {
for _, update := range updates {
err := item.ApplyUpdate(*update)
if err != nil {
return nil, err
}
}
value, err := msgpack.Marshal(&item)
if err != nil {
return nil, err
}
err = r.db.Update(func(tx *bbolt.Tx) error {
return tx.Bucket(bnItems).Put(unsafeStringToBytes(item.ID), value)
})
if err != nil {
return nil, err
}
return &item, nil
}
func (r *itemRepository) Remove(ctx context.Context, item models.Item) error {
return r.db.Update(func(tx *bbolt.Tx) error {
err := tx.Bucket(bnItems).Delete(unsafeStringToBytes(item.ID))
if err != nil {
return err
}
err = r.unIndex(tx, &item)
if err != nil {
return err
}
return nil
})
}
func (r *itemRepository) index(tx *bbolt.Tx, item *models.Item) error {
idBytes := unsafeStringToBytes(item.ID)
err := r.userIdIdx.WithTx(tx).Set(idBytes, item.UserID)
if err != nil {
return err
}
return nil
}
func (r *itemRepository) unIndex(tx *bbolt.Tx, item *models.Item) error {
idBytes := unsafeStringToBytes(item.ID)
err := r.userIdIdx.WithTx(tx).Set(idBytes)
if err != nil {
return err
}
return nil
}
func newItemRepository(db *bbolt.DB) (repositories.ItemRepository, error) {
err := db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(bnItems)
return err
})
if err != nil {
return nil, err
}
userIdIdx, err := newModelIndex(db, "Item", "UserID")
if err != nil {
return nil, err
}
return &itemRepository{
db: db,
userIdIdx: userIdIdx,
}, nil
}