befly 1.0.3 → 1.1.1
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 +1 -1
- package/main.js +121 -38
- package/package.json +2 -2
- package/plugins/db.js +1 -2
- package/plugins/tool.js +45 -0
- package/utils/curd.js +0 -186
package/README.md
CHANGED
package/main.js
CHANGED
|
@@ -10,7 +10,7 @@ import { Crypto2 } from './utils/crypto.js';
|
|
|
10
10
|
import { XMLParser } from './libs/xml/XMLParser.js';
|
|
11
11
|
import { isEmptyObject, isType, pickFields, sortPlugins, RYes, RNo, filename2, dirname2 } from './utils/util.js';
|
|
12
12
|
|
|
13
|
-
class
|
|
13
|
+
class Befly {
|
|
14
14
|
constructor(options = {}) {
|
|
15
15
|
this.apiRoutes = new Map();
|
|
16
16
|
this.pluginLists = [];
|
|
@@ -20,6 +20,9 @@ class BunPii {
|
|
|
20
20
|
|
|
21
21
|
async initCheck() {
|
|
22
22
|
try {
|
|
23
|
+
const checkStartTime = Bun.nanoseconds();
|
|
24
|
+
Logger.info('开始执行系统检查...');
|
|
25
|
+
|
|
23
26
|
const checksDir = path.join(dirname2(import.meta.url), 'checks');
|
|
24
27
|
const glob = new Bun.Glob('*.js');
|
|
25
28
|
|
|
@@ -39,6 +42,7 @@ class BunPii {
|
|
|
39
42
|
|
|
40
43
|
try {
|
|
41
44
|
totalChecks++;
|
|
45
|
+
const singleCheckStart = Bun.nanoseconds();
|
|
42
46
|
|
|
43
47
|
// 导入检查模块
|
|
44
48
|
const check = await import(file);
|
|
@@ -46,19 +50,24 @@ class BunPii {
|
|
|
46
50
|
// 执行默认导出的函数
|
|
47
51
|
if (typeof check.default === 'function') {
|
|
48
52
|
const checkResult = await check.default(this.appContext);
|
|
53
|
+
const singleCheckTime = (Bun.nanoseconds() - singleCheckStart) / 1_000_000;
|
|
54
|
+
|
|
49
55
|
if (checkResult === true) {
|
|
50
56
|
passedChecks++;
|
|
57
|
+
Logger.info(`检查 ${fileName} 通过,耗时: ${singleCheckTime.toFixed(2)}ms`);
|
|
51
58
|
} else {
|
|
52
|
-
Logger.error(`检查未通过: ${fileName}`);
|
|
59
|
+
Logger.error(`检查未通过: ${fileName},耗时: ${singleCheckTime.toFixed(2)}ms`);
|
|
53
60
|
failedChecks++;
|
|
54
61
|
}
|
|
55
62
|
} else {
|
|
56
|
-
|
|
63
|
+
const singleCheckTime = (Bun.nanoseconds() - singleCheckStart) / 1_000_000;
|
|
64
|
+
Logger.warn(`文件 ${fileName} 未导出默认函数,耗时: ${singleCheckTime.toFixed(2)}ms`);
|
|
57
65
|
failedChecks++;
|
|
58
66
|
}
|
|
59
67
|
} catch (error) {
|
|
68
|
+
const singleCheckTime = (Bun.nanoseconds() - singleCheckStart) / 1_000_000;
|
|
60
69
|
Logger.error({
|
|
61
|
-
msg: `检查失败 ${fileName}`,
|
|
70
|
+
msg: `检查失败 ${fileName},耗时: ${singleCheckTime.toFixed(2)}ms`,
|
|
62
71
|
error: error.message,
|
|
63
72
|
stack: error.stack
|
|
64
73
|
});
|
|
@@ -66,8 +75,10 @@ class BunPii {
|
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
const totalCheckTime = (Bun.nanoseconds() - checkStartTime) / 1_000_000;
|
|
79
|
+
|
|
69
80
|
// 输出检查结果统计
|
|
70
|
-
Logger.info(
|
|
81
|
+
Logger.info(`系统检查完成! 总耗时: ${totalCheckTime.toFixed(2)}ms,总检查数: ${totalChecks}, 通过: ${passedChecks}, 失败: ${failedChecks}`);
|
|
71
82
|
|
|
72
83
|
if (failedChecks > 0) {
|
|
73
84
|
process.exit();
|
|
@@ -78,7 +89,7 @@ class BunPii {
|
|
|
78
89
|
}
|
|
79
90
|
} catch (error) {
|
|
80
91
|
Logger.error({
|
|
81
|
-
msg: '
|
|
92
|
+
msg: '执行系统检查时发生错误',
|
|
82
93
|
error: error.message,
|
|
83
94
|
stack: error.stack
|
|
84
95
|
});
|
|
@@ -88,12 +99,15 @@ class BunPii {
|
|
|
88
99
|
|
|
89
100
|
async loadPlugins() {
|
|
90
101
|
try {
|
|
102
|
+
const loadStartTime = Bun.nanoseconds();
|
|
103
|
+
|
|
91
104
|
const glob = new Bun.Glob('*.js');
|
|
92
105
|
const corePlugins = [];
|
|
93
106
|
const userPlugins = [];
|
|
94
107
|
const loadedPluginNames = new Set(); // 用于跟踪已加载的插件名称
|
|
95
108
|
|
|
96
|
-
//
|
|
109
|
+
// 扫描核心插件目录
|
|
110
|
+
const corePluginsScanStart = Bun.nanoseconds();
|
|
97
111
|
for await (const file of glob.scan({
|
|
98
112
|
cwd: path.join(dirname2(import.meta.url), 'plugins'),
|
|
99
113
|
onlyFiles: true,
|
|
@@ -101,12 +115,20 @@ class BunPii {
|
|
|
101
115
|
})) {
|
|
102
116
|
const fileName = path.basename(file, '.js');
|
|
103
117
|
if (fileName.startsWith('_')) continue;
|
|
118
|
+
|
|
119
|
+
const importStart = Bun.nanoseconds();
|
|
104
120
|
const plugin = await import(file);
|
|
121
|
+
const importTime = (Bun.nanoseconds() - importStart) / 1_000_000; // 转换为毫秒
|
|
122
|
+
|
|
105
123
|
const pluginInstance = plugin.default;
|
|
106
124
|
pluginInstance.pluginName = fileName;
|
|
107
125
|
corePlugins.push(pluginInstance);
|
|
108
126
|
loadedPluginNames.add(fileName); // 记录已加载的核心插件名称
|
|
127
|
+
|
|
128
|
+
Logger.info(`核心插件 ${fileName} 导入耗时: ${importTime.toFixed(2)}ms`);
|
|
109
129
|
}
|
|
130
|
+
const corePluginsScanTime = (Bun.nanoseconds() - corePluginsScanStart) / 1_000_000;
|
|
131
|
+
Logger.info(`核心插件扫描完成,耗时: ${corePluginsScanTime.toFixed(2)}ms,共找到 ${corePlugins.length} 个插件`);
|
|
110
132
|
|
|
111
133
|
const sortedCorePlugins = sortPlugins(corePlugins);
|
|
112
134
|
if (sortedCorePlugins === false) {
|
|
@@ -114,6 +136,8 @@ class BunPii {
|
|
|
114
136
|
process.exit();
|
|
115
137
|
}
|
|
116
138
|
|
|
139
|
+
// 初始化核心插件
|
|
140
|
+
const corePluginsInitStart = Bun.nanoseconds();
|
|
117
141
|
for (const plugin of sortedCorePlugins) {
|
|
118
142
|
try {
|
|
119
143
|
this.pluginLists.push(plugin);
|
|
@@ -122,8 +146,11 @@ class BunPii {
|
|
|
122
146
|
Logger.warn(`插件 ${plugin.pluginName} 初始化失败:`, error.message);
|
|
123
147
|
}
|
|
124
148
|
}
|
|
149
|
+
const corePluginsInitTime = (Bun.nanoseconds() - corePluginsInitStart) / 1_000_000;
|
|
150
|
+
Logger.info(`核心插件初始化完成,耗时: ${corePluginsInitTime.toFixed(2)}ms`);
|
|
125
151
|
|
|
126
|
-
//
|
|
152
|
+
// 扫描用户插件目录
|
|
153
|
+
const userPluginsScanStart = Bun.nanoseconds();
|
|
127
154
|
for await (const file of glob.scan({
|
|
128
155
|
cwd: path.join(process.cwd(), 'plugins'),
|
|
129
156
|
onlyFiles: true,
|
|
@@ -138,11 +165,18 @@ class BunPii {
|
|
|
138
165
|
continue;
|
|
139
166
|
}
|
|
140
167
|
|
|
168
|
+
const importStart = Bun.nanoseconds();
|
|
141
169
|
const plugin = await import(file);
|
|
170
|
+
const importTime = (Bun.nanoseconds() - importStart) / 1_000_000; // 转换为毫秒
|
|
171
|
+
|
|
142
172
|
const pluginInstance = plugin.default;
|
|
143
173
|
pluginInstance.pluginName = fileName;
|
|
144
174
|
userPlugins.push(pluginInstance);
|
|
175
|
+
|
|
176
|
+
Logger.info(`用户插件 ${fileName} 导入耗时: ${importTime.toFixed(2)}ms`);
|
|
145
177
|
}
|
|
178
|
+
const userPluginsScanTime = (Bun.nanoseconds() - userPluginsScanStart) / 1_000_000;
|
|
179
|
+
Logger.info(`用户插件扫描完成,耗时: ${userPluginsScanTime.toFixed(2)}ms,共找到 ${userPlugins.length} 个插件`);
|
|
146
180
|
|
|
147
181
|
const sortedUserPlugins = sortPlugins(userPlugins);
|
|
148
182
|
if (sortedUserPlugins === false) {
|
|
@@ -150,14 +184,24 @@ class BunPii {
|
|
|
150
184
|
process.exit();
|
|
151
185
|
}
|
|
152
186
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
// 初始化用户插件
|
|
188
|
+
if (userPlugins.length > 0) {
|
|
189
|
+
const userPluginsInitStart = Bun.nanoseconds();
|
|
190
|
+
for (const plugin of sortedUserPlugins) {
|
|
191
|
+
try {
|
|
192
|
+
this.pluginLists.push(plugin);
|
|
193
|
+
this.appContext[plugin.pluginName] = typeof plugin?.onInit === 'function' ? await plugin?.onInit(this.appContext) : {};
|
|
194
|
+
} catch (error) {
|
|
195
|
+
Logger.warn(`插件 ${plugin.pluginName} 初始化失败:`, error.message);
|
|
196
|
+
}
|
|
159
197
|
}
|
|
198
|
+
const userPluginsInitTime = (Bun.nanoseconds() - userPluginsInitStart) / 1_000_000;
|
|
199
|
+
Logger.info(`用户插件初始化完成,耗时: ${userPluginsInitTime.toFixed(2)}ms`);
|
|
160
200
|
}
|
|
201
|
+
|
|
202
|
+
const totalLoadTime = (Bun.nanoseconds() - loadStartTime) / 1_000_000;
|
|
203
|
+
const totalPluginCount = sortedCorePlugins.length + sortedUserPlugins.length;
|
|
204
|
+
Logger.info(`插件加载完成! 总耗时: ${totalLoadTime.toFixed(2)}ms,共加载 ${totalPluginCount} 个插件`);
|
|
161
205
|
} catch (error) {
|
|
162
206
|
Logger.error({
|
|
163
207
|
msg: '加载插件时发生错误',
|
|
@@ -168,10 +212,18 @@ class BunPii {
|
|
|
168
212
|
}
|
|
169
213
|
async loadApis(dirName) {
|
|
170
214
|
try {
|
|
215
|
+
const loadStartTime = Bun.nanoseconds();
|
|
216
|
+
const dirDisplayName = dirName === 'core' ? '核心' : '用户';
|
|
217
|
+
|
|
171
218
|
const coreApisDir = path.join(dirname2(import.meta.url), 'apis');
|
|
172
219
|
const userApisDir = path.join(process.cwd(), 'apis');
|
|
173
220
|
const glob = new Bun.Glob('**/*.js');
|
|
174
221
|
const apiDir = dirName === 'core' ? coreApisDir : userApisDir;
|
|
222
|
+
|
|
223
|
+
let totalApis = 0;
|
|
224
|
+
let loadedApis = 0;
|
|
225
|
+
let failedApis = 0;
|
|
226
|
+
|
|
175
227
|
// 扫描指定目录
|
|
176
228
|
for await (const file of glob.scan({
|
|
177
229
|
cwd: apiDir,
|
|
@@ -181,29 +233,50 @@ class BunPii {
|
|
|
181
233
|
const fileName = path.basename(file, '.js');
|
|
182
234
|
const apiPath = path.relative(apiDir, file).replace(/\.js$/, '').replace(/\\/g, '/');
|
|
183
235
|
if (apiPath.indexOf('_') !== -1) continue;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
236
|
+
|
|
237
|
+
totalApis++;
|
|
238
|
+
const singleApiStart = Bun.nanoseconds();
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const api = (await import(file)).default;
|
|
242
|
+
if (isType(api.name, 'string') === false || api.name.trim() === '') {
|
|
243
|
+
throw new Error(`接口 ${apiPath} 的 name 属性必须是非空字符串`);
|
|
244
|
+
}
|
|
245
|
+
if (api.auth !== false && api.auth !== true && Array.isArray(api.auth) === false) {
|
|
246
|
+
throw new Error(`接口 ${apiPath} 的 auth 属性必须是布尔值或字符串数组`);
|
|
247
|
+
}
|
|
248
|
+
if (isType(api.fields, 'object') === false) {
|
|
249
|
+
throw new Error(`接口 ${apiPath} 的 fields 属性必须是对象`);
|
|
250
|
+
}
|
|
251
|
+
if (isType(api.required, 'array') === false) {
|
|
252
|
+
throw new Error(`接口 ${apiPath} 的 required 属性必须是数组`);
|
|
253
|
+
}
|
|
254
|
+
// 数组的每一项都必须是字符串
|
|
255
|
+
if (api.required.some((item) => isType(item, 'string') === false)) {
|
|
256
|
+
throw new Error(`接口 ${apiPath} 的 required 属性必须是字符串数组`);
|
|
257
|
+
}
|
|
258
|
+
if (isType(api.handler, 'function') === false) {
|
|
259
|
+
throw new Error(`接口 ${apiPath} 的 handler 属性必须是函数`);
|
|
260
|
+
}
|
|
261
|
+
api.route = `${api.method.toUpperCase()}/api/${dirName}/${apiPath}`;
|
|
262
|
+
this.apiRoutes.set(api.route, api);
|
|
263
|
+
|
|
264
|
+
const singleApiTime = (Bun.nanoseconds() - singleApiStart) / 1_000_000;
|
|
265
|
+
loadedApis++;
|
|
266
|
+
// Logger.info(`${dirDisplayName}接口 ${apiPath} 加载成功,耗时: ${singleApiTime.toFixed(2)}ms`);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
const singleApiTime = (Bun.nanoseconds() - singleApiStart) / 1_000_000;
|
|
269
|
+
failedApis++;
|
|
270
|
+
Logger.error({
|
|
271
|
+
msg: `${dirDisplayName}接口 ${apiPath} 加载失败,耗时: ${singleApiTime.toFixed(2)}ms`,
|
|
272
|
+
error: error.message,
|
|
273
|
+
stack: error.stack
|
|
274
|
+
});
|
|
203
275
|
}
|
|
204
|
-
api.route = `${api.method.toUpperCase()}/api/${dirName}/${apiPath}`;
|
|
205
|
-
this.apiRoutes.set(api.route, api);
|
|
206
276
|
}
|
|
277
|
+
|
|
278
|
+
const totalLoadTime = (Bun.nanoseconds() - loadStartTime) / 1_000_000;
|
|
279
|
+
Logger.info(`${dirDisplayName}接口加载完成! 总耗时: ${totalLoadTime.toFixed(2)}ms,总数: ${totalApis}, 成功: ${loadedApis}, 失败: ${failedApis}`);
|
|
207
280
|
} catch (error) {
|
|
208
281
|
Logger.error({
|
|
209
282
|
msg: '加载接口时发生错误',
|
|
@@ -217,11 +290,17 @@ class BunPii {
|
|
|
217
290
|
* 启动服务器
|
|
218
291
|
*/
|
|
219
292
|
async listen(callback) {
|
|
293
|
+
const serverStartTime = Bun.nanoseconds();
|
|
294
|
+
Logger.info('开始启动 Befly 服务器...');
|
|
295
|
+
|
|
220
296
|
await this.initCheck();
|
|
221
297
|
await this.loadPlugins();
|
|
222
298
|
await this.loadApis('core');
|
|
223
299
|
await this.loadApis('app');
|
|
224
300
|
|
|
301
|
+
const totalStartupTime = (Bun.nanoseconds() - serverStartTime) / 1_000_000;
|
|
302
|
+
Logger.info(`服务器启动准备完成,总耗时: ${totalStartupTime.toFixed(2)}ms`);
|
|
303
|
+
|
|
225
304
|
const server = Bun.serve({
|
|
226
305
|
port: Env.APP_PORT,
|
|
227
306
|
hostname: Env.APP_HOST,
|
|
@@ -229,7 +308,7 @@ class BunPii {
|
|
|
229
308
|
'/': async (req) => {
|
|
230
309
|
return Response.json({
|
|
231
310
|
code: 0,
|
|
232
|
-
msg: '
|
|
311
|
+
msg: 'Befly 接口服务已启动',
|
|
233
312
|
data: {
|
|
234
313
|
mode: Env.NODE_ENV
|
|
235
314
|
}
|
|
@@ -327,7 +406,7 @@ class BunPii {
|
|
|
327
406
|
}
|
|
328
407
|
|
|
329
408
|
// 请求记录
|
|
330
|
-
Logger.
|
|
409
|
+
Logger.info({
|
|
331
410
|
msg: '通用接口日志',
|
|
332
411
|
请求路径: apiPath,
|
|
333
412
|
请求方法: req.method,
|
|
@@ -400,10 +479,14 @@ class BunPii {
|
|
|
400
479
|
}
|
|
401
480
|
});
|
|
402
481
|
|
|
482
|
+
const finalStartupTime = (Bun.nanoseconds() - serverStartTime) / 1_000_000;
|
|
483
|
+
Logger.info(`🚀 Befly 服务器启动成功! 完整启动耗时: ${finalStartupTime.toFixed(2)}ms`);
|
|
484
|
+
Logger.info(`📡 服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
|
|
485
|
+
|
|
403
486
|
if (callback && typeof callback === 'function') {
|
|
404
487
|
callback(server);
|
|
405
488
|
}
|
|
406
489
|
}
|
|
407
490
|
}
|
|
408
491
|
|
|
409
|
-
export {
|
|
492
|
+
export { Befly, Env, Api, Jwt, Crypto2, Logger, RYes, RNo };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Buma - 为 Bun 专属打造的 API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"README.md",
|
|
50
50
|
"vitest.config.js"
|
|
51
51
|
],
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "e63250008419234f883e562b6eba2ab554602150"
|
|
53
53
|
}
|
package/plugins/db.js
CHANGED
package/plugins/tool.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
after: ['_redis', '_db'],
|
|
3
|
+
async onInit(befly) {
|
|
4
|
+
// 增强的更新方法 - 自动添加 updated_at
|
|
5
|
+
|
|
6
|
+
// 辅助函数:过滤掉 undefined 值
|
|
7
|
+
const filterUndefined = (obj) => Object.fromEntries(Object.entries(obj).filter(([key, value]) => value !== undefined));
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
async updData(data) {
|
|
11
|
+
const filteredData = filterUndefined(data);
|
|
12
|
+
|
|
13
|
+
const updateData = {
|
|
14
|
+
...fnOmit(filteredData, ['id', 'created_at', 'deleted_at']),
|
|
15
|
+
updated_at: Date.now()
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return updateData;
|
|
19
|
+
},
|
|
20
|
+
async insData(data) {
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
|
|
23
|
+
if (Array.isArray(data)) {
|
|
24
|
+
const data2 = await Promise.all(
|
|
25
|
+
data.map(async (item) => ({
|
|
26
|
+
...filterUndefined(item),
|
|
27
|
+
id: await redis.genTimeID(),
|
|
28
|
+
created_at: now,
|
|
29
|
+
updated_at: now
|
|
30
|
+
}))
|
|
31
|
+
);
|
|
32
|
+
return data2;
|
|
33
|
+
} else {
|
|
34
|
+
const data2 = {
|
|
35
|
+
...filterUndefined(data),
|
|
36
|
+
id: await redis.genTimeID(),
|
|
37
|
+
created_at: now,
|
|
38
|
+
updated_at: now
|
|
39
|
+
};
|
|
40
|
+
return data2;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
package/utils/curd.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { omitFields } from './util.js';
|
|
2
|
-
|
|
3
|
-
export class Crud {
|
|
4
|
-
constructor(db, redis, sql) {
|
|
5
|
-
this.db = db;
|
|
6
|
-
this.redis = redis;
|
|
7
|
-
this.sql = sql;
|
|
8
|
-
this.initMethods();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
initMethods() {
|
|
12
|
-
// 将所有 CRUD 方法直接挂载到 db 实例上
|
|
13
|
-
this.db.insData = this.insData.bind(this);
|
|
14
|
-
this.db.updData = this.updData.bind(this);
|
|
15
|
-
this.db.delData = this.delData.bind(this);
|
|
16
|
-
this.db.getOne = this.getOne.bind(this);
|
|
17
|
-
this.db.getList = this.getList.bind(this);
|
|
18
|
-
this.db.getAll = this.getAll.bind(this);
|
|
19
|
-
this.db.getCount = this.getCount.bind(this);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 事务方法
|
|
23
|
-
async trans(callback) {
|
|
24
|
-
return await this.db.transaction().execute(async (trx) => {
|
|
25
|
-
// 创建一个临时的 Crud 实例,使用事务连接
|
|
26
|
-
const transactionCrud = new Crud(trx, this.redis, this.sql);
|
|
27
|
-
return await callback(transactionCrud);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 增强的插入方法 - 自动添加 ID 和时间戳,支持链式调用
|
|
32
|
-
insData(tableName, data) {
|
|
33
|
-
const insertQuery = this.db.insertInto(tableName);
|
|
34
|
-
const redis = this.redis;
|
|
35
|
-
|
|
36
|
-
insertQuery.exec = async function () {
|
|
37
|
-
const now = Date.now();
|
|
38
|
-
let processedData = data;
|
|
39
|
-
|
|
40
|
-
if (Array.isArray(data)) {
|
|
41
|
-
processedData = await Promise.all(
|
|
42
|
-
data.map(async (item) => ({
|
|
43
|
-
...item,
|
|
44
|
-
id: await redis.genTimeID(),
|
|
45
|
-
created_at: now,
|
|
46
|
-
updated_at: now
|
|
47
|
-
}))
|
|
48
|
-
);
|
|
49
|
-
} else {
|
|
50
|
-
processedData = {
|
|
51
|
-
...data,
|
|
52
|
-
id: await redis.genTimeID(),
|
|
53
|
-
created_at: now,
|
|
54
|
-
updated_at: now
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const result = await this.values(processedData).execute();
|
|
59
|
-
return { data: result }; // 返回统一格式
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return insertQuery;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 增强的更新方法 - 自动添加 updated_at,支持链式调用
|
|
66
|
-
updData(tableName, data) {
|
|
67
|
-
// 剔除 undefined 值
|
|
68
|
-
const filteredData = Object.fromEntries(Object.entries(data).filter(([key, value]) => value !== undefined));
|
|
69
|
-
|
|
70
|
-
const updateData = {
|
|
71
|
-
...omitFields(filteredData, ['id', 'created_at', 'deleted_at']),
|
|
72
|
-
updated_at: Date.now()
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const updateQuery = this.db.updateTable(tableName).set(updateData);
|
|
76
|
-
|
|
77
|
-
updateQuery.exec = async function () {
|
|
78
|
-
const result = await this.execute();
|
|
79
|
-
return { data: result }; // 返回统一格式
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return updateQuery;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 增强的删除方法 - 支持链式调用
|
|
86
|
-
delData(tableName) {
|
|
87
|
-
const deleteQuery = this.db.deleteFrom(tableName);
|
|
88
|
-
|
|
89
|
-
deleteQuery.exec = async function () {
|
|
90
|
-
const result = await this.execute();
|
|
91
|
-
return { data: result }; // 返回统一格式
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
return deleteQuery;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 查询单条记录 - 支持链式调用
|
|
98
|
-
getOne(tableName, fields) {
|
|
99
|
-
let selectQuery;
|
|
100
|
-
|
|
101
|
-
if (fields) {
|
|
102
|
-
selectQuery = Array.isArray(fields) ? this.db.selectFrom(tableName).select(fields) : this.db.selectFrom(tableName).select([fields]);
|
|
103
|
-
} else {
|
|
104
|
-
selectQuery = this.db.selectFrom(tableName).selectAll();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 默认过滤软删除的数据
|
|
108
|
-
selectQuery = selectQuery.where('state', '<>', 2);
|
|
109
|
-
|
|
110
|
-
// 添加 exec 方法,自动返回单条记录
|
|
111
|
-
selectQuery.exec = async function () {
|
|
112
|
-
const result = await this.executeTakeFirst();
|
|
113
|
-
return { data: result }; // 返回统一格式
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
return selectQuery;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// 查询列表 - 支持链式调用和分页
|
|
120
|
-
getList(tableName, fields, page = 1, pageSize = 20) {
|
|
121
|
-
let selectQuery;
|
|
122
|
-
|
|
123
|
-
if (fields) {
|
|
124
|
-
selectQuery = Array.isArray(fields) ? this.db.selectFrom(tableName).select(fields) : this.db.selectFrom(tableName).select([fields]);
|
|
125
|
-
} else {
|
|
126
|
-
selectQuery = this.db.selectFrom(tableName).selectAll();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// 默认过滤软删除的数据
|
|
130
|
-
selectQuery = selectQuery.where('state', '<>', 2);
|
|
131
|
-
|
|
132
|
-
// 添加 exec 方法 - 支持分页,只返回数据列表
|
|
133
|
-
selectQuery.exec = async function () {
|
|
134
|
-
const offset = (page - 1) * pageSize;
|
|
135
|
-
const result = await this.limit(pageSize).offset(offset).execute();
|
|
136
|
-
return { data: result };
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
return selectQuery;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// 查询所有记录 - 支持链式调用
|
|
143
|
-
getAll(tableName, fields) {
|
|
144
|
-
let selectQuery;
|
|
145
|
-
|
|
146
|
-
if (fields) {
|
|
147
|
-
selectQuery = Array.isArray(fields) ? this.db.selectFrom(tableName).select(fields) : this.db.selectFrom(tableName).select([fields]);
|
|
148
|
-
} else {
|
|
149
|
-
selectQuery = this.db.selectFrom(tableName).selectAll();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 默认过滤软删除的数据
|
|
153
|
-
selectQuery = selectQuery.where('state', '<>', 2);
|
|
154
|
-
|
|
155
|
-
// 添加 exec 方法,执行查询所有记录
|
|
156
|
-
selectQuery.exec = async function () {
|
|
157
|
-
const result = await this.execute();
|
|
158
|
-
return { data: result }; // 返回统一格式
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
return selectQuery;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// 便捷的计数方法 - 支持链式调用
|
|
165
|
-
getCount(tableName) {
|
|
166
|
-
const sql = this.sql;
|
|
167
|
-
const countQuery = this.db
|
|
168
|
-
.selectFrom(tableName)
|
|
169
|
-
.select(sql`count(*)`.as('total'))
|
|
170
|
-
.where('state', '<>', 2);
|
|
171
|
-
|
|
172
|
-
// 添加便捷的 exec 方法
|
|
173
|
-
countQuery.exec = async function () {
|
|
174
|
-
const result = await this.executeTakeFirst();
|
|
175
|
-
const count = Number(result?.total || 0);
|
|
176
|
-
return { data: count }; // 返回统一格式
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
return countQuery;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// 获取原始数据库实例
|
|
183
|
-
getDb() {
|
|
184
|
-
return this.db;
|
|
185
|
-
}
|
|
186
|
-
}
|