redis

package module
v0.0.0-...-6d0931f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 7 Imported by: 0

README

go-ruby-redis/redis

redis — go-ruby-redis

Docs License Go Coverage

A pure-Go (no cgo) reimplementation of the redis / redis-client gem's RESP protocol codec and command layer — the deterministic, interpreter-independent core that encodes a Redis command to the RESP wire format and decodes every RESP2 and RESP3 reply into a small Ruby value model, then coerces each command's reply to the type the gem returns (a Hash for HGETALL, a Set for SMEMBERS, an Integer for EXISTS, a Float for ZSCORE). It builds and parses the wire without any Ruby runtime and without a live redis-server — you feed it bytes.

It is the Redis backend for go-embedded-ruby, but is a standalone, reusable module — a sibling of go-ruby-regexp and go-ruby-marshal.

What it is — and isn't. The RESP grammar and the command→reply-type mapping are fully deterministic and need no interpreter and no server, so they live here as pure Go. The actual TCP/TLS socket is a host seam, mirroring the go-ruby-net-* pattern: a Client drives its commands over an injected Conn (an io.ReadWriter) or a RoundTripper, and the host owns the connection, timeouts and TLS.

Features

  • RESP encode — serialise a command (an array of bulk strings) to the multi-bulk wire form *N\r\n$len\r\n…, plus the legacy inline form. Every argument kind the gem accepts (String, Integer, Float, Symbol, big integers) is stringified exactly as the gem does.
  • RESP decode — parse every reply type:
    • RESP2: simple string +, error -, integer :, bulk string $ (incl. null $-1), array * (incl. null *-1 and arbitrary nesting).
    • RESP3: null _, double , (incl. inf/-inf/nan), boolean #, verbatim string =, big number (, blob error !, map %, set ~, push >, and attribute | (out-of-band metadata carried onto the next reply).
  • Value modelnil / string / int64 / float64 / bool / *big.Int / []any / ordered *Map (Hash) / *Set / *Push / *VerbatimString / *CommandError.
  • Command layer — the gem's method surface, each building a RESP command and coercing its reply to the gem's type: strings (GET/SET/INCR/APPEND/ GETRANGE/MGET…), hashes (HGETALLHash…), lists, sets (SMEMBERSSet…), sorted sets (with Float score parsing), keys (EXPIRE/TTL/TYPE/SCAN→ cursor+keys), server (PING/SELECT/AUTH/HELLO/CONFIG GETHash), pub/sub message framing, MULTI/EXEC transactions and pipelining.
  • Generic escape hatchCall([...]) for any command, mirroring redis.call.
  • CGO-free and validated on all six supported 64-bit targets (amd64, arm64, riscv64, loong64, ppc64le, s390x) across Linux, macOS and Windows.

Usage

import "github.com/go-ruby-redis/redis"

// The socket is the host's; wire any io.ReadWriter (a *net.Conn, a TLS conn, …).
c := redis.NewFromConn(conn)

c.Set("greeting", "hello")             // -> "OK"
v, _ := c.Get("greeting")              // -> "hello"
c.HSet("h", "a", "1", "b", "2")
h, _ := c.HGetAll("h")                 // -> *redis.Map{ "a"=>"1", "b"=>"2" }
c.SAdd("s", "x", "y")
s, _ := c.SMembers("s")                // -> *redis.Set{ "x", "y" }

// Pipelines and transactions batch commands over one write.
res, _ := c.Pipelined(func(b *redis.Batch) {
    b.Add("INCR", "n").Add("INCR", "n")
})                                     // -> []any{int64(1), int64(2)}

// Or drive the wire codec directly, no client needed:
req := redis.EncodeCommand("GET", "foo")   // -> *2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n
val, _ := redis.DecodeBytes([]byte("$5\r\nhello\r\n")) // -> "hello"

Tests & coverage

