befly 2.3.2 → 3.0.0

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.
Files changed (93) hide show
  1. package/apis/health/info.ts +64 -0
  2. package/apis/tool/tokenCheck.ts +51 -0
  3. package/bin/befly.ts +202 -0
  4. package/checks/conflict.ts +408 -0
  5. package/checks/table.ts +284 -0
  6. package/config/env.ts +218 -0
  7. package/config/reserved.ts +96 -0
  8. package/main.ts +101 -0
  9. package/package.json +45 -16
  10. package/plugins/{db.js → db.ts} +25 -12
  11. package/plugins/logger.ts +28 -0
  12. package/plugins/redis.ts +51 -0
  13. package/plugins/tool.ts +34 -0
  14. package/scripts/syncDb/apply.ts +171 -0
  15. package/scripts/syncDb/constants.ts +70 -0
  16. package/scripts/syncDb/ddl.ts +182 -0
  17. package/scripts/syncDb/helpers.ts +172 -0
  18. package/scripts/syncDb/index.ts +215 -0
  19. package/scripts/syncDb/schema.ts +199 -0
  20. package/scripts/syncDb/sqlite.ts +50 -0
  21. package/scripts/syncDb/state.ts +104 -0
  22. package/scripts/syncDb/table.ts +204 -0
  23. package/scripts/syncDb/tableCreate.ts +142 -0
  24. package/scripts/syncDb/tests/constants.test.ts +104 -0
  25. package/scripts/syncDb/tests/ddl.test.ts +134 -0
  26. package/scripts/syncDb/tests/helpers.test.ts +70 -0
  27. package/scripts/syncDb/types.ts +92 -0
  28. package/scripts/syncDb/version.ts +73 -0
  29. package/scripts/syncDb.ts +9 -0
  30. package/scripts/syncDev.ts +112 -0
  31. package/system.ts +149 -0
  32. package/tables/_common.json +21 -0
  33. package/tables/admin.json +10 -0
  34. package/tsconfig.json +58 -0
  35. package/types/api.d.ts +246 -0
  36. package/types/befly.d.ts +234 -0
  37. package/types/common.d.ts +215 -0
  38. package/types/context.ts +167 -0
  39. package/types/crypto.d.ts +23 -0
  40. package/types/database.d.ts +278 -0
  41. package/types/index.d.ts +16 -0
  42. package/types/index.ts +459 -0
  43. package/types/jwt.d.ts +99 -0
  44. package/types/logger.d.ts +43 -0
  45. package/types/plugin.d.ts +109 -0
  46. package/types/redis.d.ts +44 -0
  47. package/types/tool.d.ts +67 -0
  48. package/types/validator.d.ts +45 -0
  49. package/utils/addonHelper.ts +60 -0
  50. package/utils/api.ts +23 -0
  51. package/utils/{colors.js → colors.ts} +79 -21
  52. package/utils/crypto.ts +308 -0
  53. package/utils/datetime.ts +51 -0
  54. package/utils/dbHelper.ts +142 -0
  55. package/utils/errorHandler.ts +68 -0
  56. package/utils/index.ts +46 -0
  57. package/utils/jwt.ts +493 -0
  58. package/utils/logger.ts +284 -0
  59. package/utils/objectHelper.ts +68 -0
  60. package/utils/pluginHelper.ts +62 -0
  61. package/utils/redisHelper.ts +338 -0
  62. package/utils/response.ts +38 -0
  63. package/utils/{sqlBuilder.js → sqlBuilder.ts} +233 -97
  64. package/utils/sqlHelper.ts +447 -0
  65. package/utils/tableHelper.ts +167 -0
  66. package/utils/tool.ts +230 -0
  67. package/utils/typeHelper.ts +101 -0
  68. package/utils/validate.ts +451 -0
  69. package/utils/{xml.js → xml.ts} +100 -74
  70. package/.npmrc +0 -3
  71. package/.prettierignore +0 -2
  72. package/.prettierrc +0 -11
  73. package/apis/health/info.js +0 -49
  74. package/apis/tool/tokenCheck.js +0 -29
  75. package/checks/table.js +0 -221
  76. package/config/env.js +0 -62
  77. package/main.js +0 -579
  78. package/plugins/logger.js +0 -14
  79. package/plugins/redis.js +0 -32
  80. package/plugins/tool.js +0 -8
  81. package/scripts/syncDb.js +0 -603
  82. package/system.js +0 -118
  83. package/tables/common.json +0 -16
  84. package/tables/tool.json +0 -6
  85. package/utils/api.js +0 -27
  86. package/utils/crypto.js +0 -260
  87. package/utils/index.js +0 -387
  88. package/utils/jwt.js +0 -387
  89. package/utils/logger.js +0 -143
  90. package/utils/redisHelper.js +0 -74
  91. package/utils/sqlManager.js +0 -471
  92. package/utils/tool.js +0 -31
  93. package/utils/validate.js +0 -228
