A Redis client for MoonBit: RESP2 and RESP3, pipelines, transactions, pub/sub, cluster and sentinel.
moon add moonbitstack/moonredisasync fn main {
let options = @moonredis.ClientOptions::at("127.0.0.1", 6379)
let conn = @socket.Connection::connect(options) catch {
_ => return
}
let client = @moonredis.Client::new(conn)
let _ = client.set("greeting", "hello")
match client.get("greeting") {
Some(bytes) => println(@utf8.decode_lossy(bytes[:]))
None => println("(nil)")
}
}| Item | Purpose |
|---|---|
| Client | The command surface: one async method per redis command, named as in redis-py. |
| Client::new(&RedisConn) | A client over a connection. |
| Client::command(Array[Bytes]) | Send a raw command (binary-safe), returning the reply value. |
| RedisConn (open trait) | The transport contract: execute(Array[Bytes]) -> RespValue, and execute_all for several commands in one round trip, which defaults to sending them one at a time. |
| FakeConn | A scripted in-memory connection for tests (new, handler). |
| RedisError | Reply(msg) for a redis error, Connection(msg), Closed, Protocol(msg), and Aborted for a transaction a watched key changed under. |
| Item | Purpose |
|---|---|
| ClientOptions | Endpoint, credentials, protocol, timeouts, and the pool/retry/tracking policies. |
| ClientOptions::at(host, port) | Options at an address over the standard defaults. |
| ClientOptions::with_auth(user?, password?), with_db(db) | Copies with auth or database set. |
| client_default, pool_default, retry_default, tracking_default | The market-standard presets. |
| Protocol | Resp2 or Resp3 (the default). |
| PoolOptions | max_idle, max_active, min_idle, idle_timeout, health_check. |
| RetryOptions | attempts, base_delay, max_delay, level, jitter. |
| TrackingOptions | enabled, bcast, optin, optout, noloop, redirect. |
| backoff_delay(attempt, retry) | The wait before a retry. |
| Item | Purpose |
|---|---|
| Pipeline | Queue commands (add) and send them in one round trip (execute); multi wraps them in MULTI/EXEC. |
| Client::watch, Client::unwatch, Client::discard | Transaction control. |
| ClusterTopology | A slot-to-node map; node_for_slot(slot). |
| ClusterSlot, ClusterSlot::new | A slot range owned by a node. |
| ClusterClient | Routes a command to the node owning its key and follows MOVED and ASK, up to limit (redirect_limit, 3). dial opens nodes it was not built with. |
| Redirect, redirect(msg) | Moved or Ask with the slot and node, read from an error reply. |
| ClusterTopology::assign(slot, node) | Record where a slot lives. |
| crc16(bytes), hash_slot(key), same_slot(keys) | Slot hashing, honouring {hash tags}. |
| decode_cluster_slots(reply) | Parse a CLUSTER SLOTS reply into a ClusterTopology. |
| SentinelClient | Resolve a master address through a list of sentinels. |
| RetryConn, should_retry(error, attempt, retry) | A retrying view of any connection; dial opens a new one after a failure and wait sleeps for the backoff. |
| Item | Purpose |
|---|---|
| Message | A pub/sub frame: kind, channel, payload, pattern, count. |
| Message::parse(value) | Parse a RESP2 array or RESP3 push frame into a Message. |
| StreamEntry | One stream entry: id and fields. |
| PendingSummary | The XPENDING summary: count, min_id, max_id, consumers. |
| Item | Purpose |
|---|---|
| Connection | A real connection over TCP or TLS; implements RedisConn. |
| Connection::connect(options) | Dial and negotiate from ClientOptions. |
| Connection::take_pushes() | Push frames read since the last command, such as the invalidations CLIENT TRACKING sends. |
| connect_retrying(options) | A RetryConn that reconnects under options.retry. Only for commands that are safe to send twice. |
| Pool | Reuse idle connections (get, put, idle_count), bounded by max_idle. |
| Subscription | subscribe/unsubscribe and next for Message frames; pattern and shard select PSUBSCRIBE and SSUBSCRIBE. |
| Item | Purpose |
|---|---|
| RespValue | Every RESP2/RESP3 value: simple string, error, integer, bulk string, null, array, boolean, double, big number, bulk error, verbatim string, map, set, push. |
| RespValue::decode(bytes), encode() | Decode one value (or encode it back). |
| RespReader | Stream a sequence of values (read, at_end, rest). |
| resp_encode_command(args), resp_command(args) | Frame a command as an array of bulk strings. |
| resp_kind(value) | A value's type name, for diagnostics. |
| Family | Methods |
|---|---|
| String | set, set_get, setnx, setex, psetex, get, mget, mset, append, strlen, incr, incrby, decr, decrby, getrange, setrange, getdel, getex |
| Key | del, unlink, exists, expire, pexpire, expireat, pexpireat, persist, ttl, pttl, type_, rename, renamenx, randomkey, touch, move_, copy, keys, scan, object_encoding, object_refcount, object_idletime, dump, restore |
| Hash | hset, hsetnx, hmset, hget, hmget, hgetall, hdel, hexists, hlen, hstrlen, hincrby, hincrbyfloat, hkeys, hvals, hscan, hrandfield |
| List | lpush, rpush, lpushx, rpushx, lpop, lpopn, rpop, rpopn, llen, lindex, lrange, lset, lrem, linsert, ltrim, rpoplpush, lmove, blpop, brpop, brpoplpush, blmove |
| Set | sadd, srem, smembers, sismember, scard, spop, spopn, srandmember, srandmembern, sinter, sunion, sdiff, sinterstore, sunionstore, sdiffstore, smove, sscan |
| Sorted set | zadd, zrem, zscore, zmscore, zincrby, zcard, zrank, zrevrank, zrange, zrange_scores, zrevrange, zrevrange_scores, zrangebyscore, zrangebyscore_scores, zrevrangebyscore, zrevrangebyscore_scores, zcount, zremrangebyrank, zremrangebyscore, zpopmin, zpopmax, zunionstore, zinterstore, zscan, zrandmember, bzpopmin, bzpopmax |
| Stream | xadd, xlen, xdel, xtrim, xrange, xrevrange, xread, xack, xgroup_create, xgroup_destroy, xgroup_createconsumer, xgroup_delconsumer, xreadgroup, xpending |
| HyperLogLog | pfadd, pfcount, pfmerge |
| Geo | geoadd, geodist, geohash, geopos, geosearch |
| Bitmap | setbit, getbit, bitcount, bitpos, bitop |
| Script / function | Script runs a script by digest and reloads it when the server forgets; eval, evalsha, script_load, script_exists, script_flush, function_load, function_call, function_flush, function_delete |
| Pub/sub | publish, spublish, subscribe, unsubscribe, psubscribe, punsubscribe, ssubscribe, sunsubscribe |
| Server / connection | ping, ping_message, echo, select, auth, auth_user, info, dbsize, flushdb, flushall, swapdb, time_, lastsave, save, bgsave, bgrewriteaof, shutdown, config_get, config_set, config_rewrite, config_resetstat, client_setname, client_getname, client_id, client_kill, command_count, slowlog_get, slowlog_len, slowlog_reset, replicaof, replicaof_noone |
let pipeline = @moonredis.Pipeline::new(conn)
pipeline.add([b"SET", b"a", b"1"])
pipeline.add([b"INCR", b"a"])
let replies = pipeline.execute() // [OK, 2]let sub = @socket.Subscription::subscribe(conn, ["news"])
let _ = publisher.publish("news", "hello")
match sub.next() {
Some(message) => println(message.channel + ": " + @utf8.decode_lossy(message.payload[:]))
None => ()
}let registry = @sd.Registry::new(client)
group.spawn_bg(() => @moonsd.hold(registry, "greeter", @moonsd.Endpoint::new("10.0.0.1", 12000)))
let endpoints = registry.resolve("greeter")| Example | Run |
|---|---|
| 01-resp | moon run src/examples/01-resp — the codec, no server. |
| 02-commands | moon run src/examples/02-commands — typed commands against a fake. |
| 03-connect | moon run src/examples/03-connect --target native — a real connection. |
| 04-pipeline | moon run src/examples/04-pipeline --target native — one round trip, and a transaction that loses a race. |
| 05-pubsub | moon run src/examples/05-pubsub --target native — a pattern subscription. |
| 06-cluster | moon run src/examples/06-cluster --target native — keys routed by slot. |
pub(open) trait RedisConn {
async fn execute(Self, Array[Bytes]) -> RespValue raise RedisError
async fn execute_all(Self, Array[Array[Bytes]]) -> Array[RespValue] raise RedisError = _
}async fn Client::auth_user(self : Client, username : String, password : String) -> Unit raise RedisErrorasync fn Client::bitcount(self : Client, key : String, start? : Int, end? : Int) -> Int64 raise RedisErrorasync fn Client::bitop(self : Client, op : String, destination : String, keys : Array[String]) -> Int64 raise RedisErrorasync fn Client::bitpos(self : Client, key : String, bit : Int, start? : Int, end? : Int) -> Int64 raise RedisErrorasync fn Client::blmove(self : Client, source : String, destination : String, wherefrom : String, whereto : String, timeout : Int) -> Bytes? raise RedisErrorasync fn Client::blpop(self : Client, keys : Array[String], timeout : Int) -> (String, Bytes)? raise RedisErrorasync fn Client::brpop(self : Client, keys : Array[String], timeout : Int) -> (String, Bytes)? raise RedisErrorasync fn Client::brpoplpush(self : Client, source : String, destination : String, timeout : Int) -> Bytes? raise RedisErrorasync fn Client::bzpopmax(self : Client, keys : Array[String], timeout : Int) -> (String, String, Double)? raise RedisErrorasync fn Client::bzpopmin(self : Client, keys : Array[String], timeout : Int) -> (String, String, Double)? raise RedisErrorasync fn Client::config_get(self : Client, parameter : String) -> Array[(String, String)] raise RedisErrorasync fn Client::config_set(self : Client, parameter : String, value : String) -> Unit raise RedisErrorasync fn Client::copy(self : Client, source : String, destination : String, db? : Int, replace? : Bool) -> Bool raise RedisErrorasync fn Client::function_load(self : Client, code : String, replace? : Bool) -> String raise RedisErrorasync fn Client::geoadd(self : Client, key : String, points : Array[(String, Double, Double)]) -> Int64 raise RedisErrorasync fn Client::geodist(self : Client, key : String, a : String, b : String, unit? : String) -> Double? raise RedisErrorasync fn Client::geohash(self : Client, key : String, members : Array[String]) -> Array[String?] raise RedisErrorasync fn Client::geopos(self : Client, key : String, members : Array[String]) -> Array[(Double, Double)?] raise RedisErrorasync fn Client::geosearch(self : Client, key : String, from_member? : String, longitude? : Double, latitude? : Double, radius? : Double, width? : Double, height? : Double, unit : String, count? : Int, asc? : Bool, desc? : Bool) -> Array[String] raise RedisErrorasync fn Client::getex(self : Client, key : String, ex? : Int64, px? : Int64, exat? : Int64, pxat? : Int64, persist? : Bool) -> Bytes? raise RedisErrorasync fn Client::getrange(self : Client, key : String, start : Int, end : Int) -> Bytes raise RedisErrorasync fn Client::hdel(self : Client, key : String, fields : Array[String]) -> Int64 raise RedisErrorasync fn Client::hincrby(self : Client, key : String, field : String, n : Int64) -> Int64 raise RedisErrorasync fn Client::hincrbyfloat(self : Client, key : String, field : String, f : Double) -> Double raise RedisErrorasync fn Client::hmget(self : Client, key : String, fields : Array[String]) -> Array[Bytes?] raise RedisErrorasync fn Client::hmset(self : Client, key : String, fields : Array[(String, String)]) -> Unit raise RedisErrorasync fn Client::hrandfield(self : Client, key : String, count? : Int) -> Array[String] raise RedisErrorasync fn Client::hrandfield_values(self : Client, key : String, count : Int) -> Array[(String, String)] raise RedisErrorasync fn Client::hscan(self : Client, key : String, cursor : String, pattern? : String, count? : Int) -> (String, Array[(String, String)]) raise RedisErrorasync fn Client::hset(self : Client, key : String, fields : Array[(String, String)]) -> Int64 raise RedisErrorasync fn Client::hsetnx(self : Client, key : String, field : String, value : String) -> Bool raise RedisErrorasync fn Client::linsert(self : Client, key : String, where_ : String, pivot : String, value : String) -> Int64 raise RedisErrorasync fn Client::lmove(self : Client, source : String, destination : String, wherefrom : String, whereto : String) -> Bytes? raise RedisErrorasync fn Client::lpush(self : Client, key : String, values : Array[String]) -> Int64 raise RedisErrorasync fn Client::lpushx(self : Client, key : String, values : Array[String]) -> Int64 raise RedisErrorasync fn Client::lrange(self : Client, key : String, start : Int, stop : Int) -> Array[Bytes] raise RedisErrorasync fn Client::lrem(self : Client, key : String, count : Int, value : String) -> Int64 raise RedisErrorasync fn Client::lset(self : Client, key : String, index : Int, value : String) -> Unit raise RedisErrorasync fn Client::ltrim(self : Client, key : String, start : Int, stop : Int) -> Unit raise RedisErrorasync fn Client::pexpire(self : Client, key : String, milliseconds : Int64) -> Bool raise RedisErrorasync fn Client::pexpireat(self : Client, key : String, milliseconds_timestamp : Int64) -> Bool raise RedisErrorasync fn Client::pfadd(self : Client, key : String, values : Array[String]) -> Int64 raise RedisErrorasync fn Client::pfmerge(self : Client, destination : String, sources : Array[String]) -> Unit raise RedisErrorasync fn Client::psetex(self : Client, key : String, milliseconds : Int64, value : String) -> Unit raise RedisErrorasync fn Client::publish(self : Client, channel : String, message : String) -> Int64 raise RedisErrorasync fn Client::restore(self : Client, key : String, ttl : Int64, serialized : Bytes, replace? : Bool, absttl? : Bool) -> Unit raise RedisErrorasync fn Client::rpoplpush(self : Client, source : String, destination : String) -> Bytes? raise RedisErrorasync fn Client::rpush(self : Client, key : String, values : Array[String]) -> Int64 raise RedisErrorasync fn Client::rpushx(self : Client, key : String, values : Array[String]) -> Int64 raise RedisErrorasync fn Client::sadd(self : Client, key : String, members : Array[String]) -> Int64 raise RedisErrorasync fn Client::scan(self : Client, cursor : String, pattern? : String, count? : Int, kind? : String) -> (String, Array[String]) raise RedisErrorasync fn Client::sdiffstore(self : Client, destination : String, keys : Array[String]) -> Int64 raise RedisErrorasync fn Client::sentinel_get_master_addr_by_name(self : Client, name : String) -> (String, Int)? raise RedisErrorasync fn Client::set(self : Client, key : String, value : String, ex? : Int64, px? : Int64, nx? : Bool, xx? : Bool, keepttl? : Bool) -> Bool raise RedisErrorasync fn Client::setbit(self : Client, key : String, offset : Int64, value : Int) -> Int64 raise RedisErrorasync fn Client::setex(self : Client, key : String, seconds : Int64, value : String) -> Unit raise RedisErrorasync fn Client::setrange(self : Client, key : String, offset : Int, value : String) -> Int64 raise RedisErrorasync fn Client::sinterstore(self : Client, destination : String, keys : Array[String]) -> Int64 raise RedisErrorasync fn Client::smove(self : Client, source : String, destination : String, m : String) -> Bool raise RedisErrorasync fn Client::spublish(self : Client, channel : String, message : String) -> Int64 raise RedisErrorasync fn Client::srandmembern(self : Client, key : String, count : Int) -> Array[String] raise RedisErrorasync fn Client::srem(self : Client, key : String, members : Array[String]) -> Int64 raise RedisErrorasync fn Client::sscan(self : Client, key : String, cursor : String, pattern? : String, count? : Int) -> (String, Array[String]) raise RedisErrorasync fn Client::sunionstore(self : Client, destination : String, keys : Array[String]) -> Int64 raise RedisErrorasync fn Client::xack(self : Client, key : String, group : String, ids : Array[String]) -> Int64 raise RedisErrorasync fn Client::xadd(self : Client, key : String, id : String, fields : Array[(String, String)], maxlen? : Int64, approx? : Bool) -> String raise RedisErrorasync fn Client::xgroup_create(self : Client, key : String, group : String, id : String, mkstream? : Bool) -> Unit raise RedisErrorasync fn Client::xgroup_createconsumer(self : Client, key : String, group : String, consumer : String) -> Bool raise RedisErrorasync fn Client::xgroup_delconsumer(self : Client, key : String, group : String, consumer : String) -> Int64 raise RedisErrorasync fn Client::xgroup_destroy(self : Client, key : String, group : String) -> Bool raise RedisErrorasync fn Client::xpending(self : Client, key : String, group : String) -> PendingSummary raise RedisErrorasync fn Client::xrange(self : Client, key : String, start : String, end : String, count? : Int) -> Array[StreamEntry] raise RedisErrorasync fn Client::xread(self : Client, streams : Array[(String, String)], count? : Int, block? : Int64) -> Array[(String, Array[StreamEntry])]? raise RedisErrorasync fn Client::xreadgroup(self : Client, group : String, consumer : String, streams : Array[(String, String)], count? : Int, block? : Int64, noack? : Bool) -> Array[(String, Array[StreamEntry])]? raise RedisErrorasync fn Client::xrevrange(self : Client, key : String, end : String, start : String, count? : Int) -> Array[StreamEntry] raise RedisErrorasync fn Client::xtrim(self : Client, key : String, maxlen : Int64, approx? : Bool) -> Int64 raise RedisErrorasync fn Client::zadd(self : Client, key : String, members : Array[(String, Double)], nx? : Bool, xx? : Bool, ch? : Bool) -> Int64 raise RedisErrorasync fn Client::zcount(self : Client, key : String, min : String, max : String) -> Int64 raise RedisErrorasync fn Client::zincrby(self : Client, key : String, increment : Double, m : String) -> Double raise RedisErrorasync fn Client::zinterstore(self : Client, destination : String, keys : Array[String], weights? : Array[Double], aggregate? : String) -> Int64 raise RedisErrorasync fn Client::zmscore(self : Client, key : String, members : Array[String]) -> Array[Double?] raise RedisErrorasync fn Client::zpopmax(self : Client, key : String, count? : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zpopmin(self : Client, key : String, count? : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zrandmember(self : Client, key : String, count? : Int) -> Array[String] raise RedisErrorasync fn Client::zrandmember_scores(self : Client, key : String, count : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zrange(self : Client, key : String, start : Int, stop : Int) -> Array[String] raise RedisErrorasync fn Client::zrange_scores(self : Client, key : String, start : Int, stop : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zrangebyscore(self : Client, key : String, min : String, max : String, offset? : Int, count? : Int) -> Array[String] raise RedisErrorasync fn Client::zrangebyscore_scores(self : Client, key : String, min : String, max : String, offset? : Int, count? : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zrem(self : Client, key : String, members : Array[String]) -> Int64 raise RedisErrorasync fn Client::zremrangebyrank(self : Client, key : String, start : Int, stop : Int) -> Int64 raise RedisErrorasync fn Client::zremrangebyscore(self : Client, key : String, min : String, max : String) -> Int64 raise RedisErrorasync fn Client::zrevrange(self : Client, key : String, start : Int, stop : Int) -> Array[String] raise RedisErrorasync fn Client::zrevrange_scores(self : Client, key : String, start : Int, stop : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zrevrangebyscore(self : Client, key : String, max : String, min : String, offset? : Int, count? : Int) -> Array[String] raise RedisErrorasync fn Client::zrevrangebyscore_scores(self : Client, key : String, max : String, min : String, offset? : Int, count? : Int) -> Array[(String, Double)] raise RedisErrorasync fn Client::zscan(self : Client, key : String, cursor : String, pattern? : String, count? : Int) -> (String, Array[String]) raise RedisErrorasync fn Client::zunionstore(self : Client, destination : String, keys : Array[String], weights? : Array[Double], aggregate? : String) -> Int64 raise RedisErrorpub(all) struct ClientOptions {
host : String
port : Int
username : String?
password : String?
db : Int
protocol : Protocol
tls : Client?
connect_timeout : Int64
read_timeout : Int64
write_timeout : Int64
pool : PoolOptions
retry : RetryOptions
tracking : TrackingOptions
}fn ClientOptions::with_auth(self : ClientOptions, username : String?, password : String?) -> ClientOptionspub struct ClusterClient {
nodes : Map[String, &RedisConn]
topology : ClusterTopology
limit : Int
dial : async (String) -> &RedisConn raise RedisError?
}async fn ClusterClient::command(self : ClusterClient, args : Array[Bytes]) -> RespValue raise RedisErrorfn ClusterClient::new(nodes : Array[(String, &RedisConn)], topology : ClusterTopology, limit? : Int, dial? : async (String) -> &RedisConn raise RedisError) -> ClusterClientpub struct ClusterSlot {
start : Int
end : Int
node : String
}pub struct Message {
kind : String
channel : String
payload : Bytes
pattern : String?
count : Int64
}pub struct PendingSummary {
count : Int64
min_id : String?
max_id : String?
consumers : Array[(String, Int64)]
}pub(all) struct PoolOptions {
max_idle : Int
max_active : Int
min_idle : Int
idle_timeout : Int64
health_check : Bool
}pub(all) enum Protocol {
Resp2
Resp3
}pub struct RetryConn {
inner : &RedisConn
retry : RetryOptions
dial : async () -> &RedisConn raise RedisError?
wait : async (Int64) -> Unit noraise?
}fn RetryConn::new(inner : &RedisConn, retry : RetryOptions, dial? : async () -> &RedisConn raise RedisError, wait? : async (Int64) -> Unit noraise) -> RetryConnpub(all) struct RetryOptions {
attempts : Int
base_delay : Int64
max_delay : Int64
level : Int
jitter : Bool
}pub struct Script {
source : String
// private fields
}pub(all) struct TrackingOptions {
enabled : Bool
bcast : Bool
optin : Bool
optout : Bool
noloop : Bool
redirect : Int64?
}fn crc16(data : Bytes) -> Intfn hash_slot(key : String) -> Intfn is_cluster_down(msg : String) -> Boolfn is_noscript(msg : String) -> Boollet redirect_limit : IntInstall
Download zipA Redis client for MoonBit: RESP2 and RESP3, pipelines, transactions, pub/sub, cluster and sentinel.