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 CHANGED
@@ -1,3 +1,3 @@
1
- # BunPii
1
+ # Befly
2
2
 
3
3
  自用框架,请勿使用。
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 BunPii {
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
- Logger.warn(`文件 ${fileName} 未导出默认函数`);
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(`总检查数: ${totalChecks}, 通过: ${passedChecks}, 失败: ${failedChecks}`);
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
- for (const plugin of sortedUserPlugins) {
154
- try {
155
- this.pluginLists.push(plugin);
156
- this.appContext[plugin.pluginName] = typeof plugin?.onInit === 'function' ? await plugin?.onInit(this.appContext) : {};
157
- } catch (error) {
158
- Logger.warn(`插件 ${plugin.pluginName} 初始化失败:`, error.message);
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
- const api = (await import(file)).default;
185
- if (isType(api.name, 'string') === false || api.name.trim() === '') {
186
- throw new Error(`接口 ${apiPath} 的 name 属性必须是非空字符串`);
187
- }
188
- if (api.auth !== false && api.auth !== true && Array.isArray(api.auth) === false) {
189
- throw new Error(`接口 ${apiPath} 的 auth 属性必须是布尔值或字符串数组`);
190
- }
191
- if (isType(api.fields, 'object') === false) {
192
- throw new Error(`接口 ${apiPath} 的 fields 属性必须是对象`);
193
- }
194
- if (isType(api.required, 'array') === false) {
195
- throw new Error(`接口 ${apiPath} 的 required 属性必须是数组`);
196
- }
197
- // 数组的每一项都必须是字符串
198
- if (api.required.some((item) => isType(item, 'string') === false)) {
199
- throw new Error(`接口 ${apiPath} required 属性必须是字符串数组`);
200
- }
201
- if (isType(api.handler, 'function') === false) {
202
- throw new Error(`接口 ${apiPath} 的 handler 属性必须是函数`);
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: 'BunPii 接口服务已启动',
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.debug({
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 { BunPii, Env, Api, Jwt, Crypto2, Logger, RYes, RNo };
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.0.3",
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": "3bd2e1f01b94f2b576467db1b63a016b6717dbbe"
52
+ "gitHead": "e63250008419234f883e562b6eba2ab554602150"
53
53
  }
package/plugins/db.js CHANGED
@@ -35,8 +35,7 @@ export default {
35
35
  // 测试数据库连接
36
36
  const result = await sql`SELECT VERSION() AS version`.execute(db);
37
37
  if (result?.rows?.[0]?.version) {
38
- // 扩展数据库实例
39
- return new Crud(db, befly.redis, sql);
38
+ return db;
40
39
  } else {
41
40
  return {};
42
41
  }
@@ -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
- }