Files
module-redis/target/redis/conn.lua

561 lines
14 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- redis_conn.lua
local redis_conn = {}
redis_conn.__index = redis_conn
--[[
转义 Redis 参数,处理包含空格等特殊字符的值
@param value 要转义的值
@return 返回转义后的字符串
]]
local function escape_value(value)
if value == nil then
return ""
end
-- 将值转换为字符串
local str = tostring(value)
-- 如果包含空格、引号或特殊字符,使用双引号包裹并转义内部引号
if string.find(str, "[%s\"'\\]") then
-- 转义反斜杠和双引号
str = string.gsub(str, "\\", "\\\\")
str = string.gsub(str, "\"", "\\\"")
return "\"" .. str .. "\""
end
return str
end
--[[
还原 Redis 字符串(去转义)
@param value 被转义的字符串
@return 返回还原后的字符串
]]
local function unescape_value(value)
if value == nil then
return nil
end
local str = tostring(value)
-- 如果是用双引号包住的,去掉包裹并恢复转义
if #str >= 2 and string.sub(str,1,1) == "\"" and string.sub(str,-1,-1) == "\"" then
str = string.sub(str,2,-2)
str = string.gsub(str, "\\\"", "\"")
str = string.gsub(str, "\\\\", "\\")
return str
end
return str
end
--[[
对数组进行去转义处理
@param arr 数组
@return 返回去转义后的数组
]]
local function unescape_array(arr)
if arr == nil or type(arr) ~= "table" then
return arr
end
local result = {}
for i, v in ipairs(arr) do
result[i] = unescape_value(v)
end
return result
end
--[[
构建 Redis 命令字符串
@param cmd 命令名称
@param ... 命令参数
@return 返回构建好的命令字符串
]]
local function build_command(cmd, ...)
local args = {...}
local parts = {cmd}
for i, arg in ipairs(args) do
if arg ~= nil then
table.insert(parts, escape_value(arg))
end
end
return table.concat(parts, " ")
end
--[[
创建一个新的 fw_redis_conn 对象
@return 返回一个新的 fw_redis_conn 对象
]]
function redis_conn.new(__module)
local instance = setmetatable({}, redis_conn)
instance.module = __module
return instance
end
--[[
关闭
]]
function redis_conn:close()
return self.module:close()
end
--[[
执行 Redis 命令
@param cmd Redis 命令字符串
@return 返回命令执行结果
]]
function redis_conn:command(cmd)
return self.module:command(cmd)
end
--[[
执行 Redis 命令
@param args 命令参数数组,会自动将参数转换为字符串
@return 返回命令执行结果
]]
function redis_conn:command_ex(args)
if args == nil or type(args) ~= "table" then
return nil
end
local str_args = {}
for i, arg in ipairs(args) do
if arg == nil then
table.insert(str_args, "")
elseif type(arg) == "number" then
-- 判断是否为整数:整数不转成小数
if arg % 1 == 0 then
-- 是整数,使用 %d 格式,避免转成小数
table.insert(str_args, string.format("%d", arg))
else
-- 是浮点数,直接转字符串
table.insert(str_args, tostring(arg))
end
else
-- 其他类型(字符串、布尔等)直接转字符串
table.insert(str_args, tostring(arg))
end
end
return self.module:command_ex(str_args)
end
-- ==================== String 操作 ====================
--[[
GET 命令:获取键的值
@param key 键名
@return 返回键的值,不存在返回 nil
]]
function redis_conn:get(key)
local result = self:command(build_command("GET", key))
return unescape_value(result)
end
--[[
SET 命令:设置键值对
@param key 键名
@param value 值(可以是字符串、数字等,会自动处理空格)
@param options 可选参数,如 "EX seconds" 或 "PX milliseconds" 或 "NX" 或 "XX"
@return 返回执行结果
]]
function redis_conn:set(key, value, options)
local args = {"SET", key, value}
if options then
-- 如果 options 是字符串,需要拆分(如 "EX 10" 或 "NX"
if type(options) == "string" then
for word in string.gmatch(options, "%S+") do
table.insert(args, word)
end
else
table.insert(args, options)
end
end
return self:command_ex(args)
end
--[[
SETEX 命令:设置键值对并设置过期时间(秒)
@param key 键名
@param seconds 过期时间(秒)
@param value 值
@return 返回执行结果
]]
function redis_conn:setex(key, seconds, value)
return self:command_ex({"SETEX", key, seconds, value})
end
--[[
SETNX 命令:当键不存在时设置键值对
@param key 键名
@param value 值
@return 返回 1 表示设置成功0 表示键已存在
]]
function redis_conn:setnx(key, value)
return self:command_ex({"SETNX", key, value})
end
--[[
DEL 命令:删除一个或多个键
@param ... 键名列表
@return 返回删除的键数量
]]
function redis_conn:del(...)
local args = {"DEL", ...}
return self:command_ex(args)
end
--[[
EXISTS 命令:检查键是否存在
@param key 键名
@return 返回 1 表示存在0 表示不存在
]]
function redis_conn:exists(key)
return self:command_ex({"EXISTS", key})
end
--[[
KEYS 命令:查找所有匹配给定模式的键
@param pattern 匹配模式,支持通配符:* 匹配任意字符,? 匹配单个字符,[] 匹配指定字符
@return 返回匹配的键数组
注意:在生产环境中应谨慎使用,建议使用 SCAN 命令替代
]]
function redis_conn:keys(pattern)
local result = self:command_ex({"KEYS", pattern})
return unescape_array(result)
end
--[[
EXPIRE 命令:设置键的过期时间(秒)
@param key 键名
@param seconds 过期时间(秒)
@return 返回 1 表示设置成功0 表示键不存在或设置失败
]]
function redis_conn:expire(key, seconds)
return self:command_ex({"EXPIRE", key, seconds})
end
--[[
TTL 命令:获取键的剩余过期时间(秒)
@param key 键名
@return 返回剩余秒数,-1 表示永不过期,-2 表示键不存在
]]
function redis_conn:ttl(key)
return self:command_ex({"TTL", key})
end
--[[
INCR 命令:将键的值加 1
@param key 键名
@return 返回增加后的值
]]
function redis_conn:incr(key)
return self:command_ex({"INCR", key})
end
--[[
DECR 命令:将键的值减 1
@param key 键名
@return 返回减少后的值
]]
function redis_conn:decr(key)
return self:command_ex({"DECR", key})
end
--[[
INCRBY 命令:将键的值增加指定数值
@param key 键名
@param increment 增量
@return 返回增加后的值
]]
function redis_conn:incrby(key, increment)
return self:command_ex({"INCRBY", key, increment})
end
--[[
DECRBY 命令:将键的值减少指定数值
@param key 键名
@param decrement 减量
@return 返回减少后的值
]]
function redis_conn:decrby(key, decrement)
return self:command_ex({"DECRBY", key, decrement})
end
-- ==================== Hash 操作 ====================
--[[
HGET 命令:获取哈希表中字段的值
@param key 键名
@param field 字段名
@return 返回字段的值,不存在返回 nil
]]
function redis_conn:hget(key, field)
local result = self:command_ex({"HGET", key, field})
return unescape_value(result)
end
--[[
HSET 命令:设置哈希表中字段的值
@param key 键名
@param field 字段名
@param value 值
@return 返回 1 表示新建字段0 表示更新字段
]]
function redis_conn:hset(key, field, value)
return self:command_ex({"HSET", key, field, value})
end
--[[
HDEL 命令:删除哈希表中的一个或多个字段
@param key 键名
@param ... 字段名列表
@return 返回删除的字段数量
]]
function redis_conn:hdel(key, ...)
local args = {"HDEL", key, ...}
return self:command_ex(args)
end
--[[
HEXISTS 命令:检查哈希表中字段是否存在
@param key 键名
@param field 字段名
@return 返回 1 表示存在0 表示不存在
]]
function redis_conn:hexists(key, field)
return self:command_ex({"HEXISTS", key, field})
end
--[[
HGETALL 命令:获取哈希表中所有字段和值
@param key 键名
@return 返回字段和值的数组
]]
function redis_conn:hgetall(key)
local result = self:command_ex({"HGETALL", key})
return unescape_array(result)
end
--[[
HKEYS 命令:获取哈希表中所有字段名
@param key 键名
@return 返回字段名数组
]]
function redis_conn:hkeys(key)
local result = self:command_ex({"HKEYS", key})
return unescape_array(result)
end
--[[
HVALS 命令:获取哈希表中所有值
@param key 键名
@return 返回值数组
]]
function redis_conn:hvals(key)
local result = self:command_ex({"HVALS", key})
return unescape_array(result)
end
--[[
HLEN 命令:获取哈希表中字段数量
@param key 键名
@return 返回字段数量
]]
function redis_conn:hlen(key)
return self:command_ex({"HLEN", key})
end
-- ==================== List 操作 ====================
--[[
LPUSH 命令:从列表左端插入一个或多个值
@param key 键名
@param ... 值列表
@return 返回插入后列表的长度
]]
function redis_conn:lpush(key, ...)
local args = {"LPUSH", key, ...}
return self:command_ex(args)
end
--[[
RPUSH 命令:从列表右端插入一个或多个值
@param key 键名
@param ... 值列表
@return 返回插入后列表的长度
]]
function redis_conn:rpush(key, ...)
local args = {"RPUSH", key, ...}
return self:command_ex(args)
end
--[[
LPOP 命令:从列表左端弹出一个值
@param key 键名
@return 返回弹出的值,列表为空返回 nil
]]
function redis_conn:lpop(key)
local result = self:command_ex({"LPOP", key})
return unescape_value(result)
end
--[[
RPOP 命令:从列表右端弹出一个值
@param key 键名
@return 返回弹出的值,列表为空返回 nil
]]
function redis_conn:rpop(key)
local result = self:command_ex({"RPOP", key})
return unescape_value(result)
end
--[[
LLEN 命令:获取列表长度
@param key 键名
@return 返回列表长度
]]
function redis_conn:llen(key)
return self:command_ex({"LLEN", key})
end
--[[
LRANGE 命令:获取列表指定范围内的元素
@param key 键名
@param start 起始索引(从 0 开始)
@param stop 结束索引(-1 表示最后一个元素)
@return 返回元素数组
]]
function redis_conn:lrange(key, start, stop)
local result = self:command_ex({"LRANGE", key, start, stop})
return unescape_array(result)
end
-- ==================== Set 操作 ====================
--[[
SADD 命令:向集合添加一个或多个成员
@param key 键名
@param ... 成员列表
@return 返回添加的成员数量
]]
function redis_conn:sadd(key, ...)
local args = {"SADD", key, ...}
return self:command_ex(args)
end
--[[
SREM 命令:从集合移除一个或多个成员
@param key 键名
@param ... 成员列表
@return 返回移除的成员数量
]]
function redis_conn:srem(key, ...)
local args = {"SREM", key, ...}
return self:command_ex(args)
end
--[[
SMEMBERS 命令:获取集合所有成员
@param key 键名
@return 返回成员数组
]]
function redis_conn:smembers(key)
local result = self:command_ex({"SMEMBERS", key})
return unescape_array(result)
end
--[[
SISMEMBER 命令:检查成员是否在集合中
@param key 键名
@param member 成员
@return 返回 1 表示存在0 表示不存在
]]
function redis_conn:sismember(key, member)
return self:command_ex({"SISMEMBER", key, member})
end
--[[
SCARD 命令:获取集合成员数量
@param key 键名
@return 返回成员数量
]]
function redis_conn:scard(key)
return self:command_ex({"SCARD", key})
end
-- ==================== Sorted Set 操作 ====================
--[[
ZADD 命令:向有序集合添加一个或多个成员
@param key 键名
@param score 分数
@param member 成员
@param ... 可选的更多 score-member 对
@return 返回添加的成员数量
]]
function redis_conn:zadd(key, score, member, ...)
local args = {"ZADD", key, score, member, ...}
return self:command_ex(args)
end
--[[
ZRANGE 命令:获取有序集合指定范围内的成员
@param key 键名
@param start 起始索引
@param stop 结束索引
@param withscores 是否包含分数,默认为 false
@return 返回成员数组(如果 withscores 为 true则包含分数
]]
function redis_conn:zrange(key, start, stop, withscores)
local args = {"ZRANGE", key, start, stop}
if withscores then
table.insert(args, "WITHSCORES")
end
local result = self:command_ex(args)
if result == nil or type(result) ~= "table" then
return result
end
-- 如果 withscores 为 true结果是 [member1, score1, member2, score2, ...]
-- 只处理成员部分(奇数索引),分数部分保持不变
if withscores then
local unescaped = {}
for i = 1, #result do
if i % 2 == 1 then
-- 成员(奇数索引)
unescaped[i] = unescape_value(result[i])
else
-- 分数(偶数索引)
unescaped[i] = result[i]
end
end
return unescaped
else
return unescape_array(result)
end
end
--[[
ZREM 命令:从有序集合移除一个或多个成员
@param key 键名
@param ... 成员列表
@return 返回移除的成员数量
]]
function redis_conn:zrem(key, ...)
local args = {"ZREM", key, ...}
return self:command_ex(args)
end
--[[
ZCARD 命令:获取有序集合成员数量
@param key 键名
@return 返回成员数量
]]
function redis_conn:zcard(key)
return self:command_ex({"ZCARD", key})
end
--[[
ZSCORE 命令:获取有序集合成员的分数
@param key 键名
@param member 成员
@return 返回分数,成员不存在返回 nil
]]
function redis_conn:zscore(key, member)
local result = self:command_ex({"ZSCORE", key, member})
-- 分数通常是数字,但为了统一处理,也进行去转义
if result ~= nil then
return unescape_value(result)
end
return result
end
return redis_conn