befly 3.8.33 → 3.8.34
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/lib/dbHelper.ts +5 -2
- package/lib/redisHelper.ts +12 -35
- package/package.json +2 -2
- package/tests/redisHelper.test.ts +13 -21
- package/types/redis.d.ts +1 -3
package/lib/dbHelper.ts
CHANGED
|
@@ -595,8 +595,11 @@ export class DbHelper {
|
|
|
595
595
|
// 转换表名:小驼峰 → 下划线
|
|
596
596
|
const snakeTable = snakeCase(table);
|
|
597
597
|
|
|
598
|
-
// 批量生成 ID
|
|
599
|
-
const ids =
|
|
598
|
+
// 批量生成 ID(逐个获取)
|
|
599
|
+
const ids: number[] = [];
|
|
600
|
+
for (let i = 0; i < dataList.length; i++) {
|
|
601
|
+
ids.push(await this.befly.redis.genTimeID());
|
|
602
|
+
}
|
|
600
603
|
const now = Date.now();
|
|
601
604
|
|
|
602
605
|
// 处理所有数据(自动添加系统字段)
|
package/lib/redisHelper.ts
CHANGED
|
@@ -80,51 +80,28 @@ export class RedisHelper {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
// ==================== ID 生成 ====================
|
|
83
|
-
// 注意:ID 生成功能强依赖 Redis 原子操作(INCR
|
|
84
|
-
// 主要被 DbHelper.insData
|
|
85
|
-
// 如未来有其他 ID 生成需求,可考虑提取到独立模块
|
|
83
|
+
// 注意:ID 生成功能强依赖 Redis 原子操作(INCR)保证分布式唯一性
|
|
84
|
+
// 主要被 DbHelper.insData 使用
|
|
86
85
|
|
|
87
86
|
/**
|
|
88
87
|
* 生成基于时间的唯一 ID
|
|
89
|
-
* 格式: 毫秒时间戳(13位) + 3
|
|
90
|
-
*
|
|
91
|
-
* 范围: 到 2286年
|
|
88
|
+
* 格式: 毫秒时间戳(13位) + 3位后缀(100-999) = 16位纯数字
|
|
89
|
+
* 每毫秒起点基于时间戳偏移,后缀分布更均匀
|
|
92
90
|
* @returns 唯一 ID (16位纯数字)
|
|
93
91
|
*/
|
|
94
92
|
async genTimeID(): Promise<number> {
|
|
95
|
-
const ids = await this.genTimeIDBatch(1);
|
|
96
|
-
return ids[0];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 批量生成基于时间的唯一 ID
|
|
101
|
-
* 格式: 毫秒时间戳(13位) + 3位自增 = 16位纯数字
|
|
102
|
-
* @param count - 需要生成的 ID 数量
|
|
103
|
-
* @returns ID 数组 (16位纯数字)
|
|
104
|
-
*/
|
|
105
|
-
async genTimeIDBatch(count: number): Promise<number[]> {
|
|
106
|
-
if (count <= 0) {
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const MAX_BATCH_SIZE = 1000;
|
|
111
|
-
if (count > MAX_BATCH_SIZE) {
|
|
112
|
-
throw new Error(`批量大小 ${count} 超过最大限制 ${MAX_BATCH_SIZE}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
93
|
const timestamp = Date.now();
|
|
116
|
-
const key = `${this.prefix}
|
|
117
|
-
const endCounter = await this.client.incrby(key, count);
|
|
118
|
-
await this.client.expire(key, 1);
|
|
94
|
+
const key = `${this.prefix}time_id:${timestamp}`;
|
|
119
95
|
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const suffix = (counter % 1000).toString().padStart(3, '0');
|
|
124
|
-
ids.push(Number(`${timestamp}${suffix}`));
|
|
96
|
+
const counter = await this.client.incr(key);
|
|
97
|
+
if (counter === 1) {
|
|
98
|
+
await this.client.expire(key, 1);
|
|
125
99
|
}
|
|
126
100
|
|
|
127
|
-
|
|
101
|
+
// 基于时间戳偏移起点,后缀 100-999 循环
|
|
102
|
+
const suffix = 100 + (((timestamp % 900) + counter - 1) % 900);
|
|
103
|
+
|
|
104
|
+
return Number(`${timestamp}${suffix}`);
|
|
128
105
|
}
|
|
129
106
|
|
|
130
107
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.34",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"pino": "^10.1.0",
|
|
74
74
|
"pino-roll": "^4.0.0"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "e6528128e0532df2c2f0ad96e32bc73e167aac84",
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"typescript": "^5.9.3"
|
|
79
79
|
}
|
|
@@ -462,33 +462,25 @@ describe('RedisHelper - ID 生成', () => {
|
|
|
462
462
|
expect(typeof id2).toBe('number');
|
|
463
463
|
expect(id1).not.toBe(id2);
|
|
464
464
|
expect(id1.toString().length).toBe(16);
|
|
465
|
-
});
|
|
466
465
|
|
|
467
|
-
|
|
468
|
-
const
|
|
466
|
+
// 验证后缀在 100-999 范围内
|
|
467
|
+
const suffix1 = id1 % 1000;
|
|
468
|
+
const suffix2 = id2 % 1000;
|
|
469
|
+
expect(suffix1).toBeGreaterThanOrEqual(100);
|
|
470
|
+
expect(suffix1).toBeLessThan(1000);
|
|
471
|
+
expect(suffix2).toBeGreaterThanOrEqual(100);
|
|
472
|
+
expect(suffix2).toBeLessThan(1000);
|
|
473
|
+
});
|
|
469
474
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
475
|
+
test('genTimeID - 多次生成保持唯一', async () => {
|
|
476
|
+
const ids: number[] = [];
|
|
477
|
+
for (let i = 0; i < 10; i++) {
|
|
478
|
+
ids.push(await redis.genTimeID());
|
|
479
|
+
}
|
|
473
480
|
|
|
474
|
-
// 验证 ID 唯一性
|
|
475
481
|
const uniqueIds = new Set(ids);
|
|
476
482
|
expect(uniqueIds.size).toBe(10);
|
|
477
483
|
});
|
|
478
|
-
|
|
479
|
-
test('genTimeIDBatch - 空数组', async () => {
|
|
480
|
-
const ids = await redis.genTimeIDBatch(0);
|
|
481
|
-
expect(ids.length).toBe(0);
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
test('genTimeIDBatch - 超过最大限制', async () => {
|
|
485
|
-
try {
|
|
486
|
-
await redis.genTimeIDBatch(1001);
|
|
487
|
-
expect(true).toBe(false); // 不应该执行到这里
|
|
488
|
-
} catch (error: any) {
|
|
489
|
-
expect(error.message).toContain('超过最大限制');
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
484
|
});
|
|
493
485
|
|
|
494
486
|
describe('RedisHelper - 连接测试', () => {
|
package/types/redis.d.ts
CHANGED
|
@@ -46,10 +46,8 @@ export interface RedisHelper {
|
|
|
46
46
|
ping(): Promise<string>;
|
|
47
47
|
|
|
48
48
|
// ==================== ID 生成 ====================
|
|
49
|
-
/** 生成基于时间的唯一 ID (
|
|
49
|
+
/** 生成基于时间的唯一 ID (16位纯数字: 13位毫秒时间戳 + 3位后缀100-999) */
|
|
50
50
|
genTimeID(): Promise<number>;
|
|
51
|
-
/** 批量生成基于时间的唯一 ID */
|
|
52
|
-
genTimeIDBatch(count: number): Promise<number[]>;
|
|
53
51
|
|
|
54
52
|
// ==================== Set 操作 ====================
|
|
55
53
|
/** 向 Set 中添加一个或多个成员 */
|