ACOR Documentation

Custom Storage

Implement custom storage backends for ACOR.

Overview

ACOR uses the KVStorage interface to abstract storage operations. You can implement custom backends for:

KVStorage Interface

type KVStorage interface {
    Get(ctx context.Context, key string) (string, error)
    Set(ctx context.Context, key string, value interface{}) error
    HGetAll(ctx context.Context, key string) (map[string]string, error)
    HSet(ctx context.Context, key string, values ...interface{}) error
    SAdd(ctx context.Context, key string, members ...interface{}) error
    SMembers(ctx context.Context, key string) ([]string, error)
    SRem(ctx context.Context, key string, members ...interface{}) error
    SCard(ctx context.Context, key string) (int64, error)
    SIsMember(ctx context.Context, key, member string) (bool, error)
    ZAdd(ctx context.Context, key string, members ...*Z) error
    ZRange(ctx context.Context, key string, start, stop int64) ([]string, error)
    ZRank(ctx context.Context, key, member string) (int64, error)
    ZScore(ctx context.Context, key, member string) (float64, error)
    ZCard(ctx context.Context, key string) (int64, error)
    ZRem(ctx context.Context, key string, members ...interface{}) error
    Del(ctx context.Context, keys ...string) error
    Exists(ctx context.Context, keys ...string) (int64, error)
    TxPipelined(ctx context.Context, fn func(Pipeliner) error) error
    Close() error
}

Example: In-Memory Storage

package main

import (
    "context"
    "fmt"
    "sync"

    "github.com/skyoo2003/acor/pkg/acor"
)

type MemoryStorage struct {
    mu     sync.RWMutex
    data   map[string]string
    sets   map[string]map[string]struct{}
    hashes map[string]map[string]string
    zsets  map[string]map[string]float64
}

func NewMemoryStorage() *MemoryStorage {
    return &MemoryStorage{
        data:   make(map[string]string),
        sets:   make(map[string]map[string]struct{}),
        hashes: make(map[string]map[string]string),
        zsets:  make(map[string]map[string]float64),
    }
}

func (m *MemoryStorage) Get(ctx context.Context, key string) (string, error) {
    m.mu.RLock()
    defer m.mu.RUnlock()
    return m.data[key], nil
}

func (m *MemoryStorage) Set(ctx context.Context, key string, value interface{}) error {
    m.mu.Lock()
    defer m.mu.Unlock()
    s, ok := value.(string)
    if !ok {
        return fmt.Errorf("unsupported value type: %T", value)
    }
    m.data[key] = s
    return nil
}

func (m *MemoryStorage) SAdd(ctx context.Context, key string, members ...interface{}) error {
    m.mu.Lock()
    defer m.mu.Unlock()
    if m.sets[key] == nil {
        m.sets[key] = make(map[string]struct{})
    }
    for _, member := range members {
        s, ok := member.(string)
        if !ok {
            return fmt.Errorf("unsupported member type: %T", member)
        }
        m.sets[key][s] = struct{}{}
    }
    return nil
}

func (m *MemoryStorage) SMembers(ctx context.Context, key string) ([]string, error) {
    m.mu.RLock()
    defer m.mu.RUnlock()
    var members []string
    for member := range m.sets[key] {
        members = append(members, member)
    }
    return members, nil
}

// Implement remaining methods...

func (m *MemoryStorage) Close() error {
    return nil
}

Using Custom Storage

Currently, ACOR uses Redis internally. Custom storage support is planned for future releases.

For testing, use miniredis which provides a Redis-compatible in-memory implementation:

import (
    "testing"
    "github.com/alicebob/miniredis/v2"
    "github.com/redis/go-redis/v9"
)

func TestWithMiniredis(t *testing.T) {
    mr, err := miniredis.Run()
    if err != nil {
        t.Fatal(err)
    }
    defer mr.Close()

    client := redis.NewClient(&redis.Options{
        Addr: mr.Addr(),
    })
    defer client.Close()

    // Use client with ACOR
}

Pipeliner Interface

For transaction support, implement Pipeliner:

type Pipeliner interface {
    SAdd(ctx context.Context, key string, members ...interface{}) error
    HSet(ctx context.Context, key string, values ...interface{}) error
    ZAdd(ctx context.Context, key string, members ...*Z) error
    Del(ctx context.Context, keys ...string) error
}

Z Type

The sorted set member type:

type Z struct {
    Score  float64
    Member string
}