A Go library providing unified interfaces for key-value stores. This library abstracts different KV database implementations (BadgerDB, BoltDB, in-memory) behind common interfaces, enabling easy switching between backends without code changes.
- Unified Interface: Common API for different key-value stores
- Generic Type Safety: Full Go 1.18+ generics support for type-safe operations
- Transaction Support: Read and write transactions with proper error handling
- Bucket Management: Organized data storage with bucket abstraction
- Metrics Integration: Built-in Prometheus metrics support
- Relation Store: Bidirectional 1:N relationship management
- Benchmarking: Performance testing framework included
go get github.com/bborbe/kvpackage main
import (
"context"
"fmt"
"github.com/bborbe/kv"
"github.com/bborbe/badgerkv" // or boltkv, memorykv
)
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
ctx := context.Background()
// Create database instance (example with badgerkv)
db, err := badgerkv.Open("/tmp/mydb")
if err != nil {
panic(err)
}
defer db.Close()
// Create a type-safe store
userStore := kv.NewStore[string, User](db, kv.BucketName("users"))
// Add a user
user := User{ID: "123", Name: "Alice", Email: "[email protected]"}
if err := userStore.Add(ctx, user.ID, user); err != nil {
panic(err)
}
// Get a user
retrievedUser, err := userStore.Get(ctx, "123")
if err != nil {
panic(err)
}
fmt.Printf("User: %+v\n", *retrievedUser)
// Check if user exists
exists, err := userStore.Exists(ctx, "123")
if err != nil {
panic(err)
}
fmt.Printf("User exists: %v\n", exists)
}// Manual transaction control
err := db.Update(ctx, func(ctx context.Context, tx kv.Tx) error {
bucket, err := tx.CreateBucket(kv.BucketName("users"))
if err != nil {
return err
}
userData, _ := json.Marshal(user)
return bucket.Put(ctx, []byte("123"), userData)
})// Stream all users
userCh := make(chan User, 10)
go func() {
defer close(userCh)
userStore.Stream(ctx, userCh)
}()
for user := range userCh {
fmt.Printf("User: %+v\n", user)
}
// Or map over all users
userStore.Map(ctx, func(ctx context.Context, key string, user User) error {
fmt.Printf("Key: %s, User: %+v\n", key, user)
return nil
})The library uses a layered interface approach:
-
DB Interface - Database lifecycle management
Update()- Write transactionsView()- Read-only transactionsSync(),Close(),Remove()- Database management
-
Transaction Interface - Bucket operations within transactions
Bucket(),CreateBucket(),DeleteBucket()- Bucket managementListBucketNames()- Bucket enumeration
-
Bucket Interface - Key-value operations
Put(),Get(),Delete()- Basic operationsIterator(),IteratorReverse()- Iteration support
-
Generic Store Layer - Type-safe operations
- Uses Go generics:
Store[KEY ~[]byte | ~string, OBJECT any] - Automatic JSON marshaling/unmarshaling
- Composed interfaces:
StoreAdder,StoreGetter,StoreRemover, etc.
- Uses Go generics:
Monitor your database operations with Prometheus metrics:
import "github.com/prometheus/client_golang/prometheus"
// Wrap your DB with metrics
metricsDB := kv.NewDBWithMetrics(db, prometheus.DefaultRegisterer, "myapp")Manage bidirectional 1:N relationships:
relationStore := kv.NewRelationStore[string, string](db, kv.BucketName("user_groups"))
// Add relationships
relationStore.Add(ctx, "user123", "group456")
relationStore.Add(ctx, "user123", "group789")
// Query relationships
groups, err := relationStore.GetByA(ctx, "user123") // Returns: ["group456", "group789"]
users, err := relationStore.GetByB(ctx, "group456") // Returns: ["user123"]This library defines interfaces implemented by three concrete packages:
- badgerkv - BadgerDB implementation (LSM-tree, high performance)
- boltkv - BoltDB implementation (B+ tree, ACID compliance)
- memorykv - In-memory implementation (testing/development)
// BadgerDB for high-performance scenarios
db, err := badgerkv.Open("/path/to/badger")
// BoltDB for ACID compliance
db, err := boltkv.Open("/path/to/bolt.db")
// In-memory for testing
db := memorykv.New()The library includes comprehensive test suites that can be reused for implementations:
import "github.com/bborbe/kv"
// Use the basic test suite for your implementation
var _ = Describe("MyKV", func() {
kv.BasicTestSuite(func() kv.Provider {
return mykvProvider{}
})
})- Go 1.18+ (for generics support)
# Full pre-commit pipeline
make precommit
# Run tests
make test
# Format code
make format
# Generate mocks
make generate
# Check code quality
make checkThis project is licensed under the BSD-style license. See the LICENSE file for details.