expand command surface: strings + sets + lists + zrange/zcount + stream extras
Adds the next layer of Redis-compatible commands plus their EVAL
dispatchers, building on the docket-critical foundation. Surface now
covers everything pydocket / docket-equivalent flows are likely to
exercise plus the supporting string/list/set CRUD.
Strings (matching upstream src/store.rs):
set (with NX/XX, EX/PX TTL), get, mget, keys (glob), ttl, expire,
incrby, decrby (and INCR/DECR alias forms in the EVAL dispatcher).
Sets: sadd, smembers, sismember, srem, scard.
Lists: lpush, rpush, llen, lindex, lrange, lpop, rpop (single +
count forms), lrem (head/tail/all directions), lset, ltrim. Stored as
a std.DoublyLinkedList of intrusive ListNode; head is index 0.
Sorted set extras (on top of earlier ZADD/ZREM/ZCARD/ZSCORE/
ZRANGEBYSCORE/ZREMRANGEBYSCORE): zrange (inclusive index range,
negative supported), zcount.
Stream extras (on top of earlier XADD/XLEN/XDEL/XGROUP CREATE/
XREADGROUP/XACK): xread, xrange, xtrimMaxlen, streamLastId,
xgroupDestroy. Plus a top-level sweepExpired(budget) hook for
background TTL maintenance.
Helpers (free functions, since methods can't reference each other
through anytype):
globMatch — Redis-style *, ?, [..], escape with \
normalizeRange — negative indices + clamping
listLen / listAt — linked-list walk helpers
freeReadResult / freeReadResults — ownership cleanup
scripting.zig now dispatches all these via redis.call, with EVAL
tests exercising SET/GET and list RPUSH/LRANGE through the Lua
bridge. 40/40 tests pass.
Still TODO (filed under #27): LMOVE/RPOPLPUSH/LINSERT/BLPOP_POLL/
BRPOP_POLL, XAUTOCLAIM/XCLAIM/XINFO_*/XPENDING_*, ZRANGESTORE,
PubSub, persistence (MessagePack).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>