@@ -1,12 +1,30 @@
1
1
  /**
2
- * SQL 构造器 - 生产级稳定版本
2
+ * SQL 构建器 - TypeScript 版本
3
+ * 提供类型安全的 SQL 查询构建功能
3
4
  */
4
- export class SqlBuilder {
5
- constructor() {
6
- this.reset();
7
- }
8
5
 
9
- reset() {
6
+ import type { OrderDirection, SqlValue } from '../types/common.js';
7
+ import type { SqlQuery, WhereOperator, WhereConditions, InsertData, UpdateData } from '../types/database';
8
+
9
+ /**
10
+ * SQL 构建器类
11
+ */
12
+ export class SqlBuilder {
13
+ private _select: string[] = [];
14
+ private _from: string = '';
15
+ private _where: string[] = [];
16
+ private _joins: string[] = [];
17
+ private _orderBy: string[] = [];
18
+ private _groupBy: string[] = [];
19
+ private _having: string[] = [];
20
+ private _limit: number | null = null;
21
+ private _offset: number | null = null;
22
+ private _params: SqlValue[] = [];
23
+
24
+ /**
25
+ * 重置构建器状态
26
+ */
27
+ reset(): this {
10
28
  this._select = [];
11
29
  this._from = '';
12
30
  this._where = [];
@@ -20,16 +38,17 @@ export class SqlBuilder {
20
38
  return this;
21
39
  }
22
40
 
23
- // 字段转义方法 - 处理字段名和表名的着重号转义
24
- _escapeField(field) {
41
+ /**
42
+ * 转义字段名
43
+ */
44
+ private _escapeField(field: string): string {
25
45
  if (typeof field !== 'string') {
26
46
  return field;
27
47
  }
28
48
 
29
- // 去除前后空格
30
49
  field = field.trim();
31
50
 
32
- // 如果是 * 或已经有着重号,直接返回
51
+ // 如果是 * 或已经有着重号或包含函数,直接返回
33
52
  if (field === '*' || field.startsWith('`') || field.includes('(')) {
34
53
  return field;
35
54
  }
@@ -48,7 +67,6 @@ export class SqlBuilder {
48
67
  return parts
49
68
  .map((part) => {
50
69
  part = part.trim();
51
- // 如果是 * 或已经有着重号,不再处理
52
70
  if (part === '*' || part.startsWith('`')) {
53
71
  return part;
54
72
  }
@@ -61,15 +79,16 @@ export class SqlBuilder {
61
79
  return `\`${field}\``;
62
80
  }
63
81
 
64
- // 转义表名
65
- _escapeTable(table) {
82
+ /**
83
+ * 转义表名
84
+ */
85
+ private _escapeTable(table: string): string {
66
86
  if (typeof table !== 'string') {
67
87
  return table;
68
88
  }
69
89
 
70
90
  table = table.trim();
71
91
 
72
- // 如果已经有着重号,直接返回
73
92
  if (table.startsWith('`')) {
74
93
  return table;
75
94
  }
@@ -78,12 +97,10 @@ export class SqlBuilder {
78
97
  if (table.includes(' ')) {
79
98
  const parts = table.split(/\s+/);
80
99
  if (parts.length === 2) {
81
- // 只有表名和别名的情况
82
100
  const tableName = parts[0].trim();
83
101
  const alias = parts[1].trim();
84
102
  return `\`${tableName}\` ${alias}`;
85
103
  } else {
86
- // 复杂情况,直接返回
87
104
  return table;
88
105
  }
89
106
  }
@@ -91,35 +108,19 @@ export class SqlBuilder {
91
108
  return `\`${table}\``;
92
109
  }
93
110
 
94
- select(fields = '*') {
95
- if (Array.isArray(fields)) {
96
- this._select = [...this._select, ...fields.map((field) => this._escapeField(field))];
97
- } else if (typeof fields === 'string') {
98
- this._select.push(this._escapeField(fields));
99
- } else {
100
- throw new Error('SELECT fields must be string or array');
101
- }
102
- return this;
103
- }
104
-
105
- from(table) {
106
- if (typeof table !== 'string' || !table.trim()) {
107
- throw new Error('FROM table must be a non-empty string');
108
- }
109
- this._from = this._escapeTable(table.trim());
110
- return this;
111
- }
112
-
113
- // 安全的参数验证
114
- _validateParam(value) {
111
+ /**
112
+ * 验证参数
113
+ */
114
+ private _validateParam(value: any): void {
115
115
  if (value === undefined) {
116
- throw new Error('Parameter value cannot be undefined');
116
+ throw new Error('参数值不能为 undefined');
117
117
  }
118
- return value;
119
118
  }
120
119
 
121
- // 处理复杂的 where 条件对象
122
- _processWhereConditions(whereObj) {
120
+ /**
121
+ * 处理复杂的 WHERE 条件对象
122
+ */
123
+ private _processWhereConditions(whereObj: WhereConditions): void {
123
124
  if (!whereObj || typeof whereObj !== 'object') {
124
125
  return;
125
126
  }
@@ -136,8 +137,8 @@ export class SqlBuilder {
136
137
  }
137
138
  } else if (key === '$or') {
138
139
  if (Array.isArray(value)) {
139
- const orConditions = [];
140
- const tempParams = [];
140
+ const orConditions: string[] = [];
141
+ const tempParams: SqlValue[] = [];
141
142
 
142
143
  value.forEach((condition) => {
143
144
  const tempBuilder = new SqlBuilder();
@@ -158,13 +159,12 @@ export class SqlBuilder {
158
159
  const lastDollarIndex = key.lastIndexOf('$');
159
160
  const fieldName = key.substring(0, lastDollarIndex);
160
161
  const escapedFieldName = this._escapeField(fieldName);
161
- const operator = '$' + key.substring(lastDollarIndex + 1);
162
-
163
- this._validateParam(value);
162
+ const operator = ('$' + key.substring(lastDollarIndex + 1)) as WhereOperator;
164
163
 
165
164
  switch (operator) {
166
165
  case '$ne':
167
166
  case '$not':
167
+ this._validateParam(value);
168
168
  this._where.push(`${escapedFieldName} != ?`);
169
169
  this._params.push(value);
170
170
  break;
@@ -184,26 +184,32 @@ export class SqlBuilder {
184
184
  }
185
185
  break;
186
186
  case '$like':
187
+ this._validateParam(value);
187
188
  this._where.push(`${escapedFieldName} LIKE ?`);
188
189
  this._params.push(value);
189
190
  break;
190
191
  case '$notLike':
192
+ this._validateParam(value);
191
193
  this._where.push(`${escapedFieldName} NOT LIKE ?`);
192
194
  this._params.push(value);
193
195
  break;
194
196
  case '$gt':
197
+ this._validateParam(value);
195
198
  this._where.push(`${escapedFieldName} > ?`);
196
199
  this._params.push(value);
197
200
  break;
198
201
  case '$gte':
202
+ this._validateParam(value);
199
203
  this._where.push(`${escapedFieldName} >= ?`);
200
204
  this._params.push(value);
201
205
  break;
202
206
  case '$lt':
207
+ this._validateParam(value);
203
208
  this._where.push(`${escapedFieldName} < ?`);
204
209
  this._params.push(value);
205
210
  break;
206
211
  case '$lte':
212
+ this._validateParam(value);
207
213
  this._where.push(`${escapedFieldName} <= ?`);
208
214
  this._params.push(value);
209
215
  break;
@@ -230,26 +236,127 @@ export class SqlBuilder {
230
236
  }
231
237
  break;
232
238
  default:
239
+ this._validateParam(value);
233
240
  this._where.push(`${escapedFieldName} = ?`);
234
241
  this._params.push(value);
235
242
  }
236
243
  } else {
237
- // 简单的等于条件
238
- this._validateParam(value);
239
- const escapedKey = this._escapeField(key);
240
- this._where.push(`${escapedKey} = ?`);
241
- this._params.push(value);
244
+ // 检查值是否为对象(嵌套条件)
245
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
246
+ // 嵌套条件:如 { age: { $gt: 18 } }
247
+ const escapedKey = this._escapeField(key);
248
+ for (const [op, val] of Object.entries(value)) {
249
+ switch (op as WhereOperator) {
250
+ case '$ne':
251
+ case '$not':
252
+ this._validateParam(val);
253
+ this._where.push(`${escapedKey} != ?`);
254
+ this._params.push(val);
255
+ break;
256
+ case '$gt':
257
+ this._validateParam(val);
258
+ this._where.push(`${escapedKey} > ?`);
259
+ this._params.push(val);
260
+ break;
261
+ case '$gte':
262
+ this._validateParam(val);
263
+ this._where.push(`${escapedKey} >= ?`);
264
+ this._params.push(val);
265
+ break;
266
+ case '$lt':
267
+ this._validateParam(val);
268
+ this._where.push(`${escapedKey} < ?`);
269
+ this._params.push(val);
270
+ break;
271
+ case '$lte':
272
+ this._validateParam(val);
273
+ this._where.push(`${escapedKey} <= ?`);
274
+ this._params.push(val);
275
+ break;
276
+ case '$like':
277
+ this._validateParam(val);
278
+ this._where.push(`${escapedKey} LIKE ?`);
279
+ this._params.push(val);
280
+ break;
281
+ case '$notLike':
282
+ this._validateParam(val);
283
+ this._where.push(`${escapedKey} NOT LIKE ?`);
284
+ this._params.push(val);
285
+ break;
286
+ case '$in':
287
+ if (Array.isArray(val) && val.length > 0) {
288
+ const placeholders = val.map(() => '?').join(',');
289
+ this._where.push(`${escapedKey} IN (${placeholders})`);
290
+ this._params.push(...val);
291
+ }
292
+ break;
293
+ case '$nin':
294
+ case '$notIn':
295
+ if (Array.isArray(val) && val.length > 0) {
296
+ const placeholders = val.map(() => '?').join(',');
297
+ this._where.push(`${escapedKey} NOT IN (${placeholders})`);
298
+ this._params.push(...val);
299
+ }
300
+ break;
301
+ case '$null':
302
+ if (val) {
303
+ this._where.push(`${escapedKey} IS NULL`);
304
+ } else {
305
+ this._where.push(`${escapedKey} IS NOT NULL`);
306
+ }
307
+ break;
308
+ default:
309
+ // 未知操作符,按等于处理
310
+ this._validateParam(val);
311
+ this._where.push(`${escapedKey} = ?`);
312
+ this._params.push(val);
313
+ }
314
+ }
315
+ } else {
316
+ // 简单的等于条件
317
+ this._validateParam(value);
318
+ const escapedKey = this._escapeField(key);
319
+ this._where.push(`${escapedKey} = ?`);
320
+ this._params.push(value);
321
+ }
242
322
  }
243
323
  });
244
324
  }
245
325
 
246
- where(condition, value = null) {
326
+ /**
327
+ * SELECT 字段
328
+ */
329
+ select(fields: string | string[] = '*'): this {
330
+ if (Array.isArray(fields)) {
331
+ this._select = [...this._select, ...fields.map((field) => this._escapeField(field))];
332
+ } else if (typeof fields === 'string') {
333
+ this._select.push(this._escapeField(fields));
334
+ } else {
335
+ throw new Error('SELECT 字段必须是字符串或数组');
336
+ }
337
+ return this;
338
+ }
339
+
340
+ /**
341
+ * FROM 表名
342
+ */
343
+ from(table: string): this {
344
+ if (typeof table !== 'string' || !table.trim()) {
345
+ throw new Error('FROM 表名必须是非空字符串');
346
+ }
347
+ this._from = this._escapeTable(table.trim());
348
+ return this;
349
+ }
350
+
351
+ /**
352
+ * WHERE 条件
353
+ */
354
+ where(condition: WhereConditions | string, value?: SqlValue): this {
247
355
  if (typeof condition === 'object' && condition !== null) {
248
- // 处理对象形式的where条件,会自动过滤undefined
249
356
  this._processWhereConditions(condition);
250
- } else if (value !== null) {
357
+ } else if (value !== undefined && value !== null) {
251
358
  this._validateParam(value);
252
- const escapedCondition = this._escapeField(condition);
359
+ const escapedCondition = this._escapeField(condition as string);
253
360
  this._where.push(`${escapedCondition} = ?`);
254
361
  this._params.push(value);
255
362
  } else if (typeof condition === 'string') {
@@ -258,35 +365,42 @@ export class SqlBuilder {
258
365
  return this;
259
366
  }
260
367
 
261
- leftJoin(table, on) {
368
+ /**
369
+ * LEFT JOIN
370
+ */
371
+ leftJoin(table: string, on: string): this {
262
372
  if (typeof table !== 'string' || typeof on !== 'string') {
263
- throw new Error('JOIN table and condition must be strings');
373
+ throw new Error('JOIN 表名和条件必须是字符串');
264
374
  }
265
375
  const escapedTable = this._escapeTable(table);
266
376
  this._joins.push(`LEFT JOIN ${escapedTable} ON ${on}`);
267
377
  return this;
268
378
  }
269
379
 
270
- orderBy(fields) {
380
+ /**
381
+ * ORDER BY
382
+ * @param fields - 格式为 ["field#ASC", "field2#DESC"]
383
+ */
384
+ orderBy(fields: string[]): this {
271
385
  if (!Array.isArray(fields)) {
272
- throw new Error('orderBy must be an array of strings in "field#direction" format');
386
+ throw new Error('orderBy 必须是字符串数组,格式为 "字段#方向"');
273
387
  }
274
388
 
275
389
  fields.forEach((item) => {
276
390
  if (typeof item !== 'string' || !item.includes('#')) {
277
- throw new Error('orderBy field must be a string in "field#direction" format (e.g., "name#ASC", "id#DESC")');
391
+ throw new Error('orderBy 字段必须是 "字段#方向" 格式的字符串(例如:"name#ASC", "id#DESC"');
278
392
  }
279
393
 
280
394
  const [fieldName, direction] = item.split('#');
281
395
  const cleanField = fieldName.trim();
282
- const cleanDir = direction.trim().toUpperCase();
396
+ const cleanDir = direction.trim().toUpperCase() as OrderDirection;
283
397
 
284
398
  if (!cleanField) {
285
- throw new Error('Field name cannot be empty in orderBy');
399
+ throw new Error('orderBy 中字段名不能为空');
286
400
  }
287
401
 
288
402
  if (!['ASC', 'DESC'].includes(cleanDir)) {
289
- throw new Error('ORDER BY direction must be ASC or DESC');
403
+ throw new Error('ORDER BY 方向必须是 ASC DESC');
290
404
  }
291
405
 
292
406
  const escapedField = this._escapeField(cleanField);
@@ -296,7 +410,10 @@ export class SqlBuilder {
296
410
  return this;
297
411
  }
298
412
 
299
- groupBy(field) {
413
+ /**
414
+ * GROUP BY
415
+ */
416
+ groupBy(field: string | string[]): this {
300
417
  if (Array.isArray(field)) {
301
418
  const escapedFields = field.filter((f) => typeof f === 'string').map((f) => this._escapeField(f));
302
419
  this._groupBy = [...this._groupBy, ...escapedFields];
@@ -306,43 +423,54 @@ export class SqlBuilder {
306
423
  return this;
307
424
  }
308
425
 
309
- having(condition) {
426
+ /**
427
+ * HAVING
428
+ */
429
+ having(condition: string): this {
310
430
  if (typeof condition === 'string') {
311
431
  this._having.push(condition);
312
432
  }
313
433
  return this;
314
434
  }
315
435
 
316
- limit(count, offset = null) {
436
+ /**
437
+ * LIMIT
438
+ */
439
+ limit(count: number, offset?: number): this {
317
440
  if (typeof count !== 'number' || count < 0) {
318
- throw new Error('LIMIT count must be a non-negative number');
441
+ throw new Error('LIMIT 数量必须是非负数');
319
442
  }
320
443
  this._limit = Math.floor(count);
321
- if (offset !== null) {
444
+ if (offset !== undefined && offset !== null) {
322
445
  if (typeof offset !== 'number' || offset < 0) {
323
- throw new Error('OFFSET must be a non-negative number');
446
+ throw new Error('OFFSET 必须是非负数');
324
447
  }
325
448
  this._offset = Math.floor(offset);
326
449
  }
327
450
  return this;
328
451
  }
329
452
 
330
- offset(count) {
453
+ /**
454
+ * OFFSET
455
+ */
456
+ offset(count: number): this {
331
457
  if (typeof count !== 'number' || count < 0) {
332
- throw new Error('OFFSET must be a non-negative number');
458
+ throw new Error('OFFSET 必须是非负数');
333
459
  }
334
460
  this._offset = Math.floor(count);
335
461
  return this;
336
462
  }
337
463
 
338
- // 构建 SELECT 查询
339
- toSelectSql() {
464
+ /**
465
+ * 构建 SELECT 查询
466
+ */
467
+ toSelectSql(): SqlQuery {
340
468
  let sql = 'SELECT ';
341
469
 
342
470
  sql += this._select.length > 0 ? this._select.join(', ') : '*';
343
471
 
344
472
  if (!this._from) {
345
- throw new Error('FROM table is required');
473
+ throw new Error('FROM 表名是必需的');
346
474
  }
347
475
  sql += ` FROM ${this._from}`;
348
476
 
@@ -376,26 +504,28 @@ export class SqlBuilder {
376
504
  return { sql, params: [...this._params] };
377
505
  }
378
506
 
379
- // 构建 INSERT 查询
380
- toInsertSql(table, data) {
507
+ /**
508
+ * 构建 INSERT 查询
509
+ */
510
+ toInsertSql(table: string, data: InsertData): SqlQuery {
381
511
  if (!table || typeof table !== 'string') {
382
- throw new Error('Table name is required for INSERT');
512
+ throw new Error('INSERT 需要表名');
383
513
  }
384
514
 
385
515
  if (!data || typeof data !== 'object') {
386
- throw new Error('Data is required for INSERT');
516
+ throw new Error('INSERT 需要数据');
387
517
  }
388
518
 
389
519
  const escapedTable = this._escapeTable(table);
390
520
 
391
521
  if (Array.isArray(data)) {
392
522
  if (data.length === 0) {
393
- throw new Error('Insert data cannot be empty');
523
+ throw new Error('插入数据不能为空');
394
524
  }
395
525
 
396
526
  const fields = Object.keys(data[0]);
397
527
  if (fields.length === 0) {
398
- throw new Error('Insert data must have at least one field');
528
+ throw new Error('插入数据必须至少有一个字段');
399
529
  }
400
530
 
401
531
  const escapedFields = fields.map((field) => this._escapeField(field));
@@ -409,7 +539,7 @@ export class SqlBuilder {
409
539
  } else {
410
540
  const fields = Object.keys(data);
411
541
  if (fields.length === 0) {
412
- throw new Error('Insert data must have at least one field');
542
+ throw new Error('插入数据必须至少有一个字段');
413
543
  }
414
544
 
415
545
  const escapedFields = fields.map((field) => this._escapeField(field));
@@ -421,40 +551,44 @@ export class SqlBuilder {
421
551
  }
422
552
  }
423
553
 
424
- // 构建 UPDATE 查询
425
- toUpdateSql(table, data) {
554
+ /**
555
+ * 构建 UPDATE 查询
556
+ */
557
+ toUpdateSql(table: string, data: UpdateData): SqlQuery {
426
558
  if (!table || typeof table !== 'string') {
427
- throw new Error('Table name is required for UPDATE');
559
+ throw new Error('UPDATE 需要表名');
428
560
  }
429
561
 
430
562
  if (!data || typeof data !== 'object' || Array.isArray(data)) {
431
- throw new Error('Data object is required for UPDATE');
563
+ throw new Error('UPDATE 需要数据对象');
432
564
  }
433
565
 
434
566
  const fields = Object.keys(data);
435
567
  if (fields.length === 0) {
436
- throw new Error('Update data must have at least one field');
568
+ throw new Error('更新数据必须至少有一个字段');
437
569
  }
438
570
 
439
571
  const escapedTable = this._escapeTable(table);
440
572
  const setFields = fields.map((field) => `${this._escapeField(field)} = ?`);
441
- const params = [...Object.values(data), ...this._params];
573
+ const params: SqlValue[] = [...Object.values(data), ...this._params];
442
574
 
443
575
  let sql = `UPDATE ${escapedTable} SET ${setFields.join(', ')}`;
444
576
 
445
577
  if (this._where.length > 0) {
446
578
  sql += ' WHERE ' + this._where.join(' AND ');
447
579
  } else {
448
- throw new Error('UPDATE requires WHERE condition for safety');
580
+ throw new Error('为安全起见,UPDATE 需要 WHERE 条件');
449
581
  }
450
582
 
451
583
  return { sql, params };
452
584
  }
453
585
 
454
- // 构建 DELETE 查询
455
- toDeleteSql(table) {
586
+ /**
587
+ * 构建 DELETE 查询
588
+ */
589
+ toDeleteSql(table: string): SqlQuery {
456
590
  if (!table || typeof table !== 'string') {
457
- throw new Error('Table name is required for DELETE');
591
+ throw new Error('DELETE 需要表名');
458
592
  }
459
593
 
460
594
  const escapedTable = this._escapeTable(table);
@@ -463,18 +597,20 @@ export class SqlBuilder {
463
597
  if (this._where.length > 0) {
464
598
  sql += ' WHERE ' + this._where.join(' AND ');
465
599
  } else {
466
- throw new Error('DELETE requires WHERE condition for safety');
600
+ throw new Error('为安全起见,DELETE 需要 WHERE 条件');
467
601
  }
468
602
 
469
603
  return { sql, params: [...this._params] };
470
604
  }
471
605
 
472
- // 构建 COUNT 查询
473
- toCountSql() {
606
+ /**
607
+ * 构建 COUNT 查询
608
+ */
609
+ toCountSql(): SqlQuery {
474
610
  let sql = 'SELECT COUNT(*) as total';
475
611
 
476
612
  if (!this._from) {
477
- throw new Error('FROM table is required for COUNT');
613
+ throw new Error('COUNT 需要 FROM 表名');
478
614
  }
479
615
  sql += ` FROM ${this._from}`;
480
616
 
@@ -491,8 +627,8 @@ export class SqlBuilder {
491
627
  }
492
628
 
493
629
  /**
494
- * 创建新的 SQL 构造器实例
630
+ * 创建新的 SQL 构建器实例
495
631
  */
496
- export function createQueryBuilder() {
632
+ export function createQueryBuilder(): SqlBuilder {
497
633
  return new SqlBuilder();
498
634
  }