befly 3.9.38 → 3.9.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -38
- package/befly.config.ts +62 -40
- package/checks/checkApi.ts +16 -16
- package/checks/checkApp.ts +19 -25
- package/checks/checkTable.ts +42 -42
- package/docs/README.md +42 -35
- package/docs/{api.md → api/api.md} +223 -231
- package/docs/cipher.md +71 -69
- package/docs/database.md +143 -141
- package/docs/{examples.md → guide/examples.md} +181 -181
- package/docs/guide/quickstart.md +331 -0
- package/docs/hooks/auth.md +38 -0
- package/docs/hooks/cors.md +28 -0
- package/docs/{hook.md → hooks/hook.md} +140 -57
- package/docs/hooks/parser.md +19 -0
- package/docs/hooks/rateLimit.md +47 -0
- package/docs/{redis.md → infra/redis.md} +84 -93
- package/docs/plugins/cipher.md +61 -0
- package/docs/plugins/database.md +128 -0
- package/docs/{plugin.md → plugins/plugin.md} +83 -81
- package/docs/quickstart.md +26 -26
- package/docs/{addon.md → reference/addon.md} +46 -46
- package/docs/{config.md → reference/config.md} +32 -80
- package/docs/{logger.md → reference/logger.md} +52 -52
- package/docs/{sync.md → reference/sync.md} +32 -35
- package/docs/{table.md → reference/table.md} +1 -1
- package/docs/{validator.md → reference/validator.md} +57 -57
- package/hooks/auth.ts +8 -4
- package/hooks/cors.ts +13 -13
- package/hooks/parser.ts +37 -17
- package/hooks/permission.ts +26 -14
- package/hooks/rateLimit.ts +276 -0
- package/hooks/validator.ts +7 -7
- package/lib/asyncContext.ts +43 -0
- package/lib/cacheHelper.ts +212 -77
- package/lib/cacheKeys.ts +38 -0
- package/lib/cipher.ts +30 -30
- package/lib/connect.ts +28 -28
- package/lib/dbHelper.ts +183 -102
- package/lib/jwt.ts +16 -16
- package/lib/logger.ts +610 -19
- package/lib/redisHelper.ts +185 -44
- package/lib/sqlBuilder.ts +90 -91
- package/lib/validator.ts +59 -39
- package/loader/loadApis.ts +48 -44
- package/loader/loadHooks.ts +40 -14
- package/loader/loadPlugins.ts +16 -17
- package/main.ts +57 -47
- package/package.json +47 -45
- package/paths.ts +15 -14
- package/plugins/cache.ts +5 -4
- package/plugins/cipher.ts +3 -3
- package/plugins/config.ts +2 -2
- package/plugins/db.ts +9 -9
- package/plugins/jwt.ts +3 -3
- package/plugins/logger.ts +8 -12
- package/plugins/redis.ts +8 -8
- package/plugins/tool.ts +6 -6
- package/router/api.ts +85 -56
- package/router/static.ts +12 -12
- package/sync/syncAll.ts +12 -12
- package/sync/syncApi.ts +55 -52
- package/sync/syncDb/apply.ts +20 -19
- package/sync/syncDb/constants.ts +25 -23
- package/sync/syncDb/ddl.ts +35 -36
- package/sync/syncDb/helpers.ts +6 -9
- package/sync/syncDb/schema.ts +10 -9
- package/sync/syncDb/sqlite.ts +7 -8
- package/sync/syncDb/table.ts +37 -35
- package/sync/syncDb/tableCreate.ts +21 -20
- package/sync/syncDb/types.ts +23 -20
- package/sync/syncDb/version.ts +10 -10
- package/sync/syncDb.ts +43 -36
- package/sync/syncDev.ts +74 -65
- package/sync/syncMenu.ts +190 -55
- package/tests/api-integration-array-number.test.ts +282 -0
- package/tests/befly-config-env.test.ts +78 -0
- package/tests/cacheHelper.test.ts +135 -104
- package/tests/cacheKeys.test.ts +41 -0
- package/tests/cipher.test.ts +90 -89
- package/tests/dbHelper-advanced.test.ts +140 -134
- package/tests/dbHelper-all-array-types.test.ts +316 -0
- package/tests/dbHelper-array-serialization.test.ts +258 -0
- package/tests/dbHelper-columns.test.ts +56 -55
- package/tests/dbHelper-execute.test.ts +45 -44
- package/tests/dbHelper-joins.test.ts +124 -119
- package/tests/fields-redis-cache.test.ts +29 -27
- package/tests/fields-validate.test.ts +38 -38
- package/tests/getClientIp.test.ts +54 -0
- package/tests/integration.test.ts +69 -67
- package/tests/jwt.test.ts +27 -26
- package/tests/logger.test.ts +267 -34
- package/tests/rateLimit-hook.test.ts +477 -0
- package/tests/redisHelper.test.ts +187 -188
- package/tests/redisKeys.test.ts +6 -73
- package/tests/scanConfig.test.ts +144 -0
- package/tests/sqlBuilder-advanced.test.ts +217 -215
- package/tests/sqlBuilder.test.ts +92 -91
- package/tests/sync-connection.test.ts +29 -29
- package/tests/syncDb-apply.test.ts +97 -96
- package/tests/syncDb-array-number.test.ts +160 -0
- package/tests/syncDb-constants.test.ts +48 -47
- package/tests/syncDb-ddl.test.ts +99 -98
- package/tests/syncDb-helpers.test.ts +29 -28
- package/tests/syncDb-schema.test.ts +61 -60
- package/tests/syncDb-types.test.ts +60 -59
- package/tests/syncMenu-paths.test.ts +68 -0
- package/tests/util.test.ts +42 -41
- package/tests/validator-array-number.test.ts +310 -0
- package/tests/validator-default.test.ts +373 -0
- package/tests/validator.test.ts +271 -266
- package/tsconfig.json +4 -5
- package/types/api.d.ts +7 -12
- package/types/befly.d.ts +60 -13
- package/types/cache.d.ts +8 -4
- package/types/common.d.ts +17 -9
- package/types/context.d.ts +2 -2
- package/types/crypto.d.ts +23 -0
- package/types/database.d.ts +19 -19
- package/types/hook.d.ts +2 -2
- package/types/jwt.d.ts +118 -0
- package/types/logger.d.ts +30 -0
- package/types/plugin.d.ts +4 -4
- package/types/redis.d.ts +7 -3
- package/types/roleApisCache.ts +23 -0
- package/types/sync.d.ts +10 -10
- package/types/table.d.ts +50 -9
- package/types/validate.d.ts +69 -0
- package/utils/addonHelper.ts +90 -0
- package/utils/arrayKeysToCamel.ts +18 -0
- package/utils/calcPerfTime.ts +13 -0
- package/utils/configTypes.ts +3 -0
- package/utils/cors.ts +19 -0
- package/utils/fieldClear.ts +75 -0
- package/utils/genShortId.ts +12 -0
- package/utils/getClientIp.ts +45 -0
- package/utils/keysToCamel.ts +22 -0
- package/utils/keysToSnake.ts +22 -0
- package/utils/modules.ts +98 -0
- package/utils/pickFields.ts +19 -0
- package/utils/process.ts +56 -0
- package/utils/regex.ts +225 -0
- package/utils/response.ts +115 -0
- package/utils/route.ts +23 -0
- package/utils/scanConfig.ts +142 -0
- package/utils/scanFiles.ts +48 -0
- package/.prettierignore +0 -2
- package/.prettierrc +0 -12
- package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
- package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
- package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
- package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
- package/hooks/requestLogger.ts +0 -84
- package/types/index.ts +0 -24
- package/util.ts +0 -283
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* 测试 Redis 操作功能
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { describe, expect,
|
|
7
|
-
import { RedisClient } from 'bun';
|
|
6
|
+
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
|
|
8
7
|
|
|
9
|
-
import { Connect } from
|
|
10
|
-
import { RedisHelper } from
|
|
8
|
+
import { Connect } from "../lib/connect.js";
|
|
9
|
+
import { RedisHelper } from "../lib/redisHelper.js";
|
|
11
10
|
|
|
12
11
|
let redis: RedisHelper;
|
|
13
12
|
|
|
@@ -22,203 +21,203 @@ afterAll(async () => {
|
|
|
22
21
|
await Connect.disconnectRedis();
|
|
23
22
|
});
|
|
24
23
|
|
|
25
|
-
describe(
|
|
26
|
-
test(
|
|
27
|
-
const result = await redis.setString(
|
|
28
|
-
expect(result).toBe(
|
|
24
|
+
describe("RedisHelper - 字符串操作", () => {
|
|
25
|
+
test("setString - 设置字符串", async () => {
|
|
26
|
+
const result = await redis.setString("test:string", "Hello Redis");
|
|
27
|
+
expect(result).toBe("OK");
|
|
29
28
|
});
|
|
30
29
|
|
|
31
|
-
test(
|
|
32
|
-
await redis.setString(
|
|
33
|
-
const value = await redis.getString(
|
|
34
|
-
expect(value).toBe(
|
|
30
|
+
test("getString - 获取字符串", async () => {
|
|
31
|
+
await redis.setString("test:string", "Hello Redis");
|
|
32
|
+
const value = await redis.getString("test:string");
|
|
33
|
+
expect(value).toBe("Hello Redis");
|
|
35
34
|
});
|
|
36
35
|
|
|
37
|
-
test(
|
|
38
|
-
const value = await redis.getString(
|
|
36
|
+
test("getString - 获取不存在的键", async () => {
|
|
37
|
+
const value = await redis.getString("test:non_existent");
|
|
39
38
|
expect(value).toBeNull();
|
|
40
39
|
});
|
|
41
40
|
|
|
42
|
-
test(
|
|
43
|
-
const result = await redis.setString(
|
|
44
|
-
expect(result).toBe(
|
|
41
|
+
test("setString - 设置带过期时间的字符串", async () => {
|
|
42
|
+
const result = await redis.setString("test:ttl", "Expire Test", 2);
|
|
43
|
+
expect(result).toBe("OK");
|
|
45
44
|
|
|
46
|
-
const value = await redis.getString(
|
|
47
|
-
expect(value).toBe(
|
|
45
|
+
const value = await redis.getString("test:ttl");
|
|
46
|
+
expect(value).toBe("Expire Test");
|
|
48
47
|
|
|
49
48
|
// 等待过期
|
|
50
49
|
await new Promise((resolve) => setTimeout(resolve, 2100));
|
|
51
50
|
|
|
52
|
-
const expiredValue = await redis.getString(
|
|
51
|
+
const expiredValue = await redis.getString("test:ttl");
|
|
53
52
|
expect(expiredValue).toBeNull();
|
|
54
53
|
});
|
|
55
54
|
});
|
|
56
55
|
|
|
57
|
-
describe(
|
|
58
|
-
test(
|
|
59
|
-
const obj = { name:
|
|
60
|
-
const result = await redis.setObject(
|
|
61
|
-
expect(result).toBe(
|
|
56
|
+
describe("RedisHelper - 对象操作", () => {
|
|
57
|
+
test("setObject - 设置对象", async () => {
|
|
58
|
+
const obj = { name: "Test", age: 25, tags: ["a", "b"] };
|
|
59
|
+
const result = await redis.setObject("test:object", obj);
|
|
60
|
+
expect(result).toBe("OK");
|
|
62
61
|
});
|
|
63
62
|
|
|
64
|
-
test(
|
|
65
|
-
const obj = { name:
|
|
66
|
-
await redis.setObject(
|
|
63
|
+
test("getObject - 获取对象", async () => {
|
|
64
|
+
const obj = { name: "Test", age: 25, tags: ["a", "b"] };
|
|
65
|
+
await redis.setObject("test:object", obj);
|
|
67
66
|
|
|
68
|
-
const value = await redis.getObject<any>(
|
|
67
|
+
const value = await redis.getObject<any>("test:object");
|
|
69
68
|
expect(value).toEqual(obj);
|
|
70
69
|
});
|
|
71
70
|
|
|
72
|
-
test(
|
|
73
|
-
const value = await redis.getObject(
|
|
71
|
+
test("getObject - 获取不存在的对象", async () => {
|
|
72
|
+
const value = await redis.getObject("test:non_existent_obj");
|
|
74
73
|
expect(value).toBeNull();
|
|
75
74
|
});
|
|
76
75
|
|
|
77
|
-
test(
|
|
78
|
-
const obj = { data:
|
|
79
|
-
const result = await redis.setObject(
|
|
80
|
-
expect(result).toBe(
|
|
76
|
+
test("setObject - 设置带过期时间的对象", async () => {
|
|
77
|
+
const obj = { data: "test" };
|
|
78
|
+
const result = await redis.setObject("test:object:ttl", obj, 1);
|
|
79
|
+
expect(result).toBe("OK");
|
|
81
80
|
|
|
82
81
|
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
83
82
|
|
|
84
|
-
const expiredValue = await redis.getObject(
|
|
83
|
+
const expiredValue = await redis.getObject("test:object:ttl");
|
|
85
84
|
expect(expiredValue).toBeNull();
|
|
86
85
|
});
|
|
87
86
|
|
|
88
|
-
test(
|
|
89
|
-
await redis.setObject(
|
|
90
|
-
await redis.delObject(
|
|
87
|
+
test("delObject - 删除对象", async () => {
|
|
88
|
+
await redis.setObject("test:delete", { data: "test" });
|
|
89
|
+
await redis.delObject("test:delete");
|
|
91
90
|
|
|
92
|
-
const value = await redis.getObject(
|
|
91
|
+
const value = await redis.getObject("test:delete");
|
|
93
92
|
expect(value).toBeNull();
|
|
94
93
|
});
|
|
95
94
|
});
|
|
96
95
|
|
|
97
|
-
describe(
|
|
98
|
-
test(
|
|
96
|
+
describe("RedisHelper - Set 操作", () => {
|
|
97
|
+
test("sadd - 添加成员到 Set", async () => {
|
|
99
98
|
// 先清除,确保测试隔离
|
|
100
|
-
await redis.del(
|
|
101
|
-
const count = await redis.sadd(
|
|
99
|
+
await redis.del("test:set:sadd");
|
|
100
|
+
const count = await redis.sadd("test:set:sadd", ["member1", "member2", "member3"]);
|
|
102
101
|
expect(count).toBeGreaterThan(0);
|
|
103
|
-
await redis.del(
|
|
102
|
+
await redis.del("test:set:sadd");
|
|
104
103
|
});
|
|
105
104
|
|
|
106
|
-
test(
|
|
107
|
-
await redis.del(
|
|
108
|
-
await redis.sadd(
|
|
105
|
+
test("sismember - 检查成员是否存在", async () => {
|
|
106
|
+
await redis.del("test:set");
|
|
107
|
+
await redis.sadd("test:set", ["member1"]);
|
|
109
108
|
|
|
110
|
-
const exists = await redis.sismember(
|
|
109
|
+
const exists = await redis.sismember("test:set", "member1");
|
|
111
110
|
expect(exists).toBe(true);
|
|
112
111
|
|
|
113
|
-
const notExists = await redis.sismember(
|
|
112
|
+
const notExists = await redis.sismember("test:set", "non_existent");
|
|
114
113
|
expect(notExists).toBe(false);
|
|
115
114
|
});
|
|
116
115
|
|
|
117
|
-
test(
|
|
118
|
-
await redis.del(
|
|
119
|
-
await redis.sadd(
|
|
116
|
+
test("scard - 获取 Set 成员数量", async () => {
|
|
117
|
+
await redis.del("test:set:count");
|
|
118
|
+
await redis.sadd("test:set:count", ["m1", "m2", "m3"]);
|
|
120
119
|
|
|
121
|
-
const count = await redis.scard(
|
|
120
|
+
const count = await redis.scard("test:set:count");
|
|
122
121
|
expect(count).toBe(3);
|
|
123
122
|
|
|
124
|
-
await redis.del(
|
|
123
|
+
await redis.del("test:set:count");
|
|
125
124
|
});
|
|
126
125
|
|
|
127
|
-
test(
|
|
128
|
-
await redis.del(
|
|
129
|
-
await redis.sadd(
|
|
126
|
+
test("smembers - 获取所有成员", async () => {
|
|
127
|
+
await redis.del("test:set:members");
|
|
128
|
+
await redis.sadd("test:set:members", ["a", "b", "c"]);
|
|
130
129
|
|
|
131
|
-
const members = await redis.smembers(
|
|
130
|
+
const members = await redis.smembers("test:set:members");
|
|
132
131
|
expect(members.length).toBe(3);
|
|
133
|
-
expect(members).toContain(
|
|
134
|
-
expect(members).toContain(
|
|
135
|
-
expect(members).toContain(
|
|
132
|
+
expect(members).toContain("a");
|
|
133
|
+
expect(members).toContain("b");
|
|
134
|
+
expect(members).toContain("c");
|
|
136
135
|
|
|
137
|
-
await redis.del(
|
|
136
|
+
await redis.del("test:set:members");
|
|
138
137
|
});
|
|
139
138
|
|
|
140
|
-
test(
|
|
139
|
+
test("saddBatch - 批量向多个 Set 添加成员", async () => {
|
|
141
140
|
const count = await redis.saddBatch([
|
|
142
|
-
{ key:
|
|
143
|
-
{ key:
|
|
141
|
+
{ key: "test:saddBatch:1", members: ["a", "b"] },
|
|
142
|
+
{ key: "test:saddBatch:2", members: ["c", "d", "e"] }
|
|
144
143
|
]);
|
|
145
144
|
expect(count).toBe(5);
|
|
146
145
|
|
|
147
146
|
// 验证
|
|
148
|
-
const members1 = await redis.smembers(
|
|
149
|
-
const members2 = await redis.smembers(
|
|
147
|
+
const members1 = await redis.smembers("test:saddBatch:1");
|
|
148
|
+
const members2 = await redis.smembers("test:saddBatch:2");
|
|
150
149
|
expect(members1.length).toBe(2);
|
|
151
150
|
expect(members2.length).toBe(3);
|
|
152
151
|
|
|
153
152
|
// 清理
|
|
154
|
-
await redis.delBatch([
|
|
153
|
+
await redis.delBatch(["test:saddBatch:1", "test:saddBatch:2"]);
|
|
155
154
|
});
|
|
156
155
|
|
|
157
|
-
test(
|
|
156
|
+
test("saddBatch - 空数组返回 0", async () => {
|
|
158
157
|
const count = await redis.saddBatch([]);
|
|
159
158
|
expect(count).toBe(0);
|
|
160
159
|
});
|
|
161
160
|
|
|
162
|
-
test(
|
|
163
|
-
await redis.sadd(
|
|
161
|
+
test("sismemberBatch - 批量检查成员是否存在", async () => {
|
|
162
|
+
await redis.sadd("test:sismemberBatch", ["a", "b", "c"]);
|
|
164
163
|
|
|
165
164
|
const results = await redis.sismemberBatch([
|
|
166
|
-
{ key:
|
|
167
|
-
{ key:
|
|
168
|
-
{ key:
|
|
165
|
+
{ key: "test:sismemberBatch", member: "a" },
|
|
166
|
+
{ key: "test:sismemberBatch", member: "b" },
|
|
167
|
+
{ key: "test:sismemberBatch", member: "x" }
|
|
169
168
|
]);
|
|
170
169
|
expect(results).toEqual([true, true, false]);
|
|
171
170
|
|
|
172
171
|
// 清理
|
|
173
|
-
await redis.del(
|
|
172
|
+
await redis.del("test:sismemberBatch");
|
|
174
173
|
});
|
|
175
174
|
|
|
176
|
-
test(
|
|
175
|
+
test("sismemberBatch - 空数组返回空数组", async () => {
|
|
177
176
|
const results = await redis.sismemberBatch([]);
|
|
178
177
|
expect(results).toEqual([]);
|
|
179
178
|
});
|
|
180
179
|
});
|
|
181
180
|
|
|
182
|
-
describe(
|
|
183
|
-
test(
|
|
184
|
-
await redis.setString(
|
|
181
|
+
describe("RedisHelper - 键操作", () => {
|
|
182
|
+
test("exists - 检查键是否存在", async () => {
|
|
183
|
+
await redis.setString("test:exists", "value");
|
|
185
184
|
|
|
186
|
-
const exists = await redis.exists(
|
|
185
|
+
const exists = await redis.exists("test:exists");
|
|
187
186
|
expect(exists).toBe(true);
|
|
188
187
|
|
|
189
|
-
const notExists = await redis.exists(
|
|
188
|
+
const notExists = await redis.exists("test:not_exists");
|
|
190
189
|
expect(notExists).toBe(false);
|
|
191
190
|
|
|
192
|
-
await redis.del(
|
|
191
|
+
await redis.del("test:exists");
|
|
193
192
|
});
|
|
194
193
|
|
|
195
|
-
test(
|
|
196
|
-
await redis.setString(
|
|
197
|
-
const result = await redis.expire(
|
|
194
|
+
test("expire - 设置过期时间", async () => {
|
|
195
|
+
await redis.setString("test:expire", "value");
|
|
196
|
+
const result = await redis.expire("test:expire", 1);
|
|
198
197
|
expect(result).toBe(1);
|
|
199
198
|
|
|
200
199
|
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
201
200
|
|
|
202
|
-
const value = await redis.getString(
|
|
201
|
+
const value = await redis.getString("test:expire");
|
|
203
202
|
expect(value).toBeNull();
|
|
204
203
|
});
|
|
205
204
|
|
|
206
|
-
test(
|
|
207
|
-
await redis.setString(
|
|
205
|
+
test("ttl - 获取剩余过期时间", async () => {
|
|
206
|
+
await redis.setString("test:ttl:check", "value", 10);
|
|
208
207
|
|
|
209
|
-
const ttl = await redis.ttl(
|
|
208
|
+
const ttl = await redis.ttl("test:ttl:check");
|
|
210
209
|
expect(ttl).toBeGreaterThan(0);
|
|
211
210
|
expect(ttl).toBeLessThanOrEqual(10);
|
|
212
211
|
|
|
213
|
-
await redis.del(
|
|
212
|
+
await redis.del("test:ttl:check");
|
|
214
213
|
});
|
|
215
214
|
|
|
216
|
-
test(
|
|
217
|
-
await redis.setString(
|
|
218
|
-
await redis.setString(
|
|
215
|
+
test("ttlBatch - 批量获取剩余过期时间", async () => {
|
|
216
|
+
await redis.setString("test:ttlBatch:1", "value1", 60);
|
|
217
|
+
await redis.setString("test:ttlBatch:2", "value2", 120);
|
|
219
218
|
// test:ttlBatch:3 不存在
|
|
220
219
|
|
|
221
|
-
const results = await redis.ttlBatch([
|
|
220
|
+
const results = await redis.ttlBatch(["test:ttlBatch:1", "test:ttlBatch:2", "test:ttlBatch:3"]);
|
|
222
221
|
expect(results.length).toBe(3);
|
|
223
222
|
expect(results[0]).toBeGreaterThan(0);
|
|
224
223
|
expect(results[0]).toBeLessThanOrEqual(60);
|
|
@@ -227,239 +226,239 @@ describe('RedisHelper - 键操作', () => {
|
|
|
227
226
|
expect(results[2]).toBe(-2); // 键不存在
|
|
228
227
|
|
|
229
228
|
// 清理
|
|
230
|
-
await redis.delBatch([
|
|
229
|
+
await redis.delBatch(["test:ttlBatch:1", "test:ttlBatch:2"]);
|
|
231
230
|
});
|
|
232
231
|
|
|
233
|
-
test(
|
|
232
|
+
test("ttlBatch - 空数组返回空数组", async () => {
|
|
234
233
|
const results = await redis.ttlBatch([]);
|
|
235
234
|
expect(results).toEqual([]);
|
|
236
235
|
});
|
|
237
236
|
|
|
238
|
-
test(
|
|
239
|
-
await redis.setString(
|
|
237
|
+
test("ttlBatch - 无过期时间返回 -1", async () => {
|
|
238
|
+
await redis.setString("test:ttlBatch:nox", "value"); // 无 TTL
|
|
240
239
|
|
|
241
|
-
const results = await redis.ttlBatch([
|
|
240
|
+
const results = await redis.ttlBatch(["test:ttlBatch:nox"]);
|
|
242
241
|
expect(results[0]).toBe(-1);
|
|
243
242
|
|
|
244
243
|
// 清理
|
|
245
|
-
await redis.del(
|
|
244
|
+
await redis.del("test:ttlBatch:nox");
|
|
246
245
|
});
|
|
247
246
|
|
|
248
|
-
test(
|
|
249
|
-
await redis.setString(
|
|
247
|
+
test("del - 删除键", async () => {
|
|
248
|
+
await redis.setString("test:delete:key", "value");
|
|
250
249
|
|
|
251
|
-
const count = await redis.del(
|
|
250
|
+
const count = await redis.del("test:delete:key");
|
|
252
251
|
expect(count).toBe(1);
|
|
253
252
|
|
|
254
|
-
const value = await redis.getString(
|
|
253
|
+
const value = await redis.getString("test:delete:key");
|
|
255
254
|
expect(value).toBeNull();
|
|
256
255
|
});
|
|
257
256
|
|
|
258
|
-
test(
|
|
257
|
+
test("delBatch - 批量删除键", async () => {
|
|
259
258
|
// 创建多个键
|
|
260
|
-
await redis.setString(
|
|
261
|
-
await redis.setString(
|
|
262
|
-
await redis.setString(
|
|
259
|
+
await redis.setString("test:batch:1", "value1");
|
|
260
|
+
await redis.setString("test:batch:2", "value2");
|
|
261
|
+
await redis.setString("test:batch:3", "value3");
|
|
263
262
|
|
|
264
263
|
// 批量删除
|
|
265
|
-
const count = await redis.delBatch([
|
|
264
|
+
const count = await redis.delBatch(["test:batch:1", "test:batch:2", "test:batch:3"]);
|
|
266
265
|
expect(count).toBe(3);
|
|
267
266
|
|
|
268
267
|
// 验证删除成功
|
|
269
|
-
const value1 = await redis.getString(
|
|
270
|
-
const value2 = await redis.getString(
|
|
271
|
-
const value3 = await redis.getString(
|
|
268
|
+
const value1 = await redis.getString("test:batch:1");
|
|
269
|
+
const value2 = await redis.getString("test:batch:2");
|
|
270
|
+
const value3 = await redis.getString("test:batch:3");
|
|
272
271
|
expect(value1).toBeNull();
|
|
273
272
|
expect(value2).toBeNull();
|
|
274
273
|
expect(value3).toBeNull();
|
|
275
274
|
});
|
|
276
275
|
|
|
277
|
-
test(
|
|
276
|
+
test("delBatch - 空数组返回 0", async () => {
|
|
278
277
|
const count = await redis.delBatch([]);
|
|
279
278
|
expect(count).toBe(0);
|
|
280
279
|
});
|
|
281
280
|
|
|
282
|
-
test(
|
|
283
|
-
const count = await redis.delBatch([
|
|
281
|
+
test("delBatch - 删除不存在的键返回 0", async () => {
|
|
282
|
+
const count = await redis.delBatch(["test:non:existent:1", "test:non:existent:2"]);
|
|
284
283
|
expect(count).toBe(0);
|
|
285
284
|
});
|
|
286
285
|
|
|
287
|
-
test(
|
|
288
|
-
await redis.setString(
|
|
289
|
-
await redis.setString(
|
|
286
|
+
test("delBatch - 部分存在的键", async () => {
|
|
287
|
+
await redis.setString("test:partial:1", "value1");
|
|
288
|
+
await redis.setString("test:partial:2", "value2");
|
|
290
289
|
// test:partial:3 不存在
|
|
291
290
|
|
|
292
|
-
const count = await redis.delBatch([
|
|
291
|
+
const count = await redis.delBatch(["test:partial:1", "test:partial:2", "test:partial:3"]);
|
|
293
292
|
expect(count).toBe(2); // 只有 2 个键被删除
|
|
294
293
|
});
|
|
295
294
|
|
|
296
|
-
test(
|
|
295
|
+
test("setBatch - 批量设置对象", async () => {
|
|
297
296
|
const items = [
|
|
298
|
-
{ key:
|
|
299
|
-
{ key:
|
|
300
|
-
{ key:
|
|
297
|
+
{ key: "test:setBatch:1", value: { name: "Alice" } },
|
|
298
|
+
{ key: "test:setBatch:2", value: { name: "Bob" } },
|
|
299
|
+
{ key: "test:setBatch:3", value: { name: "Charlie" } }
|
|
301
300
|
];
|
|
302
301
|
|
|
303
302
|
const count = await redis.setBatch(items);
|
|
304
303
|
expect(count).toBe(3);
|
|
305
304
|
|
|
306
305
|
// 验证设置成功
|
|
307
|
-
const value1 = await redis.getObject(
|
|
308
|
-
const value2 = await redis.getObject(
|
|
309
|
-
const value3 = await redis.getObject(
|
|
310
|
-
expect(value1).toEqual({ name:
|
|
311
|
-
expect(value2).toEqual({ name:
|
|
312
|
-
expect(value3).toEqual({ name:
|
|
306
|
+
const value1 = await redis.getObject("test:setBatch:1");
|
|
307
|
+
const value2 = await redis.getObject("test:setBatch:2");
|
|
308
|
+
const value3 = await redis.getObject("test:setBatch:3");
|
|
309
|
+
expect(value1).toEqual({ name: "Alice" });
|
|
310
|
+
expect(value2).toEqual({ name: "Bob" });
|
|
311
|
+
expect(value3).toEqual({ name: "Charlie" });
|
|
313
312
|
|
|
314
313
|
// 清理
|
|
315
|
-
await redis.delBatch([
|
|
314
|
+
await redis.delBatch(["test:setBatch:1", "test:setBatch:2", "test:setBatch:3"]);
|
|
316
315
|
});
|
|
317
316
|
|
|
318
|
-
test(
|
|
317
|
+
test("setBatch - 空数组返回 0", async () => {
|
|
319
318
|
const count = await redis.setBatch([]);
|
|
320
319
|
expect(count).toBe(0);
|
|
321
320
|
});
|
|
322
321
|
|
|
323
|
-
test(
|
|
322
|
+
test("setBatch - 带 TTL 的批量设置", async () => {
|
|
324
323
|
const items = [
|
|
325
|
-
{ key:
|
|
326
|
-
{ key:
|
|
324
|
+
{ key: "test:setBatch:ttl:1", value: { data: 1 }, ttl: 10 },
|
|
325
|
+
{ key: "test:setBatch:ttl:2", value: { data: 2 }, ttl: 10 }
|
|
327
326
|
];
|
|
328
327
|
|
|
329
328
|
const count = await redis.setBatch(items);
|
|
330
329
|
expect(count).toBe(2);
|
|
331
330
|
|
|
332
331
|
// 验证 TTL 已设置
|
|
333
|
-
const ttl1 = await redis.ttl(
|
|
334
|
-
const ttl2 = await redis.ttl(
|
|
332
|
+
const ttl1 = await redis.ttl("test:setBatch:ttl:1");
|
|
333
|
+
const ttl2 = await redis.ttl("test:setBatch:ttl:2");
|
|
335
334
|
expect(ttl1).toBeGreaterThan(0);
|
|
336
335
|
expect(ttl1).toBeLessThanOrEqual(10);
|
|
337
336
|
expect(ttl2).toBeGreaterThan(0);
|
|
338
337
|
expect(ttl2).toBeLessThanOrEqual(10);
|
|
339
338
|
|
|
340
339
|
// 清理
|
|
341
|
-
await redis.delBatch([
|
|
340
|
+
await redis.delBatch(["test:setBatch:ttl:1", "test:setBatch:ttl:2"]);
|
|
342
341
|
});
|
|
343
342
|
|
|
344
|
-
test(
|
|
343
|
+
test("getBatch - 批量获取对象", async () => {
|
|
345
344
|
// 设置测试数据
|
|
346
|
-
await redis.setObject(
|
|
347
|
-
await redis.setObject(
|
|
348
|
-
await redis.setObject(
|
|
345
|
+
await redis.setObject("test:getBatch:1", { name: "Alice" });
|
|
346
|
+
await redis.setObject("test:getBatch:2", { name: "Bob" });
|
|
347
|
+
await redis.setObject("test:getBatch:3", { name: "Charlie" });
|
|
349
348
|
|
|
350
349
|
// 批量获取
|
|
351
|
-
const results = await redis.getBatch([
|
|
350
|
+
const results = await redis.getBatch(["test:getBatch:1", "test:getBatch:2", "test:getBatch:3"]);
|
|
352
351
|
expect(results.length).toBe(3);
|
|
353
|
-
expect(results[0]).toEqual({ name:
|
|
354
|
-
expect(results[1]).toEqual({ name:
|
|
355
|
-
expect(results[2]).toEqual({ name:
|
|
352
|
+
expect(results[0]).toEqual({ name: "Alice" });
|
|
353
|
+
expect(results[1]).toEqual({ name: "Bob" });
|
|
354
|
+
expect(results[2]).toEqual({ name: "Charlie" });
|
|
356
355
|
|
|
357
356
|
// 清理
|
|
358
|
-
await redis.delBatch([
|
|
357
|
+
await redis.delBatch(["test:getBatch:1", "test:getBatch:2", "test:getBatch:3"]);
|
|
359
358
|
});
|
|
360
359
|
|
|
361
|
-
test(
|
|
360
|
+
test("getBatch - 空数组返回空数组", async () => {
|
|
362
361
|
const results = await redis.getBatch([]);
|
|
363
362
|
expect(results).toEqual([]);
|
|
364
363
|
});
|
|
365
364
|
|
|
366
|
-
test(
|
|
367
|
-
const results = await redis.getBatch([
|
|
365
|
+
test("getBatch - 不存在的键返回 null", async () => {
|
|
366
|
+
const results = await redis.getBatch(["test:non:existent:a", "test:non:existent:b"]);
|
|
368
367
|
expect(results).toEqual([null, null]);
|
|
369
368
|
});
|
|
370
369
|
|
|
371
|
-
test(
|
|
372
|
-
await redis.setObject(
|
|
370
|
+
test("getBatch - 部分存在的键", async () => {
|
|
371
|
+
await redis.setObject("test:partial:a", { data: "a" });
|
|
373
372
|
// test:partial:b 不存在
|
|
374
373
|
|
|
375
|
-
const results = await redis.getBatch([
|
|
374
|
+
const results = await redis.getBatch(["test:partial:a", "test:partial:b"]);
|
|
376
375
|
expect(results.length).toBe(2);
|
|
377
|
-
expect(results[0]).toEqual({ data:
|
|
376
|
+
expect(results[0]).toEqual({ data: "a" });
|
|
378
377
|
expect(results[1]).toBeNull();
|
|
379
378
|
|
|
380
379
|
// 清理
|
|
381
|
-
await redis.del(
|
|
380
|
+
await redis.del("test:partial:a");
|
|
382
381
|
});
|
|
383
382
|
|
|
384
|
-
test(
|
|
385
|
-
await redis.setString(
|
|
386
|
-
await redis.setString(
|
|
383
|
+
test("existsBatch - 批量检查键是否存在", async () => {
|
|
384
|
+
await redis.setString("test:existsBatch:1", "value1");
|
|
385
|
+
await redis.setString("test:existsBatch:2", "value2");
|
|
387
386
|
// test:existsBatch:3 不存在
|
|
388
387
|
|
|
389
|
-
const results = await redis.existsBatch([
|
|
388
|
+
const results = await redis.existsBatch(["test:existsBatch:1", "test:existsBatch:2", "test:existsBatch:3"]);
|
|
390
389
|
expect(results).toEqual([true, true, false]);
|
|
391
390
|
|
|
392
391
|
// 清理
|
|
393
|
-
await redis.delBatch([
|
|
392
|
+
await redis.delBatch(["test:existsBatch:1", "test:existsBatch:2"]);
|
|
394
393
|
});
|
|
395
394
|
|
|
396
|
-
test(
|
|
395
|
+
test("existsBatch - 空数组返回空数组", async () => {
|
|
397
396
|
const results = await redis.existsBatch([]);
|
|
398
397
|
expect(results).toEqual([]);
|
|
399
398
|
});
|
|
400
399
|
|
|
401
|
-
test(
|
|
402
|
-
const results = await redis.existsBatch([
|
|
400
|
+
test("existsBatch - 全部不存在", async () => {
|
|
401
|
+
const results = await redis.existsBatch(["test:none:1", "test:none:2"]);
|
|
403
402
|
expect(results).toEqual([false, false]);
|
|
404
403
|
});
|
|
405
404
|
|
|
406
|
-
test(
|
|
407
|
-
await redis.setString(
|
|
408
|
-
await redis.setString(
|
|
405
|
+
test("expireBatch - 批量设置过期时间", async () => {
|
|
406
|
+
await redis.setString("test:expireBatch:1", "value1");
|
|
407
|
+
await redis.setString("test:expireBatch:2", "value2");
|
|
409
408
|
|
|
410
409
|
const count = await redis.expireBatch([
|
|
411
|
-
{ key:
|
|
412
|
-
{ key:
|
|
410
|
+
{ key: "test:expireBatch:1", seconds: 60 },
|
|
411
|
+
{ key: "test:expireBatch:2", seconds: 120 }
|
|
413
412
|
]);
|
|
414
413
|
expect(count).toBe(2);
|
|
415
414
|
|
|
416
415
|
// 验证 TTL 已设置
|
|
417
|
-
const ttl1 = await redis.ttl(
|
|
418
|
-
const ttl2 = await redis.ttl(
|
|
416
|
+
const ttl1 = await redis.ttl("test:expireBatch:1");
|
|
417
|
+
const ttl2 = await redis.ttl("test:expireBatch:2");
|
|
419
418
|
expect(ttl1).toBeGreaterThan(0);
|
|
420
419
|
expect(ttl1).toBeLessThanOrEqual(60);
|
|
421
420
|
expect(ttl2).toBeGreaterThan(0);
|
|
422
421
|
expect(ttl2).toBeLessThanOrEqual(120);
|
|
423
422
|
|
|
424
423
|
// 清理
|
|
425
|
-
await redis.delBatch([
|
|
424
|
+
await redis.delBatch(["test:expireBatch:1", "test:expireBatch:2"]);
|
|
426
425
|
});
|
|
427
426
|
|
|
428
|
-
test(
|
|
427
|
+
test("expireBatch - 空数组返回 0", async () => {
|
|
429
428
|
const count = await redis.expireBatch([]);
|
|
430
429
|
expect(count).toBe(0);
|
|
431
430
|
});
|
|
432
431
|
|
|
433
|
-
test(
|
|
432
|
+
test("expireBatch - 不存在的键返回 0", async () => {
|
|
434
433
|
const count = await redis.expireBatch([
|
|
435
|
-
{ key:
|
|
436
|
-
{ key:
|
|
434
|
+
{ key: "test:expire:none:1", seconds: 60 },
|
|
435
|
+
{ key: "test:expire:none:2", seconds: 60 }
|
|
437
436
|
]);
|
|
438
437
|
expect(count).toBe(0);
|
|
439
438
|
});
|
|
440
439
|
|
|
441
|
-
test(
|
|
442
|
-
await redis.setString(
|
|
440
|
+
test("expireBatch - 部分存在的键", async () => {
|
|
441
|
+
await redis.setString("test:expire:partial:1", "value1");
|
|
443
442
|
// test:expire:partial:2 不存在
|
|
444
443
|
|
|
445
444
|
const count = await redis.expireBatch([
|
|
446
|
-
{ key:
|
|
447
|
-
{ key:
|
|
445
|
+
{ key: "test:expire:partial:1", seconds: 60 },
|
|
446
|
+
{ key: "test:expire:partial:2", seconds: 60 }
|
|
448
447
|
]);
|
|
449
448
|
expect(count).toBe(1);
|
|
450
449
|
|
|
451
450
|
// 清理
|
|
452
|
-
await redis.del(
|
|
451
|
+
await redis.del("test:expire:partial:1");
|
|
453
452
|
});
|
|
454
453
|
});
|
|
455
454
|
|
|
456
|
-
describe(
|
|
457
|
-
test(
|
|
455
|
+
describe("RedisHelper - ID 生成", () => {
|
|
456
|
+
test("genTimeID - 生成唯一 ID", async () => {
|
|
458
457
|
const id1 = await redis.genTimeID();
|
|
459
458
|
const id2 = await redis.genTimeID();
|
|
460
459
|
|
|
461
|
-
expect(typeof id1).toBe(
|
|
462
|
-
expect(typeof id2).toBe(
|
|
460
|
+
expect(typeof id1).toBe("number");
|
|
461
|
+
expect(typeof id2).toBe("number");
|
|
463
462
|
expect(id1).not.toBe(id2);
|
|
464
463
|
expect(id1.toString().length).toBe(16);
|
|
465
464
|
|
|
@@ -472,7 +471,7 @@ describe('RedisHelper - ID 生成', () => {
|
|
|
472
471
|
expect(suffix2).toBeLessThan(1000);
|
|
473
472
|
});
|
|
474
473
|
|
|
475
|
-
test(
|
|
474
|
+
test("genTimeID - 多次生成保持唯一", async () => {
|
|
476
475
|
const ids: number[] = [];
|
|
477
476
|
for (let i = 0; i < 10; i++) {
|
|
478
477
|
ids.push(await redis.genTimeID());
|
|
@@ -483,9 +482,9 @@ describe('RedisHelper - ID 生成', () => {
|
|
|
483
482
|
});
|
|
484
483
|
});
|
|
485
484
|
|
|
486
|
-
describe(
|
|
487
|
-
test(
|
|
485
|
+
describe("RedisHelper - 连接测试", () => {
|
|
486
|
+
test("ping - 测试连接", async () => {
|
|
488
487
|
const result = await redis.ping();
|
|
489
|
-
expect(result).toBe(
|
|
488
|
+
expect(result).toBe("PONG");
|
|
490
489
|
});
|
|
491
490
|
});
|