scriptling.badgerdb
Overview
scriptling.badgerdb embeds BadgerDB as a local key/value store, no server needed. The string-KV core is mirrored exactly by scriptling.valkey, so those scripts move between local storage and a shared cache by changing the open line and nothing else: strings, hashes, batch operations, counters and TTLs. Valkey’s sets, queues and database selection have no counterpart here; badgerdb implements what the store does natively.
import scriptling.badgerdb as badger
client = badger.open("/var/data/state")
client.set("greeting", "hello", ttl_seconds=60)
print(client.get("greeting")) # hello
print(client.ttl("greeting")) # remaining seconds
client.incr("hits")
print(client.keys("gr*")) # ["greeting"]
client.close()Badger allows one process to hold a database open at a time (a second open fails on the lock file). The directory must fall inside the host’s --allowed-paths when one is configured.
Available Functions
| Function | Description |
|---|---|
open(path) |
Open (creating if needed) a database directory and return a Client |
Client
Identical surface to the valkey Client:
| Method | Description |
|---|---|
get(key) |
Value stored at key, or None when missing |
set(key, value, ttl_seconds=0) |
Store a string; ttl_seconds of 0 means no expiry |
set_if_absent(key, value, ttl_seconds=0) |
Store only when the key does not exist, returning whether it was stored |
mget(*keys) |
Values for the keys in one call, in order; None where a key is missing |
mset(mapping, ttl_seconds=0) |
Store every entry of a dict in one call |
delete(*keys) |
Delete keys, returning how many existed |
exists(*keys) |
Return how many of the keys exist |
expire(key, ttl_seconds) |
Set a key’s time to live; False when the key is missing |
persist(key) |
Remove a key’s expiry so it lives forever; False when missing |
ttl(key) |
Remaining seconds, None when missing, -1 when the key has no expiry |
incr(key, amount=1) |
Add to the integer stored at key, returning the new value |
decr(key, amount=1) |
Subtract from the integer stored at key |
hash_set(key, field, value) |
Set one hash field, returning 1 when the field was new, 0 when it overwrote |
Hashes and plain values keep separate identities, as they do on valkey: a hash command on a key holding a plain value fails with a WRONGTYPE error (and so does a plain command on a hash key), so neither side can overwrite the other’s data.
| hash_get(key, field) | The field’s value, or None when the key or field is missing |
| hash_delete(key, *fields) | Delete fields, returning how many existed; the key disappears with its last field |
| hash_all(key) | Every field and value as a dict; empty when the key is missing |
| hash_size(key) | How many fields the hash holds |
| keys(pattern) | Keys matching a glob pattern (* and ?) |
| ping() | Check the store is reachable, raising on failure |
| close() | Close the database and release its lock |
Transactions, iterators and value-log plumbing stay implementation details inside the plugin: scripts see flat operations. incr preserves a key’s TTL, matching redis semantics.
Hashes
Hashes are implemented the way a key/value store does them natively: a hash
occupies one key, so keys(), exists, delete, expire, ttl and
persist see the whole hash as one key with one expiry covering every field.
The expiry survives field writes and the key disappears with its last field,
the same semantics as on valkey:
client.hash_set("session:1", "user", "ada")
client.hash_set("session:1", "role", "admin")
client.hash_get("session:1", "user") # -> "ada"
client.hash_all("session:1") # -> {"user": "ada", "role": "admin"}
client.expire("session:1", 300) # expiry covers the whole hash
client.hash_size("session:1") # -> 2See Also
- Valkey: the same string-KV core against a server, plus sets and queues
- Database Libraries: all four backends, two API shapes