-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrepo.bolt.go
129 lines (114 loc) · 3.38 KB
/
repo.bolt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/boltdb/bolt"
"go.uber.org/zap"
)
type boltBookStorage struct {
logger *zap.Logger
client *bolt.DB
config *BoltDBConfig
}
// GetBoltClient setup the database and the bucket then provides a ready to use client.
func GetBoltDBClient(config *Config) (*bolt.DB, error) {
db, err := bolt.Open(config.BoltDB.FilePath, 0o644, &bolt.Options{Timeout: config.BoltDB.Timeout})
if err != nil {
return nil, fmt.Errorf("failed to open the database, %v", err)
}
err = db.Update(func(tx *bolt.Tx) error {
if _, errB := tx.CreateBucketIfNotExists([]byte(config.BoltDB.BucketName)); errB != nil {
return fmt.Errorf("failed to create %s bucket: %v", config.BoltDB.BucketName, errB)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to set up bucket: %v", err)
}
return db, nil
}
// NewBoltBookStorage provides an instance of bolt-based book storage.
func NewBoltBookStorage(logger *zap.Logger, boltConfig *BoltDBConfig, client *bolt.DB) BookStorage {
return &boltBookStorage{
logger: logger,
client: client,
config: boltConfig,
}
}
// Close shuts down the bolt-based book storage.
func (bs *boltBookStorage) Close() error {
return bs.client.Close()
}
// Add inserts a new book record into boltdb store.
func (bs *boltBookStorage) Add(_ context.Context, id string, book Book) error {
bookBytes, err := json.Marshal(book)
if err != nil {
return err
}
err = bs.client.Update(func(tx *bolt.Tx) error {
return tx.Bucket([]byte(bs.config.BucketName)).Put([]byte(id), bookBytes)
})
return err
}
// GetOne retrieves a book record based on its ID from boltdb store.
func (bs *boltBookStorage) GetOne(_ context.Context, id string) (Book, error) {
var book Book
// initialize a readable transaction.
tx, err := bs.client.Begin(false)
if err != nil {
return book, err
}
defer func() {
_ = tx.Rollback()
}()
result := tx.Bucket([]byte(bs.config.BucketName)).Get([]byte(id))
if result == nil {
return book, ErrBookNotFound
}
err = json.Unmarshal(result, &book)
return book, err
}
// Delete removes a book record based on its ID from boltdb store.
func (bs *boltBookStorage) Delete(_ context.Context, id string) error {
return bs.client.Update(func(tx *bolt.Tx) error {
return tx.Bucket([]byte(bs.config.BucketName)).Delete([]byte(id))
})
}
// Update replaces existing book record data or inserts a new book if does not exist.
func (bs *boltBookStorage) Update(_ context.Context, id string, book Book) (Book, error) {
bookBytes, err := json.Marshal(book)
if err != nil {
return book, err
}
err = bs.client.Update(func(tx *bolt.Tx) error {
return tx.Bucket([]byte(bs.config.BucketName)).Put([]byte(id), bookBytes)
})
return book, err
}
// GetAll retrieves a list of all books stored in the bolt database.
func (bs *boltBookStorage) GetAll(_ context.Context) ([]Book, error) {
tx, err := bs.client.Begin(false)
if err != nil {
return nil, err
}
defer func() {
_ = tx.Rollback()
}()
// Create a cursor on the books' bucket.
c := tx.Bucket([]byte(bs.config.BucketName)).Cursor()
books := []Book{}
for k, v := c.First(); k != nil; k, v = c.Next() {
var book Book
if err = json.Unmarshal(v, &book); err != nil {
return nil, err
}
books = append(books, book)
}
return books, nil
}
// DeleteAll removes all stored books.
func (bs *boltBookStorage) DeleteAll(_ context.Context) error {
// TODO
return nil
}