The deterministic, ruby-free suite (golden RESP byte vectors built from the spec, plus a scripted Conn/RoundTripper for the command layer) holds 100% statement coverage on its own, so every CI lane passes the gate. A differential oracle additionally validates the codec against the reference implementation — the redis-client gem's RedisClient::RESP3.dump / .parse (no live server needed) — on the lanes where Ruby ≥ 4.0 with the gem is present; it skips itself elsewhere.

GOWORK=off go test ./...

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-redis/redis authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package redis is a pure-Go (CGO-free) reimplementation of the RESP protocol codec and command layer of Ruby's redis / redis-client gem. It encodes a command (an array of bulk strings) to the RESP wire format and decodes every RESP2 and RESP3 reply type into a small, explicit Ruby value model, then maps each command's reply to the typed value the gem returns (a Hash for HGETALL, a Set for SMEMBERS, an Integer for EXISTS, and so on).

The actual TCP/TLS socket is deliberately not part of this package: it is a host seam, mirroring the go-ruby-net-* pattern. A Client drives its commands over an injected Conn (an io.ReadWriter) or a RoundTripper the host wires to a live connection; this package owns only the deterministic, ruby-free wire grammar and command surface.

Ruby value model

A decoded reply is represented by an [any] drawn from a small, fixed set of Go types so a host (such as go-embedded-ruby) can map replies onto its own object graph:

RESP                       Go value
----                       --------
null ($-1, *-1, _)         nil
simple string (+)          string
simple error (-)           *CommandError
blob error (!)             *CommandError
integer (:)                int64
double (,)                 float64
big number (()             *big.Int
boolean (#)                bool
bulk string ($)            string
verbatim string ($=/=)     *VerbatimString
array (*)                  []any
map (%)                    *Map (ordered)
set (~)                    *Set
push (>)                   *Push
attribute (|)              carried on the following reply, not a value

The command layer then coerces these primitives into the types the gem's methods return (see reply.go).

Index

Constants

This section is empty.

Variables

View Source
var ErrProtocol = errors.New("redis: protocol error")

ErrProtocol reports a malformed RESP stream — a byte the grammar does not permit, or a truncated frame. The gem raises Redis::ProtocolError in the same situations; a host may map this error onto that class.

Functions

func DecodeBytes

func DecodeBytes(b []byte) (any, error)

DecodeBytes decodes a single reply from a complete byte slice — the golden- vector path used by the ruby-free tests: hand-built RESP bytes in, a value model out. It errors if the bytes hold no complete reply.

func EncodeCommand

func EncodeCommand(args ...any) []byte

EncodeCommand serialises one command — a name plus its arguments — to the RESP multi-bulk wire format: `*N\r\n$len\r\n<arg>\r\n…`. This is the RESP2 request framing every Redis command uses on the wire (RESP3 requests are identical; only replies differ). Every argument is stringified via [arg].

func EncodeInline

func EncodeInline(args ...any) []byte

EncodeInline serialises a command in the legacy inline form: the arguments separated by single spaces and terminated by CRLF. Redis accepts inline commands when a request does not begin with `*`; the gem never emits them, but a host may need to (e.g. a bare "PING\r\n"). Arguments must not contain spaces or CRLF; callers that need those must use EncodeCommand.

Types

type Batch

type Batch struct {
	// contains filtered or unexported fields
}

Batch accumulates commands to be sent together. redis.pipelined and redis.multi yield an object like this; each queued command records its arguments, and the batch is flushed as one write with the replies read back in order.

func (*Batch) Add

func (b *Batch) Add(args ...any) *Batch

Add queues a command (name plus arguments) on the batch. It mirrors calling a command method inside a pipelined/multi block: the command is not sent until the batch is executed.

func (*Batch) Len

func (b *Batch) Len() int

Len reports how many commands are queued.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a Redis client bound to a host connection seam. It builds RESP commands, sends them over the seam, decodes the replies and coerces each to the typed value the redis / redis-client gem returns. It owns no socket: the caller supplies a Conn (streaming, the default) or a RoundTripper.

A zero Client is not usable; construct one with New, NewFromConn or NewFromRoundTripper.

func New

func New(c Conn, opts Options) (*Client, error)

New builds a Client over a streaming Conn and records opts for a host driver to apply during its handshake. It mirrors Redis.new(**opts) at the protocol layer; the actual AUTH/SELECT/HELLO round-trips are the caller's to issue (see Client.Handshake).

func NewFromConn

func NewFromConn(c Conn) *Client

NewFromConn builds a Client that speaks over a streaming Conn. This is the primary constructor: it supports pipelining, MULTI/EXEC and pub/sub.

func NewFromRoundTripper

func NewFromRoundTripper(rt RoundTripper) *Client

NewFromRoundTripper builds a Client that speaks over a request/reply RoundTripper. Pipelining and transactions still work: the batch is encoded as one request and its concatenated replies are decoded in order.

func (*Client) Append

func (c *Client) Append(key, value any) (any, error)

Append appends value to key and returns the new length (APPEND).

func (*Client) Auth

func (c *Client) Auth(args ...any) (any, error)

Auth authenticates the connection, returning "OK" (AUTH). Pass one argument for password-only auth or two for username+password (ACL) auth.

func (*Client) Call

func (c *Client) Call(args ...any) (any, error)

Call sends one command — a variadic name plus arguments — and returns the raw decoded reply (the value model, no per-command coercion), mirroring redis.call([...]). A Redis error reply is promoted to a returned error, as the gem raises Redis::CommandError. This is the escape hatch for commands the typed surface does not wrap.

func (*Client) ConfigGet

func (c *Client) ConfigGet(pattern any) (any, error)

ConfigGet returns matching configuration parameters as an ordered Map (CONFIG GET).

func (*Client) Decr

func (c *Client) Decr(key any) (any, error)

Decr decrements the integer at key by one (DECR).

func (*Client) DecrBy

func (c *Client) DecrBy(key, n any) (any, error)

DecrBy decrements the integer at key by n (DECRBY).

func (*Client) Del

func (c *Client) Del(keys ...any) (any, error)

Del removes the given keys and returns the count removed (DEL).

func (*Client) Echo

func (c *Client) Echo(message any) (any, error)

Echo returns its message argument (ECHO).

func (*Client) Exists

func (c *Client) Exists(keys ...any) (any, error)

Exists returns how many of the given keys exist, as an Integer (EXISTS).

func (*Client) Expire

func (c *Client) Expire(key, seconds any) (any, error)

Expire sets a key's TTL in seconds and returns a boolean (EXPIRE).

func (*Client) ExpireAt

func (c *Client) ExpireAt(key, ts any) (any, error)

ExpireAt sets a key's expiry to a UNIX timestamp, returning a boolean (EXPIREAT).

func (*Client) FlushDB

func (c *Client) FlushDB() (any, error)

FlushDB empties the current database, returning "OK" (FLUSHDB).

func (*Client) Get

func (c *Client) Get(key any) (any, error)

Get returns the string value of key, or nil if the key is absent (GET).

func (*Client) GetRange

func (c *Client) GetRange(key, start, stop any) (any, error)

GetRange returns the substring of key between start and stop (GETRANGE).

func (*Client) GetSet

func (c *Client) GetSet(key, value any) (any, error)

GetSet atomically sets key to value and returns its old value (GETSET).

func (*Client) HDel

func (c *Client) HDel(key any, fields ...any) (any, error)

HDel removes hash fields and returns the count removed (HDEL).

func (*Client) HExists

func (c *Client) HExists(key, field any) (any, error)

HExists reports whether a hash field exists, as a boolean (HEXISTS).

func (*Client) HGet

func (c *Client) HGet(key, field any) (any, error)

HGet returns the value of a hash field, or nil (HGET).

func (*Client) HGetAll

func (c *Client) HGetAll(key any) (any, error)

HGetAll returns a hash's fields and values as an ordered Map (HGETALL).

func (*Client) HIncrBy

func (c *Client) HIncrBy(key, field, n any) (any, error)

HIncrBy increments a hash field by an integer (HINCRBY).

func (*Client) HIncrByFloat

func (c *Client) HIncrByFloat(key, field, n any) (any, error)

HIncrByFloat increments a hash field by a float, returning a Float (HINCRBYFLOAT).

func (*Client) HKeys

func (c *Client) HKeys(key any) (any, error)

HKeys returns a hash's field names as an Array (HKEYS).

func (*Client) HLen

func (c *Client) HLen(key any) (any, error)

HLen returns the number of fields in a hash (HLEN).

func (*Client) HMGet

func (c *Client) HMGet(key any, fields ...any) (any, error)

HMGet returns the values of the given hash fields as an Array (HMGET).

func (*Client) HSet

func (c *Client) HSet(key any, pairs ...any) (any, error)

HSet sets one or more field/value pairs on a hash and returns the number of new fields (HSET).

func (*Client) HVals

func (c *Client) HVals(key any) (any, error)

HVals returns a hash's values as an Array (HVALS).

func (*Client) Handshake

func (c *Client) Handshake() error

Handshake applies the recorded Options to a fresh connection the way the gem does after connecting: HELLO for RESP3 (or AUTH for RESP2), then SELECT. It is a convenience over the individual commands; a host that manages its own handshake need not call it.

func (*Client) Hello

func (c *Client) Hello(args ...any) (any, error)

Hello performs the RESP3 handshake, returning the server's HELLO reply as an ordered Map (HELLO). Pass the protocol version (2 or 3) and any AUTH/SETNAME options; requesting 3 flips the connection into RESP3 for subsequent replies.

func (*Client) Incr

func (c *Client) Incr(key any) (any, error)

Incr increments the integer at key by one (INCR).

func (*Client) IncrBy

func (c *Client) IncrBy(key, n any) (any, error)

IncrBy increments the integer at key by n (INCRBY).

func (*Client) IncrByFloat

func (c *Client) IncrByFloat(key, n any) (any, error)

IncrByFloat increments the float at key by n, returning a Float (INCRBYFLOAT).

func (*Client) IsRESP3

func (c *Client) IsRESP3() bool

IsRESP3 reports whether the connection has been switched to RESP3.

func (*Client) Keys

func (c *Client) Keys(pattern any) (any, error)

Keys returns all keys matching pattern as an Array of String (KEYS).

func (*Client) LIndex

func (c *Client) LIndex(key, index any) (any, error)

LIndex returns the list element at index, or nil (LINDEX).

func (*Client) LLen

func (c *Client) LLen(key any) (any, error)

LLen returns the length of a list (LLEN).

func (*Client) LPop

func (c *Client) LPop(key any) (any, error)

LPop pops from the head of a list, returning a String or nil (LPOP).

func (*Client) LPush

func (c *Client) LPush(key any, values ...any) (any, error)

LPush prepends values to a list and returns the new length (LPUSH).

func (*Client) LRange

func (c *Client) LRange(key, start, stop any) (any, error)

LRange returns the elements of a list between start and stop as an Array (LRANGE).

func (*Client) LSet

func (c *Client) LSet(key, index, value any) (any, error)

LSet sets the list element at index, returning "OK" (LSET).

func (*Client) LTrim

func (c *Client) LTrim(key, start, stop any) (any, error)

LTrim trims a list to the given range, returning "OK" (LTRIM).

func (*Client) MGet

func (c *Client) MGet(keys ...any) (any, error)

MGet returns the values of the given keys as an Array with nil for missing keys (MGET).

func (*Client) MSet

func (c *Client) MSet(pairs ...any) (any, error)

MSet sets the given key/value pairs and returns "OK" (MSET).

func (*Client) Multi

func (c *Client) Multi(fn func(*Batch)) (any, error)

Multi runs fn to queue commands, wraps them in a MULTI/EXEC transaction and returns the array of results EXEC yields (redis.multi). The wire framing is MULTI, then every queued command (each answered "+QUEUED"), then EXEC, whose reply is the array of the queued commands' results. A nil EXEC reply means the transaction was aborted (a watched key changed); it is returned as nil with no error, as the gem returns nil from a discarded multi block.

func (*Client) NextMessage

func (c *Client) NextMessage() (*Message, error)

NextMessage reads and classifies the next pub/sub frame from the connection — the read side of a redis.subscribe loop. It only works on a streaming Conn client (pub/sub is inherently multi-reply); on a RoundTripper client it returns an error.

func (*Client) PSubscribe

func (c *Client) PSubscribe(patterns ...any) (*Message, error)

PSubscribe sends a PSUBSCRIBE for the given patterns (PSUBSCRIBE).

func (*Client) PTTL

func (c *Client) PTTL(key any) (any, error)

PTTL returns a key's TTL in milliseconds (PTTL).

func (*Client) PUnsubscribe

func (c *Client) PUnsubscribe(patterns ...any) (*Message, error)

PUnsubscribe sends a PUNSUBSCRIBE (PUNSUBSCRIBE).

func (*Client) Persist

func (c *Client) Persist(key any) (any, error)

Persist removes a key's TTL, returning a boolean (PERSIST).

func (*Client) Ping

func (c *Client) Ping(message ...any) (any, error)

Ping returns "PONG" (or echoes its message argument) (PING).

func (*Client) Pipelined

func (c *Client) Pipelined(fn func(*Batch)) ([]any, error)

Pipelined runs fn to queue commands on a fresh Batch, sends them all in one write, then reads and returns each reply in order (redis.pipelined). A Redis error reply for a queued command is returned as a *CommandError value in the results slice (not a returned error), so one failed command does not mask the others — matching the gem, which collects per-command results. A stream or protocol fault aborts with a non-nil error.

func (*Client) Publish

func (c *Client) Publish(channel, message any) (any, error)

Publish sends a PUBLISH and returns the number of subscribers that received the message (PUBLISH).

func (*Client) RPop

func (c *Client) RPop(key any) (any, error)

RPop pops from the tail of a list, returning a String or nil (RPOP).

func (*Client) RPush

func (c *Client) RPush(key any, values ...any) (any, error)

RPush appends values to a list and returns the new length (RPUSH).

func (*Client) Rename

func (c *Client) Rename(key, newkey any) (any, error)

Rename renames a key, returning "OK" (RENAME).

func (*Client) SAdd

func (c *Client) SAdd(key any, members ...any) (any, error)

SAdd adds members to a set and returns the count added (SADD).

func (*Client) SCard

func (c *Client) SCard(key any) (any, error)

SCard returns the cardinality of a set (SCARD).

func (*Client) SDiff

func (c *Client) SDiff(keys ...any) (any, error)

SDiff returns the difference of the given sets as a Ruby Set (SDIFF).

func (*Client) SInter

func (c *Client) SInter(keys ...any) (any, error)

SInter returns the intersection of the given sets as a Ruby Set (SINTER).

func (*Client) SIsMember

func (c *Client) SIsMember(key, member any) (any, error)

SIsMember reports whether a value is a set member, as a boolean (SISMEMBER).

func (*Client) SMembers

func (c *Client) SMembers(key any) (any, error)

SMembers returns all members of a set as a Ruby Set (SMEMBERS).

func (*Client) SRem

func (c *Client) SRem(key any, members ...any) (any, error)

SRem removes members from a set and returns the count removed (SREM).

func (*Client) SUnion

func (c *Client) SUnion(keys ...any) (any, error)

SUnion returns the union of the given sets as a Ruby Set (SUNION).

func (*Client) Scan

func (c *Client) Scan(cursor any, opts ...any) (any, error)

Scan performs one SCAN iteration from cursor, returning a ScanResult. Extra options (MATCH/COUNT/TYPE) may be appended as further args.

func (*Client) Select

func (c *Client) Select(index any) (any, error)

Select switches the connection to database index, returning "OK" (SELECT).

func (*Client) Set

func (c *Client) Set(key, value any, opts ...any) (any, error)

Set stores value at key and returns the "OK" status (SET). Extra options (EX/PX/NX/XX/…) may be appended as further args.

func (*Client) SetNX

func (c *Client) SetNX(key, value any) (any, error)

SetNX sets key to value only if it does not exist, returning a boolean (SETNX).

func (*Client) SetRange

func (c *Client) SetRange(key, offset, value any) (any, error)

SetRange overwrites part of key starting at offset, returning the new length (SETRANGE).

func (*Client) Strlen

func (c *Client) Strlen(key any) (any, error)

Strlen returns the length of the string at key (STRLEN).

func (*Client) Subscribe

func (c *Client) Subscribe(channels ...any) (*Message, error)

Subscribe sends a SUBSCRIBE for the given channels and returns the request's first reply (the first subscribe confirmation) as a Message. Redis answers one confirmation per channel; a host reads the remaining confirmations and the subsequent deliveries with Client.NextMessage.

func (*Client) TTL

func (c *Client) TTL(key any) (any, error)

TTL returns a key's remaining time-to-live in seconds (TTL): -2 if the key is gone, -1 if it has no expiry.

func (*Client) Type

func (c *Client) Type(key any) (any, error)

Type returns a key's type name as a String (TYPE).

func (*Client) Unsubscribe

func (c *Client) Unsubscribe(channels ...any) (*Message, error)

Unsubscribe sends an UNSUBSCRIBE (UNSUBSCRIBE). With no channels it unsubscribes from all.

func (*Client) ZAdd

func (c *Client) ZAdd(key any, scoreMembers ...any) (any, error)

ZAdd adds scored members to a sorted set, returning the count added (ZADD). Arguments alternate score, member (plus any leading NX/XX/GT/LT/CH options).

func (*Client) ZCard

func (c *Client) ZCard(key any) (any, error)

ZCard returns the cardinality of a sorted set (ZCARD).

func (*Client) ZIncrBy

func (c *Client) ZIncrBy(key, increment, member any) (any, error)

ZIncrBy increments a member's score, returning the new score as a Float (ZINCRBY).

func (*Client) ZRange

func (c *Client) ZRange(key, start, stop any, opts ...any) (any, error)

ZRange returns members in the given rank range as an Array (ZRANGE). Append "WITHSCORES" to interleave scores.

func (*Client) ZRank

func (c *Client) ZRank(key, member any) (any, error)

ZRank returns a member's rank, or nil (ZRANK).

func (*Client) ZRem

func (c *Client) ZRem(key any, members ...any) (any, error)

ZRem removes members from a sorted set, returning the count removed (ZREM).

func (*Client) ZScore

func (c *Client) ZScore(key, member any) (any, error)

ZScore returns a member's score as a Float, or nil (ZSCORE).

type CommandError

type CommandError struct {
	// Message is the full error text, e.g. "WRONGTYPE Operation against a key
	// holding the wrong kind of value".
	Message string
}

CommandError is a Redis error reply — the RESP2 `-` simple error, or the RESP3 `!` blob error. Ruby's redis gem raises a Redis::CommandError carrying this message; the value model surfaces it as an error so a host can decide whether to raise. It satisfies the Go error interface.

func (*CommandError) Code

func (e *CommandError) Code() string

Code returns the leading upper-case error code (the word before the first space), e.g. "WRONGTYPE" or "ERR". Redis conventionally prefixes error messages with such a code; the gem exposes it likewise. An empty message yields "".

func (*CommandError) Error

func (e *CommandError) Error() string

Error implements the error interface.

type Conn

type Conn = io.ReadWriter

Conn is the streaming host seam: a bidirectional byte pipe (an io.ReadWriter) the Client writes requests to and reads replies from. A live *net.Conn or a TLS connection satisfies it directly. This is the primary seam — it supports pipelining, transactions and pub/sub, which need many replies read from one stream — while RoundTripper suits simple request/reply transports.

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder reads RESP replies from a stream. It handles both RESP2 and RESP3: the two protocols share request framing and every RESP2 reply type, and RESP3 adds the typed replies (null, double, boolean, big number, verbatim string, map, set, push, attribute, blob error). One Decoder may read any mix of the two, because the leading type byte disambiguates every frame.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder wraps r in a Decoder.

func (*Decoder) Decode

func (d *Decoder) Decode() (any, error)

Decode reads and returns exactly one reply, mapping it to the value model. A Redis error reply (RESP2 `-` or RESP3 `!`) is returned as a value of type *CommandError with a nil error; only stream/protocol faults produce a non-nil error. This mirrors the gem, which turns an error reply into a raised Redis::CommandError the caller handles, distinct from a broken connection.

func (*Decoder) LastAttribute

func (d *Decoder) LastAttribute() *Map

LastAttribute returns the RESP3 attribute dictionary that preceded the most recently decoded reply, or nil if none did. Attributes are out-of-band metadata (e.g. key popularity, client-side-caching hints); the gem exposes them separately from the value, and so does this decoder.

type Map

type Map struct {
	// contains filtered or unexported fields
}

Map is an insertion-ordered key/value collection — the value model's Ruby Hash. RESP3 maps (`%`) decode to a Map, and command coercions that build a Hash reply (HGETALL, CONFIG GET, XPENDING summaries, …) return one so key order is preserved on round-trip, exactly as Ruby's ordered Hash does.

func NewMap

func NewMap() *Map

NewMap returns an empty ordered Map.

func (*Map) Each

func (m *Map) Each(fn func(key, value any))

Each calls fn for every entry in insertion order.

func (*Map) Get

func (m *Map) Get(key any) (any, bool)

Get returns the value stored for key and whether it was present.

func (*Map) Keys

func (m *Map) Keys() []any

Keys returns the keys in insertion order.

func (*Map) Len

func (m *Map) Len() int

Len reports the number of entries.

func (*Map) Set

func (m *Map) Set(key, value any)

Set inserts or updates key with value, preserving first-insertion order.

type Message

type Message struct {
	Kind    MessageKind
	Pattern string // set for pmessage / (p)subscribe patterns
	Channel string // channel (or pattern for psubscribe confirmations)
	Payload string // set for message / pmessage
	Count   int64  // set for (un)subscribe confirmations
}

Message is a decoded pub/sub frame. Depending on Kind, some fields are unset: a "message" carries Channel and Payload; a "pmessage" also carries Pattern; a subscribe/unsubscribe confirmation carries Channel and Count (the number of channels/patterns still subscribed).

type MessageKind

type MessageKind string

MessageKind classifies a pub/sub frame.

const (
	// KindSubscribe is a "subscribe" confirmation (channel subscribed).
	KindSubscribe MessageKind = "subscribe"
	// KindUnsubscribe is an "unsubscribe" confirmation.
	KindUnsubscribe MessageKind = "unsubscribe"
	// KindPSubscribe is a "psubscribe" pattern-subscription confirmation.
	KindPSubscribe MessageKind = "psubscribe"
	// KindPUnsubscribe is a "punsubscribe" confirmation.
	KindPUnsubscribe MessageKind = "punsubscribe"
	// KindMessage is a "message" delivery on a subscribed channel.
	KindMessage MessageKind = "message"
	// KindPMessage is a "pmessage" delivery matching a subscribed pattern.
	KindPMessage MessageKind = "pmessage"
)

type Options

type Options struct {
	// Username and Password are sent via AUTH (or HELLO … AUTH) when non-empty,
	// matching Redis.new(username:, password:). This package does not itself
	// perform the handshake — call [Client.Auth] / [Client.Hello] — but the
	// options are recorded so a host driver can.
	Username string
	Password string
	// DB is the logical database index selected with SELECT after connecting
	// (Redis.new(db:)). Zero means the default database.
	DB int
	// Protocol is 2 or 3; 3 requests the RESP3 handshake via HELLO 3. Zero
	// defaults to 2, matching the gem's default.
	Protocol int
}

Options configures a Client. The fields mirror the gem's Redis.new keywords that affect the protocol layer; transport keywords (host/port/ssl/timeouts) belong to the host that owns the socket, not to this codec.

type Push

type Push struct {
	Values []any
}

Push is a RESP3 out-of-band push message (`>`): the frame pub/sub and other server-initiated notifications arrive on. Its Values are the decoded elements (the first is the kind, e.g. "message", "subscribe", "pmessage").

func (*Push) Kind

func (p *Push) Kind() string

Kind returns the first element of a Push as a string (the message kind), or "" if the push is empty or its head is not a string.

type RoundTripper

type RoundTripper interface {
	// RoundTrip sends one request frame and returns its reply frame(s). For a
	// single command the reply is one RESP value; the Client parses it.
	RoundTrip(request []byte) (reply []byte, err error)
}

RoundTripper is the host seam for a single request/response exchange: given the encoded RESP bytes of a command, it returns the raw RESP bytes of the reply. A host wires this to a live TCP/TLS connection (the socket lives outside this package, mirroring the go-ruby-net-* design). A Client built on a RoundTripper drives one command at a time; pipelines and transactions send a batch and read a matching run of replies, so a RoundTripper-backed Client serialises those onto a Conn-style stream internally.

type ScanResult

type ScanResult struct {
	Cursor   string
	Elements []any
}

ScanResult is the value model of a cursored scan reply. Cursor is the opaque continuation token ("0" when the scan is complete) and Elements are the keys / members / field-value pairs returned by this iteration.

func (*ScanResult) Done

func (r *ScanResult) Done() bool

Done reports whether the scan has completed (the cursor returned to "0").

type Set

type Set struct {
	// contains filtered or unexported fields
}

Set is the value model's Ruby Set: an insertion-ordered collection of unique members. RESP3 sets (`~`) decode to a Set, and SMEMBERS / SUNION / SDIFF / SINTER coerce their array reply into one, matching the gem.

func NewSet

func NewSet() *Set

NewSet returns an empty Set.

func (*Set) Add

func (s *Set) Add(member any) bool

Add inserts member if it is not already present, preserving insertion order. It reports whether the member was newly added.

func (*Set) Include

func (s *Set) Include(member any) bool

Include reports whether member is in the set.

func (*Set) Len

func (s *Set) Len() int

Len reports the number of members.

func (*Set) Members

func (s *Set) Members() []any

Members returns the members in insertion order.

type Stringer

type Stringer interface{ String() string }

Stringer mirrors fmt.Stringer without pulling fmt into the arg fast path.

type Symbol

type Symbol string

Symbol is a Ruby Symbol (`:name`). A host may pass a Symbol as a command argument (the gem accepts symbols and stringifies them by name); the encoder serialises it as its bare name.

type Value

type Value = any

Value is the interface satisfied by every Ruby value this package produces. It is purely documentary — the public API uses any — but a host may use it to constrain its own adapters.

type VerbatimString

type VerbatimString struct {
	// Format is the three-character type hint (e.g. "txt", "mkd").
	Format string
	// Text is the string payload (without the "fmt:" prefix).
	Text string
}

VerbatimString is a RESP3 verbatim string (`=`): a bulk string carrying a three-byte format hint (e.g. "txt" or "mkd"). The gem treats it as a plain String; this model keeps the format so a host may inspect it.

func (*VerbatimString) String

func (v *VerbatimString) String() string

String returns the payload, so a VerbatimString stringifies like the plain String the gem exposes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL