Skip to content

feat: Redis command serialization + client API #133

@FumingPower3925

Description

@FumingPower3925

Summary

Implement the Redis client API with type-safe command methods built on top of the RESP parser. The client handles connection management, command execution, and response deserialization.

Design

Package: driver/redis/client.go

Client

type Client struct {
    pool    *Pool
    state   *RedisState
}

func NewClient(addr string, opts ...Option) (*Client, error)
func (c *Client) Close() error

Command Methods

// Strings
func (c *Client) Get(ctx context.Context, key string) (string, error)
func (c *Client) Set(ctx context.Context, key string, value any, expiration time.Duration) error
func (c *Client) SetNX(ctx context.Context, key string, value any, expiration time.Duration) (bool, error)
func (c *Client) Del(ctx context.Context, keys ...string) (int64, error)
func (c *Client) Exists(ctx context.Context, keys ...string) (int64, error)
func (c *Client) Incr(ctx context.Context, key string) (int64, error)
func (c *Client) Expire(ctx context.Context, key string, expiration time.Duration) (bool, error)
func (c *Client) TTL(ctx context.Context, key string) (time.Duration, error)

// Hashes
func (c *Client) HGet(ctx context.Context, key, field string) (string, error)
func (c *Client) HSet(ctx context.Context, key string, values ...any) (int64, error)
func (c *Client) HGetAll(ctx context.Context, key string) (map[string]string, error)

// Lists
func (c *Client) LPush(ctx context.Context, key string, values ...any) (int64, error)
func (c *Client) LPop(ctx context.Context, key string) (string, error)
func (c *Client) LRange(ctx context.Context, key string, start, stop int64) ([]string, error)

// Sets
func (c *Client) SAdd(ctx context.Context, key string, members ...any) (int64, error)
func (c *Client) SMembers(ctx context.Context, key string) ([]string, error)

// Sorted Sets
func (c *Client) ZAdd(ctx context.Context, key string, members ...Z) (int64, error)
func (c *Client) ZRange(ctx context.Context, key string, start, stop int64) ([]string, error)
func (c *Client) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) ([]string, error)

Command Execution Bridge

Same async-to-sync bridge pattern as PostgreSQL:

  1. Handler goroutine calls client.Get(ctx, "key")
  2. Serializes *2\r\n$3\r\nGET\r\n$3\r\nkey\r\n via RESP writer
  3. Writes to event loop via writeFn
  4. Creates pending with doneCh chan Value
  5. Blocks on <-doneCh or ctx.Done()
  6. Event loop receives RESP response, parses, sends on doneCh

RedisState (event loop protocol handler)

// driver/redis/state.go
type RedisState struct {
    reader  *resp.Reader
    pending queue[*request]   // FIFO — Redis guarantees in-order responses
    writeFn func([]byte)
}

func (s *RedisState) ProcessRedis(data []byte) error

ProcessRedis is called by the event loop on data arrival — same pattern as ProcessH1/ProcessH2.

Options

type Option func(*config)

func WithPassword(password string) Option
func WithDB(db int) Option
func WithDialTimeout(d time.Duration) Option
func WithReadTimeout(d time.Duration) Option
func WithWriteTimeout(d time.Duration) Option
func WithPoolSize(size int) Option
func WithEngine(srv *celeris.Server) Option  // integrated mode

Acceptance Criteria

  • All listed command methods implemented
  • Type-safe return values (no interface{} in public API)
  • Context cancellation support
  • AUTH + SELECT on connection init
  • RedisState + ProcessRedis for event loop integration
  • Connection error handling and reconnection
  • Unit tests for command serialization
  • Integration tests against real Redis

Dependencies

  • Depends on 132 (RESP parser)

Metadata

Metadata

Labels

area/driverDatabase/cache driver infrastructuredriver/redisRedis driver

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions