Documentation
¶
Overview ¶
Package kv provides a command-oriented data access layer for key-value, cache, and document stores. It is part of the Grove ecosystem and shares Grove's hook, plugin, CRDT, and internal infrastructure.
Grove KV is not a fake SQL abstraction over SET/GET — it exposes native idioms per store (Redis pipelines, DynamoDB expressions, Memcached CAS) while providing a unified Store interface for common operations.
Quick Start ¶
rdb := redisdriver.New() // import "github.com/xraph/grove/kv/drivers/redisdriver"
rdb.Open(ctx, "redis://localhost:6379/0")
store, _ := kv.Open(rdb,
kv.WithCodec(codec.JSON()),
)
defer store.Close()
// Basic Get/Set
store.Set(ctx, "user:1", user, kv.WithTTL(time.Hour))
store.Get(ctx, "user:1", &user)
Design Principles ¶
- Command-oriented, not query-oriented
- Native idioms per store via Unwrap()
- Shared DNA with Grove (hooks, plugins, CRDT, observability)
- CRDT-native distributed state
- Struct-aware serialization via codecs
- First-class TTL and eviction
Index ¶
- Constants
- Variables
- func CommandName(op hook.Operation) string
- func Drivers() []string
- func OpenDriver(ctx context.Context, name, dsn string) (driver.Driver, error)
- func RegisterDriver(name string, factory DriverFactory)
- type Batch
- type BatchResult
- type DriverFactory
- type Entry
- type Option
- type SetOption
- type Store
- func (s *Store) Close() error
- func (s *Store) Codec() codec.Codec
- func (s *Store) Delete(ctx context.Context, keys ...string) error
- func (s *Store) Driver() driver.Driver
- func (s *Store) Eval(ctx context.Context, script string, keys []string, args ...any) (any, error)
- func (s *Store) EvalSHA(ctx context.Context, sha string, keys []string, args ...any) (any, error)
- func (s *Store) Exists(ctx context.Context, keys ...string) (int64, error)
- func (s *Store) Expire(ctx context.Context, key string, ttl time.Duration) error
- func (s *Store) Get(ctx context.Context, key string, dest any) error
- func (s *Store) GetRaw(ctx context.Context, key string) ([]byte, error)
- func (s *Store) HDel(ctx context.Context, key string, fields ...string) (int64, error)
- func (s *Store) HGet(ctx context.Context, key, field string) ([]byte, error)
- func (s *Store) HGetAll(ctx context.Context, key string) (map[string][]byte, error)
- func (s *Store) HLen(ctx context.Context, key string) (int64, error)
- func (s *Store) HSet(ctx context.Context, key string, fields map[string][]byte) (int64, error)
- func (s *Store) Hooks() *hook.Engine
- func (s *Store) MGet(ctx context.Context, keys []string, dest map[string]any) error
- func (s *Store) MGetRaw(ctx context.Context, keys []string) ([][]byte, error)
- func (s *Store) MSet(ctx context.Context, pairs map[string]any, opts ...SetOption) error
- func (s *Store) Ping(ctx context.Context) error
- func (s *Store) Publish(ctx context.Context, channel string, message []byte) error
- func (s *Store) SAdd(ctx context.Context, key string, members ...string) (int64, error)
- func (s *Store) SCard(ctx context.Context, key string) (int64, error)
- func (s *Store) SIsMember(ctx context.Context, key, member string) (bool, error)
- func (s *Store) SMembers(ctx context.Context, key string) ([]string, error)
- func (s *Store) SRem(ctx context.Context, key string, members ...string) (int64, error)
- func (s *Store) Scan(ctx context.Context, pattern string, fn func(key string) error) error
- func (s *Store) ScriptLoad(ctx context.Context, script string) (string, error)
- func (s *Store) Set(ctx context.Context, key string, value any, opts ...SetOption) error
- func (s *Store) SetRaw(ctx context.Context, key string, value []byte, opts ...SetOption) error
- func (s *Store) Subscribe(ctx context.Context, channel string, handler func(msg []byte)) error
- func (s *Store) SupportsHashes() bool
- func (s *Store) SupportsPubSub() bool
- func (s *Store) SupportsScripts() bool
- func (s *Store) SupportsSets() bool
- func (s *Store) SupportsSortedSets() bool
- func (s *Store) SupportsStreams() bool
- func (s *Store) TTL(ctx context.Context, key string) (time.Duration, error)
- func (s *Store) XAdd(ctx context.Context, stream string, values map[string][]byte) (string, error)
- func (s *Store) XDel(ctx context.Context, stream string, ids ...string) (int64, error)
- func (s *Store) XLen(ctx context.Context, stream string) (int64, error)
- func (s *Store) XRange(ctx context.Context, stream, start, stop string, count int64) ([]driver.StreamMessage, error)
- func (s *Store) ZAdd(ctx context.Context, key string, members ...driver.ScoredMember) (int64, error)
- func (s *Store) ZCard(ctx context.Context, key string) (int64, error)
- func (s *Store) ZRange(ctx context.Context, key string, spec driver.RangeSpec) ([]string, error)
- func (s *Store) ZRangeWithScores(ctx context.Context, key string, spec driver.RangeSpec) ([]driver.ScoredMember, error)
- func (s *Store) ZRem(ctx context.Context, key string, members ...string) (int64, error)
- func (s *Store) ZScore(ctx context.Context, key, member string) (float64, bool, error)
Constants ¶
const ( OpGet hook.Operation = 100 + iota // GET key OpSet // SET key value OpDelete // DEL key [key ...] OpExists // EXISTS key [key ...] OpMGet // MGET key [key ...] OpMSet // MSET key value [key value ...] OpTTL // TTL key OpExpire // EXPIRE key seconds OpScan // SCAN cursor MATCH pattern // Collection operations. A hook sees these the same way it sees the // scalar commands above, which is what lets metrics, tracing, and // tests observe the work a queue or an index actually does rather // than only the plain key reads around it. OpZAdd // ZADD key score member [score member ...] OpZRange // ZRANGEBYSCORE key min max OpZRem // ZREM key member [member ...] OpZCard // ZCARD key OpZScore // ZSCORE key member OpSAdd // SADD key member [member ...] OpSRem // SREM key member [member ...] OpSMbrs // SMEMBERS key OpSCard // SCARD key OpSIsMbr // SISMEMBER key member OpHSet // HSET key field value [field value ...] OpHGet // HGET key field OpHGetAll // HGETALL key OpHDel // HDEL key field [field ...] OpHLen // HLEN key OpPublish // PUBLISH channel message OpSubscr // SUBSCRIBE channel OpEval // EVAL script numkeys key [key ...] arg [arg ...] OpXAdd // XADD stream field value [field value ...] OpXRange // XRANGE stream start end OpXDel // XDEL stream id [id ...] OpXLen // XLEN stream )
KV-specific operations. These extend hook.Operation at an offset to avoid collision with ORM operations (OpSelect, OpInsert, etc.).
Variables ¶
var ( // ErrNotFound is returned when a key does not exist. ErrNotFound = errors.New("kv: key not found") // ErrConflict is returned when a CAS operation detects a version conflict. ErrConflict = errors.New("kv: version conflict (CAS mismatch)") // ErrStoreClosed is returned when an operation is attempted on a closed store. ErrStoreClosed = errors.New("kv: store has been closed") // ErrScriptNotLoaded is returned when EvalSHA names a digest the // server no longer has cached. Callers recover by loading the script // again and retrying; a script cache is not durable across restarts. ErrScriptNotLoaded = errors.New("kv: script not loaded") // ErrNotSupported is returned when a driver does not support the requested operation. ErrNotSupported = errors.New("kv: operation not supported by driver") // ErrHookDenied is returned when a hook denies the operation. ErrHookDenied = errors.New("kv: hook denied the operation") // ErrHookKeyCount is returned when a pre-query hook changes how many // keys a command touches. Hooks may rewrite keys, as a namespace does, // but results are matched to the caller's keys by position. ErrHookKeyCount = errors.New("kv: hook changed the number of keys") // ErrCodecEncode is returned when value encoding fails. ErrCodecEncode = errors.New("kv: codec encode failed") // ErrCodecDecode is returned when value decoding fails. ErrCodecDecode = errors.New("kv: codec decode failed") // ErrKeyEmpty is returned when an empty key is provided. ErrKeyEmpty = errors.New("kv: key must not be empty") // ErrNilValue is returned when a nil value is provided to Set. ErrNilValue = errors.New("kv: value must not be nil") )
Sentinel errors returned by KV operations.
Functions ¶
func CommandName ¶
CommandName returns a human-readable name for a KV operation.
func OpenDriver ¶
OpenDriver creates a new driver instance by its registered name and opens it with the given DSN. Returns an error if no factory is registered for the given name.
func RegisterDriver ¶
func RegisterDriver(name string, factory DriverFactory)
RegisterDriver registers a named KV driver factory. It is typically called from a driver package's init() function. Subsequent calls with the same name overwrite the previous registration.
Example (in redisdriver package):
func init() {
kv.RegisterDriver("redis", func() driver.Driver { return New() })
}
Types ¶
type Batch ¶
type Batch struct {
// contains filtered or unexported fields
}
Batch provides a fluent builder for multi-key operations.
func (*Batch) Exec ¶
func (b *Batch) Exec(ctx context.Context) (*BatchResult, error)
Exec executes all queued batch operations.
func (*Batch) WithOptions ¶
WithOptions sets options for the batch Set operations.
type BatchResult ¶
type BatchResult struct {
// Values holds the raw bytes retrieved by Get operations, keyed by key.
Values map[string][]byte
// Written is the number of keys written.
Written int64
// Deleted is the number of keys deleted.
Deleted int64
}
BatchResult holds the results of a batch operation.
type DriverFactory ¶
DriverFactory is a function that creates a new, unconnected KV driver instance. Drivers register factories via RegisterDriver so that callers can create drivers by name (e.g., from YAML configuration) without importing driver packages directly.
Each driver module should register its factory in an init() function.
type Entry ¶
type Entry[T any] struct { // Key is the full key string. Key string // Value is the decoded value. Value T // TTL is the remaining time-to-live. Zero means no expiry. TTL time.Duration // Version is the CAS version (if supported by the driver). Version uint64 // Metadata carries arbitrary key-value metadata. Metadata map[string]string }
Entry is a typed wrapper around a KV value that carries metadata.
type Option ¶
type Option func(*options)
Option configures a Store during Open.
type SetOption ¶
type SetOption func(*setOptions)
SetOption configures a single Set operation.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the top-level KV handle. It manages the driver connection, hook engine, default codec, and provides entry points for all KV operations.
func Open ¶
Open creates a new Store with the given driver and options. The driver must already be connected (call driver.Open before kv.Open).
func (*Store) EvalSHA ¶ added in v1.6.1
EvalSHA runs a loaded script by digest.
It returns ErrScriptNotLoaded when the server has dropped the script, which happens across restarts: callers reload and retry rather than treating it as a failure.
func (*Store) GetRaw ¶
GetRaw retrieves the raw bytes for key without codec decoding. Used by Keyspace[T] to apply its own codec.
func (*Store) HGet ¶ added in v1.6.1
HGet returns one field's value, or ErrNotFound when it is absent.
func (*Store) MGet ¶
MGet retrieves multiple keys. dest must be a pointer to a map[string]any or similar.
func (*Store) MGetRaw ¶ added in v1.6.1
MGetRaw reads many keys, returning a slice positionally aligned with keys and holding nil where a key was absent.
It is the raw counterpart to MGet, which decodes into a map and so cannot say which key produced which value when some are missing. Positional results are what a caller filtering a batch needs.
func (*Store) Publish ¶ added in v1.6.1
Publish sends a message to a channel.
Delivery is at-most-once and only to subscribers connected at the moment of publication: this is a notification primitive, not a queue. Callers that must not miss a message need a durable structure behind it, with the message serving only to shorten the latency.
func (*Store) ScriptLoad ¶ added in v1.6.1
ScriptLoad caches a script and returns its digest.
func (*Store) SetRaw ¶
SetRaw stores raw bytes under key without codec encoding. Used by Keyspace[T] to apply its own codec.
func (*Store) Subscribe ¶ added in v1.6.1
Subscribe registers a handler for a channel, called for every message until the context ends.
func (*Store) SupportsHashes ¶ added in v1.6.1
SupportsHashes reports whether the driver has hash maps.
func (*Store) SupportsPubSub ¶ added in v1.6.1
SupportsPubSub reports whether the driver has publish/subscribe.
func (*Store) SupportsScripts ¶ added in v1.6.1
SupportsScripts reports whether the driver runs server-side scripts.
func (*Store) SupportsSets ¶ added in v1.6.1
SupportsSets reports whether the driver has unordered sets.
func (*Store) SupportsSortedSets ¶ added in v1.6.1
SupportsSortedSets reports whether the driver has sorted sets.
func (*Store) SupportsStreams ¶ added in v1.6.1
SupportsStreams reports whether the driver has append-only streams.
func (*Store) XRange ¶ added in v1.6.1
func (s *Store) XRange( ctx context.Context, stream, start, stop string, count int64, ) ([]driver.StreamMessage, error)
XRange returns entries between start and stop inclusive, oldest first.
func (*Store) ZAdd ¶ added in v1.6.1
func (s *Store) ZAdd(ctx context.Context, key string, members ...driver.ScoredMember) (int64, error)
ZAdd inserts or updates members of a sorted set.
func (*Store) ZRangeWithScores ¶ added in v1.6.1
func (s *Store) ZRangeWithScores( ctx context.Context, key string, spec driver.RangeSpec, ) ([]driver.ScoredMember, error)
ZRangeWithScores is ZRange carrying each member's score.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package codec provides serialization codecs for KV values.
|
Package codec provides serialization codecs for KV values. |
|
Package kvcrdt bridges grove/crdt types into KV storage, enabling distributed, eventually-consistent state without a relational database.
|
Package kvcrdt bridges grove/crdt types into KV storage, enabling distributed, eventually-consistent state without a relational database. |
|
Package driver defines the interface contract that every KV backend must implement.
|
Package driver defines the interface contract that every KV backend must implement. |
|
drivers
|
|
|
redisdriver
module
|
|
|
extension
module
|
|
|
Package keyspace provides typed, namespaced key partitions for Grove KV.
|
Package keyspace provides typed, namespaced key partitions for Grove KV. |
|
Package kvtest provides a mock KV driver and conformance test suite.
|
Package kvtest provides a mock KV driver and conformance test suite. |
|
Package middleware provides composable middleware for Grove KV operations.
|
Package middleware provides composable middleware for Grove KV operations. |
|
Package extension provides application-level patterns built on Grove KV.
|
Package extension provides application-level patterns built on Grove KV. |