Skip to content

kristoff-it/zig-okredis

Repository files navigation

OkRedis

OkRedis is a zero-allocation client for Redis 6+

Handy and Efficient

OkRedis aims to offer an interface with great ergonomics without compromising on performance or flexibility.

Project status

OkRedis is currently in alpha. The main features are mostly complete, but a lot of polishing is still required. Zig version 0.10.1 is supported. Once async is available in a stable release, OkRedis will pivot to a new Zig version.

Everything mentioned in the docs is already implemented and you can just zig run example.zig to quickly see what it can do. Remember OkRedis only supports Redis 6 and above.

Zero dynamic allocations, unless explicitly wanted

The client has two main interfaces to send commands: send and sendAlloc. Following Zig's mantra of making dynamic allocations explicit, only sendAlloc can allocate dynamic memory, and only does so by using a user-provided allocator.

The way this is achieved is by making good use of RESP3's typed responses and Zig's metaprogramming facilities. The library uses compile-time reflection to specialize down to the parser level, allowing OkRedis to decode whenever possible a reply directly into a function frame, without any intermediate dynamic allocation. If you want more information about Zig's comptime:

By using sendAlloc you can decode replies with arbrirary shape at the cost of occasionally performing dynamic allocations. The interface takes an allocator as input, so the user can setup custom allocation schemes such as arenas.

Quickstart

const std = @import("std");
const okredis = @import("./src/okredis.zig");
const SET = okredis.commands.strings.SET;
const OrErr = okredis.types.OrErr;
const Client = okredis.Client;

pub fn main() !void {
    const addr = try std.net.Address.parseIp4("127.0.0.1", 6379);
    var connection = try std.net.tcpConnectToAddress(addr);

    var client: Client = undefined;
    try client.init(connection);
    defer client.close();

    // Basic interface
    try client.send(void, .{ "SET", "key", "42" });
    const reply = try client.send(i64, .{ "GET", "key" });
    if (reply != 42) @panic("out of towels");


    // Command builder interface
    const cmd = SET.init("key", "43", .NoExpire, .IfAlreadyExisting);
    const otherReply = try client.send(OrErr(void), cmd);
    switch (otherReply) {
        .Nil => @panic("command should not have returned nil"),
        .Err => @panic("command should not have returned an error"),
        .Ok => std.debug.print("success!", .{}),
    }
}

Available Documentation

The reference documentation is available here.

Extending OkRedis

If you are a Lua script or Redis module author, you might be interested in reading the final sections of COMMANDS.md and REPLIES.md.

Embedding OkRedis in a higher level language

Take a look at the final section of REPLIES.md.

TODOS

  • Implement remaining command builders
  • Better connection management (ipv6, unixsockets, ...)
  • Streamline design of Zig errors
  • Refine support for async/await and think about connection pooling
  • Refine the Redis traits
  • Pub/Sub