befly 3.10.12 → 3.10.14

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 CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { WhereConditions, JoinOption } from "../types/common.js";
7
- import type { QueryOptions, InsertOptions, UpdateOptions, DeleteOptions, ListResult, AllResult, TransactionCallback } from "../types/database.js";
7
+ import type { QueryOptions, InsertOptions, UpdateOptions, DeleteOptions, ListResult, AllResult, TransactionCallback, DbResult, SqlInfo, ListSql } from "../types/database.js";
8
8
  import type { DbDialect } from "./dbDialect.js";
9
9
 
10
10
  import { snakeCase } from "es-toolkit/string";
@@ -36,18 +36,16 @@ export class DbHelper {
36
36
  private dialect: DbDialect;
37
37
  private sql: any = null;
38
38
  private isTransaction: boolean = false;
39
- private debug: number = 0;
40
39
 
41
40
  /**
42
41
  * 构造函数
43
42
  * @param redis - Redis 实例
44
43
  * @param sql - Bun SQL 客户端(可选,用于事务)
45
44
  */
46
- constructor(options: { redis: RedisCacheLike; sql?: any | null; dialect?: DbDialect; debug?: number }) {
45
+ constructor(options: { redis: RedisCacheLike; sql?: any | null; dialect?: DbDialect }) {
47
46
  this.redis = options.redis;
48
47
  this.sql = options.sql || null;
49
48
  this.isTransaction = !!options.sql;
50
- this.debug = options.debug === 1 ? 1 : 0;
51
49
 
52
50
  // 默认使用 MySQL 方言(当前 core 的表结构/语法也主要基于 MySQL)
53
51
  this.dialect = options.dialect ? options.dialect : new MySqlDialect();
@@ -73,7 +71,8 @@ export class DbHelper {
73
71
 
74
72
  // 2. 缓存未命中,查询数据库
75
73
  const query = this.dialect.getTableColumnsQuery(table);
76
- const result = await this.executeWithConn(query.sql, query.params);
74
+ const execRes = await this.executeWithConn(query.sql, query.params);
75
+ const result = execRes.data;
77
76
 
78
77
  if (!result || result.length === 0) {
79
78
  throw new Error(`表 ${table} 不存在或没有字段`);
@@ -157,9 +156,12 @@ export class DbHelper {
157
156
  }
158
157
  }
159
158
  /**
160
- * 执行 SQL(使用 sql.unsafe,带慢查询日志和错误处理)
159
+ * 执行 SQL(使用 sql.unsafe
160
+ *
161
+ * - DbHelper 不再负责打印 SQL 调试日志
162
+ * - SQL 信息由调用方基于返回值中的 sql 自行输出
161
163
  */
162
- private async executeWithConn(sqlStr: string, params?: any[]): Promise<any> {
164
+ private async executeWithConn(sqlStr: string, params?: any[]): Promise<DbResult<any>> {
163
165
  if (!this.sql) {
164
166
  throw new Error("数据库连接未初始化");
165
167
  }
@@ -172,11 +174,13 @@ export class DbHelper {
172
174
  // 记录开始时间
173
175
  const startTime = Date.now();
174
176
 
177
+ const safeParams = Array.isArray(params) ? params : [];
178
+
175
179
  try {
176
180
  // 使用 sql.unsafe 执行查询
177
181
  let result;
178
- if (params && params.length > 0) {
179
- result = await this.sql.unsafe(sqlStr, params);
182
+ if (safeParams.length > 0) {
183
+ result = await this.sql.unsafe(sqlStr, safeParams);
180
184
  } else {
181
185
  result = await this.sql.unsafe(sqlStr);
182
186
  }
@@ -184,57 +188,28 @@ export class DbHelper {
184
188
  // 计算执行时间
185
189
  const duration = Date.now() - startTime;
186
190
 
187
- if (this.debug === 1) {
188
- const sqlPreview = sqlStr.length > 500 ? sqlStr.substring(0, 500) + "..." : sqlStr;
189
-
190
- Logger.info(
191
- {
192
- subsystem: "db",
193
- event: "query",
194
- duration: duration,
195
- sqlPreview: sqlPreview,
196
- paramsCount: (params || []).length,
197
- params: params || []
198
- },
199
- "DB"
200
- );
201
- }
202
-
203
- // 慢查询警告(超过 5000ms)
204
- if (duration > 5000) {
205
- Logger.warn(
206
- {
207
- subsystem: "db",
208
- event: "slow",
209
- duration: duration,
210
- sqlPreview: sqlStr,
211
- params: params || [],
212
- paramsCount: (params || []).length
213
- },
214
- "🐌 检测到慢查询"
215
- );
216
- }
191
+ const sql: SqlInfo = {
192
+ sql: sqlStr,
193
+ params: safeParams,
194
+ duration: duration
195
+ };
217
196
 
218
- return result;
197
+ return {
198
+ data: result,
199
+ sql: sql
200
+ };
219
201
  } catch (error: any) {
220
202
  const duration = Date.now() - startTime;
221
203
 
222
- const sqlPreview = sqlStr.length > 200 ? sqlStr.substring(0, 200) + "..." : sqlStr;
223
- Logger.error(
224
- {
225
- err: error,
226
- sqlPreview: sqlPreview,
227
- params: params || [],
228
- duration: duration
229
- },
230
- "SQL 执行错误"
231
- );
232
-
233
204
  const enhancedError: any = new Error(`SQL执行失败: ${error.message}`);
234
205
  enhancedError.originalError = error;
235
- enhancedError.sql = sqlStr;
236
- enhancedError.params = params || [];
206
+ enhancedError.params = safeParams;
237
207
  enhancedError.duration = duration;
208
+ enhancedError.sqlInfo = {
209
+ sql: sqlStr,
210
+ params: safeParams,
211
+ duration: duration
212
+ };
238
213
  throw enhancedError;
239
214
  }
240
215
  }
@@ -245,7 +220,7 @@ export class DbHelper {
245
220
  * - 复用当前 DbHelper 持有的连接/事务
246
221
  * - 统一走 executeWithConn,保持参数校验与错误行为一致
247
222
  */
248
- public async unsafe(sqlStr: string, params?: any[]): Promise<any> {
223
+ public async unsafe(sqlStr: string, params?: any[]): Promise<DbResult<any>> {
249
224
  return await this.executeWithConn(sqlStr, params);
250
225
  }
251
226
 
@@ -254,14 +229,18 @@ export class DbHelper {
254
229
  * @param tableName - 表名(支持小驼峰,会自动转换为下划线)
255
230
  * @returns 表是否存在
256
231
  */
257
- async tableExists(tableName: string): Promise<boolean> {
232
+ async tableExists(tableName: string): Promise<DbResult<boolean>> {
258
233
  // 将表名转换为下划线格式
259
234
  const snakeTableName = snakeCase(tableName);
260
235
 
261
236
  const query = this.dialect.tableExistsQuery(snakeTableName);
262
- const result = await this.executeWithConn(query.sql, query.params);
237
+ const execRes = await this.executeWithConn(query.sql, query.params);
238
+ const exists = (execRes.data?.[0]?.count || 0) > 0;
263
239
 
264
- return result?.[0]?.count > 0;
240
+ return {
241
+ data: exists,
242
+ sql: execRes.sql
243
+ };
265
244
  }
266
245
 
267
246
  /**
@@ -281,7 +260,7 @@ export class DbHelper {
281
260
  * where: { 'o.state': 1 }
282
261
  * });
283
262
  */
284
- async getCount(options: Omit<QueryOptions, "fields" | "page" | "limit" | "orderBy">): Promise<number> {
263
+ async getCount(options: Omit<QueryOptions, "fields" | "page" | "limit" | "orderBy">): Promise<DbResult<number>> {
285
264
  const { table, where, joins, tableQualifier } = await this.prepareQueryOptions(options as QueryOptions);
286
265
 
287
266
  const builder = this.createSqlBuilder()
@@ -293,9 +272,13 @@ export class DbHelper {
293
272
  this.applyJoins(builder, joins);
294
273
 
295
274
  const { sql, params } = builder.toSelectSql();
296
- const result = await this.executeWithConn(sql, params);
275
+ const execRes = await this.executeWithConn(sql, params);
276
+ const count = execRes.data?.[0]?.count || 0;
297
277
 
298
- return result?.[0]?.count || 0;
278
+ return {
279
+ data: count,
280
+ sql: execRes.sql
281
+ };
299
282
  }
300
283
 
301
284
  /**
@@ -314,7 +297,7 @@ export class DbHelper {
314
297
  * where: { 'o.id': 1 }
315
298
  * })
316
299
  */
317
- async getOne<T extends Record<string, any> = Record<string, any>>(options: QueryOptions): Promise<T | null> {
300
+ async getOne<T extends Record<string, any> = Record<string, any>>(options: QueryOptions): Promise<DbResult<T | null>> {
318
301
  const { table, fields, where, joins, tableQualifier } = await this.prepareQueryOptions(options);
319
302
 
320
303
  const builder = this.createSqlBuilder()
@@ -326,20 +309,35 @@ export class DbHelper {
326
309
  this.applyJoins(builder, joins);
327
310
 
328
311
  const { sql, params } = builder.toSelectSql();
329
- const result = await this.executeWithConn(sql, params);
312
+ const execRes = await this.executeWithConn(sql, params);
313
+ const result = execRes.data;
330
314
 
331
315
  // 字段名转换:下划线 → 小驼峰
332
316
  const row = result?.[0] || null;
333
- if (!row) return null;
317
+ if (!row) {
318
+ return {
319
+ data: null,
320
+ sql: execRes.sql
321
+ };
322
+ }
334
323
 
335
324
  const camelRow = keysToCamel<T>(row);
336
325
 
337
326
  // 反序列化数组字段(JSON 字符串 → 数组)
338
327
  const deserialized = DbUtils.deserializeArrayFields<T>(camelRow);
339
- if (!deserialized) return null;
328
+ if (!deserialized) {
329
+ return {
330
+ data: null,
331
+ sql: execRes.sql
332
+ };
333
+ }
340
334
 
341
335
  // 转换 BIGINT 字段(id, pid 等)为数字类型
342
- return convertBigIntFields<T>([deserialized])[0];
336
+ const data = convertBigIntFields<T>([deserialized])[0];
337
+ return {
338
+ data: data,
339
+ sql: execRes.sql
340
+ };
343
341
  }
344
342
 
345
343
  /**
@@ -364,7 +362,7 @@ export class DbHelper {
364
362
  * limit: 10
365
363
  * })
366
364
  */
367
- async getList<T extends Record<string, any> = Record<string, any>>(options: QueryOptions): Promise<ListResult<T>> {
365
+ async getList<T extends Record<string, any> = Record<string, any>>(options: QueryOptions): Promise<DbResult<ListResult<T>, ListSql>> {
368
366
  const prepared = await this.prepareQueryOptions(options);
369
367
 
370
368
  // 参数上限校验
@@ -385,17 +383,22 @@ export class DbHelper {
385
383
  this.applyJoins(countBuilder, prepared.joins);
386
384
 
387
385
  const { sql: countSql, params: countParams } = countBuilder.toSelectSql();
388
- const countResult = await this.executeWithConn(countSql, countParams);
389
- const total = countResult?.[0]?.total || 0;
386
+ const countExecRes = await this.executeWithConn(countSql, countParams);
387
+ const total = countExecRes.data?.[0]?.total || 0;
390
388
 
391
389
  // 如果总数为 0,直接返回,不执行第二次查询
392
390
  if (total === 0) {
393
391
  return {
394
- lists: [],
395
- total: 0,
396
- page: prepared.page,
397
- limit: prepared.limit,
398
- pages: 0
392
+ data: {
393
+ lists: [],
394
+ total: 0,
395
+ page: prepared.page,
396
+ limit: prepared.limit,
397
+ pages: 0
398
+ },
399
+ sql: {
400
+ count: countExecRes.sql
401
+ }
399
402
  };
400
403
  }
401
404
 
@@ -412,7 +415,8 @@ export class DbHelper {
412
415
  }
413
416
 
414
417
  const { sql: dataSql, params: dataParams } = dataBuilder.toSelectSql();
415
- const list = (await this.executeWithConn(dataSql, dataParams)) || [];
418
+ const dataExecRes = await this.executeWithConn(dataSql, dataParams);
419
+ const list = dataExecRes.data || [];
416
420
 
417
421
  // 字段名转换:下划线 → 小驼峰
418
422
  const camelList = arrayKeysToCamel<T>(list);
@@ -422,11 +426,17 @@ export class DbHelper {
422
426
 
423
427
  // 转换 BIGINT 字段(id, pid 等)为数字类型
424
428
  return {
425
- lists: convertBigIntFields<T>(deserializedList),
426
- total: total,
427
- page: prepared.page,
428
- limit: prepared.limit,
429
- pages: Math.ceil(total / prepared.limit)
429
+ data: {
430
+ lists: convertBigIntFields<T>(deserializedList),
431
+ total: total,
432
+ page: prepared.page,
433
+ limit: prepared.limit,
434
+ pages: Math.ceil(total / prepared.limit)
435
+ },
436
+ sql: {
437
+ count: countExecRes.sql,
438
+ data: dataExecRes.sql
439
+ }
430
440
  };
431
441
  }
432
442
 
@@ -447,7 +457,7 @@ export class DbHelper {
447
457
  * where: { 'o.state': 1 }
448
458
  * })
449
459
  */
450
- async getAll<T extends Record<string, any> = Record<string, any>>(options: Omit<QueryOptions, "page" | "limit">): Promise<AllResult<T>> {
460
+ async getAll<T extends Record<string, any> = Record<string, any>>(options: Omit<QueryOptions, "page" | "limit">): Promise<DbResult<AllResult<T>, ListSql>> {
451
461
  // 添加硬性上限保护,防止内存溢出
452
462
  const MAX_LIMIT = 10000;
453
463
  const WARNING_LIMIT = 1000;
@@ -463,14 +473,19 @@ export class DbHelper {
463
473
  this.applyJoins(countBuilder, prepared.joins);
464
474
 
465
475
  const { sql: countSql, params: countParams } = countBuilder.toSelectSql();
466
- const countResult = await this.executeWithConn(countSql, countParams);
467
- const total = countResult?.[0]?.total || 0;
476
+ const countExecRes = await this.executeWithConn(countSql, countParams);
477
+ const total = countExecRes.data?.[0]?.total || 0;
468
478
 
469
479
  // 如果总数为 0,直接返回
470
480
  if (total === 0) {
471
481
  return {
472
- lists: [],
473
- total: 0
482
+ data: {
483
+ lists: [],
484
+ total: 0
485
+ },
486
+ sql: {
487
+ count: countExecRes.sql
488
+ }
474
489
  };
475
490
  }
476
491
 
@@ -485,7 +500,8 @@ export class DbHelper {
485
500
  }
486
501
 
487
502
  const { sql: dataSql, params: dataParams } = dataBuilder.toSelectSql();
488
- const result = (await this.executeWithConn(dataSql, dataParams)) || [];
503
+ const dataExecRes = await this.executeWithConn(dataSql, dataParams);
504
+ const result = dataExecRes.data || [];
489
505
 
490
506
  // 警告日志:返回数据超过警告阈值
491
507
  if (result.length >= WARNING_LIMIT) {
@@ -507,8 +523,14 @@ export class DbHelper {
507
523
  const lists = convertBigIntFields<T>(deserializedList);
508
524
 
509
525
  return {
510
- lists: lists,
511
- total: total
526
+ data: {
527
+ lists: lists,
528
+ total: total
529
+ },
530
+ sql: {
531
+ count: countExecRes.sql,
532
+ data: dataExecRes.sql
533
+ }
512
534
  };
513
535
  }
514
536
 
@@ -516,7 +538,7 @@ export class DbHelper {
516
538
  * 插入数据(自动生成 ID、时间戳、state)
517
539
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
518
540
  */
519
- async insData(options: InsertOptions): Promise<number> {
541
+ async insData(options: InsertOptions): Promise<DbResult<number>> {
520
542
  const { table, data } = options;
521
543
 
522
544
  const snakeTable = snakeCase(table);
@@ -540,8 +562,12 @@ export class DbHelper {
540
562
  const { sql, params } = builder.toInsertSql(snakeTable, processed);
541
563
 
542
564
  // 执行
543
- const result = await this.executeWithConn(sql, params);
544
- return processed.id || result?.lastInsertRowid || 0;
565
+ const execRes = await this.executeWithConn(sql, params);
566
+ const insertedId = processed.id || execRes.data?.lastInsertRowid || 0;
567
+ return {
568
+ data: insertedId,
569
+ sql: execRes.sql
570
+ };
545
571
  }
546
572
 
547
573
  /**
@@ -550,10 +576,14 @@ export class DbHelper {
550
576
  * 自动生成系统字段并包装在事务中
551
577
  * @param table - 表名(支持小驼峰或下划线格式,会自动转换)
552
578
  */
553
- async insBatch(table: string, dataList: Record<string, any>[]): Promise<number[]> {
579
+ async insBatch(table: string, dataList: Record<string, any>[]): Promise<DbResult<number[]>> {
554
580
  // 空数组直接返回
555
581
  if (dataList.length === 0) {
556
- return [];
582
+ const sql: SqlInfo = { sql: "", params: [], duration: 0 };
583
+ return {
584
+ data: [],
585
+ sql: sql
586
+ };
557
587
  }
558
588
 
559
589
  // 限制批量大小
@@ -586,8 +616,11 @@ export class DbHelper {
586
616
 
587
617
  // 在事务中执行批量插入
588
618
  try {
589
- await this.executeWithConn(sql, params);
590
- return ids;
619
+ const execRes = await this.executeWithConn(sql, params);
620
+ return {
621
+ data: ids,
622
+ sql: execRes.sql
623
+ };
591
624
  } catch (error: any) {
592
625
  Logger.error(
593
626
  {
@@ -603,9 +636,13 @@ export class DbHelper {
603
636
  }
604
637
  }
605
638
 
606
- async delForceBatch(table: string, ids: number[]): Promise<number> {
639
+ async delForceBatch(table: string, ids: number[]): Promise<DbResult<number>> {
607
640
  if (ids.length === 0) {
608
- return 0;
641
+ const sql: SqlInfo = { sql: "", params: [], duration: 0 };
642
+ return {
643
+ data: 0,
644
+ sql: sql
645
+ };
609
646
  }
610
647
 
611
648
  const snakeTable = snakeCase(table);
@@ -616,13 +653,21 @@ export class DbHelper {
616
653
  ids: ids,
617
654
  quoteIdent: this.dialect.quoteIdent.bind(this.dialect)
618
655
  });
619
- const result: any = await this.executeWithConn(query.sql, query.params);
620
- return result?.changes || 0;
656
+ const execRes = await this.executeWithConn(query.sql, query.params);
657
+ const changes = execRes.data?.changes || 0;
658
+ return {
659
+ data: changes,
660
+ sql: execRes.sql
661
+ };
621
662
  }
622
663
 
623
- async updBatch(table: string, dataList: Array<{ id: number; data: Record<string, any> }>): Promise<number> {
664
+ async updBatch(table: string, dataList: Array<{ id: number; data: Record<string, any> }>): Promise<DbResult<number>> {
624
665
  if (dataList.length === 0) {
625
- return 0;
666
+ const sql: SqlInfo = { sql: "", params: [], duration: 0 };
667
+ return {
668
+ data: 0,
669
+ sql: sql
670
+ };
626
671
  }
627
672
 
628
673
  const snakeTable = snakeCase(table);
@@ -643,7 +688,11 @@ export class DbHelper {
643
688
 
644
689
  const fields = Array.from(fieldSet).sort();
645
690
  if (fields.length === 0) {
646
- return 0;
691
+ const sql: SqlInfo = { sql: "", params: [], duration: 0 };
692
+ return {
693
+ data: 0,
694
+ sql: sql
695
+ };
647
696
  }
648
697
 
649
698
  const query = SqlBuilder.toUpdateCaseByIdSql({
@@ -658,15 +707,19 @@ export class DbHelper {
658
707
  stateGtZero: true
659
708
  });
660
709
 
661
- const result: any = await this.executeWithConn(query.sql, query.params);
662
- return result?.changes || 0;
710
+ const execRes = await this.executeWithConn(query.sql, query.params);
711
+ const changes = execRes.data?.changes || 0;
712
+ return {
713
+ data: changes,
714
+ sql: execRes.sql
715
+ };
663
716
  }
664
717
 
665
718
  /**
666
719
  * 更新数据(强制更新时间戳,系统字段不可修改)
667
720
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
668
721
  */
669
- async updData(options: UpdateOptions): Promise<number> {
722
+ async updData(options: UpdateOptions): Promise<DbResult<number>> {
670
723
  const { table, data, where } = options;
671
724
 
672
725
  // 清理条件(排除 null 和 undefined)
@@ -684,15 +737,19 @@ export class DbHelper {
684
737
  const { sql, params } = builder.toUpdateSql(snakeTable, processed);
685
738
 
686
739
  // 执行
687
- const result = await this.executeWithConn(sql, params);
688
- return result?.changes || 0;
740
+ const execRes = await this.executeWithConn(sql, params);
741
+ const changes = execRes.data?.changes || 0;
742
+ return {
743
+ data: changes,
744
+ sql: execRes.sql
745
+ };
689
746
  }
690
747
 
691
748
  /**
692
749
  * 软删除数据(deleted_at 设置为当前时间,state 设置为 0)
693
750
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
694
751
  */
695
- async delData(options: DeleteOptions): Promise<number> {
752
+ async delData(options: DeleteOptions): Promise<DbResult<number>> {
696
753
  const { table, where } = options;
697
754
 
698
755
  return await this.updData({
@@ -706,7 +763,7 @@ export class DbHelper {
706
763
  * 硬删除数据(物理删除,不可恢复)
707
764
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
708
765
  */
709
- async delForce(options: Omit<DeleteOptions, "hard">): Promise<number> {
766
+ async delForce(options: Omit<DeleteOptions, "hard">): Promise<DbResult<number>> {
710
767
  const { table, where } = options;
711
768
 
712
769
  // 转换表名:小驼峰 → 下划线
@@ -720,15 +777,19 @@ export class DbHelper {
720
777
  const builder = this.createSqlBuilder().where(snakeWhere);
721
778
  const { sql, params } = builder.toDeleteSql(snakeTable);
722
779
 
723
- const result = await this.executeWithConn(sql, params);
724
- return result?.changes || 0;
780
+ const execRes = await this.executeWithConn(sql, params);
781
+ const changes = execRes.data?.changes || 0;
782
+ return {
783
+ data: changes,
784
+ sql: execRes.sql
785
+ };
725
786
  }
726
787
 
727
788
  /**
728
789
  * 禁用数据(设置 state=2)
729
790
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
730
791
  */
731
- async disableData(options: Omit<DeleteOptions, "hard">): Promise<number> {
792
+ async disableData(options: Omit<DeleteOptions, "hard">): Promise<DbResult<number>> {
732
793
  const { table, where } = options;
733
794
 
734
795
  return await this.updData({
@@ -744,7 +805,7 @@ export class DbHelper {
744
805
  * 启用数据(设置 state=1)
745
806
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
746
807
  */
747
- async enableData(options: Omit<DeleteOptions, "hard">): Promise<number> {
808
+ async enableData(options: Omit<DeleteOptions, "hard">): Promise<DbResult<number>> {
748
809
  const { table, where } = options;
749
810
 
750
811
  return await this.updData({
@@ -769,7 +830,7 @@ export class DbHelper {
769
830
  // 使用 Bun SQL 的 begin 方法开启事务
770
831
  // begin 方法会自动处理 commit/rollback
771
832
  return await this.sql.begin(async (tx: any) => {
772
- const trans = new DbHelper({ redis: this.redis, sql: tx, dialect: this.dialect, debug: this.debug });
833
+ const trans = new DbHelper({ redis: this.redis, sql: tx, dialect: this.dialect });
773
834
  return await callback(trans);
774
835
  });
775
836
  }
@@ -777,7 +838,7 @@ export class DbHelper {
777
838
  /**
778
839
  * 执行原始 SQL
779
840
  */
780
- async query(sql: string, params?: any[]): Promise<any> {
841
+ async query(sql: string, params?: any[]): Promise<DbResult<any>> {
781
842
  return await this.executeWithConn(sql, params);
782
843
  }
783
844
 
@@ -785,27 +846,31 @@ export class DbHelper {
785
846
  * 检查数据是否存在(优化性能)
786
847
  * @param options.table - 表名(支持小驼峰或下划线格式,会自动转换)
787
848
  */
788
- async exists(options: Omit<QueryOptions, "fields" | "orderBy" | "page" | "limit">): Promise<boolean> {
849
+ async exists(options: Omit<QueryOptions, "fields" | "orderBy" | "page" | "limit">): Promise<DbResult<boolean>> {
789
850
  const { table, where, tableQualifier } = await this.prepareQueryOptions({ ...options, page: 1, limit: 1 } as any);
790
851
 
791
852
  // 使用 COUNT(1) 性能更好
792
853
  const builder = this.createSqlBuilder()
793
- .select(["COUNT(1) as cnt"])
854
+ .selectRaw("COUNT(1) as cnt")
794
855
  .from(table)
795
856
  .where(DbUtils.addDefaultStateFilter(where, tableQualifier, false))
796
857
  .limit(1);
797
858
 
798
859
  const { sql, params } = builder.toSelectSql();
799
- const result = await this.executeWithConn(sql, params);
860
+ const execRes = await this.executeWithConn(sql, params);
861
+ const exists = (execRes.data?.[0]?.cnt || 0) > 0;
800
862
 
801
- return (result?.[0]?.cnt || 0) > 0;
863
+ return {
864
+ data: exists,
865
+ sql: execRes.sql
866
+ };
802
867
  }
803
868
 
804
869
  /**
805
870
  * 查询单个字段值(带字段名验证)
806
871
  * @param field - 字段名(支持小驼峰或下划线格式)
807
872
  */
808
- async getFieldValue<T = any>(options: Omit<QueryOptions, "fields"> & { field: string }): Promise<T | null> {
873
+ async getFieldValue<T = any>(options: Omit<QueryOptions, "fields"> & { field: string }): Promise<DbResult<T | null>> {
809
874
  const { field, ...queryOptions } = options;
810
875
 
811
876
  // 验证字段名格式(只允许字母、数字、下划线)
@@ -813,33 +878,49 @@ export class DbHelper {
813
878
  throw new Error(`无效的字段名: ${field},只允许字母、数字和下划线`);
814
879
  }
815
880
 
816
- const result = await this.getOne({
881
+ const oneRes = await this.getOne({
817
882
  ...queryOptions,
818
883
  fields: [field]
819
884
  });
820
885
 
886
+ const result = oneRes.data;
821
887
  if (!result) {
822
- return null;
888
+ return {
889
+ data: null,
890
+ sql: oneRes.sql
891
+ };
823
892
  }
824
893
 
825
894
  // 尝试直接访问字段(小驼峰)
826
895
  if (field in result) {
827
- return result[field];
896
+ return {
897
+ data: result[field],
898
+ sql: oneRes.sql
899
+ };
828
900
  }
829
901
 
830
902
  // 转换为小驼峰格式再尝试访问(支持用户传入下划线格式)
831
903
  const camelField = field.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
832
904
  if (camelField !== field && camelField in result) {
833
- return result[camelField];
905
+ return {
906
+ data: result[camelField],
907
+ sql: oneRes.sql
908
+ };
834
909
  }
835
910
 
836
911
  // 转换为下划线格式再尝试访问(支持用户传入小驼峰格式)
837
912
  const snakeField = field.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
838
913
  if (snakeField !== field && snakeField in result) {
839
- return result[snakeField];
914
+ return {
915
+ data: result[snakeField],
916
+ sql: oneRes.sql
917
+ };
840
918
  }
841
919
 
842
- return null;
920
+ return {
921
+ data: null,
922
+ sql: oneRes.sql
923
+ };
843
924
  }
844
925
 
845
926
  /**
@@ -847,7 +928,7 @@ export class DbHelper {
847
928
  * @param table - 表名(支持小驼峰或下划线格式,会自动转换)
848
929
  * @param field - 字段名(支持小驼峰或下划线格式,会自动转换)
849
930
  */
850
- async increment(table: string, field: string, where: WhereConditions, value: number = 1): Promise<number> {
931
+ async increment(table: string, field: string, where: WhereConditions, value: number = 1): Promise<DbResult<number>> {
851
932
  // 转换表名和字段名:小驼峰 → 下划线
852
933
  const snakeTable = snakeCase(table);
853
934
  const snakeField = snakeCase(field);
@@ -883,8 +964,12 @@ export class DbHelper {
883
964
  const quotedField = this.dialect.quoteIdent(snakeField);
884
965
  const sql = whereClause ? `UPDATE ${quotedTable} SET ${quotedField} = ${quotedField} + ? WHERE ${whereClause}` : `UPDATE ${quotedTable} SET ${quotedField} = ${quotedField} + ?`;
885
966
 
886
- const result = await this.executeWithConn(sql, [value, ...whereParams]);
887
- return result?.changes || 0;
967
+ const execRes = await this.executeWithConn(sql, [value, ...whereParams]);
968
+ const changes = execRes.data?.changes || 0;
969
+ return {
970
+ data: changes,
971
+ sql: execRes.sql
972
+ };
888
973
  }
889
974
 
890
975
  /**
@@ -892,7 +977,7 @@ export class DbHelper {
892
977
  * @param table - 表名(支持小驼峰或下划线格式,会自动转换)
893
978
  * @param field - 字段名(支持小驼峰或下划线格式,会自动转换)
894
979
  */
895
- async decrement(table: string, field: string, where: WhereConditions, value: number = 1): Promise<number> {
980
+ async decrement(table: string, field: string, where: WhereConditions, value: number = 1): Promise<DbResult<number>> {
896
981
  return await this.increment(table, field, where, -value);
897
982
  }
898
983
  }