conn.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. -- redis_conn.lua
  2. local redis_conn = {}
  3. redis_conn.__index = redis_conn
  4. --[[
  5. 转义 Redis 参数,处理包含空格等特殊字符的值
  6. @param value 要转义的值
  7. @return 返回转义后的字符串
  8. ]]
  9. local function escape_value(value)
  10. if value == nil then
  11. return ""
  12. end
  13. -- 将值转换为字符串
  14. local str = tostring(value)
  15. -- 如果包含空格、引号或特殊字符,使用双引号包裹并转义内部引号
  16. if string.find(str, "[%s\"'\\]") then
  17. -- 转义反斜杠和双引号
  18. str = string.gsub(str, "\\", "\\\\")
  19. str = string.gsub(str, "\"", "\\\"")
  20. return "\"" .. str .. "\""
  21. end
  22. return str
  23. end
  24. --[[
  25. 还原 Redis 字符串(去转义)
  26. @param value 被转义的字符串
  27. @return 返回还原后的字符串
  28. ]]
  29. local function unescape_value(value)
  30. if value == nil then
  31. return nil
  32. end
  33. local str = tostring(value)
  34. -- 如果是用双引号包住的,去掉包裹并恢复转义
  35. if #str >= 2 and string.sub(str,1,1) == "\"" and string.sub(str,-1,-1) == "\"" then
  36. str = string.sub(str,2,-2)
  37. str = string.gsub(str, "\\\"", "\"")
  38. str = string.gsub(str, "\\\\", "\\")
  39. return str
  40. end
  41. return str
  42. end
  43. --[[
  44. 对数组进行去转义处理
  45. @param arr 数组
  46. @return 返回去转义后的数组
  47. ]]
  48. local function unescape_array(arr)
  49. if arr == nil or type(arr) ~= "table" then
  50. return arr
  51. end
  52. local result = {}
  53. for i, v in ipairs(arr) do
  54. result[i] = unescape_value(v)
  55. end
  56. return result
  57. end
  58. --[[
  59. 构建 Redis 命令字符串
  60. @param cmd 命令名称
  61. @param ... 命令参数
  62. @return 返回构建好的命令字符串
  63. ]]
  64. local function build_command(cmd, ...)
  65. local args = {...}
  66. local parts = {cmd}
  67. for i, arg in ipairs(args) do
  68. if arg ~= nil then
  69. table.insert(parts, escape_value(arg))
  70. end
  71. end
  72. return table.concat(parts, " ")
  73. end
  74. --[[
  75. 创建一个新的 fw_redis_conn 对象
  76. @return 返回一个新的 fw_redis_conn 对象
  77. ]]
  78. function redis_conn.new(__module)
  79. local instance = setmetatable({}, redis_conn)
  80. instance.module = __module
  81. return instance
  82. end
  83. --[[
  84. 关闭
  85. ]]
  86. function redis_conn:close()
  87. return self.module:close()
  88. end
  89. --[[
  90. 执行 Redis 命令
  91. @param cmd Redis 命令字符串
  92. @return 返回命令执行结果
  93. ]]
  94. function redis_conn:command(cmd)
  95. return self.module:command(cmd)
  96. end
  97. --[[
  98. 执行 Redis 命令
  99. @param args 命令参数数组,会自动将参数转换为字符串
  100. @return 返回命令执行结果
  101. ]]
  102. function redis_conn:command_ex(args)
  103. if args == nil or type(args) ~= "table" then
  104. return nil
  105. end
  106. local str_args = {}
  107. for i, arg in ipairs(args) do
  108. if arg == nil then
  109. table.insert(str_args, "")
  110. elseif type(arg) == "number" then
  111. -- 判断是否为整数:整数不转成小数
  112. if arg % 1 == 0 then
  113. -- 是整数,使用 %d 格式,避免转成小数
  114. table.insert(str_args, string.format("%d", arg))
  115. else
  116. -- 是浮点数,直接转字符串
  117. table.insert(str_args, tostring(arg))
  118. end
  119. else
  120. -- 其他类型(字符串、布尔等)直接转字符串
  121. table.insert(str_args, tostring(arg))
  122. end
  123. end
  124. return self.module:command_ex(str_args)
  125. end
  126. -- ==================== String 操作 ====================
  127. --[[
  128. GET 命令:获取键的值
  129. @param key 键名
  130. @return 返回键的值,不存在返回 nil
  131. ]]
  132. function redis_conn:get(key)
  133. local result = self:command(build_command("GET", key))
  134. return unescape_value(result)
  135. end
  136. --[[
  137. SET 命令:设置键值对
  138. @param key 键名
  139. @param value 值(可以是字符串、数字等,会自动处理空格)
  140. @param options 可选参数,如 "EX seconds" 或 "PX milliseconds" 或 "NX" 或 "XX"
  141. @return 返回执行结果
  142. ]]
  143. function redis_conn:set(key, value, options)
  144. local args = {"SET", key, value}
  145. if options then
  146. -- 如果 options 是字符串,需要拆分(如 "EX 10" 或 "NX")
  147. if type(options) == "string" then
  148. for word in string.gmatch(options, "%S+") do
  149. table.insert(args, word)
  150. end
  151. else
  152. table.insert(args, options)
  153. end
  154. end
  155. return self:command_ex(args)
  156. end
  157. --[[
  158. SETEX 命令:设置键值对并设置过期时间(秒)
  159. @param key 键名
  160. @param seconds 过期时间(秒)
  161. @param value 值
  162. @return 返回执行结果
  163. ]]
  164. function redis_conn:setex(key, seconds, value)
  165. return self:command_ex({"SETEX", key, seconds, value})
  166. end
  167. --[[
  168. SETNX 命令:当键不存在时设置键值对
  169. @param key 键名
  170. @param value 值
  171. @return 返回 1 表示设置成功,0 表示键已存在
  172. ]]
  173. function redis_conn:setnx(key, value)
  174. return self:command_ex({"SETNX", key, value})
  175. end
  176. --[[
  177. DEL 命令:删除一个或多个键
  178. @param ... 键名列表
  179. @return 返回删除的键数量
  180. ]]
  181. function redis_conn:del(...)
  182. local args = {"DEL", ...}
  183. return self:command_ex(args)
  184. end
  185. --[[
  186. EXISTS 命令:检查键是否存在
  187. @param key 键名
  188. @return 返回 1 表示存在,0 表示不存在
  189. ]]
  190. function redis_conn:exists(key)
  191. return self:command_ex({"EXISTS", key})
  192. end
  193. --[[
  194. KEYS 命令:查找所有匹配给定模式的键
  195. @param pattern 匹配模式,支持通配符:* 匹配任意字符,? 匹配单个字符,[] 匹配指定字符
  196. @return 返回匹配的键数组
  197. 注意:在生产环境中应谨慎使用,建议使用 SCAN 命令替代
  198. ]]
  199. function redis_conn:keys(pattern)
  200. local result = self:command_ex({"KEYS", pattern})
  201. return unescape_array(result)
  202. end
  203. --[[
  204. EXPIRE 命令:设置键的过期时间(秒)
  205. @param key 键名
  206. @param seconds 过期时间(秒)
  207. @return 返回 1 表示设置成功,0 表示键不存在或设置失败
  208. ]]
  209. function redis_conn:expire(key, seconds)
  210. return self:command_ex({"EXPIRE", key, seconds})
  211. end
  212. --[[
  213. TTL 命令:获取键的剩余过期时间(秒)
  214. @param key 键名
  215. @return 返回剩余秒数,-1 表示永不过期,-2 表示键不存在
  216. ]]
  217. function redis_conn:ttl(key)
  218. return self:command_ex({"TTL", key})
  219. end
  220. --[[
  221. INCR 命令:将键的值加 1
  222. @param key 键名
  223. @return 返回增加后的值
  224. ]]
  225. function redis_conn:incr(key)
  226. return self:command_ex({"INCR", key})
  227. end
  228. --[[
  229. DECR 命令:将键的值减 1
  230. @param key 键名
  231. @return 返回减少后的值
  232. ]]
  233. function redis_conn:decr(key)
  234. return self:command_ex({"DECR", key})
  235. end
  236. --[[
  237. INCRBY 命令:将键的值增加指定数值
  238. @param key 键名
  239. @param increment 增量
  240. @return 返回增加后的值
  241. ]]
  242. function redis_conn:incrby(key, increment)
  243. return self:command_ex({"INCRBY", key, increment})
  244. end
  245. --[[
  246. DECRBY 命令:将键的值减少指定数值
  247. @param key 键名
  248. @param decrement 减量
  249. @return 返回减少后的值
  250. ]]
  251. function redis_conn:decrby(key, decrement)
  252. return self:command_ex({"DECRBY", key, decrement})
  253. end
  254. -- ==================== Hash 操作 ====================
  255. --[[
  256. HGET 命令:获取哈希表中字段的值
  257. @param key 键名
  258. @param field 字段名
  259. @return 返回字段的值,不存在返回 nil
  260. ]]
  261. function redis_conn:hget(key, field)
  262. local result = self:command_ex({"HGET", key, field})
  263. return unescape_value(result)
  264. end
  265. --[[
  266. HSET 命令:设置哈希表中字段的值
  267. @param key 键名
  268. @param field 字段名
  269. @param value 值
  270. @return 返回 1 表示新建字段,0 表示更新字段
  271. ]]
  272. function redis_conn:hset(key, field, value)
  273. return self:command_ex({"HSET", key, field, value})
  274. end
  275. --[[
  276. HDEL 命令:删除哈希表中的一个或多个字段
  277. @param key 键名
  278. @param ... 字段名列表
  279. @return 返回删除的字段数量
  280. ]]
  281. function redis_conn:hdel(key, ...)
  282. local args = {"HDEL", key, ...}
  283. return self:command_ex(args)
  284. end
  285. --[[
  286. HEXISTS 命令:检查哈希表中字段是否存在
  287. @param key 键名
  288. @param field 字段名
  289. @return 返回 1 表示存在,0 表示不存在
  290. ]]
  291. function redis_conn:hexists(key, field)
  292. return self:command_ex({"HEXISTS", key, field})
  293. end
  294. --[[
  295. HGETALL 命令:获取哈希表中所有字段和值
  296. @param key 键名
  297. @return 返回字段和值的数组
  298. ]]
  299. function redis_conn:hgetall(key)
  300. local result = self:command_ex({"HGETALL", key})
  301. return unescape_array(result)
  302. end
  303. --[[
  304. HKEYS 命令:获取哈希表中所有字段名
  305. @param key 键名
  306. @return 返回字段名数组
  307. ]]
  308. function redis_conn:hkeys(key)
  309. local result = self:command_ex({"HKEYS", key})
  310. return unescape_array(result)
  311. end
  312. --[[
  313. HVALS 命令:获取哈希表中所有值
  314. @param key 键名
  315. @return 返回值数组
  316. ]]
  317. function redis_conn:hvals(key)
  318. local result = self:command_ex({"HVALS", key})
  319. return unescape_array(result)
  320. end
  321. --[[
  322. HLEN 命令:获取哈希表中字段数量
  323. @param key 键名
  324. @return 返回字段数量
  325. ]]
  326. function redis_conn:hlen(key)
  327. return self:command_ex({"HLEN", key})
  328. end
  329. -- ==================== List 操作 ====================
  330. --[[
  331. LPUSH 命令:从列表左端插入一个或多个值
  332. @param key 键名
  333. @param ... 值列表
  334. @return 返回插入后列表的长度
  335. ]]
  336. function redis_conn:lpush(key, ...)
  337. local args = {"LPUSH", key, ...}
  338. return self:command_ex(args)
  339. end
  340. --[[
  341. RPUSH 命令:从列表右端插入一个或多个值
  342. @param key 键名
  343. @param ... 值列表
  344. @return 返回插入后列表的长度
  345. ]]
  346. function redis_conn:rpush(key, ...)
  347. local args = {"RPUSH", key, ...}
  348. return self:command_ex(args)
  349. end
  350. --[[
  351. LPOP 命令:从列表左端弹出一个值
  352. @param key 键名
  353. @return 返回弹出的值,列表为空返回 nil
  354. ]]
  355. function redis_conn:lpop(key)
  356. local result = self:command_ex({"LPOP", key})
  357. return unescape_value(result)
  358. end
  359. --[[
  360. RPOP 命令:从列表右端弹出一个值
  361. @param key 键名
  362. @return 返回弹出的值,列表为空返回 nil
  363. ]]
  364. function redis_conn:rpop(key)
  365. local result = self:command_ex({"RPOP", key})
  366. return unescape_value(result)
  367. end
  368. --[[
  369. LLEN 命令:获取列表长度
  370. @param key 键名
  371. @return 返回列表长度
  372. ]]
  373. function redis_conn:llen(key)
  374. return self:command_ex({"LLEN", key})
  375. end
  376. --[[
  377. LRANGE 命令:获取列表指定范围内的元素
  378. @param key 键名
  379. @param start 起始索引(从 0 开始)
  380. @param stop 结束索引(-1 表示最后一个元素)
  381. @return 返回元素数组
  382. ]]
  383. function redis_conn:lrange(key, start, stop)
  384. local result = self:command_ex({"LRANGE", key, start, stop})
  385. return unescape_array(result)
  386. end
  387. -- ==================== Set 操作 ====================
  388. --[[
  389. SADD 命令:向集合添加一个或多个成员
  390. @param key 键名
  391. @param ... 成员列表
  392. @return 返回添加的成员数量
  393. ]]
  394. function redis_conn:sadd(key, ...)
  395. local args = {"SADD", key, ...}
  396. return self:command_ex(args)
  397. end
  398. --[[
  399. SREM 命令:从集合移除一个或多个成员
  400. @param key 键名
  401. @param ... 成员列表
  402. @return 返回移除的成员数量
  403. ]]
  404. function redis_conn:srem(key, ...)
  405. local args = {"SREM", key, ...}
  406. return self:command_ex(args)
  407. end
  408. --[[
  409. SMEMBERS 命令:获取集合所有成员
  410. @param key 键名
  411. @return 返回成员数组
  412. ]]
  413. function redis_conn:smembers(key)
  414. local result = self:command_ex({"SMEMBERS", key})
  415. return unescape_array(result)
  416. end
  417. --[[
  418. SISMEMBER 命令:检查成员是否在集合中
  419. @param key 键名
  420. @param member 成员
  421. @return 返回 1 表示存在,0 表示不存在
  422. ]]
  423. function redis_conn:sismember(key, member)
  424. return self:command_ex({"SISMEMBER", key, member})
  425. end
  426. --[[
  427. SCARD 命令:获取集合成员数量
  428. @param key 键名
  429. @return 返回成员数量
  430. ]]
  431. function redis_conn:scard(key)
  432. return self:command_ex({"SCARD", key})
  433. end
  434. -- ==================== Sorted Set 操作 ====================
  435. --[[
  436. ZADD 命令:向有序集合添加一个或多个成员
  437. @param key 键名
  438. @param score 分数
  439. @param member 成员
  440. @param ... 可选的更多 score-member 对
  441. @return 返回添加的成员数量
  442. ]]
  443. function redis_conn:zadd(key, score, member, ...)
  444. local args = {"ZADD", key, score, member, ...}
  445. return self:command_ex(args)
  446. end
  447. --[[
  448. ZRANGE 命令:获取有序集合指定范围内的成员
  449. @param key 键名
  450. @param start 起始索引
  451. @param stop 结束索引
  452. @param withscores 是否包含分数,默认为 false
  453. @return 返回成员数组(如果 withscores 为 true,则包含分数)
  454. ]]
  455. function redis_conn:zrange(key, start, stop, withscores)
  456. local args = {"ZRANGE", key, start, stop}
  457. if withscores then
  458. table.insert(args, "WITHSCORES")
  459. end
  460. local result = self:command_ex(args)
  461. if result == nil or type(result) ~= "table" then
  462. return result
  463. end
  464. -- 如果 withscores 为 true,结果是 [member1, score1, member2, score2, ...]
  465. -- 只处理成员部分(奇数索引),分数部分保持不变
  466. if withscores then
  467. local unescaped = {}
  468. for i = 1, #result do
  469. if i % 2 == 1 then
  470. -- 成员(奇数索引)
  471. unescaped[i] = unescape_value(result[i])
  472. else
  473. -- 分数(偶数索引)
  474. unescaped[i] = result[i]
  475. end
  476. end
  477. return unescaped
  478. else
  479. return unescape_array(result)
  480. end
  481. end
  482. --[[
  483. ZREM 命令:从有序集合移除一个或多个成员
  484. @param key 键名
  485. @param ... 成员列表
  486. @return 返回移除的成员数量
  487. ]]
  488. function redis_conn:zrem(key, ...)
  489. local args = {"ZREM", key, ...}
  490. return self:command_ex(args)
  491. end
  492. --[[
  493. ZCARD 命令:获取有序集合成员数量
  494. @param key 键名
  495. @return 返回成员数量
  496. ]]
  497. function redis_conn:zcard(key)
  498. return self:command_ex({"ZCARD", key})
  499. end
  500. --[[
  501. ZSCORE 命令:获取有序集合成员的分数
  502. @param key 键名
  503. @param member 成员
  504. @return 返回分数,成员不存在返回 nil
  505. ]]
  506. function redis_conn:zscore(key, member)
  507. local result = self:command_ex({"ZSCORE", key, member})
  508. -- 分数通常是数字,但为了统一处理,也进行去转义
  509. if result ~= nil then
  510. return unescape_value(result)
  511. end
  512. return result
  513. end
  514. return redis_conn