Skip to content

Commit

Permalink
Add ErrKeyNotFound to reader.Get (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
gerardsn authored Jan 3, 2023
1 parent 6137e9b commit 3ed9b65
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 18 deletions.
2 changes: 1 addition & 1 deletion badger/badger.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func (t badgerShelf) Get(key stoabs.Key) ([]byte, error) {
item, err := t.tx.badgerTx.Get(t.key(key).Bytes())
if err != nil {
if errors.Is(err, badger.ErrKeyNotFound) {
return nil, nil
return nil, stoabs.ErrKeyNotFound
}
return nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions bbolt/bbolt.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ type bboltShelf struct {

func (t bboltShelf) Get(key stoabs.Key) ([]byte, error) {
value := t.bucket.Get(key.Bytes())
if value == nil {
return nil, stoabs.ErrKeyNotFound
}

// Because things will go terribly wrong when you use a []byte returned by BBolt outside its transaction,
// we want to make sure to work with a copy.
//
Expand Down
4 changes: 1 addition & 3 deletions bbolt/bbolt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ func TestBBolt_WriteShelf(t *testing.T) {
actual, err = reader.Get(stoabs.BytesKey(key))
return err
})
if !assert.NoError(t, err) {
return
}
assert.ErrorIs(t, err, stoabs.ErrKeyNotFound)
assert.Nil(t, actual)
})
}
Expand Down
10 changes: 4 additions & 6 deletions kvtests/common_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestReadingAndWriting(t *testing.T, storeProvider StoreProvider) {
t.Fatal()
return nil
})
assert.NoError(t, err)
assert.ErrorIs(t, err, stoabs.ErrKeyNotFound)
})

t.Run("read non-existing key", func(t *testing.T) {
Expand All @@ -134,9 +134,7 @@ func TestReadingAndWriting(t *testing.T, storeProvider StoreProvider) {
actual, err = reader.Get(bytesKey)
return err
})
if !assert.NoError(t, err) {
return
}
assert.ErrorIs(t, err, stoabs.ErrKeyNotFound)
assert.Nil(t, actual)
})
})
Expand Down Expand Up @@ -598,7 +596,7 @@ func TestWriteTransactions(t *testing.T, storeProvider StoreProvider) {
actual, err = reader.Get(bytesKey)
return err
})
assert.NoError(t, err)
assert.ErrorIs(t, err, stoabs.ErrKeyNotFound)
assert.Nil(t, actual)
})
})
Expand Down Expand Up @@ -685,7 +683,7 @@ func TestDelete(t *testing.T, storeProvider StoreProvider) {
actual, err = reader.Get(bytesKey)
return err
})
assert.NoError(t, err)
assert.ErrorIs(t, err, stoabs.ErrKeyNotFound)
assert.Nil(t, actual)
})
t.Run("delete non-existing entry", func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions redis7/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ func (s shelf) Delete(key stoabs.Key) error {

func (s shelf) Get(key stoabs.Key) ([]byte, error) {
result, err := s.reader.Get(s.ctx, s.toRedisKey(key)).Result()
if err == redis.Nil {
return nil, nil
if errors.Is(err, redis.Nil) {
return nil, stoabs.ErrKeyNotFound
} else if err != nil {
return nil, stoabs.DatabaseError(err)
}
Expand Down
16 changes: 10 additions & 6 deletions store.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type ErrDatabase struct {

func (e ErrDatabase) Error() string {
// Use Sprintf to avoid dereferencing of wrapped nil error
return fmt.Sprintf("Database Error: %s", e.error)
return fmt.Sprintf("database error: %s", e.error)
}

func (e ErrDatabase) Is(other error) bool {
Expand All @@ -58,6 +58,12 @@ func (e ErrDatabase) Unwrap() error {
// ErrStoreIsClosed is returned when an operation is executed on a closed store. Is also a ErrDatabase.
var ErrStoreIsClosed = DatabaseError(errors.New("database not open"))

// ErrCommitFailed is returned when the commit of transaction fails. Is also a ErrDatabase.
var ErrCommitFailed = DatabaseError(errors.New("unable to commit transaction"))

// ErrKeyNotFound is returned when the requested key does not exist
var ErrKeyNotFound = errors.New("key not found")

const DefaultTransactionTimeout = 30 * time.Second

const defaultLockAcquisitionTimeout = 3 * time.Second
Expand Down Expand Up @@ -138,7 +144,8 @@ type CallerFn func(key Key, value []byte) error

// Reader is used to read from a shelf.
type Reader interface {
// Get returns the value for the given key. If it does not exist it returns nil.
// Get returns the value for the given key.
// If the key does not exist it returns ErrKeyNotFound.
// Returns a ErrDatabase if unsuccessful.
Get(key Key) ([]byte, error)
// Iterate walks over all key/value pairs for this shelf. Ordering is not guaranteed.
Expand All @@ -164,9 +171,6 @@ type Writer interface {
Delete(key Key) error
}

// ErrCommitFailed is returned when the commit of transaction fails. Is also a ErrDatabase.
var ErrCommitFailed = DatabaseError(errors.New("unable to commit transaction"))

type Store interface {
// Close releases all resources associated with the store. It is safe to call multiple (subsequent) times.
// The context being passed can be used to specify a timeout for the close operation.
Expand Down Expand Up @@ -259,7 +263,7 @@ type ReadTx interface {
type NilReader struct{}

func (n NilReader) Get(_ Key) ([]byte, error) {
return nil, nil
return nil, ErrKeyNotFound
}

func (n NilReader) Iterate(_ CallerFn, _ Key) error {
Expand Down
11 changes: 11 additions & 0 deletions store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func TestDatabaseError(t *testing.T) {
assert.ErrorAs(t, ErrStoreIsClosed, new(ErrDatabase), "ErrStoreIsClosed should be a ErrDatabase")
assert.ErrorAs(t, ErrCommitFailed, new(ErrDatabase), "ErrCommitFailed should be a ErrDatabase")
})
t.Run("does not wrap non-db errors", func(t *testing.T) {
assert.False(t, errors.As(ErrKeyNotFound, new(ErrDatabase)), "ErrKeyNotFound is not a ErrDatabase")
})
t.Run("does not double wrap", func(t *testing.T) {
firstError := DatabaseError(errors.New("this is wrapped"))
secondError := DatabaseError(fmt.Errorf("this is not wrapped: %w", firstError))
Expand All @@ -68,3 +71,11 @@ func TestNewErrorWriter(t *testing.T) {
assert.ErrorIs(t, ErrDatabase{}, err)
})
}

func TestNilReader_Get(t *testing.T) {
t.Run("returns error", func(t *testing.T) {
data, err := NilReader{}.Get(BytesKey{})
assert.ErrorIs(t, err, ErrKeyNotFound)
assert.Nil(t, data)
})
}

0 comments on commit 3ed9b65

Please sign in to comment.