Skip to content

fix: pr #545

@sj817

Description

@sj817

Pull Request Overview
补充并完善 mock Redis 客户端缺失的常用命令,实现与真实 Redis API 更高的兼容性,并修复过期管理方法错误仅限 HyperLogLog 的问题。

新增字符串、过期控制、键管理、数值操作等 18 个常用方法
修复 pExpire/pTTL/pExpireAt 仅适用于 HyperLogLog 的错误实现
增强键重命名与过期处理、随机键、数据库统计等辅助能力
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

packages/core/src/core/db/redis/mock/index.ts
评论行 +326 到 +331
async setNX (key: string, value: string | Buffer): Promise {
if (this.store[key] && !this.checkExpire(key)) {
return false
}
await this.set(key, value, { NX: true })
return true
https://github.com/apps/copilot-pull-request-reviewer AI
1分钟前
The return type deviates from Redis semantics; SETNX returns an integer reply (1 if a key was set, 0 otherwise) rather than a boolean. To maintain API compatibility, change the return type to Promise and return 1/0.

Suggested change
async setNX (key: string, value: string | Buffer): Promise {
if (this.store[key] && !this.checkExpire(key)) {
return false
}
await this.set(key, value, { NX: true })
return true
async setNX (key: string, value: string | Buffer): Promise {
if (this.store[key] && !this.checkExpire(key)) {
return 0
}
await this.set(key, value, { NX: true })
return 1
Copilot 使用 AI。请检查错误。

@sj817 回复...
packages/core/src/core/db/redis/mock/index.ts
评论行 +511 到 +553
async rename (key: string, newKey: string): Promise {
if (!this.store[key]) throw new Error('no such key')

// 获取原键的数据
const { type, expire } = this.store[key]
const value = this.getValueStringByKey(key)

// 删除旧键
this.#del(key)

// 创建新键
this.store[newKey] = { type, expire }

// 根据类型设置值
switch (type) {
  case Key.STR:
    this.#str[newKey] = value
    break
  case Key.NUM:
    this.#num[newKey] = Number(value)
    break
  case Key.HASH:
    this.#hash[newKey] = JSON.parse(value)
    break
  case Key.LIST:
    this.#list[newKey] = JSON.parse(value)
    break
  case Key.SET:
    this.#set[newKey] = new Set(JSON.parse(value))
    break
  case Key.ZSET:
    this.#zset[newKey] = JSON.parse(value)
    break
  case Key.PF:
    this.#pf[newKey] = new Set(JSON.parse(value))
    break
  case Key.BIT:
    this.#bit[newKey] = Buffer.from(value, 'base64')
    break
}

this.#sqlite.set(newKey, value, type, expire)
return 'OK'

https://github.com/apps/copilot-pull-request-reviewer AI
1分钟前
When newKey already exists, Redis RENAME overwrites the destination, but this implementation does not remove existing type-specific data for newKey before assignment, potentially leaving orphaned data (e.g., stale this.#hash[newKey]). Add a pre-step to delete newKey (if different from key) via this.#del(newKey) to avoid inconsistent internal state, and optionally guard key === newKey to mimic Redis error semantics.

Copilot 使用 AI。请检查错误。

@sj817 回复...
packages/core/src/core/db/redis/mock/index.ts
评论行 +561 到 +567
async renameNX (key: string, newKey: string): Promise {
if (!this.store[key]) return 0
if (this.store[newKey] && !this.checkExpire(newKey)) return 0

await this.rename(key, newKey)
return 1

}
https://github.com/apps/copilot-pull-request-reviewer AI
1分钟前
renameNX should fail (return 0) if key === newKey per Redis semantics (identical source/destination not allowed), but current logic delegates to rename and returns 1. Add an early check if (key === newKey) return 0 (or throw) for fidelity.

Copilot 使用 AI。请检查错误。

@sj817 回复...
packages/core/src/core/db/redis/mock/index.ts
评论行 +674 到 +685
async incrByFloat (key: string, increment: number): Promise {
if (!this.#num[key]) {
this.#num[key] = 0
this.store[key] = { type: Key.NUM, expire: -1 }
} else if (this.checkExpire(key, false)) {
this.store[key].expire = -1
this.#num[key] = 0
}

this.#num[key] += increment
this.#sqlite.set(key, String(this.#num[key]), Key.NUM, this.store[key].expire)
return this.#num[key]

https://github.com/apps/copilot-pull-request-reviewer AI
1分钟前
INCRBYFLOAT in Redis returns the new value as a bulk string; returning a number here introduces an incompatibility for consumers expecting string output. Consider returning String(this.#num[key]) (and adjusting the return type) to align with Redis behavior.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions