NURLNURL registrynurl-lang.org →

← redis

redis 0.3.1 API

resp.nu

packages/redis/src/resp.nu — RESP (REdis Serialization Protocol, RESP2) codec, pure and I/O-free so it can be unit-tested without a server.

A request is an array of bulk strings: *<n>\r\n ( $<len>\r\n<arg>\r\n ) x n

A reply is one of: simple string (+), error (-), integer (:), bulk string ($, with $-1 = nil) or array (, with -1 = nil). Arrays nest arbitrarily (pub/sub, XRANGE, COMMAND, …), so a reply is decoded into a flat node arena — a Vec RNode where array nodes hold the pool indices of their children. One Vec plus one String per node: no nested Vecs in structs beyond the child-index list. A reply is a plain value: dropping it drops the arena.

( resp_encode args ) → ( Vec u ) request bytes ( resp_parse buf start ) → RespParse one reply (or Incomplete) ( resp_reply_free reply ) → v early release (optional)

Node walking (power users): resp_reply_root / resp_node_kind / resp_node_int / resp_node_str / resp_node_is_nil / resp_node_arr_len / resp_node_arr_at

API

: RNode

: RNode {
    i kind
    i ival  // integer value; for arrays, the element count
    String sval  // string / error text (empty otherwise)
    ( Vec i ) kids  // child node indices (only populated for arrays)
}

RNode.kind: 0 nil · 1 integer · 2 string (simple or bulk) · 3 error · 4 array

: RedisReply

: RedisReply {
    ( Vec RNode ) nodes
    i root
}

A decoded reply: the node arena plus the index of the root node.

: RespParse

: RespParse {
    i status
    RedisReply reply
    i consumed
}

Result of one parse attempt over a byte buffer. status: 0 ok · 1 incomplete (need more bytes) · 2 malformed consumed: bytes consumed from start when status == 0

: RespBuilder

: RespBuilder {
    ( Vec RNode ) nodes
    i status
    i cur
}

Mutable parse state threaded through the recursive descent (an inout local, so the recursion shares one cursor / status / arena).

@ resp_encode ( Vec String ) args → ( Vec u )

Encode a command — an array of bulk strings — into RESP request bytes.

@ resp_parse ( Vec u ) buf i start → RespParse

Parse one reply from buf starting at start. On Incomplete (status 1) the returned reply holds a (partial) arena; it is dropped with the RespParse.

@ resp_reply_free sink RedisReply r → v

Let go of r now rather than at the end of its owner's scope.

@ resp_reply_root RedisReply r → i

@ resp_node_kind RedisReply r i node → i

@ resp_node_int RedisReply r i node → i

@ resp_node_str RedisReply r i node → s

Borrowed view of a string/error node's text (lifetime tied to r).

@ resp_node_is_nil RedisReply r i node → b

@ resp_node_arr_len RedisReply r i node → i

@ resp_node_arr_at RedisReply r i node i k → i


redis.nu

