File: database.go

package info (click to toggle)
golang-github-smallstep-nosql 0.3.8-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 204 kB
  • sloc: makefile: 41
file content (259 lines) | stat: -rw-r--r-- 6,987 bytes parent folder | download | duplicates (2)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
package database

import (
	"fmt"

	"errors"
)

var (
	// ErrNotFound is the type returned on DB implementations if an item does not
	// exist.
	ErrNotFound = errors.New("not found")
	// ErrOpNotSupported is the type returned on DB implementations if an operation
	// is not supported.
	ErrOpNotSupported = errors.New("operation not supported")
)

// IsErrNotFound returns true if the cause of the given error is ErrNotFound.
func IsErrNotFound(err error) bool {
	return err == ErrNotFound || cause(err) == ErrNotFound
}

// IsErrOpNotSupported returns true if the cause of the given error is ErrOpNotSupported.
func IsErrOpNotSupported(err error) bool {
	return err == ErrOpNotSupported || cause(err) == ErrNotFound
}

// cause (from github.com/pkg/errors) returns the underlying cause of the
// error, if possible. An error value has a cause if it implements the
// following interface:
//
//     type causer interface {
//            Cause() error
//     }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}

// Options are configuration options for the database.
type Options struct {
	Database              string
	ValueDir              string
	BadgerFileLoadingMode string
}

// Option is the modifier type over Options.
type Option func(o *Options) error

// WithValueDir is a modifier that sets the ValueDir attribute of Options.
func WithValueDir(path string) Option {
	return func(o *Options) error {
		o.ValueDir = path
		return nil
	}
}

// WithDatabase is a modifier that sets the Database attribute of Options.
func WithDatabase(db string) Option {
	return func(o *Options) error {
		o.Database = db
		return nil
	}
}

// WithBadgerFileLoadingMode is a modifier that sets the ValueLogLoadingMode
// of Badger db.
func WithBadgerFileLoadingMode(mode string) Option {
	return func(o *Options) error {
		o.BadgerFileLoadingMode = mode
		return nil
	}
}

// DB is a interface to be implemented by the databases.
type DB interface {
	// Open opens the database available with the given options.
	Open(dataSourceName string, opt ...Option) error
	// Close closes the current database.
	Close() error
	// Get returns the value stored in the given table/bucket and key.
	Get(bucket, key []byte) (ret []byte, err error)
	// Set sets the given value in the given table/bucket and key.
	Set(bucket, key, value []byte) error
	// CmpAndSwap swaps the value at the given bucket and key if the current
	// value is equivalent to the oldValue input. Returns 'true' if the
	// swap was successful and 'false' otherwise.
	CmpAndSwap(bucket, key, oldValue, newValue []byte) ([]byte, bool, error)
	// Del deletes the data in the given table/bucket and key.
	Del(bucket, key []byte) error
	// List returns a list of all the entries in a given table/bucket.
	List(bucket []byte) ([]*Entry, error)
	// Update performs a transaction with multiple read-write commands.
	Update(tx *Tx) error
	// CreateTable creates a table or a bucket in the database.
	CreateTable(bucket []byte) error
	// DeleteTable deletes a table or a bucket in the database.
	DeleteTable(bucket []byte) error
}

// Badger FileLoadingMode constants.
const (
	BadgerMemoryMap = "mmap"
	BadgerFileIO    = "fileio"
)

// TxCmd is the type used to represent database command and operations.
type TxCmd int

const (
	// CreateTable on a TxEntry will represent the creation of a table or
	// bucket on the database.
	CreateTable TxCmd = iota
	// DeleteTable on a TxEntry will represent the deletion of a table or
	// bucket on the database.
	DeleteTable
	// Get on a TxEntry will represent a command to retrieve data from the
	// database.
	Get
	// Set on a TxEntry will represent a command to write data on the
	// database.
	Set
	// Delete on a TxEntry represent a command to delete data on the database.
	Delete
	// CmpAndSwap on a TxEntry will represent a compare and swap operation on
	// the database. It will compare the value read and change it if it's
	// different. The TxEntry will contain the value read.
	CmpAndSwap
	// CmpOrRollback on a TxEntry will represent a read transaction that will
	// compare the values will the ones passed, and if they don't match the
	// transaction will fail
	CmpOrRollback
)

// String implements the fmt.Stringer interface on TxCmd.
func (o TxCmd) String() string {
	switch o {
	case CreateTable:
		return "create-table"
	case DeleteTable:
		return "delete-table"
	case Get:
		return "read"
	case Set:
		return "write"
	case Delete:
		return "delete"
	case CmpAndSwap:
		return "compare-and-swap"
	case CmpOrRollback:
		return "compare-and-rollback"
	default:
		return fmt.Sprintf("unknown(%d)", o)
	}
}

// Tx represents a transaction and it's list of multiple TxEntry. Each TxEntry
// represents a read or write operation on the database.
type Tx struct {
	Operations []*TxEntry
}

// CreateTable adds a new create query to the transaction.
func (tx *Tx) CreateTable(bucket []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Cmd:    CreateTable,
	})
}

// DeleteTable adds a new create query to the transaction.
func (tx *Tx) DeleteTable(bucket []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Cmd:    DeleteTable,
	})
}

// Get adds a new read query to the transaction.
func (tx *Tx) Get(bucket, key []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Key:    key,
		Cmd:    Get,
	})
}

// Set adds a new write query to the transaction.
func (tx *Tx) Set(bucket, key, value []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Key:    key,
		Value:  value,
		Cmd:    Set,
	})
}

// Del adds a new delete query to the transaction.
func (tx *Tx) Del(bucket, key []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Key:    key,
		Cmd:    Delete,
	})
}

// Cas adds a new compare-and-swap query to the transaction.
func (tx *Tx) Cas(bucket, key, value []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Key:    key,
		Value:  value,
		Cmd:    CmpAndSwap,
	})
}

// Cmp adds a new compare-or-rollback query to the transaction.
func (tx *Tx) Cmp(bucket, key, value []byte) {
	tx.Operations = append(tx.Operations, &TxEntry{
		Bucket: bucket,
		Key:    key,
		Value:  value,
		Cmd:    CmpOrRollback,
	})
}

// TxEntry is the base elements for the transactions, a TxEntry is a read or
// write operation on the database.
type TxEntry struct {
	Bucket   []byte
	Key      []byte
	Value    []byte
	CmpValue []byte
	// Where the result of Get or CmpAndSwap txns is stored.
	Result  []byte
	Cmd     TxCmd
	Swapped bool
}

// Entry is the return value for list commands.
type Entry struct {
	Bucket []byte
	Key    []byte
	Value  []byte
}