mm_mysql 2.0.2 → 2.0.4

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/sql.js CHANGED
@@ -33,7 +33,7 @@ class Sql {
33
33
  * @param {Object} value 值
34
34
  * @return {String} 返回执行结果
35
35
  */
36
- this.escape = function(value) {
36
+ this.escape = function (value) {
37
37
  return escape(value);
38
38
  };
39
39
 
@@ -42,7 +42,7 @@ class Sql {
42
42
  * @param {String} key 键
43
43
  * @return {String} 返回执行结果
44
44
  */
45
- this.escapeId = function(key) {
45
+ this.escapeId = function (key) {
46
46
  return escapeId(key);
47
47
  };
48
48
 
@@ -146,7 +146,7 @@ class Sql {
146
146
  /**
147
147
  * 清理存储的数据
148
148
  */
149
- Sql.prototype.clear = async function() {
149
+ Sql.prototype.clear = async function () {
150
150
  this.run = run;
151
151
  this.exec = exec;
152
152
  this.sql = "";
@@ -165,7 +165,7 @@ Sql.prototype.clear = async function() {
165
165
  * 过滤查询参数
166
166
  * @param {Object} query 查询参数
167
167
  */
168
- Sql.prototype.filter = function(query) {
168
+ Sql.prototype.filter = function (query) {
169
169
  var m = this.config.filter;
170
170
  for (var k in m) {
171
171
  var key = m[k];
@@ -183,7 +183,7 @@ Sql.prototype.filter = function(query) {
183
183
  * @param {String} view 返回的字段
184
184
  * @return {String} 返回查询条件语句
185
185
  */
186
- Sql.prototype.toQuery = function(where, sort, view) {
186
+ Sql.prototype.toQuery = function (where, sort, view) {
187
187
  var sql = "SELECT {1} FROM `{0}`";
188
188
  if (!view) {
189
189
  view = "*";
@@ -208,7 +208,7 @@ Sql.prototype.toQuery = function(where, sort, view) {
208
208
  * @param {String} val 用作增加的值集合
209
209
  * @return {Promise|Object} 执行结果
210
210
  */
211
- Sql.prototype.addSql = function(key, val) {
211
+ Sql.prototype.addSql = function (key, val) {
212
212
  var sql = "INSERT INTO `{0}` ({1}) VALUES ({2});";
213
213
  sql = sql.replace("{0}", this.table).replace("{1}", key).replace("{2}", val);
214
214
  return this.exec(sql);
@@ -218,7 +218,7 @@ Sql.prototype.addSql = function(key, val) {
218
218
  * @param {String} where 删除条件
219
219
  * @return {Promise|Object} 执行结果
220
220
  */
221
- Sql.prototype.delSql = function(where) {
221
+ Sql.prototype.delSql = function (where) {
222
222
  var sql = "DELETE FROM `{0}` WHERE {1};";
223
223
  sql = sql.replace("{0}", this.table).replace("{1}", where);
224
224
  return this.exec(sql);
@@ -229,7 +229,7 @@ Sql.prototype.delSql = function(where) {
229
229
  * @param {String} set 修改的键值
230
230
  * @return {Promise|Object} 执行结果
231
231
  */
232
- Sql.prototype.setSql = function(where, set) {
232
+ Sql.prototype.setSql = function (where, set) {
233
233
  var sql = "UPDATE `{0}` SET {1} WHERE {2};";
234
234
  sql = sql.replace("{0}", this.table).replace("{1}", set).replace("{2}", where);
235
235
  return this.exec(sql);
@@ -241,7 +241,7 @@ Sql.prototype.setSql = function(where, set) {
241
241
  * @param {String} view 显示的字段
242
242
  * @return {Promise|Array} 查询结果数组
243
243
  */
244
- Sql.prototype.getSql = function(where, sort, view) {
244
+ Sql.prototype.getSql = function (where, sort, view) {
245
245
  var sql = this.toQuery(where, sort, view);
246
246
  return this.run(sql);
247
247
  };
@@ -251,7 +251,7 @@ Sql.prototype.getSql = function(where, sort, view) {
251
251
  * @param {String} where 查询条件
252
252
  * @return {Promise|Number} 返回结果总数
253
253
  */
254
- Sql.prototype.countSql = async function(where) {
254
+ Sql.prototype.countSql = async function (where) {
255
255
  var sql = "SELECT count(*) count FROM `" + this.table + "`";
256
256
  if (where) {
257
257
  sql += ' WHERE ' + where;
@@ -271,7 +271,7 @@ Sql.prototype.countSql = async function(where) {
271
271
  * @param {String} view 返回的字段
272
272
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
273
273
  */
274
- Sql.prototype.getCountSql = async function(where, sort, view) {
274
+ Sql.prototype.getCountSql = async function (where, sort, view) {
275
275
  var list = [];
276
276
  var count = await this.countSql(where);
277
277
  if (count > 0) {
@@ -292,7 +292,7 @@ Sql.prototype.getCountSql = async function(where, sort, view) {
292
292
  * @param {String} sort 排序方式
293
293
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
294
294
  */
295
- Sql.prototype.groupMathSql = async function(where, groupby, view, sort, method) {
295
+ Sql.prototype.groupMathSql = async function (where, groupby, view, sort, method) {
296
296
  if (!view) {
297
297
  view = "*"
298
298
  }
@@ -334,7 +334,7 @@ Sql.prototype.groupMathSql = async function(where, groupby, view, sort, method)
334
334
  * @param {String} sort 排序方式
335
335
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
336
336
  */
337
- Sql.prototype.groupAvgSql = async function(where, groupby, view, sort) {
337
+ Sql.prototype.groupAvgSql = async function (where, groupby, view, sort) {
338
338
  return await this.groupMathSql(where, groupby, view, sort, "AVG");
339
339
  };
340
340
 
@@ -346,7 +346,7 @@ Sql.prototype.groupAvgSql = async function(where, groupby, view, sort) {
346
346
  * @param {String} sort 排序方式
347
347
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
348
348
  */
349
- Sql.prototype.groupSumSql = async function(where, groupby, view, sort) {
349
+ Sql.prototype.groupSumSql = async function (where, groupby, view, sort) {
350
350
  return await this.groupMathSql(where, groupby, view, sort, "SUM");
351
351
  };
352
352
 
@@ -357,7 +357,7 @@ Sql.prototype.groupSumSql = async function(where, groupby, view, sort) {
357
357
  * @param {String} view 返回的字段
358
358
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
359
359
  */
360
- Sql.prototype.groupCountSql = async function(where, groupby, view, sort) {
360
+ Sql.prototype.groupCountSql = async function (where, groupby, view, sort) {
361
361
  return await this.groupMathSql(where, groupby, view, sort, "COUNT");
362
362
  };
363
363
 
@@ -370,7 +370,7 @@ Sql.prototype.groupCountSql = async function(where, groupby, view, sort) {
370
370
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
371
371
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
372
372
  */
373
- Sql.prototype.groupMath = async function(query, groupby, view, sort, method, like) {
373
+ Sql.prototype.groupMath = async function (query, groupby, view, sort, method, like) {
374
374
  var where = this.toWhere(query, like);
375
375
  return await this.groupMathSql(where, groupby, view, sort, method);
376
376
  };
@@ -383,7 +383,7 @@ Sql.prototype.groupMath = async function(query, groupby, view, sort, method, lik
383
383
  * @param {String} sort 排序方式
384
384
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
385
385
  */
386
- Sql.prototype.groupAvg = async function(query, groupby, view, sort) {
386
+ Sql.prototype.groupAvg = async function (query, groupby, view, sort) {
387
387
  return await this.groupMath(query, groupby, view, sort, "AVG");
388
388
  };
389
389
 
@@ -395,7 +395,7 @@ Sql.prototype.groupAvg = async function(query, groupby, view, sort) {
395
395
  * @param {String} sort 排序方式
396
396
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
397
397
  */
398
- Sql.prototype.groupSum = async function(query, groupby, view, sort) {
398
+ Sql.prototype.groupSum = async function (query, groupby, view, sort) {
399
399
  return await this.groupMath(query, groupby, view, sort, "SUM");
400
400
  };
401
401
 
@@ -406,7 +406,7 @@ Sql.prototype.groupSum = async function(query, groupby, view, sort) {
406
406
  * @param {String} view 返回的字段
407
407
  * @return {Promise|Object} 查询到的内容列表和符合条件总数
408
408
  */
409
- Sql.prototype.groupCount = async function(query, groupby, view, sort) {
409
+ Sql.prototype.groupCount = async function (query, groupby, view, sort) {
410
410
  return await this.groupMath(query, groupby, view, sort, "COUNT");
411
411
  };
412
412
 
@@ -417,7 +417,7 @@ Sql.prototype.groupCount = async function(query, groupby, view, sort) {
417
417
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
418
418
  * @return {String} where格式sql语句字符串
419
419
  */
420
- Sql.prototype.toWhere = function(obj, like) {
420
+ Sql.prototype.toWhere = function (obj, like) {
421
421
  var where = "";
422
422
  if (like === undefined) {
423
423
  like = this.like;
@@ -425,7 +425,7 @@ Sql.prototype.toWhere = function(obj, like) {
425
425
  if (like) {
426
426
  for (var k in obj) {
427
427
  var val = obj[k];
428
- if (val && typeof(val) === "string") {
428
+ if (val && typeof (val) === "string") {
429
429
  val = val.trim("'");
430
430
  }
431
431
  val = escape(val);
@@ -442,7 +442,7 @@ Sql.prototype.toWhere = function(obj, like) {
442
442
  where += " and " + escapeId(k.replace('_has', "")) + " in (" + vals.join(',') + ")";
443
443
  } else if (k.endWith('_like')) {
444
444
  where += " and " + escapeId(k.replace('_like', "")) + " LIKE '%" + val.trim("'") + "%'";
445
- } else if (typeof(val) === "string" && !/^[0-9]+$/.test(val)) {
445
+ } else if (typeof (val) === "string" && !/^[0-9]+$/.test(val)) {
446
446
  where += " and " + escapeId(k) + " LIKE '%" + val.trim("'") + "%'";
447
447
  } else {
448
448
  where += " and " + escapeId(k) + " = " + val;
@@ -451,7 +451,7 @@ Sql.prototype.toWhere = function(obj, like) {
451
451
  } else {
452
452
  for (var k in obj) {
453
453
  var val = obj[k];
454
- if (val && typeof(val) === "string") {
454
+ if (val && typeof (val) === "string") {
455
455
  val = val.trim("'");
456
456
  }
457
457
  val = escape(val);
@@ -481,24 +481,30 @@ Sql.prototype.toWhere = function(obj, like) {
481
481
  * @param {Object} obj 用作拼接的对象
482
482
  * @return {String} set格式sql语句字符串
483
483
  */
484
- Sql.prototype.toSet = function(obj) {
484
+ Sql.prototype.toSet = function (obj) {
485
485
  var set = "";
486
- for (var k in obj) {
487
- var val = obj[k];
488
- if (val && typeof(val) == "string") {
486
+ for (const k in obj) {
487
+ if (!Object.prototype.hasOwnProperty.call(obj, k)) continue;
488
+
489
+ let val = obj[k];
490
+ if (val === undefined || val === null) continue;
491
+
492
+ if (typeof val === "string") {
489
493
  val = val.trim("'");
490
494
  }
491
495
  val = escape(val);
496
+
492
497
  if (k.endWith('_add')) {
493
- var k2 = escapeId(k.replace('_add', ""));
498
+ const k2 = escapeId(k.replace('_add', ""));
494
499
  set += "," + k2 + " = " + k2 + " + " + val;
495
500
  } else if (k.endWith('_del')) {
496
- var k3 = escapeId(k.replace('_del', ""));
501
+ const k3 = escapeId(k.replace('_del', ""));
497
502
  set += "," + k3 + " = " + k3 + " - " + val;
498
503
  } else {
499
504
  set += "," + escapeId(k) + " = " + val;
500
505
  }
501
506
  }
507
+
502
508
  return set.replace(",", "");
503
509
  };
504
510
 
@@ -507,20 +513,31 @@ Sql.prototype.toSet = function(obj) {
507
513
  * @param {Object} item 用作添加的键值
508
514
  * @return {String} sql语句
509
515
  */
510
- Sql.prototype.toAddSql = function(item) {
511
- var key = "";
512
- var value = "";
513
- for (var k in item) {
516
+ Sql.prototype.toAddSql = function (item) {
517
+ if (!this.table || !item || typeof item !== 'object') {
518
+ throw new Error('表名或数据未设置');
519
+ }
520
+
521
+ let key = "";
522
+ let value = "";
523
+
524
+ for (const k in item) {
525
+ if (!Object.prototype.hasOwnProperty.call(item, k)) continue;
526
+
514
527
  key += "," + escapeId(k);
515
- var val = item[k];
516
- if (val && typeof(val) == "string") {
528
+ let val = item[k];
529
+ if (typeof val === "string") {
517
530
  val = val.trim("'");
518
531
  }
519
532
  value += "," + escape(val);
520
533
  }
521
- var sql = "INSERT INTO `{0}` ({1}) VALUES ({2});";
522
- return sql.replace("{0}", this.table).replace("{1}", key.replace(",", "")).replace("{2}", value.replace(",",
523
- ""));
534
+
535
+ const sql = "INSERT INTO `{0}` ({1}) VALUES ({2});"
536
+ .replace("{0}", this.table)
537
+ .replace("{1}", key.replace(",", ""))
538
+ .replace("{2}", value.replace(",", ""));
539
+
540
+ return sql;
524
541
  };
525
542
 
526
543
  /**
@@ -529,10 +546,15 @@ Sql.prototype.toAddSql = function(item) {
529
546
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
530
547
  * @return {String} sql语句
531
548
  */
532
- Sql.prototype.toDelSql = function(query, like) {
533
- var where = this.toWhere(query, like);
534
- var sql = "DELETE FROM `{0}` WHERE {1};";
535
- return sql.replace("{0}", this.table).replace("{1}", where);
549
+ Sql.prototype.toDelSql = function (query, like) {
550
+ if (!this.table) {
551
+ throw new Error('表名未设置');
552
+ }
553
+ const where = this.toWhere(query, like);
554
+ const sql = "DELETE FROM `{0}` WHERE {1};"
555
+ .replace("{0}", this.table)
556
+ .replace("{1}", where);
557
+ return sql;
536
558
  };
537
559
 
538
560
  /**
@@ -542,11 +564,17 @@ Sql.prototype.toDelSql = function(query, like) {
542
564
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
543
565
  * @return {String} sql语句
544
566
  */
545
- Sql.prototype.toSetSql = function(query, item, like) {
546
- var where = this.toWhere(query, like);
547
- var set = this.toSet(item);
548
- var sql = "UPDATE `{0}` SET {1} WHERE {2};";
549
- return sql.replace("{0}", this.table).replace("{1}", set).replace("{2}", where);
567
+ Sql.prototype.toSetSql = function (query, item, like) {
568
+ if (!this.table) {
569
+ throw new Error('表名未设置');
570
+ }
571
+ const where = this.toWhere(query, like);
572
+ const set = this.toSet(item);
573
+ const sql = "UPDATE `{0}` SET {1} WHERE {2};"
574
+ .replace("{0}", this.table)
575
+ .replace("{1}", set)
576
+ .replace("{2}", where);
577
+ return sql;
550
578
  };
551
579
 
552
580
  /**
@@ -557,30 +585,42 @@ Sql.prototype.toSetSql = function(query, item, like) {
557
585
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
558
586
  * @return {String} sql语句
559
587
  */
560
- Sql.prototype.toGetSql = function(query, sort, view, like) {
561
- var where = this.toWhere(query, like);
562
- var sql = this.toQuery(where, sort, view);
563
- return sql;
588
+ Sql.prototype.toGetSql = function (query, sort, view, like) {
589
+ const where = this.toWhere(query, like);
590
+ return this.toQuery(where, sort, view);
564
591
  };
592
+
565
593
  /* === 传入对象操作 === */
566
594
  /**
567
595
  * 增加数据
568
596
  * @param {Object} body 添加的对象
569
597
  * @return {Promise|Object} 执行结果
570
598
  */
571
- Sql.prototype.add = async function(body) {
572
- await $.eventer.run("mysql_add_before:" + this.table, {
573
- body
574
- });
575
- var sql = this.toAddSql(body);
576
- var bl = await this.exec(sql);
577
- await $.eventer.run("mysql_add_after:" + this.table, {
578
- body,
579
- sql: this.sql,
580
- error: this.error,
581
- bl
582
- });
583
- return bl
599
+ Sql.prototype.add = async function (body) {
600
+ if (!this.table || !body || typeof body !== 'object') {
601
+ throw new Error('表名或数据未设置');
602
+ }
603
+ try {
604
+ // 触发前置事件
605
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
606
+ await $.eventer.run("mysql_add_before:" + this.table, { body });
607
+ }
608
+
609
+ const sql = this.toAddSql(body);
610
+ this.sql = sql;
611
+ const bl = await this.exec(sql);
612
+
613
+ // 触发后置事件
614
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
615
+ await $.eventer.run("mysql_add_after:" + this.table, { body, sql: this.sql, error: this.error, bl });
616
+ }
617
+
618
+ return bl;
619
+ } catch (err) {
620
+ this.error = err.message;
621
+ $.log.error(`添加数据失败: ${err.message}`);
622
+ throw err;
623
+ }
584
624
  };
585
625
 
586
626
  /**
@@ -589,21 +629,31 @@ Sql.prototype.add = async function(body) {
589
629
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
590
630
  * @return {Promise|Object} 执行结果
591
631
  */
592
- Sql.prototype.del = async function(query, like) {
593
- await $.eventer.run("mysql_del_before:" + this.table, {
594
- query,
595
- like
596
- });
597
- var sql = this.toDelSql(query, like);
598
- var bl = await this.exec(sql);
599
- await $.eventer.run("mysql_del_after:" + this.table, {
600
- query,
601
- like,
602
- sql: this.sql,
603
- error: this.error,
604
- bl
605
- });
606
- return bl
632
+ Sql.prototype.del = async function (query, like) {
633
+ if (!this.table) {
634
+ throw new Error('表名未设置');
635
+ }
636
+ try {
637
+ // 触发前置事件
638
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
639
+ await $.eventer.run("mysql_del_before:" + this.table, { query, like });
640
+ }
641
+
642
+ const sql = this.toDelSql(query, like);
643
+ this.sql = sql;
644
+ const bl = await this.exec(sql);
645
+
646
+ // 触发后置事件
647
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
648
+ await $.eventer.run("mysql_del_after:" + this.table, { query, like, sql: this.sql, error: this.error, bl });
649
+ }
650
+
651
+ return bl;
652
+ } catch (err) {
653
+ this.error = err.message;
654
+ $.log.error(`删除数据失败: ${err.message}`);
655
+ throw err;
656
+ }
607
657
  };
608
658
 
609
659
  /**
@@ -613,111 +663,120 @@ Sql.prototype.del = async function(query, like) {
613
663
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
614
664
  * @return {Promise|Object} 执行结果
615
665
  */
616
- Sql.prototype.set = async function(query, body, like) {
617
- await $.eventer.run("mysql_set_before:" + this.table, {
618
- query,
619
- body,
620
- like,
621
- page: this.page,
622
- size: this.size
623
- });
624
- var sql = this.toSetSql(query, body, like);
625
- var bl = await this.exec(sql);
626
- await $.eventer.run("mysql_set_after:" + this.table, {
627
- query,
628
- body,
629
- like,
630
- page: this.page,
631
- size: this.size,
632
- sql: this.sql,
633
- error: this.error,
634
- bl
635
- });
636
- return bl
666
+ Sql.prototype.set = async function (query, body, like) {
667
+ if (!this.table || !body || typeof body !== 'object') {
668
+ throw new Error('表名或数据未设置');
669
+ }
670
+ try {
671
+ // 触发前置事件
672
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
673
+ await $.eventer.run("mysql_set_before:" + this.table, { query, body, like, page: this.page, size: this.size });
674
+ }
675
+
676
+ const sql = this.toSetSql(query, body, like);
677
+ this.sql = sql;
678
+ const bl = await this.exec(sql);
679
+
680
+ // 触发后置事件
681
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
682
+ await $.eventer.run("mysql_set_after:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql, error: this.error, bl });
683
+ }
684
+
685
+ return bl;
686
+ } catch (err) {
687
+ this.error = err.message;
688
+ $.log.error(`修改数据失败: ${err.message}`);
689
+ throw err;
690
+ }
637
691
  };
638
692
 
639
693
  /**
640
694
  * 添加或修改
641
- * @param {String} where 查询条件
642
- * @param {String} set 修改的键值
695
+ * @param {String|Object} where 查询条件
696
+ * @param {String|Object} set 修改的键值
643
697
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
644
698
  * @return {Promise|Object} 执行结果
645
699
  */
646
- Sql.prototype.addOrSetSql = async function(where, set, like) {
647
- if (!where || !set) {
648
- return -1;
649
- }
650
- var query = where;
651
- var body = set;
652
- if (typeof(where) === "object") {
653
- where = await this.toWhere(where, like);
700
+ Sql.prototype.addOrSetSql = async function (where, set, like) {
701
+ if (!this.table || !where || !set) {
702
+ throw new Error('表名、条件或数据未设置');
654
703
  }
655
- var count = await this.countSql(where);
656
- if (count === 0) {
657
- var key = "";
658
- var value = "";
659
- if (typeof(set) === "string") {
660
- var arr = set.split(",");
661
- for (var i = 0; i < arr.length; i++) {
662
- var o = arr[i];
663
- var ar = o.split('=');
664
- if (ar.length === 2) {
665
- key += "," + ar[0];
666
- value += "," + ar[1];
704
+ try {
705
+ let query = where;
706
+ let body = set;
707
+ let whereStr;
708
+
709
+ if (typeof where === "object") {
710
+ whereStr = await this.toWhere(where, like);
711
+ } else {
712
+ whereStr = where;
713
+ }
714
+
715
+ const count = await this.countSql(whereStr);
716
+
717
+ if (count === 0) {
718
+ let key = "";
719
+ let value = "";
720
+
721
+ if (typeof set === "string") {
722
+ const arr = set.split(",");
723
+ for (const o of arr) {
724
+ const ar = o.split('=');
725
+ if (ar.length === 2) {
726
+ key += "," + ar[0];
727
+ value += "," + ar[1];
728
+ }
729
+ }
730
+ } else {
731
+ // 触发前置事件
732
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
733
+ await $.eventer.run("mysql_add_before:" + this.table, { body });
734
+ }
735
+
736
+ for (const k in set) {
737
+ if (!Object.prototype.hasOwnProperty.call(set, k)) continue;
738
+
739
+ key += "," + escapeId(k);
740
+ let val = set[k];
741
+ if (typeof val === "string") {
742
+ val = val.trim("'");
743
+ }
744
+ value += "," + escape(val);
667
745
  }
668
746
  }
747
+
748
+ const bl = await this.addSql(key.replace(",", ""), value.replace(",", ""));
749
+
750
+ // 触发后置事件
751
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
752
+ await $.eventer.run("mysql_add_after:" + this.table, { body, sql: this.sql, error: this.error, bl });
753
+ }
754
+
755
+ return bl;
669
756
  } else {
670
- if (typeof(body) === "object") {
671
- await $.eventer.run("mysql_add_before:" + this.table, {
672
- body
673
- });
757
+ // 触发前置事件
758
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof set === "object") {
759
+ await $.eventer.run("mysql_set_before:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql });
674
760
  }
675
- for (var k in set) {
676
- key += "," + escapeId(k);
677
- var val = set[k];
678
- if (val && typeof(val) === "string") {
679
- val = val.trim("'");
680
- }
681
- value += "," + escape(val);
761
+
762
+ if (typeof set === "object") {
763
+ set = await this.toSet(set);
682
764
  }
683
- }
684
- var bl = await this.addSql(key.replace(",", ""), value.replace(",", ""));
685
- if (typeof(body) === "object") {
686
- await $.eventer.run("mysql_add_after:" + this.table, {
687
- body,
688
- sql: this.sql,
689
- error: this.error,
690
- bl
691
- });
692
- }
693
- return bl
694
- }
695
765
 
696
- if (typeof(set) === "object") {
697
- await $.eventer.run("mysql_set_before:" + this.table, {
698
- query,
699
- body,
700
- like,
701
- page: this.page,
702
- size: this.size,
703
- sql: this.sql
704
- });
705
- set = await this.toSet(set);
706
- }
707
- var bl1 = await this.setSql(where, set);
708
- if (typeof(body) === "object") {
709
- await $.eventer.run("mysql_set_after:" + this.table, {
710
- query,
711
- body,
712
- like,
713
- page: this.page,
714
- size: this.size,
715
- sql: this.sql,
716
- error: this.error,
717
- bl: bl1
718
- });
766
+ const bl1 = await this.setSql(whereStr, set);
767
+
768
+ // 触发后置事件
769
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
770
+ await $.eventer.run("mysql_set_after:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql, error: this.error, bl: bl1 });
771
+ }
772
+
773
+ return bl1;
774
+ }
775
+ } catch (err) {
776
+ this.error = err.message;
777
+ $.log.error(`添加或修改数据失败: ${err.message}`);
778
+ throw err;
719
779
  }
720
- return bl1
721
780
  };
722
781
 
723
782
  /**
@@ -726,129 +785,201 @@ Sql.prototype.addOrSetSql = async function(where, set, like) {
726
785
  * @param {String} sort 排序
727
786
  * @param {String} view 返回的字段
728
787
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
788
+ * @param {Number} timeout 超时时间(毫秒),默认30000ms
729
789
  * @return {Promise|Array} 查询结果
730
790
  */
731
- Sql.prototype.get = async function(query, sort, view, like) {
732
- await $.eventer.run("mysql_get_before:" + this.table, {
733
- query,
734
- sort,
735
- view,
736
- like,
737
- page: this.page,
738
- size: this.size
739
- });
740
- var sql = this.toGetSql(query, sort, view, like);
741
- var list = await this.run(sql);
742
- await $.eventer.run("mysql_get_after:" + this.table, {
743
- query,
744
- sort,
745
- view,
746
- like,
747
- page: this.page,
748
- size: this.size,
749
- sql: this.sql,
750
- error: this.error,
751
- list
752
- });
753
- return list
791
+ Sql.prototype.get = async function (query, sort, view, like, timeout = 30000) {
792
+ if (!this.table) {
793
+ throw new Error('表名未设置');
794
+ }
795
+
796
+ try {
797
+ // 添加超时控制的Promise
798
+ const timeoutPromise = new Promise((_, reject) => {
799
+ setTimeout(() => reject(new Error('查询操作超时')), timeout);
800
+ });
801
+
802
+ // 使用Promise.race实现超时控制
803
+ return await Promise.race([
804
+ (async () => {
805
+ // 安全触发事件,避免事件系统问题影响核心功能
806
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
807
+ try {
808
+ // 添加超时保护的事件触发
809
+ await Promise.race([
810
+ $.eventer.run("mysql_get_before:" + this.table, {
811
+ query,
812
+ sort,
813
+ view,
814
+ like,
815
+ page: this.page,
816
+ size: this.size
817
+ }),
818
+ new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
819
+ ]);
820
+ } catch (eventError) {
821
+ $.log.warn(`事件处理失败,但不影响查询: ${eventError.message}`);
822
+ }
823
+ }
824
+
825
+ // 生成SQL并执行
826
+ const sql = this.toGetSql(query, sort, view, like);
827
+ this.sql = sql;
828
+ const list = await this.run(sql);
829
+
830
+ // 安全触发后置事件
831
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
832
+ try {
833
+ // 添加超时保护的事件触发
834
+ await Promise.race([
835
+ $.eventer.run("mysql_get_after:" + this.table, {
836
+ query,
837
+ sort,
838
+ view,
839
+ like,
840
+ page: this.page,
841
+ size: this.size,
842
+ sql: this.sql,
843
+ error: this.error,
844
+ list
845
+ }),
846
+ new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
847
+ ]);
848
+ } catch (eventError) {
849
+ $.log.warn(`事件处理失败,但不影响查询返回: ${eventError.message}`);
850
+ }
851
+ }
852
+
853
+ return list;
854
+ })(),
855
+ timeoutPromise
856
+ ]);
857
+ } catch (err) {
858
+ this.error = err.message;
859
+ $.log.error(`查询数据失败: ${err.message}`, { sql: this.sql });
860
+ throw err;
861
+ }
754
862
  };
755
863
 
756
864
  /**
757
- * 查询一条数据
865
+ * 查询单条数据
758
866
  * @param {Object} query 查询条件
759
867
  * @param {String} sort 排序
760
868
  * @param {String} view 返回的字段
761
869
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
762
- * @return {Promise|Array} 查询结果
870
+ * @param {Number} timeout 超时时间(毫秒),默认30000ms
871
+ * @return {Promise|Object|null} 查询结果
763
872
  */
764
- Sql.prototype.getObj = async function(query, sort, view, like) {
765
- await $.eventer.run("mysql_getObj_before:" + this.table, {
766
- query,
767
- sort,
768
- view,
769
- like
770
- });
873
+ Sql.prototype.getObj = async function (query, sort, view, like, timeout = 30000) {
874
+ try {
875
+ // 保存当前分页设置
876
+ const oldPage = this.page;
877
+ const oldSize = this.size;
771
878
 
772
- this.page = 1;
773
- this.size = 1;
774
- var key = this.key;
775
- if (key) {
776
- if (view && view.indexOf(key) === -1 && view.indexOf('*') === -1) {
777
- view += "," + escapeId(key);
778
- }
779
- }
780
- var sql = this.toGetSql(query, sort, view, like);
781
- var list = await this.run(sql);
782
-
783
- var obj = null;
784
- if (list.length > 0) {
785
- obj = list[0];
786
- if (key) {
787
- obj = this.model(obj);
879
+ // 设置为只查询一条
880
+ this.page = 1;
881
+ this.size = 1;
882
+
883
+ // 使用优化后的get方法
884
+ const list = await this.get(query, sort, view, like, timeout);
885
+
886
+ // 恢复分页设置
887
+ this.page = oldPage;
888
+ this.size = oldSize;
889
+
890
+ var obj = null;
891
+ if (list.length > 0) {
892
+ obj = list[0];
893
+ if (this.key) {
894
+ obj = this.model(obj);
895
+ }
788
896
  }
789
- }
790
897
 
791
- await $.eventer.run("mysql_getObj_after:" + this.table, {
792
- query,
793
- sort,
794
- view,
795
- like,
796
- sql: this.sql,
797
- error: this.error,
798
- obj
799
- });
800
- return obj;
898
+ return obj;
899
+ } catch (err) {
900
+ this.error = err.message;
901
+ $.log.error(`查询单条数据失败: ${err.message}`, { sql: this.sql });
902
+ throw err;
903
+ }
801
904
  };
802
905
 
803
906
  /**
804
- * 添加或修改
805
- * @param {Object} query 查询条件集合
806
- * @param {Object} set 修改的键值
907
+ * 统计记录数
908
+ * @param {Object} query 查询条件
807
909
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
808
- * @return {Promise|Object} 执行结果
910
+ * @param {Number} timeout 超时时间(毫秒),默认30000ms
911
+ * @return {Promise|Number} 记录数
809
912
  */
810
- Sql.prototype.addOrSet = async function(query, set, like) {
811
- await $.eventer.run("mysql_addOrSet_before:" + this.table, {
812
- query,
813
- set,
814
- like,
815
- page: this.page,
816
- size: this.size
817
- });
818
- var bl = await this.addOrSetSql(query, set, like);
819
- await $.eventer.run("mysql_addOrSet_after:" + this.table, {
820
- query,
821
- set,
822
- like,
823
- page: this.page,
824
- size: this.size,
825
- sql: this.sql,
826
- error: this.error,
827
- bl
828
- });
829
- return bl
830
- };
913
+ Sql.prototype.count = async function (query, like, timeout = 30000) {
914
+ if (!this.table) {
915
+ throw new Error('表名未设置');
916
+ }
831
917
 
832
- /**
833
- * 查询符合结果总数
834
- * @param {Object} query 查询条件集合
835
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
836
- * @return {Promise|Number} 查询结果
837
- */
838
- Sql.prototype.count = function(query, like) {
839
- return this.countSql(this.toWhere(query, like));
918
+ try {
919
+ // 添加超时控制
920
+ const timeoutPromise = new Promise((_, reject) => {
921
+ setTimeout(() => reject(new Error('统计操作超时')), timeout);
922
+ });
923
+
924
+ return await Promise.race([
925
+ (async () => {
926
+ // 安全触发事件
927
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
928
+ try {
929
+ await Promise.race([
930
+ $.eventer.run("mysql_count_before:" + this.table, { query, like }),
931
+ new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
932
+ ]);
933
+ } catch (eventError) {
934
+ $.log.warn(`事件处理失败,但不影响统计: ${eventError.message}`);
935
+ }
936
+ }
937
+
938
+ // 正确生成count SQL
939
+ const where = typeof query === 'string' ? query : await this.toWhere(query, like);
940
+ const sql = "SELECT COUNT(*) as num FROM `" + this.table + "`" + (where ? " WHERE " + where : "");
941
+ this.sql = sql;
942
+ const list = await this.run(sql);
943
+ const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
944
+
945
+ // 安全触发事件
946
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
947
+ try {
948
+ await Promise.race([
949
+ $.eventer.run("mysql_count_after:" + this.table, {
950
+ query,
951
+ like,
952
+ sql: this.sql,
953
+ error: this.error,
954
+ total
955
+ }),
956
+ new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
957
+ ]);
958
+ } catch (eventError) {
959
+ $.log.warn(`事件处理失败,但不影响统计返回: ${eventError.message}`);
960
+ }
961
+ }
962
+
963
+ return total;
964
+ })(),
965
+ timeoutPromise
966
+ ]);
967
+ } catch (err) {
968
+ this.error = err.message;
969
+ $.log.error(`统计数据失败: ${err.message}`, { sql: this.sql });
970
+ throw err;
971
+ }
840
972
  };
841
973
 
842
974
  /**
843
- * 查询数据并返回符合条件总数
975
+ * 统计记录数(别名)
844
976
  * @param {Object} query 查询条件
845
- * @param {String} sort 排序
846
- * @param {String} view 返回的字段
847
977
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
848
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
978
+ * @param {Number} timeout 超时时间(毫秒),默认30000ms
979
+ * @return {Promise|Number} 记录数
849
980
  */
850
- Sql.prototype.getCount = async function(query, sort, view, like) {
851
- return this.getCountSql(this.toWhere(query, like), sort, view);
981
+ Sql.prototype.getCount = async function (query, like, timeout = 30000) {
982
+ return await this.count(query, like, timeout);
852
983
  };
853
984
 
854
985
  /* === 传入数组操作 === */
@@ -856,44 +987,250 @@ Sql.prototype.getCount = async function(query, sort, view, like) {
856
987
  * 添加多条数据
857
988
  * @param {Array} list 对象数组
858
989
  * @param {Boolean} lock 是否锁定
859
- * @return {Promise|Object} 执行结果
990
+ * @param {Number} batchSize 每批处理数量,默认100
991
+ * @param {Number} timeout 超时时间(毫秒),默认60000
992
+ * @return {Promise<Object>} 执行结果
860
993
  */
861
- Sql.prototype.addList = function(list, lock = true) {
862
- var sql = lock ? "BEGIN;\r\n" : "\r\n";
863
- var len = list.length;
864
- for (var i = 0; i < len; i++) {
865
- sql += this.toAddSql(list[i]) + "\r\n";
994
+ Sql.prototype.addList = async function (list, lock = true, batchSize = 100, timeout = 60000) {
995
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
996
+ throw new Error('表名或数据列表未设置');
997
+ }
998
+ try {
999
+ // 添加整体操作超时控制
1000
+ const timeoutPromise = new Promise((_, reject) => {
1001
+ setTimeout(() => reject(new Error('批量添加数据操作超时')), timeout);
1002
+ });
1003
+
1004
+ return await Promise.race([
1005
+ (async () => {
1006
+ // 如果数据量较小,直接处理
1007
+ if (list.length <= batchSize) {
1008
+ // 使用批量插入语法,不使用事务包装
1009
+ this.sql = this.toBatchAddSql(list);
1010
+ return await this.exec(this.sql);
1011
+ }
1012
+
1013
+ // 分批处理大数据量
1014
+ const totalBatches = Math.ceil(list.length / batchSize);
1015
+ $.log.info(`开始分批添加数据,共${totalBatches}批,每批${batchSize}条`);
1016
+
1017
+ // 分批执行,每批一个单独的批量插入语句
1018
+ let finalResult = null;
1019
+ for (let i = 0; i < totalBatches; i++) {
1020
+ const batch = list.slice(i * batchSize, (i + 1) * batchSize);
1021
+ $.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
1022
+
1023
+ // 生成批量插入SQL
1024
+ const batchSql = this.toBatchAddSql(batch);
1025
+ this.sql = batchSql;
1026
+
1027
+ // 为每批操作添加超时控制
1028
+ finalResult = await Promise.race([
1029
+ this.exec(batchSql),
1030
+ new Promise((_, reject) => {
1031
+ setTimeout(() => reject(new Error(`第${i + 1}批数据处理超时`)), timeout / totalBatches);
1032
+ })
1033
+ ]);
1034
+ }
1035
+
1036
+ $.log.success(`批量添加数据完成,共${list.length}条`);
1037
+ return finalResult;
1038
+ })(),
1039
+ timeoutPromise
1040
+ ]);
1041
+ } catch (error) {
1042
+ $.log.error(`[${this.constructor.name}] [addList]`, '批量添加数据失败', {
1043
+ error: error.message,
1044
+ table: this.table,
1045
+ list_length: list.length
1046
+ });
1047
+ throw error;
866
1048
  }
867
- sql += lock ? "COMMIT;" : "";
868
- return this.exec(sql);
869
1049
  };
1050
+
1051
+ /**
1052
+ * 生成批量插入SQL语句
1053
+ * @param {Array} list 数据列表
1054
+ * @return {String} 批量插入SQL语句
1055
+ */
1056
+ Sql.prototype.toBatchAddSql = function (list) {
1057
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
1058
+ throw new Error('表名或数据列表未设置');
1059
+ }
1060
+
1061
+ // 获取第一个对象的键名作为列名
1062
+ const firstItem = list[0];
1063
+ if (!firstItem || typeof firstItem !== 'object') {
1064
+ throw new Error('数据格式错误');
1065
+ }
1066
+
1067
+ let keys = [];
1068
+ for (const k in firstItem) {
1069
+ if (Object.prototype.hasOwnProperty.call(firstItem, k)) {
1070
+ keys.push(this.escapeId(k));
1071
+ }
1072
+ }
1073
+
1074
+ // 构建列名部分
1075
+ const columns = keys.join(',');
1076
+
1077
+ // 构建值部分
1078
+ const valuesList = [];
1079
+ for (const item of list) {
1080
+ const values = [];
1081
+ for (const k of keys) {
1082
+ const unescapedKey = k.replace(/`/g, '');
1083
+ let val = item[unescapedKey];
1084
+ if (typeof val === "string") {
1085
+ val = val.trim("'");
1086
+ }
1087
+ values.push(this.escape(val));
1088
+ }
1089
+ valuesList.push(`(${values.join(',')})`);
1090
+ }
1091
+
1092
+ // 生成最终SQL
1093
+ const sql = `INSERT INTO \`${this.table}\` (${columns}) VALUES ${valuesList.join(',')}`;
1094
+ return sql;
1095
+ };
1096
+
870
1097
  /**
871
1098
  * 删除多条数据
872
1099
  * @param {Array} list 对象数组
873
1100
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
874
- * @return {Promise|Object} 执行结果
1101
+ * @param {Number} batchSize 每批处理数量,默认100
1102
+ * @param {Number} timeout 超时时间(毫秒),默认60000
1103
+ * @return {Promise<Object>} 执行结果
875
1104
  */
876
- Sql.prototype.delList = function(list, like) {
877
- var sql = "";
878
- var len = list.length;
879
- for (var i = 0; i < len; i++) {
880
- sql += this.toDelSql(list[i].query, like);
1105
+ Sql.prototype.delList = async function (list, like, batchSize = 100, timeout = 60000) {
1106
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
1107
+ throw new Error('表名或数据列表未设置');
1108
+ }
1109
+ try {
1110
+ // 添加整体操作超时控制
1111
+ const timeoutPromise = new Promise((_, reject) => {
1112
+ setTimeout(() => reject(new Error('批量删除数据操作超时')), timeout);
1113
+ });
1114
+
1115
+ return await Promise.race([
1116
+ (async () => {
1117
+ // 如果数据量较小,直接处理
1118
+ if (list.length <= batchSize) {
1119
+ let sql = "";
1120
+ for (const item of list) {
1121
+ sql += this.toDelSql(item.query, like);
1122
+ }
1123
+ this.sql = sql;
1124
+ return await this.exec(sql);
1125
+ }
1126
+
1127
+ // 分批处理大数据量
1128
+ const totalBatches = Math.ceil(list.length / batchSize);
1129
+ $.log.info(`开始分批删除数据,共${totalBatches}批,每批${batchSize}条`);
1130
+
1131
+ // 使用事务包装整个操作以保证原子性
1132
+ let finalResult = null;
1133
+ try {
1134
+ // 开始事务
1135
+ await this.exec("BEGIN;", 15000);
1136
+
1137
+ // 分批处理
1138
+ for (let i = 0; i < totalBatches; i++) {
1139
+ const batch = list.slice(i * batchSize, (i + 1) * batchSize);
1140
+ $.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
1141
+
1142
+ let batchSql = "";
1143
+ for (const item of batch) {
1144
+ batchSql += this.toDelSql(item.query, like);
1145
+ }
1146
+
1147
+ // 为每批操作添加超时控制
1148
+ finalResult = await Promise.race([
1149
+ this.exec(batchSql),
1150
+ new Promise((_, reject) => {
1151
+ setTimeout(() => reject(new Error(`第${i + 1}批数据删除超时`)), timeout / totalBatches);
1152
+ })
1153
+ ]);
1154
+ }
1155
+
1156
+ // 提交事务
1157
+ await this.exec("COMMIT;", 15000);
1158
+ } catch (error) {
1159
+ // 发生错误时回滚事务
1160
+ try {
1161
+ await this.exec("ROLLBACK;", 15000);
1162
+ $.log.error(`批量删除数据失败,事务已回滚: ${error.message}`);
1163
+ } catch (rollbackError) {
1164
+ $.log.error(`批量删除数据失败,事务回滚也失败: ${rollbackError.message}`);
1165
+ }
1166
+ throw error;
1167
+ }
1168
+
1169
+ $.log.success(`批量删除数据完成,共${list.length}条`);
1170
+ return finalResult;
1171
+ })(),
1172
+ timeoutPromise
1173
+ ]);
1174
+ } catch (err) {
1175
+ this.error = err.message;
1176
+ $.log.error(`批量删除数据失败: ${err.message}`);
1177
+ throw err;
881
1178
  }
882
- return this.exec(sql);
883
1179
  };
1180
+
884
1181
  /**
885
1182
  * 修改多条数据
886
1183
  * @param {Array} list 对象数组
887
1184
  * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
888
- * @return {Promise|Object} 执行结果
1185
+ * @param {Number} batchSize 每批处理数量,默认100
1186
+ * @param {Number} timeout 超时时间(毫秒),默认60000
1187
+ * @return {Promise<Object>} 执行结果
889
1188
  */
890
- Sql.prototype.setList = function(list, like) {
891
- var sql = "";
892
- var len = list.length;
893
- for (var i = 0; i < len; i++) {
894
- sql += this.toSetSql(list[i].query, list[i].item, like);
1189
+ Sql.prototype.setList = async function (list, like = false, batchSize = 100, timeout = 60000) {
1190
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
1191
+ throw new Error('表名或数据列表未设置');
1192
+ }
1193
+ try {
1194
+ // 添加整体操作超时控制
1195
+ const timeoutPromise = new Promise((_, reject) => {
1196
+ setTimeout(() => reject(new Error('批量修改数据操作超时')), timeout);
1197
+ });
1198
+
1199
+ return await Promise.race([
1200
+ (async () => {
1201
+ // 分批处理大数据量
1202
+ const totalBatches = Math.ceil(list.length / batchSize);
1203
+ $.log.info(`开始分批修改数据,共${totalBatches}批,每批${batchSize}条`);
1204
+
1205
+ let finalResult = null;
1206
+
1207
+ // 逐条处理记录,保持简单可靠
1208
+ for (let i = 0; i < list.length; i++) {
1209
+ const item = list[i];
1210
+ $.log.debug(`处理第${i + 1}/${list.length}条记录`);
1211
+
1212
+ // 生成单个更新SQL
1213
+ const sql = this.toSetSql(item.query, item.item, like);
1214
+ this.sql = sql;
1215
+
1216
+ // 为每条操作添加超时控制
1217
+ finalResult = await Promise.race([
1218
+ this.exec(sql),
1219
+ new Promise((_, reject) => {
1220
+ setTimeout(() => reject(new Error(`第${i + 1}条数据修改超时`)), 5000); // 固定超时时间
1221
+ })
1222
+ ]);
1223
+ }
1224
+
1225
+ return finalResult;
1226
+ })(),
1227
+ timeoutPromise
1228
+ ]);
1229
+ } catch (error) {
1230
+ this.error = error.message;
1231
+ $.log.error(`批量修改数据失败: ${error.message}`);
1232
+ throw error;
895
1233
  }
896
- return this.exec(sql);
897
1234
  };
898
1235
 
899
1236
  /* 辅助类 */
@@ -901,35 +1238,39 @@ Sql.prototype.setList = function(list, like) {
901
1238
  * 判断SQL模板是否包含某些参数
902
1239
  * @param {Object} paramDt 参数集合
903
1240
  * @param {Object} sqlDt sql模板集合
904
- * @return {Bool} 有则返回true,没有则返回false
1241
+ * @return {Boolean} 有则返回true,没有则返回false
905
1242
  */
906
- Sql.prototype.has_param = function(paramDt, sqlDt) {
907
- var bl = false;
908
- for (var key in sqlDt) {
909
- var value = paramDt[key];
1243
+ Sql.prototype.has_param = function (paramDt, sqlDt) {
1244
+ if (!paramDt || !sqlDt) {
1245
+ return false;
1246
+ }
1247
+ for (const key in sqlDt) {
1248
+ if (!Object.prototype.hasOwnProperty.call(sqlDt, key)) continue;
1249
+ const value = paramDt[key];
910
1250
  if (value !== undefined && value !== null && value !== "") {
911
- bl = true;
912
- break;
1251
+ return true;
913
1252
  }
914
1253
  }
915
- return bl;
1254
+ return false;
916
1255
  };
917
1256
 
918
1257
  /**
919
1258
  * 判断某些参数是否没有SQL模板
920
1259
  * @param {Object} paramDt 参数集合
921
1260
  * @param {Object} sqlDt sql模板集合
922
- * @return {Bool} 没有模板则返回名称,都有则返回undefined
1261
+ * @return {String|undefined} 没有模板则返回名称,都有则返回undefined
923
1262
  */
924
- Sql.prototype.not_param = function(paramDt, sqlDt) {
925
- var name;
926
- for (var key in paramDt) {
1263
+ Sql.prototype.not_param = function (paramDt, sqlDt) {
1264
+ if (!paramDt || !sqlDt) {
1265
+ return undefined;
1266
+ }
1267
+ for (const key in paramDt) {
1268
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
927
1269
  if (!sqlDt[key]) {
928
- name = key;
929
- break;
1270
+ return key;
930
1271
  }
931
1272
  }
932
- return name;
1273
+ return undefined;
933
1274
  };
934
1275
 
935
1276
  /**
@@ -938,11 +1279,15 @@ Sql.prototype.not_param = function(paramDt, sqlDt) {
938
1279
  * @param {Object} sqlDt sql模板集合
939
1280
  * @return {Object} 返回过滤后的参数集合
940
1281
  */
941
- Sql.prototype.filter_param = function(paramDt, sqlDt) {
942
- var dt = [];
943
- for (var key in paramDt) {
1282
+ Sql.prototype.filter_param = function (paramDt, sqlDt) {
1283
+ const dt = {};
1284
+ if (!paramDt || !sqlDt) {
1285
+ return dt;
1286
+ }
1287
+ for (const key in paramDt) {
1288
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
944
1289
  if (!sqlDt[key]) {
945
- dt.Add(key, o.Value);
1290
+ dt[key] = paramDt[key];
946
1291
  }
947
1292
  }
948
1293
  return dt;
@@ -954,100 +1299,99 @@ Sql.prototype.filter_param = function(paramDt, sqlDt) {
954
1299
  * @param {Object} sqlDt 模板集合
955
1300
  * @return {String} 返回拼接的查询参数
956
1301
  */
957
- Sql.prototype.tpl_query = function(paramDt, sqlDt) {
958
- var sql = "";
1302
+ Sql.prototype.tpl_query = function (paramDt, sqlDt) {
1303
+ let sql = "";
1304
+ if (!paramDt) {
1305
+ return sql;
1306
+ }
1307
+ const l = this.config.separator;
959
1308
  if (sqlDt) {
960
- var l = this.config.separator;
961
1309
  if (l) {
962
- for (var key in paramDt) {
963
- var value = paramDt[key] + "";
964
- var arr = value.split(l);
965
- var tpl = sqlDt[key];
1310
+ const conditions = [];
1311
+ for (const key in paramDt) {
1312
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
1313
+
1314
+ let value = String(paramDt[key]);
1315
+ const arr = value.split(l);
1316
+ const tpl = sqlDt[key];
1317
+
966
1318
  if (tpl) {
967
1319
  if (arr.length > 1) {
968
1320
  // 如果数量大于0,则增加多条件
969
- var sl = "(";
970
- var len = arr.length;
971
- for (var i = 0; i < len; i++) {
972
- var val = arr[i];
973
- if (val && typeof(val) == "string") {
974
- val = val.trim("'");
975
- }
976
- sl += " || " + tpl.replaceAll("{0}", escape(val).trim("'"));
1321
+ let subConditions = [];
1322
+ for (const val of arr) {
1323
+ const cleanVal = typeof val === "string" ? val.trim("'") : val;
1324
+ subConditions.push(tpl.replaceAll("{0}", escape(cleanVal).trim("'")));
977
1325
  }
978
- sl = sl.replace(" || ", "") + ")";
979
- sql += " && " + sl;
1326
+ conditions.push("(" + subConditions.join(" || ") + ")");
980
1327
  } else {
981
- if (value && typeof(value) == "string") {
982
- value = value.trim("'");
983
- }
984
- sql += " && " + tpl.replaceAll("{0}", escape(value).trim("'"));
1328
+ const cleanVal = typeof value === "string" ? value.trim("'") : value;
1329
+ conditions.push(tpl.replaceAll("{0}", escape(cleanVal).trim("'")));
985
1330
  }
986
1331
  } else {
987
1332
  if (arr.length > 1) {
988
1333
  // 如果数量大于0,则增加多条件
989
- var sl = "(";
990
- var len = arr.length;
991
- for (var i = 0; i < len; i++) {
992
- var val = arr[i];
993
- if (val && typeof(val) == "string") {
994
- val = val.trim("'");
995
- }
996
- sl += " || " + escapeId(key) + " = " + escape(val);
1334
+ let subConditions = [];
1335
+ for (const val of arr) {
1336
+ subConditions.push(escapeId(key) + " = " + escape(val));
997
1337
  }
998
- sl = sl.replace(" || ", "") + ")";
999
- sql += " && " + sl;
1338
+ conditions.push("(" + subConditions.join(" || ") + ")");
1000
1339
  } else {
1001
- if (value && typeof(value) == "string") {
1002
- value = value.trim("'");
1003
- }
1004
- sql += " && " + escapeId(key) + " = " + escape(value);
1340
+ const cleanVal = typeof value === "string" ? value.trim("'") : value;
1341
+ conditions.push(escapeId(key) + " = " + escape(cleanVal));
1005
1342
  }
1006
1343
  }
1007
1344
  }
1345
+ sql = conditions.join(" && ");
1008
1346
  } else {
1009
- for (var key in paramDt) {
1010
- var value = paramDt[key];
1011
- if (value && typeof(value) == "string") {
1347
+ const conditions = [];
1348
+ for (const key in paramDt) {
1349
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
1350
+ let value = paramDt[key];
1351
+ if (typeof value === "string") {
1012
1352
  value = value.trim("'");
1013
1353
  }
1014
1354
  value = escape(value);
1015
1355
  if (sqlDt[key]) {
1016
- sql += " && " + sqlDt[key].replaceAll("{0}", value.trim("'"));
1356
+ conditions.push(sqlDt[key].replaceAll("{0}", value.trim("'")));
1017
1357
  } else {
1018
- sql += " && " + escapeId(key) + " = " + value;
1358
+ conditions.push(escapeId(key) + " = " + value);
1019
1359
  }
1020
1360
  }
1361
+ sql = conditions.join(" && ");
1021
1362
  }
1022
1363
  } else {
1023
1364
  // 如果没有模板,则直接拼接参数
1024
- var l = this.config.separator;
1025
1365
  if (l) {
1026
1366
  // 使用分隔数组拼接
1027
- for (var key in paramDt) {
1028
- var value = paramDt[key];
1029
- var arr = value.split(l);
1367
+ const conditions = [];
1368
+ for (const key in paramDt) {
1369
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
1370
+ const value = paramDt[key];
1371
+ const arr = String(value).split(l);
1030
1372
  if (arr.length > 1) {
1031
1373
  // 如果数量大于0,则增加多条件
1032
- var sl = "(";
1033
- var len = arr.length;
1034
- for (var i = 0; i < len; i++) {
1035
- sl += " || " + escapeId(key) + " = " + escape(arr[i]);
1374
+ let subConditions = [];
1375
+ for (const val of arr) {
1376
+ subConditions.push(escapeId(key) + " = " + escape(val));
1036
1377
  }
1037
- sl = sl.replace(" || ", "") + ")";
1038
- sql += " && " + sl;
1378
+ conditions.push("(" + subConditions.join(" || ") + ")");
1039
1379
  } else {
1040
- sql += " && " + escapeId(key) + " = " + escape(value);
1380
+ conditions.push(escapeId(key) + " = " + escape(value));
1041
1381
  }
1042
1382
  }
1383
+ sql = conditions.join(" && ");
1043
1384
  } else {
1044
1385
  // 直接拼接
1045
- for (var key in paramDt) {
1046
- sql += " && " + escapeId(key) + " = " + escape(paramDt[key]);
1386
+ const conditions = [];
1387
+ for (const key in paramDt) {
1388
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
1389
+ conditions.push(escapeId(key) + " = " + escape(paramDt[key]));
1047
1390
  }
1391
+ sql = conditions.join(" && ");
1048
1392
  }
1049
1393
  }
1050
- return sql.replace(" && ", "");
1394
+ return sql;
1051
1395
  };
1052
1396
 
1053
1397
  /**
@@ -1056,65 +1400,318 @@ Sql.prototype.tpl_query = function(paramDt, sqlDt) {
1056
1400
  * @param {Object} sqlDt 模板集合
1057
1401
  * @return {String} 返回拼接的查询参数
1058
1402
  */
1059
- Sql.prototype.tpl_body = function(paramDt, sqlDt) {
1060
- var sql = "";
1061
- if (!sqlDt || sqlDt.length === 0) {
1062
- for (var key in paramDt) {
1063
- sql += ", " + escapeId(key) + " = " + escape(val[key]);
1403
+ Sql.prototype.tpl_body = function (paramDt, sqlDt) {
1404
+ if (!paramDt) {
1405
+ return "";
1406
+ }
1407
+ const parts = [];
1408
+ if (!sqlDt || Object.keys(sqlDt).length === 0) {
1409
+ for (const key in paramDt) {
1410
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
1411
+ parts.push(" " + escapeId(key) + " = " + escape(paramDt[key]));
1064
1412
  }
1065
1413
  } else {
1066
- for (var key in paramDt) {
1067
- var value = escape(paramDt[key]);
1414
+ for (const key in paramDt) {
1415
+ if (!Object.prototype.hasOwnProperty.call(paramDt, key)) continue;
1416
+ const value = escape(paramDt[key]);
1068
1417
  if (sqlDt[key]) {
1069
- sql += ", " + sqlDt[key].replace("{0}", value).replace('+ -', '- ').replace('- -', '+ ');
1418
+ parts.push(" " + sqlDt[key].replace("{0}", value).replace(/\+ -/g, "- ").replace(/- -/g, "+ "));
1070
1419
  } else {
1071
- sql += ", " + escapeId(key) + " = " + value;
1420
+ parts.push(" " + escapeId(key) + " = " + value);
1072
1421
  }
1073
1422
  }
1074
1423
  }
1075
- return sql.replace(", ", "");
1424
+ return parts.join(",").replace(", ", "");
1425
+ };
1426
+
1427
+ /**
1428
+ * 从SQL文件加载数据库结构和数据
1429
+ * @param {String} file - SQL文件路径
1430
+ * @returns {Promise<boolean>} 是否加载成功
1431
+ */
1432
+ Sql.prototype.load = async function (file) {
1433
+ try {
1434
+ // 记录操作日志
1435
+ if (this.config && this.config.debug) {
1436
+ $.log.debug(`[${this.constructor.name}] [load] 开始从文件加载数据库`, {
1437
+ file: file
1438
+ });
1439
+ }
1440
+
1441
+ // 检查文件是否存在
1442
+ if (!file.hasFile()) {
1443
+ throw new Error(`SQL文件不存在: ${file}`);
1444
+ }
1445
+
1446
+ // 读取SQL文件内容
1447
+ const sqlContent = await $.file.readText(file);
1448
+
1449
+ if (!sqlContent || sqlContent.trim() === '') {
1450
+ throw new Error(`SQL文件内容为空: ${file}`);
1451
+ }
1452
+
1453
+ // 分割SQL语句(按分号分割,但需要注意处理字符串中的分号)
1454
+ const sqlStatements = this._splitSqlStatements(sqlContent);
1455
+
1456
+ // 开始事务执行SQL语句
1457
+ await this.exec('START TRANSACTION');
1458
+
1459
+ try {
1460
+ // 逐个执行SQL语句
1461
+ for (const sql of sqlStatements) {
1462
+ const trimmedSql = sql.trim();
1463
+ if (trimmedSql) {
1464
+ await this.exec(trimmedSql);
1465
+ }
1466
+ }
1467
+
1468
+ // 提交事务
1469
+ await this.exec('COMMIT');
1470
+
1471
+ if (this.config && this.config.debug) {
1472
+ $.log.info(`[${this.constructor.name}] [load] 数据库加载成功`, {
1473
+ file: file,
1474
+ statementCount: sqlStatements.length
1475
+ });
1476
+ }
1477
+
1478
+ return true;
1479
+ } catch (err) {
1480
+ // 回滚事务
1481
+ await this.exec('ROLLBACK').catch(rollbackErr => {
1482
+ $.log.error(`[${this.constructor.name}] [load] 事务回滚失败`, {
1483
+ error: rollbackErr.message
1484
+ });
1485
+ });
1486
+
1487
+ throw err;
1488
+ }
1489
+ } catch (error) {
1490
+ // 记录错误日志
1491
+ $.log.error(`[${this.constructor.name}] [load] 数据库加载失败`, {
1492
+ error: error.message,
1493
+ file: file
1494
+ });
1495
+
1496
+ // 抛出错误
1497
+ throw error;
1498
+ }
1499
+ };
1500
+
1501
+ /**
1502
+ * 分割SQL语句
1503
+ * @private
1504
+ * @param {String} sqlContent - SQL内容
1505
+ * @returns {Array} SQL语句数组
1506
+ */
1507
+ Sql.prototype._splitSqlStatements = function(sqlContent) {
1508
+ const statements = [];
1509
+ let inString = false;
1510
+ let stringChar = '';
1511
+ let inComment = false;
1512
+ let currentStatement = '';
1513
+
1514
+ for (let i = 0; i < sqlContent.length; i++) {
1515
+ const char = sqlContent[i];
1516
+ const nextChar = i + 1 < sqlContent.length ? sqlContent[i + 1] : '';
1517
+
1518
+ // 处理注释
1519
+ if (!inString && !inComment && char === '-' && nextChar === '-') {
1520
+ inComment = true;
1521
+ i++; // 跳过第二个'-'
1522
+ continue;
1523
+ }
1524
+
1525
+ if (inComment && char === '\n') {
1526
+ inComment = false;
1527
+ continue;
1528
+ }
1529
+
1530
+ if (inComment) {
1531
+ continue;
1532
+ }
1533
+
1534
+ // 处理多行注释
1535
+ if (!inString && !inComment && char === '/' && nextChar === '*') {
1536
+ inComment = true;
1537
+ i++; // 跳过'*'
1538
+ continue;
1539
+ }
1540
+
1541
+ if (inComment && char === '*' && nextChar === '/') {
1542
+ inComment = false;
1543
+ i++; // 跳过'/'
1544
+ continue;
1545
+ }
1546
+
1547
+ // 处理字符串
1548
+ if (!inComment && (char === "'" || char === '"') && (!inString || stringChar === char)) {
1549
+ // 检查是否是转义的引号
1550
+ let escaped = false;
1551
+ for (let j = i - 1; j >= 0; j--) {
1552
+ if (sqlContent[j] === '\\') {
1553
+ escaped = !escaped;
1554
+ } else {
1555
+ break;
1556
+ }
1557
+ }
1558
+
1559
+ if (!escaped) {
1560
+ if (inString && stringChar === char) {
1561
+ inString = false;
1562
+ stringChar = '';
1563
+ } else if (!inString) {
1564
+ inString = true;
1565
+ stringChar = char;
1566
+ }
1567
+ }
1568
+ }
1569
+
1570
+ // 分割语句
1571
+ if (!inString && !inComment && char === ';') {
1572
+ statements.push(currentStatement.trim());
1573
+ currentStatement = '';
1574
+ } else {
1575
+ currentStatement += char;
1576
+ }
1577
+ }
1578
+
1579
+ // 添加最后一个语句(如果有)
1580
+ if (currentStatement.trim()) {
1581
+ statements.push(currentStatement.trim());
1582
+ }
1583
+
1584
+ return statements;
1076
1585
  };
1077
1586
 
1078
1587
  /**
1079
- * 构建实体模型
1080
- * @param {Object} obj 模型对象
1588
+ * 模型监听函数
1589
+ * @param {Object} model - 模型对象
1081
1590
  * @return {Object} 返回监听操作的对象
1082
1591
  */
1083
- Sql.prototype.model = function(model) {
1084
- var _this = this;
1085
- return new Proxy(model, {
1086
- set: function(obj, prop, value) {
1087
- if (_this.key) {
1088
- var query = {};
1089
- var arr = _this.key.split(',');
1090
- for (var i = 0; i < arr.length; i++) {
1091
- var key = arr[i];
1592
+ Sql.prototype.model = function (model) {
1593
+ const _this = this;
1594
+ return new Proxy(model || {}, {
1595
+ set: function (obj, prop, value) {
1596
+ if (_this.key && prop !== 'length' && !prop.toString().startsWith('__')) {
1597
+ const query = {};
1598
+ const arr = _this.key.split(',');
1599
+ for (const key of arr) {
1092
1600
  query[key] = obj[key];
1093
1601
  }
1094
- if (typeof(value) === "number") {
1095
- var n = obj[prop];
1096
- var cha = value - n;
1097
- var where = _this.toWhere(query);
1602
+
1603
+ if (typeof value === "number") {
1604
+ const n = obj[prop] || 0;
1605
+ const cha = value - n;
1606
+ const where = _this.toWhere(query);
1098
1607
  if (cha > 0) {
1099
- _this.setSql(where, "`" + prop + "` = `" +
1100
- prop + "` + " + cha);
1608
+ _this.setSql(where, "`" + prop + "` = `" + prop + "` + " + cha);
1101
1609
  } else if (cha < 0) {
1102
- _this.setSql(where, "`" + prop + "` = `" +
1103
- prop + "` - " + (-cha));
1610
+ _this.setSql(where, "`" + prop + "` = `" + prop + "` - " + (-cha));
1104
1611
  } else {
1105
- _this.setSql(where, "`" + prop + "` = " +
1106
- value);
1612
+ _this.setSql(where, "`" + prop + "` = " + value);
1107
1613
  }
1108
1614
  } else {
1109
- var set = {};
1615
+ const set = {};
1110
1616
  set[prop] = value;
1111
- _this.set(query, set, false);
1617
+ _this.set(query, set, false).catch(err => {
1618
+ $.log.error(`模型数据更新失败: ${err.message}`);
1619
+ });
1112
1620
  }
1113
1621
  }
1114
1622
  obj[prop] = value;
1115
- return obj;
1623
+ return true;
1116
1624
  }
1117
1625
  });
1118
1626
  };
1119
1627
 
1628
+ /**
1629
+ * 添加或修改数据(存在则修改,不存在则添加)
1630
+ * @param {Object|String} where 查询条件
1631
+ * @param {Object|String} set 要设置的数据
1632
+ * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
1633
+ * @return {Promise<Object>} 执行结果
1634
+ */
1635
+ Sql.prototype.addOrSet = async function(where, set, like) {
1636
+ if (!this.table || !where || !set) {
1637
+ throw new Error('表名、条件或数据未设置');
1638
+ }
1639
+ try {
1640
+ let query = where;
1641
+ let body = set;
1642
+ let whereStr;
1643
+
1644
+ if (typeof where === "object") {
1645
+ whereStr = await this.toWhere(where, like);
1646
+ } else {
1647
+ whereStr = where;
1648
+ }
1649
+
1650
+ const count = await this.countSql(whereStr);
1651
+
1652
+ if (count === 0) {
1653
+ let key = "";
1654
+ let value = "";
1655
+
1656
+ if (typeof set === "string") {
1657
+ const arr = set.split(",");
1658
+ for (const o of arr) {
1659
+ const ar = o.split('=');
1660
+ if (ar.length === 2) {
1661
+ key += "," + ar[0];
1662
+ value += "," + ar[1];
1663
+ }
1664
+ }
1665
+ } else {
1666
+ // 触发前置事件
1667
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
1668
+ await $.eventer.run("mysql_add_before:" + this.table, { body });
1669
+ }
1670
+
1671
+ for (const k in set) {
1672
+ if (!Object.prototype.hasOwnProperty.call(set, k)) continue;
1673
+
1674
+ key += "," + escapeId(k);
1675
+ let val = set[k];
1676
+ if (typeof val === "string") {
1677
+ val = val.trim("'");
1678
+ }
1679
+ value += "," + escape(val);
1680
+ }
1681
+ }
1682
+
1683
+ const bl = await this.addSql(key.replace(",", ""), value.replace(",", ""));
1684
+
1685
+ // 触发后置事件
1686
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
1687
+ await $.eventer.run("mysql_add_after:" + this.table, { body, sql: this.sql, error: this.error, bl });
1688
+ }
1689
+
1690
+ return bl;
1691
+ } else {
1692
+ // 触发前置事件
1693
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof set === "object") {
1694
+ await $.eventer.run("mysql_set_before:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql });
1695
+ }
1696
+
1697
+ if (typeof set === "object") {
1698
+ set = await this.toSet(set);
1699
+ }
1700
+
1701
+ const bl1 = await this.setSql(whereStr, set);
1702
+
1703
+ // 触发后置事件
1704
+ if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
1705
+ await $.eventer.run("mysql_set_after:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql, error: this.error, bl: bl1 });
1706
+ }
1707
+
1708
+ return bl1;
1709
+ }
1710
+ } catch (err) {
1711
+ this.error = err.message;
1712
+ $.log.error(`添加或修改数据失败: ${err.message}`);
1713
+ throw err;
1714
+ }
1715
+ };
1716
+
1120
1717
  module.exports = Sql;