packages/redis/src/redis.nu — a pure-NURL Redis client. Speaks RESP2 over a plain libc TCP socket, or over the pure-NURL TLS client (rediss://) with no OpenSSL on the target. The RESP wire format lives in resp.nu; this file owns the connection, the request/reply round-trip and an ergonomic command surface (GET / SET / INCR / lists / hashes / sets / pub-sub …).

( redis_connect host port ) → !RedisConn RedisErr ( redis_connect_tls host port sni verify ) → !RedisConn RedisErr ( redis_auth conn user password ) → !v RedisErr ( redis_command conn args ) → !RedisReply RedisErr (raw) ( redis_get conn key ) / ( redis_set … ) … → typed helpers ( redis_close conn ) → v early release (optional)

Build arbitrary commands with the arg builder: : ( Vec String ) a ( redis_args ) ( redis_arg a SET ) ( redis_arg a key ) ( redis_arg a val ) : !RedisReply RedisErr r ( redis_command c a )

A RedisConn is a handle: every copy is the same connection, and the last owner closes it (the TLS session or the socket). Replies, strings, messages and argument vectors are plain values. Nothing here is released by hand; the *free functions and redisclose are optional early releases.

API

: | RedisErr

: | RedisErr {
    RedisConnFail  // could not open the TCP socket
    RedisTls  // TLS upgrade failed (handshake / cert error)
    RedisProtocol  // malformed RESP from the server
    RedisIo  // socket read/write failure or unexpected EOF
    RedisServerError  // server returned a RESP error — see redis_last_error
    RedisType  // reply was not the type the helper expected
}

@ redis_err_name RedisErr e → s

: RedisStr

: RedisStr {
    i found
    String val
}

Optional bulk-string reply. found == 0 means the server answered nil (e.g. GET on a missing key); val is owned and empty in that case. A named struct rather than ?String so it round-trips through !T E.

@ redis_str_is_nil RedisStr s → b

@ redis_str_val RedisStr s → s

@ redis_str_free sink RedisStr s → v

Let go of s now rather than at the end of its owner's scope.

: RedisMessage

: RedisMessage {
    i kind
    String channel
    String pattern
    String payload
    i count
}

A pub/sub frame. kind: 0 message · 1 subscribe · 2 unsubscribe · 3 pmessage · 4 psubscribe · 5 punsubscribe · -1 unrecognised. pattern is set only for the p* variants; count is the live subscription count carried by (un)subscribe confirmations.

@ redis_message_kind RedisMessage m → i

@ redis_message_channel RedisMessage m → s

@ redis_message_pattern RedisMessage m → s

@ redis_message_payload RedisMessage m → s

@ redis_message_count RedisMessage m → i

@ redis_message_is_payload RedisMessage m → b

True for an actual published message (message / pmessage), false for a subscribe/unsubscribe control frame.

@ redis_message_free sink RedisMessage m → v

Let go of m now rather than at the end of its owner's scope.

: RedisConnImpl

: RedisConnImpl {
    i tls  // 0 plaintext, 1 TLS
    i raw  // raw socket fd (plaintext reads / fd the TLS layer took over)
    TcpConn tcp  // plaintext transport (writes via tcp_write_all)
    TlsConn tc  // TLS transport (when tls = 1)
    ( Vec u ) rxbuf  // bytes read but not yet parsed into a reply
    String lasterr  // last server error text
    String host_name
    i port_num
    i db_index
}

% Drop RedisConnImpl { @ drop RedisConnImpl c → v { ( __r_close_transport . c tls . c tc . c raw ) } }

The transport is the connection's raw resource: its last owner closes the TLS session or the socket, as redis_close did. The buffer and the strings go with the drop glue.

: RedisConn { s ctl }

@ RedisConn_drop sink RedisConn h → v

@ redis_command RedisConn c__h ( Vec String ) args → !RedisReply RedisErr

Send a command (array of bulk strings) and return its reply. A RESP error reply is surfaced as RedisServerError with the text in conn.lasterr. The caller keeps args and owns the returned reply.

@ redis_args → ( Vec String )

@ redis_arg ( Vec String ) v s a → v

@ redis_arg_i ( Vec String ) v i n → v

@ redis_args_free sink ( Vec String ) v → v

Let go of v now rather than at the end of its owner's scope.

@ redis_connect s host i port → !RedisConn RedisErr

@ redis_connect_tls s host i port s server_name i verify → !RedisConn RedisErr

verify != 0 → verify-full (chain + hostname); verify == 0 → encrypt only.

@ redis_close sink RedisConn c → v

Let go of c now rather than at the end of its owner's scope (the last owner closes the connection).

@ redis_auth RedisConn c__h s user s password → !v RedisErr

AUTH: one-arg (password only) or two-arg (ACL user + password). Pass an empty user for the legacy single-argument form.

@ redis_ping RedisConn c__h → !b RedisErr

@ redis_echo RedisConn c__h s msg → !RedisStr RedisErr

@ redis_set RedisConn c__h s key s val → !v RedisErr

@ redis_get RedisConn c__h s key → !RedisStr RedisErr

@ redis_del RedisConn c__h s key → !i RedisErr

@ redis_exists RedisConn c__h s key → !b RedisErr

@ redis_incr RedisConn c__h s key → !i RedisErr

@ redis_decr RedisConn c__h s key → !i RedisErr

@ redis_incrby RedisConn c__h s key i n → !i RedisErr

@ redis_expire RedisConn c__h s key i secs → !b RedisErr

@ redis_ttl RedisConn c__h s key → !i RedisErr

@ redis_keys RedisConn c__h s pattern → !( Vec String ) RedisErr

@ redis_lpush RedisConn c__h s key s val → !i RedisErr

@ redis_rpush RedisConn c__h s key s val → !i RedisErr

@ redis_llen RedisConn c__h s key → !i RedisErr

@ redis_lrange RedisConn c__h s key i start i stop → !( Vec String ) RedisErr

@ redis_hset RedisConn c__h s key s field s val → !i RedisErr

@ redis_hget RedisConn c__h s key s field → !RedisStr RedisErr

@ redis_hgetall RedisConn c__h s key → !( Vec String ) RedisErr

Flat [field, value, field, value, …] of the whole hash.

@ redis_sadd RedisConn c__h s key s member → !i RedisErr

@ redis_smembers RedisConn c__h s key → !( Vec String ) RedisErr

@ redis_publish RedisConn c__h s channel s msg → !i RedisErr

@ redis_subscribe RedisConn c__h s channel → !RedisMessage RedisErr

Subscribe to a channel (or pattern). Returns the subscription confirmation; thereafter call redis_next_message to receive published messages. While subscribed only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING are valid commands.

@ redis_unsubscribe RedisConn c__h s channel → !RedisMessage RedisErr

@ redis_psubscribe RedisConn c__h s pattern → !RedisMessage RedisErr

@ redis_punsubscribe RedisConn c__h s pattern → !RedisMessage RedisErr

@ redis_next_message RedisConn c__h → !RedisMessage RedisErr

Block until the next pub/sub frame arrives, then decode it. Returns a message / pmessage for delivered payloads, or a (un)subscribe control frame; RedisIo on a closed connection.

@ redis_flushdb RedisConn c__h → !v RedisErr


main.nu

packages/redis/src/main.nu — the redis command: a small redis-cli-style client built on the pure-NURL Redis client. Connects over RESP2 with an optional pure-NURL TLS upgrade (rediss://, no OpenSSL on the target), authenticates with AUTH, runs one command with -c or starts a REPL.

redis [flags] ["redis://[user:pass@]host:port/db"] -h HOST host (default $REDIS_HOST or 127.0.0.1) -p PORT port (default $REDIS_PORT or 6379) -a PASSWORD AUTH password (default $REDIS_PASSWORD) --user USER ACL username for AUTH (Redis 6+) -n DB SELECT database index (default 0) --tls connect over TLS (verify-full) --insecure with --tls / rediss://, skip certificate verification -c "CMD ARGS" run one command and exit; otherwise start a REPL A rediss:// URL implies --tls.

API

& c @ isatty i32 fd → i32

: ConnInfo

: ConnInfo {
    String host
    i port
    String user
    String password
    i db
    i tlsmode  // 0 plain, 1 tls insecure, 2 tls verify-full
}

@ main → i