Files
labmem c812cfb663 wip(lyra): 保存带选项列表查询的未完成设计
- 添加通用查询选项、分类过滤选项及动态缓存键生成
- 新增分类创建与更新时间字段

当前实现尚未完成,留待后续继续设计:
- 明确通用查询选项、模型过滤条件与缓存策略的边界
- 补齐数据库回源,修正分类返回类型及过滤条件生效问题
- 修正分页偏移计算,增加参数边界校验和稳定排序
- 完善缓存故障降级、空结果缓存及写后失效策略
- 修正缓存键参数编码歧义,补齐查询名和版本前缀
- 补充测试并验证编译与查询行为
2026-10-21 00:11:37 +08:00

86 lines
2.0 KiB
Go

package cache
import (
"context"
"crypto/md5"
"encoding/json/v2"
"errors"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
type Entry[T any] struct {
Key string
Value T
TTL time.Duration
}
type Cache struct {
client *redis.Client
operationTimeout time.Duration
}
func NewCache(client *redis.Client, timeout time.Duration) *Cache {
return &Cache{
client: client,
operationTimeout: timeout,
}
}
func (c *Cache) Get[T any](ctx context.Context, key string) (T, bool, error) {
var zero T
operationCtx, cancel := context.WithTimeout(ctx, c.operationTimeout)
defer cancel()
payload, err := c.client.Get(operationCtx, key).Result()
cancel()
if errors.Is(err, redis.Nil) {
return zero, false, nil
}
if err != nil {
return zero, false, fmt.Errorf("读取缓存失败:%w", err)
}
var value T
if err := json.Unmarshal([]byte(payload), &value); err != nil {
return zero, false, fmt.Errorf("缓存解码失败:%w", err)
}
return value, true, nil
}
func (c *Cache) Set[T any](ctx context.Context, entry Entry[T]) error {
if entry.TTL < 0 {
return fmt.Errorf("缓存过期时间必须大于等于零: %v", entry.TTL)
}
if err := ctx.Err(); err != nil {
return fmt.Errorf("写入缓存失败:%w", err)
}
payload, err := json.Marshal(entry.Value)
if err != nil {
return fmt.Errorf("缓存编码失败:%w", err)
}
operationCtx, cancel := context.WithTimeout(ctx, c.operationTimeout)
defer cancel()
if err := c.client.Set(operationCtx, entry.Key, payload, entry.TTL).Err(); err != nil {
return fmt.Errorf("写入缓存失败:%w", err)
}
return nil
}
func GenCacheKey(table, sql string, args ...any) (key string, err error) {
prefix := fmt.Sprintf("lyra:cache:%s:", table)
h := md5.New()
// 写入查询语句
h.Write([]byte(sql))
// 序列化并写入每个参数
for _, arg := range args {
jsonData, err := json.Marshal(arg)
if err != nil {
return "", fmt.Errorf("序列化参数失败:%w", err)
}
h.Write(jsonData)
}
return prefix + fmt.Sprintf("%x", h.Sum(nil)), nil
}