befly 3.8.20 → 3.8.24
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/checks/checkApi.ts +92 -0
- package/checks/checkApp.ts +31 -0
- package/checks/checkTable.ts +247 -0
- package/config.ts +71 -0
- package/hooks/auth.ts +30 -0
- package/hooks/cors.ts +48 -0
- package/hooks/errorHandler.ts +23 -0
- package/hooks/parser.ts +67 -0
- package/hooks/permission.ts +54 -0
- package/hooks/rateLimit.ts +70 -0
- package/hooks/requestId.ts +24 -0
- package/hooks/requestLogger.ts +25 -0
- package/hooks/responseFormatter.ts +64 -0
- package/hooks/validator.ts +34 -0
- package/package.json +15 -14
- package/tests/cipher.test.ts +248 -0
- package/tests/dbHelper-advanced.test.ts +717 -0
- package/tests/dbHelper-columns.test.ts +266 -0
- package/tests/dbHelper-execute.test.ts +240 -0
- package/tests/fields-redis-cache.test.ts +123 -0
- package/tests/fields-validate.test.ts +99 -0
- package/tests/integration.test.ts +202 -0
- package/tests/jwt.test.ts +122 -0
- package/tests/logger.test.ts +94 -0
- package/tests/redisHelper.test.ts +231 -0
- package/tests/sqlBuilder-advanced.test.ts +593 -0
- package/tests/sqlBuilder.test.ts +184 -0
- package/tests/util.test.ts +95 -0
- package/tests/validator-advanced.test.ts +653 -0
- package/tests/validator.test.ts +148 -0
- package/tests/xml.test.ts +101 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { SqlBuilder } from '../lib/sqlBuilder';
|
|
3
|
+
|
|
4
|
+
describe('SqlBuilder - SELECT 查询', () => {
|
|
5
|
+
test('简单查询', () => {
|
|
6
|
+
const builder = new SqlBuilder();
|
|
7
|
+
const result = builder.select(['id', 'name']).from('users').toSelectSql();
|
|
8
|
+
expect(result.sql).toContain('SELECT `id`, `name` FROM `users`');
|
|
9
|
+
expect(result.params).toEqual([]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('查询所有字段', () => {
|
|
13
|
+
const builder = new SqlBuilder();
|
|
14
|
+
const result = builder.select(['*']).from('users').toSelectSql();
|
|
15
|
+
expect(result.sql).toContain('SELECT * FROM `users`');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('带 WHERE 条件', () => {
|
|
19
|
+
const builder = new SqlBuilder();
|
|
20
|
+
const result = builder.select(['*']).from('users').where({ id: 1 }).toSelectSql();
|
|
21
|
+
expect(result.sql).toContain('WHERE `id` = ?');
|
|
22
|
+
expect(result.params).toEqual([1]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('多个 WHERE 条件', () => {
|
|
26
|
+
const builder = new SqlBuilder();
|
|
27
|
+
const result = builder.select(['*']).from('users').where({ id: 1, status: 'active' }).toSelectSql();
|
|
28
|
+
expect(result.sql).toContain('WHERE');
|
|
29
|
+
expect(result.sql).toContain('AND');
|
|
30
|
+
expect(result.params).toEqual([1, 'active']);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('ORDER BY', () => {
|
|
34
|
+
const builder = new SqlBuilder();
|
|
35
|
+
const result = builder.select(['*']).from('users').orderBy(['created_at#DESC']).toSelectSql();
|
|
36
|
+
expect(result.sql).toContain('ORDER BY `created_at` DESC');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('LIMIT 和 OFFSET', () => {
|
|
40
|
+
const builder = new SqlBuilder();
|
|
41
|
+
const result = builder.select(['*']).from('users').limit(10).offset(20).toSelectSql();
|
|
42
|
+
expect(result.sql).toContain('LIMIT 10 OFFSET 20');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('SqlBuilder - WHERE 操作符', () => {
|
|
47
|
+
test('$ne 不等于', () => {
|
|
48
|
+
const builder = new SqlBuilder();
|
|
49
|
+
const result = builder
|
|
50
|
+
.select(['*'])
|
|
51
|
+
.from('users')
|
|
52
|
+
.where({ status: { $ne: 'deleted' } })
|
|
53
|
+
.toSelectSql();
|
|
54
|
+
expect(result.sql).toContain('`status` != ?');
|
|
55
|
+
expect(result.params).toEqual(['deleted']);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('$in 包含', () => {
|
|
59
|
+
const builder = new SqlBuilder();
|
|
60
|
+
const result = builder
|
|
61
|
+
.select(['*'])
|
|
62
|
+
.from('users')
|
|
63
|
+
.where({ id: { $in: [1, 2, 3] } })
|
|
64
|
+
.toSelectSql();
|
|
65
|
+
expect(result.sql).toContain('`id` IN (?,?,?)');
|
|
66
|
+
expect(result.params).toEqual([1, 2, 3]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('$gt 大于', () => {
|
|
70
|
+
const builder = new SqlBuilder();
|
|
71
|
+
const result = builder
|
|
72
|
+
.select(['*'])
|
|
73
|
+
.from('users')
|
|
74
|
+
.where({ age: { $gt: 18 } })
|
|
75
|
+
.toSelectSql();
|
|
76
|
+
expect(result.sql).toContain('`age` > ?');
|
|
77
|
+
expect(result.params).toEqual([18]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('$gte 大于等于', () => {
|
|
81
|
+
const builder = new SqlBuilder();
|
|
82
|
+
const result = builder
|
|
83
|
+
.select(['*'])
|
|
84
|
+
.from('users')
|
|
85
|
+
.where({ age: { $gte: 18 } })
|
|
86
|
+
.toSelectSql();
|
|
87
|
+
expect(result.sql).toContain('`age` >= ?');
|
|
88
|
+
expect(result.params).toEqual([18]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('$lt 小于', () => {
|
|
92
|
+
const builder = new SqlBuilder();
|
|
93
|
+
const result = builder
|
|
94
|
+
.select(['*'])
|
|
95
|
+
.from('users')
|
|
96
|
+
.where({ age: { $lt: 60 } })
|
|
97
|
+
.toSelectSql();
|
|
98
|
+
expect(result.sql).toContain('`age` < ?');
|
|
99
|
+
expect(result.params).toEqual([60]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('$lte 小于等于', () => {
|
|
103
|
+
const builder = new SqlBuilder();
|
|
104
|
+
const result = builder
|
|
105
|
+
.select(['*'])
|
|
106
|
+
.from('users')
|
|
107
|
+
.where({ age: { $lte: 60 } })
|
|
108
|
+
.toSelectSql();
|
|
109
|
+
expect(result.sql).toContain('`age` <= ?');
|
|
110
|
+
expect(result.params).toEqual([60]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('$like 模糊匹配', () => {
|
|
114
|
+
const builder = new SqlBuilder();
|
|
115
|
+
const result = builder
|
|
116
|
+
.select(['*'])
|
|
117
|
+
.from('users')
|
|
118
|
+
.where({ name: { $like: '%john%' } })
|
|
119
|
+
.toSelectSql();
|
|
120
|
+
expect(result.sql).toContain('`name` LIKE ?');
|
|
121
|
+
expect(result.params).toEqual(['%john%']);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('SqlBuilder - INSERT', () => {
|
|
126
|
+
test('插入单条数据', () => {
|
|
127
|
+
const builder = new SqlBuilder();
|
|
128
|
+
const result = builder.toInsertSql('users', { name: 'John', age: 25 });
|
|
129
|
+
expect(result.sql).toContain('INSERT INTO `users`');
|
|
130
|
+
expect(result.sql).toContain('(`name`, `age`)');
|
|
131
|
+
expect(result.sql).toContain('VALUES (?, ?)');
|
|
132
|
+
expect(result.params).toEqual(['John', 25]);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('SqlBuilder - UPDATE', () => {
|
|
137
|
+
test('更新数据', () => {
|
|
138
|
+
const builder = new SqlBuilder();
|
|
139
|
+
const result = builder.where({ id: 1 }).toUpdateSql('users', { name: 'Jane' });
|
|
140
|
+
expect(result.sql).toContain('UPDATE `users`');
|
|
141
|
+
expect(result.sql).toContain('SET `name` = ?');
|
|
142
|
+
expect(result.sql).toContain('WHERE `id` = ?');
|
|
143
|
+
expect(result.params).toEqual(['Jane', 1]);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('SqlBuilder - DELETE', () => {
|
|
148
|
+
test('删除数据', () => {
|
|
149
|
+
const builder = new SqlBuilder();
|
|
150
|
+
const result = builder.where({ id: 1 }).toDeleteSql('users');
|
|
151
|
+
expect(result.sql).toContain('DELETE FROM `users`');
|
|
152
|
+
expect(result.sql).toContain('WHERE `id` = ?');
|
|
153
|
+
expect(result.params).toEqual([1]);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('SqlBuilder - 链式调用', () => {
|
|
158
|
+
test('复杂查询', () => {
|
|
159
|
+
const builder = new SqlBuilder();
|
|
160
|
+
const result = builder
|
|
161
|
+
.select(['id', 'name', 'email'])
|
|
162
|
+
.from('users')
|
|
163
|
+
.where({ status: 'active', age: { $gte: 18 } })
|
|
164
|
+
.orderBy(['created_at#DESC'])
|
|
165
|
+
.limit(10)
|
|
166
|
+
.toSelectSql();
|
|
167
|
+
|
|
168
|
+
expect(result.sql).toContain('SELECT');
|
|
169
|
+
expect(result.sql).toContain('FROM `users`');
|
|
170
|
+
expect(result.sql).toContain('WHERE');
|
|
171
|
+
expect(result.sql).toContain('ORDER BY');
|
|
172
|
+
expect(result.sql).toContain('LIMIT 10');
|
|
173
|
+
expect(result.params.length).toBeGreaterThan(0);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('reset 重置', () => {
|
|
177
|
+
const builder = new SqlBuilder();
|
|
178
|
+
builder.select(['*']).from('users').where({ id: 1 });
|
|
179
|
+
builder.reset();
|
|
180
|
+
const result = builder.select(['*']).from('posts').toSelectSql();
|
|
181
|
+
expect(result.sql).toContain('FROM `posts`');
|
|
182
|
+
expect(result.sql).not.toContain('users');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { keysToCamel, keysToSnake, arrayKeysToCamel, calcPerfTime, fieldClear } from 'befly-util';
|
|
3
|
+
|
|
4
|
+
describe('Util - keysToCamel', () => {
|
|
5
|
+
test('转换对象键名为驼峰', () => {
|
|
6
|
+
const result = keysToCamel({ user_name: 'John', user_id: 123 });
|
|
7
|
+
expect(result.userName).toBe('John');
|
|
8
|
+
expect(result.userId).toBe(123);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('保持已有驼峰格式', () => {
|
|
12
|
+
const result = keysToCamel({ userName: 'John', userId: 123 });
|
|
13
|
+
expect(result.userName).toBe('John');
|
|
14
|
+
expect(result.userId).toBe(123);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('处理空对象', () => {
|
|
18
|
+
const result = keysToCamel({});
|
|
19
|
+
expect(Object.keys(result).length).toBe(0);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('处理嵌套对象', () => {
|
|
23
|
+
const result = keysToCamel({ user_info: { first_name: 'John' } });
|
|
24
|
+
expect(result.userInfo).toBeDefined();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('Util - keysToSnake', () => {
|
|
29
|
+
test('转换对象键名为下划线', () => {
|
|
30
|
+
const result = keysToSnake({ userName: 'John', userId: 123 });
|
|
31
|
+
expect(result.user_name).toBe('John');
|
|
32
|
+
expect(result.user_id).toBe(123);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('保持已有下划线格式', () => {
|
|
36
|
+
const result = keysToSnake({ user_name: 'John', user_id: 123 });
|
|
37
|
+
expect(result.user_name).toBe('John');
|
|
38
|
+
expect(result.user_id).toBe(123);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('处理空对象', () => {
|
|
42
|
+
const result = keysToSnake({});
|
|
43
|
+
expect(Object.keys(result).length).toBe(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('Util - arrayKeysToCamel', () => {
|
|
48
|
+
test('转换数组中对象键名为驼峰', () => {
|
|
49
|
+
const result = arrayKeysToCamel([
|
|
50
|
+
{ user_name: 'John', user_id: 1 },
|
|
51
|
+
{ user_name: 'Jane', user_id: 2 }
|
|
52
|
+
]);
|
|
53
|
+
expect(result[0].userName).toBe('John');
|
|
54
|
+
expect(result[0].userId).toBe(1);
|
|
55
|
+
expect(result[1].userName).toBe('Jane');
|
|
56
|
+
expect(result[1].userId).toBe(2);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('处理空数组', () => {
|
|
60
|
+
const result = arrayKeysToCamel([]);
|
|
61
|
+
expect(result.length).toBe(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('Util - fieldClear', () => {
|
|
66
|
+
test('移除 null 和 undefined', () => {
|
|
67
|
+
const result = fieldClear({ a: 1, b: null, c: undefined, d: 'test' }, { excludeValues: [null, undefined] });
|
|
68
|
+
expect(result.a).toBe(1);
|
|
69
|
+
expect(result.b).toBeUndefined();
|
|
70
|
+
expect(result.c).toBeUndefined();
|
|
71
|
+
expect(result.d).toBe('test');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('保留指定值', () => {
|
|
75
|
+
const result = fieldClear({ a: 1, b: null, c: 0 }, { excludeValues: [null, undefined], keepMap: { c: 0 } });
|
|
76
|
+
expect(result.a).toBe(1);
|
|
77
|
+
expect(result.b).toBeUndefined();
|
|
78
|
+
expect(result.c).toBe(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('处理空对象', () => {
|
|
82
|
+
const result = fieldClear({});
|
|
83
|
+
expect(Object.keys(result).length).toBe(0);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('Util - calcPerfTime', () => {
|
|
88
|
+
test('计算性能时间', () => {
|
|
89
|
+
const start = Bun.nanoseconds();
|
|
90
|
+
const result = calcPerfTime(start);
|
|
91
|
+
expect(result).toContain('毫秒');
|
|
92
|
+
expect(typeof result).toBe('string');
|
|
93
|
+
expect(result).toMatch(/\d+(\.\d+)?\s*毫秒/);
|
|
94
|
+
});
|
|
95
|
+
});
|