mm_mysql 2.4.2 → 2.4.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.
Files changed (4) hide show
  1. package/index.js +2 -3
  2. package/package.json +4 -4
  3. package/sql.js +145 -145
  4. package/test2.js +381 -0
package/index.js CHANGED
@@ -124,8 +124,6 @@ Mysql.prototype.open = async function () {
124
124
  // 测试连接池连接
125
125
  let conn = await this._pool.getConnection();
126
126
  conn.release();
127
-
128
- this.log('info', '数据库连接池创建成功');
129
127
  return true;
130
128
  } catch (error) {
131
129
  this.log('error', '数据库连接池创建失败', error);
@@ -195,6 +193,7 @@ Mysql.prototype.run = async function (sql, params = []) {
195
193
  let [rows] = await conn.query(sql, params);
196
194
  ret = rows;
197
195
  } catch (err) {
196
+ console.error('SQL执行失败', err);
198
197
  this.sql = err.sql;
199
198
  this.error = {
200
199
  code: err.errno,
@@ -233,7 +232,7 @@ Mysql.prototype.exec = async function (sql, params = []) {
233
232
  let [result] = await conn.execute(sql, params);
234
233
  ret = result.insertId || result.affectedRows || result.changedRows || 1;
235
234
  } catch (error) {
236
- this.log('error', 'SQL执行失败', error);
235
+ console.error('SQL执行失败', error);
237
236
  this.sql = error.sql;
238
237
  this.error = {
239
238
  code: error.errno,
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "mm_mysql",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
4
4
  "description": "这是超级美眉mysql帮助函数模块,用于便捷操作mysql,使用await方式,可以避免嵌套函数",
5
5
  "main": "index.js",
6
6
  "dependencies": {
7
- "mm_expand": "^2.3.1",
7
+ "mm_expand": "^2.3.4",
8
8
  "mysql2": "^3.22.3",
9
9
  "sqlstring": "^2.3.3"
10
10
  },
@@ -36,8 +36,8 @@
36
36
  "node": ">=12.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "eslint": "^10.2.1",
40
- "eslint-plugin-jsdoc": "^62.9.0",
39
+ "eslint": "^10.4.0",
40
+ "eslint-plugin-jsdoc": "^63.0.0",
41
41
  "mm_eslint": "^1.7.1"
42
42
  }
43
43
  }
package/sql.js CHANGED
@@ -301,7 +301,7 @@ Sql.prototype.getCountSql = async function (where, sort, view) {
301
301
  * @returns {Promise | object} 查询到的内容列表和符合条件总数
302
302
  */
303
303
  Sql.prototype.groupMathSql = async function (where, groupby, view, sort, method) {
304
- const view_val = view || '*';
304
+ let view_val = view || '*';
305
305
  var view_str = '';
306
306
  if (view_val.indexOf(',') !== -1) {
307
307
  var arr = view_val.split(',');
@@ -428,13 +428,13 @@ Sql.prototype.groupCount = async function (query, groupby, view, sort) {
428
428
  */
429
429
  Sql.prototype.toWhere = function (obj, like) {
430
430
  var where = '';
431
- const use_like = like === undefined ? this.like : like;
431
+ let use_like = like === undefined ? this.like : like;
432
432
  if (use_like) {
433
433
  where = this._buildLikeWhere(obj);
434
434
  } else {
435
435
  where = this._buildExactWhere(obj);
436
436
  }
437
- return where.replace(' and ', '');
437
+ return where.replace(/^ and /, '');
438
438
  };
439
439
 
440
440
  Sql.prototype._buildLikeWhere = function (obj) {
@@ -498,7 +498,7 @@ Sql.prototype._buildExactWhere = function (obj) {
498
498
  */
499
499
  Sql.prototype.toSet = function (obj) {
500
500
  var set = '';
501
- for (const k in obj) {
501
+ for (let k in obj) {
502
502
 
503
503
  let val = obj[k];
504
504
  if (val === undefined || val === null) continue;
@@ -507,17 +507,17 @@ Sql.prototype.toSet = function (obj) {
507
507
  val = escape(val);
508
508
 
509
509
  if (k.endsWith('_add')) {
510
- const k2 = escapeId(k.replace('_add', ''));
510
+ let k2 = escapeId(k.replace('_add', ''));
511
511
  set += ',' + k2 + ' = ' + k2 + ' + ' + val;
512
512
  } else if (k.endsWith('_del')) {
513
- const k3 = escapeId(k.replace('_del', ''));
513
+ let k3 = escapeId(k.replace('_del', ''));
514
514
  set += ',' + k3 + ' = ' + k3 + ' - ' + val;
515
515
  } else {
516
516
  set += ',' + escapeId(k) + ' = ' + val;
517
517
  }
518
518
  }
519
519
 
520
- return set.replace(',', '');
520
+ return set.replace(/^,/, '');
521
521
  };
522
522
 
523
523
  /**
@@ -533,13 +533,13 @@ Sql.prototype.toAddSql = function (item) {
533
533
  let key = '';
534
534
  let value = '';
535
535
 
536
- for (const k in item) {
536
+ for (let k in item) {
537
537
  key += ',' + escapeId(k);
538
538
  value += ',' + escape(item[k]);
539
539
  }
540
540
 
541
541
  // 使用直接拼接的方式,避免模板替换错误
542
- const sql = `INSERT INTO \`${this.table}\` (${key.replace(',', '')}) VALUES (${value.replace(',', '')});`;
542
+ let sql = `INSERT INTO \`${this.table}\` (${key.replace(',', '')}) VALUES (${value.replace(',', '')});`;
543
543
 
544
544
  return sql;
545
545
  };
@@ -554,10 +554,10 @@ Sql.prototype.toDelSql = function (query, like) {
554
554
  if (!this.table) {
555
555
  throw new Error('表名未设置');
556
556
  }
557
- const where = this.toWhere(query, like);
557
+ let where = this.toWhere(query, like);
558
558
 
559
559
  // 使用直接拼接的方式,避免模板替换错误
560
- const sql = `DELETE FROM \`${this.table}\` WHERE ${where};`;
560
+ let sql = `DELETE FROM \`${this.table}\` WHERE ${where};`;
561
561
 
562
562
  return sql;
563
563
  };
@@ -573,11 +573,11 @@ Sql.prototype.toSetSql = function (query, item, like) {
573
573
  if (!this.table) {
574
574
  throw new Error('表名未设置');
575
575
  }
576
- const where = this.toWhere(query, like);
577
- const set = this.toSet(item);
576
+ let where = this.toWhere(query, like);
577
+ let set = this.toSet(item);
578
578
 
579
579
  // 使用直接拼接的方式,避免模板替换错误
580
- const sql = `UPDATE \`${this.table}\` SET ${set} WHERE ${where};`;
580
+ let sql = `UPDATE \`${this.table}\` SET ${set} WHERE ${where};`;
581
581
 
582
582
  return sql;
583
583
  };
@@ -591,7 +591,7 @@ Sql.prototype.toSetSql = function (query, item, like) {
591
591
  * @returns {string} sql语句
592
592
  */
593
593
  Sql.prototype.toGetSql = function (query, sort, view, like) {
594
- const where = this.toWhere(query, like);
594
+ let where = this.toWhere(query, like);
595
595
  return this.toQuery(where, sort, view);
596
596
  };
597
597
 
@@ -605,7 +605,7 @@ Sql.prototype.add = async function (body) {
605
605
  if (!this.table || !body || typeof body !== 'object') {
606
606
  throw new Error('表名或数据未设置');
607
607
  }
608
- const sql = this.toAddSql(body);
608
+ let sql = this.toAddSql(body);
609
609
  this.sql = sql;
610
610
  return await this.exec(sql);
611
611
  };
@@ -620,9 +620,9 @@ Sql.prototype.del = async function (query, like) {
620
620
  if (!this.table) {
621
621
  throw new Error('表名未设置');
622
622
  }
623
- const sql = this.toDelSql(query, like);
623
+ let sql = this.toDelSql(query, like);
624
624
  this.sql = sql;
625
- const bl = await this.exec(sql);
625
+ let bl = await this.exec(sql);
626
626
  return bl;
627
627
  };
628
628
 
@@ -637,9 +637,9 @@ Sql.prototype.set = async function (query, body, like) {
637
637
  if (!this.table || !body || typeof body !== 'object') {
638
638
  throw new Error('表名或数据未设置');
639
639
  }
640
- const sql = this.toSetSql(query, body, like);
640
+ let sql = this.toSetSql(query, body, like);
641
641
  this.sql = sql;
642
- const bl = await this.exec(sql);
642
+ let bl = await this.exec(sql);
643
643
  return bl;
644
644
  };
645
645
 
@@ -654,8 +654,8 @@ Sql.prototype.addOrSetSql = async function (where, set, like) {
654
654
  if (!this.table || !where || !set) {
655
655
  throw new Error('表名、条件或数据未设置');
656
656
  }
657
- const where_str = await this._getWhereStr(where, like);
658
- const count = await this.countSql(where_str);
657
+ let where_str = await this._getWhereStr(where, like);
658
+ let count = await this.countSql(where_str);
659
659
 
660
660
  if (count === 0) {
661
661
  return await this._addData(set);
@@ -672,7 +672,7 @@ Sql.prototype._getWhereStr = async function (where, like) {
672
672
  };
673
673
 
674
674
  Sql.prototype._addData = async function (set) {
675
- const { key_str, val_str } = await this._parseSetData(set);
675
+ let { key_str, val_str } = await this._parseSetData(set);
676
676
  return await this.addSql(key_str, val_str);
677
677
  };
678
678
 
@@ -689,16 +689,16 @@ Sql.prototype._parseSetData = async function (set) {
689
689
  let val_str = '';
690
690
 
691
691
  if (typeof set === 'string') {
692
- const arr = set.split(',');
693
- for (const o of arr) {
694
- const ar = o.split('=');
692
+ let arr = set.split(',');
693
+ for (let o of arr) {
694
+ let ar = o.split('=');
695
695
  if (ar.length === 2) {
696
696
  key_str += ',' + ar[0];
697
697
  val_str += ',' + ar[1];
698
698
  }
699
699
  }
700
700
  } else {
701
- for (const k in set) {
701
+ for (let k in set) {
702
702
  key_str += ',' + escapeId(k);
703
703
  let val = set[k];
704
704
  val_str += ',' + escape(val);
@@ -725,9 +725,9 @@ Sql.prototype.get = async function (query, sort, view, like, timeout = 20000) {
725
725
  throw new Error('表名未设置');
726
726
  }
727
727
 
728
- const sql = this.toGetSql(query, sort, view, like);
728
+ let sql = this.toGetSql(query, sort, view, like);
729
729
  this.sql = sql;
730
- const list = await this.run(sql);
730
+ let list = await this.run(sql);
731
731
  return list;
732
732
  };
733
733
 
@@ -742,15 +742,15 @@ Sql.prototype.get = async function (query, sort, view, like, timeout = 20000) {
742
742
  */
743
743
  Sql.prototype.getObj = async function (query, sort, view, like, timeout = 20000) {
744
744
  // 保存当前分页设置
745
- const old_page = this.page;
746
- const old_size = this.size;
745
+ let old_page = this.page;
746
+ let old_size = this.size;
747
747
 
748
748
  // 设置为只查询一条
749
749
  this.page = 1;
750
750
  this.size = 1;
751
751
 
752
752
  // 使用优化后的get方法
753
- const list = await this.get(query, sort, view, like, timeout);
753
+ let list = await this.get(query, sort, view, like, timeout);
754
754
 
755
755
  // 恢复分页设置
756
756
  this.page = old_page;
@@ -778,11 +778,11 @@ Sql.prototype.count = async function (query, like, timeout = 20000) {
778
778
  if (!this.table) {
779
779
  throw new Error('表名未设置');
780
780
  }
781
- const where = typeof query === 'string' ? query : await this.toWhere(query, like);
782
- const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
781
+ let where = typeof query === 'string' ? query : await this.toWhere(query, like);
782
+ let sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
783
783
  this.sql = sql;
784
- const list = await this.run(sql);
785
- const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
784
+ let list = await this.run(sql);
785
+ let total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
786
786
  return total;
787
787
  };
788
788
 
@@ -818,17 +818,17 @@ Sql.prototype.addList = async function (list, batch_size = 100, timeout = 60000)
818
818
  }
819
819
 
820
820
  // 分批处理大数据量
821
- const batches = Math.ceil(list.length / batch_size);
821
+ let batches = Math.ceil(list.length / batch_size);
822
822
  this.log('info', `开始分批添加数据,共${batches}批,每批${batch_size}条`);
823
823
 
824
824
  // 分批执行,每批一个单独的批量插入语句
825
825
  let final_res = null;
826
826
  for (let i = 0; i < batches; i++) {
827
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
827
+ let batch = list.slice(i * batch_size, (i + 1) * batch_size);
828
828
  this.log('debug', `处理第${i + 1}/${batches}批数据,${batch.length}条`);
829
829
 
830
830
  // 生成批量插入SQL
831
- const batch_sql = this.toBatchAddSql(batch);
831
+ let batch_sql = this.toBatchAddSql(batch);
832
832
  this.sql = batch_sql;
833
833
  final_res = await this.exec(batch_sql);
834
834
  }
@@ -847,32 +847,32 @@ Sql.prototype.toBatchAddSql = function (list) {
847
847
  throw new Error('表名或数据列表未设置');
848
848
  }
849
849
 
850
- const first_obj = list[0];
850
+ let first_obj = list[0];
851
851
  if (!first_obj || typeof first_obj !== 'object') {
852
852
  throw new Error('数据格式错误');
853
853
  }
854
854
 
855
- const keys = this._getKeys(first_obj);
856
- const columns = keys.join(',');
857
- const val_list = this._buildValueList(list, keys);
855
+ let keys = this._getKeys(first_obj);
856
+ let columns = keys.join(',');
857
+ let val_list = this._buildValueList(list, keys);
858
858
 
859
859
  return `INSERT INTO \`${this.table}\` (${columns}) VALUES ${val_list.join(',')}`;
860
860
  };
861
861
 
862
862
  Sql.prototype._getKeys = function (obj) {
863
- const keys = [];
864
- for (const k in obj) {
863
+ let keys = [];
864
+ for (let k in obj) {
865
865
  keys.push(this.escapeId(k));
866
866
  }
867
867
  return keys;
868
868
  };
869
869
 
870
870
  Sql.prototype._buildValueList = function (list, keys) {
871
- const val_list = [];
872
- for (const item of list) {
873
- const values = [];
874
- for (const k of keys) {
875
- const key = k.replace(/`/g, '');
871
+ let val_list = [];
872
+ for (let item of list) {
873
+ let values = [];
874
+ for (let k of keys) {
875
+ let key = k.replace(/`/g, '');
876
876
  let val = item[key];
877
877
  values.push(this.escape(val));
878
878
  }
@@ -896,7 +896,7 @@ Sql.prototype.delList = async function (list, like, batch_size = 100, timeout =
896
896
  // 如果数据量较小,直接处理
897
897
  if (list.length <= batch_size) {
898
898
  let sql = '';
899
- for (const item of list) {
899
+ for (let item of list) {
900
900
  sql += this.toDelSql(item.query, like);
901
901
  }
902
902
  this.sql = sql;
@@ -904,7 +904,7 @@ Sql.prototype.delList = async function (list, like, batch_size = 100, timeout =
904
904
  }
905
905
 
906
906
  // 分批处理大数据量
907
- const batches = Math.ceil(list.length / batch_size);
907
+ let batches = Math.ceil(list.length / batch_size);
908
908
  this.log('info', `开始分批删除数据,共${batches}批,每批${batch_size}条`);
909
909
 
910
910
  // 使用事务包装整个操作以保证原子性
@@ -915,11 +915,11 @@ Sql.prototype.delList = async function (list, like, batch_size = 100, timeout =
915
915
 
916
916
  // 分批处理exec删除语句
917
917
  for (let i = 0; i < batches; i++) {
918
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
918
+ let batch = list.slice(i * batch_size, (i + 1) * batch_size);
919
919
  this.log('debug', `处理第${i + 1}/${batches}批数据,${batch.length}条`);
920
920
 
921
921
  let batch_sql = '';
922
- for (const item of batch) {
922
+ for (let item of batch) {
923
923
  batch_sql += this.toDelSql(item.query, like);
924
924
  }
925
925
  final_res = await this.exec(batch_sql);
@@ -951,7 +951,7 @@ Sql.prototype.setList = async function (list, like = false, batch_size = 100, ti
951
951
  throw new Error('表名或数据列表未设置');
952
952
  }
953
953
  // 分批处理大数据量
954
- const batches = Math.ceil(list.length / batch_size);
954
+ let batches = Math.ceil(list.length / batch_size);
955
955
  this.log('info', `开始分批修改数据,共${batches}批,每批${batch_size}条`);
956
956
 
957
957
  let final_res = null;
@@ -963,11 +963,11 @@ Sql.prototype.setList = async function (list, like = false, batch_size = 100, ti
963
963
 
964
964
  // 逐条处理记录,保持简单可靠
965
965
  for (let i = 0; i < list.length; i++) {
966
- const item = list[i];
966
+ let item = list[i];
967
967
  this.log('debug', `处理第${i + 1}/${list.length}条记录`);
968
968
 
969
969
  // 生成单个更新SQL
970
- const sql = this.toSetSql(item.query, item.item, like);
970
+ let sql = this.toSetSql(item.query, item.item, like);
971
971
  this.sql = sql;
972
972
 
973
973
  final_res = await this.exec(sql, [], timeout);
@@ -995,8 +995,8 @@ Sql.prototype.has = function (param_dt, sql_dt) {
995
995
  if (!param_dt || !sql_dt) {
996
996
  return false;
997
997
  }
998
- for (const key in sql_dt) {
999
- const value = param_dt[key];
998
+ for (let key in sql_dt) {
999
+ let value = param_dt[key];
1000
1000
  if (value !== undefined && value !== null && value !== '') {
1001
1001
  return true;
1002
1002
  }
@@ -1014,7 +1014,7 @@ Sql.prototype.not = function (param_dt, sql_dt) {
1014
1014
  if (!param_dt || !sql_dt) {
1015
1015
  return undefined;
1016
1016
  }
1017
- for (const key in param_dt) {
1017
+ for (let key in param_dt) {
1018
1018
  if (!sql_dt[key]) {
1019
1019
  return key;
1020
1020
  }
@@ -1029,11 +1029,11 @@ Sql.prototype.not = function (param_dt, sql_dt) {
1029
1029
  * @returns {object} 返回过滤后的参数集合
1030
1030
  */
1031
1031
  Sql.prototype.filterParams = function (param_dt, sql_dt) {
1032
- const dt = {};
1032
+ let dt = {};
1033
1033
  if (!param_dt || !sql_dt) {
1034
1034
  return dt;
1035
1035
  }
1036
- for (const key in param_dt) {
1036
+ for (let key in param_dt) {
1037
1037
  if (!sql_dt[key]) {
1038
1038
  dt[key] = param_dt[key];
1039
1039
  }
@@ -1049,16 +1049,16 @@ Sql.prototype.filterParams = function (param_dt, sql_dt) {
1049
1049
  * @returns {string} 拼接的查询条件
1050
1050
  */
1051
1051
  Sql.prototype._tplQueryWithSep = function (param_dt, sql_dt, l) {
1052
- const conds = [];
1053
- for (const key in param_dt) {
1052
+ let conds = [];
1053
+ for (let key in param_dt) {
1054
1054
  let value = String(param_dt[key]);
1055
- const arr = value.split(l);
1056
- const tpl = sql_dt[key];
1055
+ let arr = value.split(l);
1056
+ let tpl = sql_dt[key];
1057
1057
 
1058
1058
  if (tpl) {
1059
1059
  if (arr.length > 1) {
1060
- const sub_conds = [];
1061
- for (const val of arr) {
1060
+ let sub_conds = [];
1061
+ for (let val of arr) {
1062
1062
  // 使用直接替换方式,避免模板替换错误
1063
1063
  sub_conds.push(tpl.replaceAll('{0}', escape(val).trim("'")));
1064
1064
  }
@@ -1069,8 +1069,8 @@ Sql.prototype._tplQueryWithSep = function (param_dt, sql_dt, l) {
1069
1069
  }
1070
1070
  } else {
1071
1071
  if (arr.length > 1) {
1072
- const sub_conds = [];
1073
- for (const val of arr) {
1072
+ let sub_conds = [];
1073
+ for (let val of arr) {
1074
1074
  sub_conds.push(escapeId(key) + ' = ' + escape(val));
1075
1075
  }
1076
1076
  conds.push('(' + sub_conds.join(' || ') + ')');
@@ -1089,8 +1089,8 @@ Sql.prototype._tplQueryWithSep = function (param_dt, sql_dt, l) {
1089
1089
  * @returns {string} 拼接的查询条件
1090
1090
  */
1091
1091
  Sql.prototype._tplQueryNoSep = function (param_dt, sql_dt) {
1092
- const conds = [];
1093
- for (const key in param_dt) {
1092
+ let conds = [];
1093
+ for (let key in param_dt) {
1094
1094
  value = escape(param_dt[key]);
1095
1095
  if (sql_dt[key]) {
1096
1096
  // 使用直接替换方式,避免模板替换错误
@@ -1109,13 +1109,13 @@ Sql.prototype._tplQueryNoSep = function (param_dt, sql_dt) {
1109
1109
  * @returns {string} 拼接的查询条件
1110
1110
  */
1111
1111
  Sql.prototype._noTplQueryWithSep = function (param_dt, l) {
1112
- const conds = [];
1113
- for (const key in param_dt) {
1114
- const value = param_dt[key];
1115
- const arr = String(value).split(l);
1112
+ let conds = [];
1113
+ for (let key in param_dt) {
1114
+ let value = param_dt[key];
1115
+ let arr = String(value).split(l);
1116
1116
  if (arr.length > 1) {
1117
- const sub_conds = [];
1118
- for (const val of arr) {
1117
+ let sub_conds = [];
1118
+ for (let val of arr) {
1119
1119
  sub_conds.push(escapeId(key) + ' = ' + escape(val));
1120
1120
  }
1121
1121
  conds.push('(' + sub_conds.join(' || ') + ')');
@@ -1132,8 +1132,8 @@ Sql.prototype._noTplQueryWithSep = function (param_dt, l) {
1132
1132
  * @returns {string} 拼接的查询条件
1133
1133
  */
1134
1134
  Sql.prototype._noTplQueryNoSep = function (param_dt) {
1135
- const conds = [];
1136
- for (const key in param_dt) {
1135
+ let conds = [];
1136
+ for (let key in param_dt) {
1137
1137
  conds.push(escapeId(key) + ' = ' + escape(param_dt[key]));
1138
1138
  }
1139
1139
  return conds.join(' && ');
@@ -1150,7 +1150,7 @@ Sql.prototype.tplQuery = function (param_dt, sql_dt) {
1150
1150
  if (!param_dt) {
1151
1151
  return sql;
1152
1152
  }
1153
- const l = this.config.separator;
1153
+ let l = this.config.separator;
1154
1154
  if (sql_dt) {
1155
1155
  if (l) {
1156
1156
  sql = this._tplQueryWithSep(param_dt, sql_dt, l);
@@ -1177,17 +1177,17 @@ Sql.prototype.tplBody = function (param_dt, sql_dt) {
1177
1177
  if (!param_dt) {
1178
1178
  return '';
1179
1179
  }
1180
- const parts = [];
1180
+ let parts = [];
1181
1181
  if (!sql_dt || Object.keys(sql_dt).length === 0) {
1182
- for (const key in param_dt) {
1182
+ for (let key in param_dt) {
1183
1183
  parts.push(' ' + escapeId(key) + ' = ' + escape(param_dt[key]));
1184
1184
  }
1185
1185
  } else {
1186
- for (const key in param_dt) {
1186
+ for (let key in param_dt) {
1187
1187
  let value = escape(param_dt[key]);
1188
1188
  if (sql_dt[key]) {
1189
1189
  // 使用直接替换方式,避免模板替换错误
1190
- const replaced = sql_dt[key].replaceAll('{0}', value.trim("'"));
1190
+ let replaced = sql_dt[key].replaceAll('{0}', value.trim("'"));
1191
1191
  parts.push(' ' + replaced.replace(/\+ -/g, '- ').replace(/- -/g, '+ '));
1192
1192
  } else {
1193
1193
  parts.push(' ' + escapeId(key) + ' = ' + value);
@@ -1206,7 +1206,7 @@ Sql.prototype.load = async function (file) {
1206
1206
 
1207
1207
  await this._logLoadStart(file);
1208
1208
  await this._validateFile(file);
1209
- const sql_stmts = await this._readAndSplitSql(file);
1209
+ let sql_stmts = await this._readAndSplitSql(file);
1210
1210
  return await this._execSqlStmts(file, sql_stmts);
1211
1211
  };
1212
1212
 
@@ -1240,7 +1240,7 @@ Sql.prototype._validateFile = async function (file) {
1240
1240
  * @returns {Promise<string[]>} SQL语句数组
1241
1241
  */
1242
1242
  Sql.prototype._readAndSplitSql = async function (file) {
1243
- const sql_content = await $.file.readText(file);
1243
+ let sql_content = await $.file.readText(file);
1244
1244
  if (!sql_content || sql_content.trim() === '') {
1245
1245
  throw new Error(`SQL文件内容为空: ${file}`);
1246
1246
  }
@@ -1272,8 +1272,8 @@ Sql.prototype._execSqlStmts = async function (file, sql_stmts) {
1272
1272
  * @returns {Promise<void>}
1273
1273
  */
1274
1274
  Sql.prototype._executeStatements = async function (sql_stmts) {
1275
- for (const sql of sql_stmts) {
1276
- const trimmed_sql = sql.trim();
1275
+ for (let sql of sql_stmts) {
1276
+ let trimmed_sql = sql.trim();
1277
1277
  if (trimmed_sql) {
1278
1278
  await this.exec(trimmed_sql);
1279
1279
  }
@@ -1386,18 +1386,18 @@ Sql.prototype._handleString = function (char, sql_content, i, in_str, str_char,
1386
1386
  * @returns {Array} SQL语句数组
1387
1387
  */
1388
1388
  Sql.prototype._splitSqlStatements = function (sql_content) {
1389
- const stmts = [];
1389
+ let stmts = [];
1390
1390
  let in_str = false;
1391
1391
  let str_char = '';
1392
1392
  let in_comment = false;
1393
1393
  let cur_stmt = '';
1394
1394
 
1395
1395
  for (let i = 0; i < sql_content.length; i++) {
1396
- const char = sql_content[i];
1397
- const next_char = i + 1 < sql_content.length ? sql_content[i + 1] : '';
1396
+ let char = sql_content[i];
1397
+ let next_char = i + 1 < sql_content.length ? sql_content[i + 1] : '';
1398
1398
 
1399
1399
  // 处理注释
1400
- const line_comment = this._handleLineComment(char, next_char, in_str, in_comment);
1400
+ let line_comment = this._handleLineComment(char, next_char, in_str, in_comment);
1401
1401
  if (line_comment.skip > 0) {
1402
1402
  i += line_comment.skip;
1403
1403
  in_comment = line_comment.in_comment;
@@ -1405,7 +1405,7 @@ Sql.prototype._splitSqlStatements = function (sql_content) {
1405
1405
  }
1406
1406
  in_comment = line_comment.in_comment;
1407
1407
 
1408
- const block_comment = this._handleBlockComment(char, next_char, in_str, in_comment);
1408
+ let block_comment = this._handleBlockComment(char, next_char, in_str, in_comment);
1409
1409
  if (block_comment.skip > 0) {
1410
1410
  i += block_comment.skip;
1411
1411
  in_comment = block_comment.in_comment;
@@ -1418,7 +1418,7 @@ Sql.prototype._splitSqlStatements = function (sql_content) {
1418
1418
  }
1419
1419
 
1420
1420
  // 处理字符串
1421
- const str_res = this._handleString(char, sql_content, i, in_str, str_char, in_comment);
1421
+ let str_res = this._handleString(char, sql_content, i, in_str, str_char, in_comment);
1422
1422
  in_str = str_res.in_str;
1423
1423
  str_char = str_res.str_char;
1424
1424
 
@@ -1445,20 +1445,20 @@ Sql.prototype._splitSqlStatements = function (sql_content) {
1445
1445
  * @returns {object} 返回监听操作的对象
1446
1446
  */
1447
1447
  Sql.prototype.model = function (model) {
1448
- const self = this;
1448
+ let self = this;
1449
1449
  return new Proxy(model || {}, {
1450
1450
  set: function (obj, prop, value) {
1451
1451
  if (self.key && prop !== 'length' && !prop.toString().startsWith('__')) {
1452
- const query = {};
1453
- const arr = self.key.split(',');
1454
- for (const key of arr) {
1452
+ let query = {};
1453
+ let arr = self.key.split(',');
1454
+ for (let key of arr) {
1455
1455
  query[key] = obj[key];
1456
1456
  }
1457
1457
 
1458
1458
  if (typeof value === 'number') {
1459
- const n = obj[prop] || 0;
1460
- const cha = value - n;
1461
- const where = self.toWhere(query);
1459
+ let n = obj[prop] || 0;
1460
+ let cha = value - n;
1461
+ let where = self.toWhere(query);
1462
1462
  if (cha > 0) {
1463
1463
  self.setSql(where, '`' + prop + '` = `' + prop + '` + ' + cha);
1464
1464
  } else if (cha < 0) {
@@ -1467,14 +1467,14 @@ Sql.prototype.model = function (model) {
1467
1467
  self.setSql(where, '`' + prop + '` = ' + value);
1468
1468
  }
1469
1469
  } else {
1470
- const set = {};
1470
+ let set = {};
1471
1471
  set[prop] = value;
1472
1472
  self.set(query, set, false).catch(err => {
1473
1473
  self.log('error', '模型数据更新失败', err);
1474
1474
  });
1475
1475
  }
1476
1476
  }
1477
- const new_obj = { ...obj };
1477
+ let new_obj = { ...obj };
1478
1478
  new_obj[prop] = value;
1479
1479
  return true;
1480
1480
  }
@@ -1492,8 +1492,8 @@ Sql.prototype.addOrSet = async function (where, set, like) {
1492
1492
  if (!this.table || !where || !set) {
1493
1493
  throw new Error('表名、条件或数据未设置');
1494
1494
  }
1495
- const where_str = await this._getWhereStr(where, like);
1496
- const count = await this.countSql(where_str);
1495
+ let where_str = await this._getWhereStr(where, like);
1496
+ let count = await this.countSql(where_str);
1497
1497
 
1498
1498
  if (count === 0) {
1499
1499
  return await this._addData(set);
@@ -1509,8 +1509,8 @@ Sql.prototype.addOrSet = async function (where, set, like) {
1509
1509
  */
1510
1510
  Sql.prototype._getCreateTableSql = async function () {
1511
1511
  // 查询表结构信息(MySQL 使用 SHOW CREATE TABLE)
1512
- const sql = `SHOW CREATE TABLE \`${this.table}\``;
1513
- const result = await this.run(sql);
1512
+ let sql = `SHOW CREATE TABLE \`${this.table}\``;
1513
+ let result = await this.run(sql);
1514
1514
 
1515
1515
  if (result && result.length > 0 && result[0]['Create Table']) {
1516
1516
  // 在创建表语句中添加 IF NOT EXISTS 条件
@@ -1533,23 +1533,23 @@ Sql.prototype._getTableComments = async function () {
1533
1533
  let commentSql = '';
1534
1534
 
1535
1535
  // 获取表注释
1536
- const tableCommentSql = `
1536
+ let tableCommentSql = `
1537
1537
  SELECT TABLE_COMMENT
1538
1538
  FROM information_schema.TABLES
1539
1539
  WHERE TABLE_SCHEMA = DATABASE()
1540
1540
  AND TABLE_NAME = '${this.table}'
1541
1541
  `;
1542
- const tableCommentResult = await this.run(tableCommentSql);
1542
+ let tableCommentResult = await this.run(tableCommentSql);
1543
1543
 
1544
1544
  if (tableCommentResult && tableCommentResult.length > 0 && tableCommentResult[0].TABLE_COMMENT) {
1545
- const tableComment = tableCommentResult[0].TABLE_COMMENT;
1545
+ let tableComment = tableCommentResult[0].TABLE_COMMENT;
1546
1546
  if (tableComment && tableComment.trim() !== '') {
1547
1547
  commentSql += `\n-- 表注释: ${tableComment}\n`;
1548
1548
  }
1549
1549
  }
1550
1550
 
1551
1551
  // 获取列注释
1552
- const columnCommentSql = `
1552
+ let columnCommentSql = `
1553
1553
  SELECT COLUMN_NAME, COLUMN_COMMENT
1554
1554
  FROM information_schema.COLUMNS
1555
1555
  WHERE TABLE_SCHEMA = DATABASE()
@@ -1558,11 +1558,11 @@ Sql.prototype._getTableComments = async function () {
1558
1558
  AND COLUMN_COMMENT != ''
1559
1559
  ORDER BY ORDINAL_POSITION
1560
1560
  `;
1561
- const columnCommentResult = await this.run(columnCommentSql);
1561
+ let columnCommentResult = await this.run(columnCommentSql);
1562
1562
 
1563
1563
  if (columnCommentResult && columnCommentResult.length > 0) {
1564
1564
  commentSql += '\n-- 列注释:\n';
1565
- for (const column of columnCommentResult) {
1565
+ for (let column of columnCommentResult) {
1566
1566
  commentSql += `-- ${column.COLUMN_NAME}: ${column.COLUMN_COMMENT}\n`;
1567
1567
  }
1568
1568
  }
@@ -1586,7 +1586,7 @@ Sql.prototype.backup = async function (file, create = false) {
1586
1586
  }
1587
1587
 
1588
1588
  // 获取所有数据
1589
- const data = await this.getSql('', '', '*');
1589
+ let data = await this.getSql('', '', '*');
1590
1590
 
1591
1591
  if (!data || !Array.isArray(data)) {
1592
1592
  throw new Error('获取数据失败');
@@ -1601,12 +1601,12 @@ Sql.prototype.backup = async function (file, create = false) {
1601
1601
 
1602
1602
  // 如果create为true,添加创建表语句
1603
1603
  if (create) {
1604
- const createTableSql = await this._getCreateTableSql();
1604
+ let createTableSql = await this._getCreateTableSql();
1605
1605
  if (createTableSql) {
1606
1606
  sqlContent += createTableSql + '\n\n';
1607
1607
 
1608
1608
  // 添加表注释信息
1609
- const commentSql = await this._getTableComments();
1609
+ let commentSql = await this._getTableComments();
1610
1610
  if (commentSql) {
1611
1611
  sqlContent += commentSql + '\n';
1612
1612
  }
@@ -1614,18 +1614,18 @@ Sql.prototype.backup = async function (file, create = false) {
1614
1614
  }
1615
1615
 
1616
1616
  // 添加数据插入语句
1617
- for (const row of data) {
1618
- const keys = Object.keys(row).map(key => this.escapeId(key)).join(', ');
1619
- const values = Object.values(row).map(value => this.escape(value)).join(', ');
1617
+ for (let row of data) {
1618
+ let keys = Object.keys(row).map(key => this.escapeId(key)).join(', ');
1619
+ let values = Object.values(row).map(value => this.escape(value)).join(', ');
1620
1620
  sqlContent += `INSERT INTO \`${this.table}\` (${keys}) VALUES (${values});\n`;
1621
1621
  }
1622
1622
 
1623
1623
  // 写入文件(这里需要文件系统模块,实际使用时需要引入 fs)
1624
- const fs = require('fs');
1625
- const path = require('path');
1624
+ let fs = require('fs');
1625
+ let path = require('path');
1626
1626
 
1627
1627
  // 确保目录存在
1628
- const dir = path.dirname(file);
1628
+ let dir = path.dirname(file);
1629
1629
  if (!fs.existsSync(dir)) {
1630
1630
  fs.mkdirSync(dir, { recursive: true });
1631
1631
  }
@@ -1649,20 +1649,20 @@ Sql.prototype.restore = async function (file) {
1649
1649
  throw new TypeError('表名未设置');
1650
1650
  }
1651
1651
 
1652
- const fs = require('fs');
1652
+ let fs = require('fs');
1653
1653
 
1654
1654
  if (!fs.existsSync(file)) {
1655
1655
  throw new Error('备份文件不存在');
1656
1656
  }
1657
1657
 
1658
1658
  // 读取 SQL 文件
1659
- const sqlContent = fs.readFileSync(file, 'utf8');
1659
+ let sqlContent = fs.readFileSync(file, 'utf8');
1660
1660
 
1661
1661
  // 解析 SQL 语句
1662
- const statements = this._parseSqlStatements(sqlContent);
1662
+ let statements = this._parseSqlStatements(sqlContent);
1663
1663
 
1664
1664
  // 执行每个 SQL 语句
1665
- for (const stmt of statements) {
1665
+ for (let stmt of statements) {
1666
1666
  if (stmt.trim() && !stmt.startsWith('--')) {
1667
1667
  await this.exec(stmt);
1668
1668
  }
@@ -1678,15 +1678,15 @@ Sql.prototype.restore = async function (file) {
1678
1678
  * @private
1679
1679
  */
1680
1680
  Sql.prototype._parseSqlStatements = function (sql) {
1681
- const stmts = [];
1681
+ let stmts = [];
1682
1682
  let cur_stmt = '';
1683
1683
  let in_str = false;
1684
1684
  let in_cmt = false;
1685
1685
  let quote_char = '';
1686
1686
 
1687
1687
  for (let i = 0; i < sql.length; i++) {
1688
- const char = sql[i];
1689
- const next_char = sql[i + 1] || '';
1688
+ let char = sql[i];
1689
+ let next_char = sql[i + 1] || '';
1690
1690
 
1691
1691
  // 处理字符串
1692
1692
  if (!in_cmt && (char === "'" || char === '"') && (i === 0 || sql[i - 1] !== '\\')) {
@@ -1765,7 +1765,7 @@ Sql.prototype.backup = async function (file, create = false) {
1765
1765
  }
1766
1766
 
1767
1767
  // 获取所有数据
1768
- const data = await this.getSql('', '', '*');
1768
+ let data = await this.getSql('', '', '*');
1769
1769
 
1770
1770
  if (!data || !Array.isArray(data)) {
1771
1771
  throw new Error('获取数据失败');
@@ -1780,25 +1780,25 @@ Sql.prototype.backup = async function (file, create = false) {
1780
1780
 
1781
1781
  // 如果create为true,添加创建表语句
1782
1782
  if (create) {
1783
- const create_table_sql = await this._getCreateTableSql();
1783
+ let create_table_sql = await this._getCreateTableSql();
1784
1784
  if (create_table_sql) {
1785
1785
  sql_content += create_table_sql + '\n\n';
1786
1786
  }
1787
1787
  }
1788
1788
 
1789
1789
  // 添加数据插入语句
1790
- for (const row of data) {
1791
- const keys = Object.keys(row).map(key => this.escapeId(key)).join(', ');
1792
- const values = Object.values(row).map(value => this.escape(value)).join(', ');
1790
+ for (let row of data) {
1791
+ let keys = Object.keys(row).map(key => this.escapeId(key)).join(', ');
1792
+ let values = Object.values(row).map(value => this.escape(value)).join(', ');
1793
1793
  sql_content += `INSERT INTO \`${this.table}\` (${keys}) VALUES (${values});\n`;
1794
1794
  }
1795
1795
 
1796
1796
  // 写入文件(这里需要文件系统模块,实际使用时需要引入 fs)
1797
- const fs = require('fs');
1798
- const path = require('path');
1797
+ let fs = require('fs');
1798
+ let path = require('path');
1799
1799
 
1800
1800
  // 确保目录存在
1801
- const dir = path.dirname(file);
1801
+ let dir = path.dirname(file);
1802
1802
  if (!fs.existsSync(dir)) {
1803
1803
  fs.mkdirSync(dir, { recursive: true });
1804
1804
  }
@@ -1822,7 +1822,7 @@ Sql.prototype.restore = async function (file) {
1822
1822
  throw new TypeError('表名未设置');
1823
1823
  }
1824
1824
 
1825
- const fs = require('fs');
1825
+ let fs = require('fs');
1826
1826
 
1827
1827
  // 检查文件是否存在
1828
1828
  if (!fs.existsSync(file)) {
@@ -1830,14 +1830,14 @@ Sql.prototype.restore = async function (file) {
1830
1830
  }
1831
1831
 
1832
1832
  // 读取文件内容
1833
- const sql_content = fs.readFileSync(file, 'utf8');
1833
+ let sql_content = fs.readFileSync(file, 'utf8');
1834
1834
 
1835
1835
  if (!sql_content) {
1836
1836
  throw new Error('备份文件为空');
1837
1837
  }
1838
1838
 
1839
1839
  // 解析 SQL 语句
1840
- const sql_stmts = this._parseSqlStatements(sql_content);
1840
+ let sql_stmts = this._parseSqlStatements(sql_content);
1841
1841
 
1842
1842
  if (!sql_stmts || sql_stmts.length === 0) {
1843
1843
  throw new Error('未找到有效的 SQL 语句');
@@ -1848,8 +1848,8 @@ Sql.prototype.restore = async function (file) {
1848
1848
 
1849
1849
  try {
1850
1850
  // 逐个执行SQL语句
1851
- for (const sql of sql_stmts) {
1852
- const trim_sql = sql.trim();
1851
+ for (let sql of sql_stmts) {
1852
+ let trim_sql = sql.trim();
1853
1853
  if (trim_sql) {
1854
1854
  await this.exec(trim_sql);
1855
1855
  }
@@ -1885,8 +1885,8 @@ Sql.prototype.restore = async function (file) {
1885
1885
  */
1886
1886
  Sql.prototype._getCreateTableSql = async function () {
1887
1887
  // 查询表结构信息(MySQL 使用 SHOW CREATE TABLE)
1888
- const sql = `SHOW CREATE TABLE \`${this.table}\``;
1889
- const result = await this.run(sql);
1888
+ let sql = `SHOW CREATE TABLE \`${this.table}\``;
1889
+ let result = await this.run(sql);
1890
1890
 
1891
1891
  if (result && result.length > 0 && result[0]['Create Table']) {
1892
1892
  // 在创建表语句中添加 IF NOT EXISTS 条件
package/test2.js ADDED
@@ -0,0 +1,381 @@
1
+ /**
2
+ * MySQL错误处理测试文件
3
+ * @file test2.js
4
+ * @description 测试Mysql类的错误日志输出功能
5
+ */
6
+
7
+ const { Mysql } = require('./index.js');
8
+
9
+ /**
10
+ * 错误测试类
11
+ * @class ErrorTestMysql
12
+ */
13
+ class ErrorTestMysql {
14
+ /**
15
+ * 构造函数
16
+ * @param {object} config - 数据库配置
17
+ */
18
+ constructor(config) {
19
+ this.config = {
20
+ host: '127.0.0.1',
21
+ port: 3306,
22
+ user: 'root',
23
+ password: 'Asd159357',
24
+ database: 'test_db',
25
+ debug: true,
26
+ ...config || {}
27
+ };
28
+
29
+ this._mysql = null;
30
+ this._test_results = [];
31
+ }
32
+
33
+ /**
34
+ * 初始化测试
35
+ * @returns {Promise<boolean>}
36
+ */
37
+ async _init() {
38
+ try {
39
+ this._mysql = new Mysql(this.config);
40
+ await this._mysql.open();
41
+ console.log('=== 错误处理测试初始化完成 ===');
42
+ return true;
43
+ } catch (error) {
44
+ console.error('初始化失败:', error.message);
45
+ return false;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 记录测试结果
51
+ * @param {string} test_name - 测试名称
52
+ * @param {boolean} success - 是否成功
53
+ * @param {string} message - 测试信息
54
+ */
55
+ _recordResult(test_name, success, message) {
56
+ this._test_results.push({
57
+ test_name,
58
+ success,
59
+ message,
60
+ timestamp: new Date().toISOString()
61
+ });
62
+
63
+ const status = success ? '✓' : '✗';
64
+ console.log(`${status} ${test_name}: ${message}`);
65
+ }
66
+
67
+ /**
68
+ * 测试无效表查询错误
69
+ * @returns {Promise<boolean>}
70
+ */
71
+ async testInvalidTable() {
72
+ try {
73
+ console.log('\n--- 测试1: 查询不存在的表 ---');
74
+
75
+ // 执行无效SQL
76
+ const invalid_sql = 'SELECT * FROM non_existent_table_xyz';
77
+ const result = await this._mysql.run(invalid_sql);
78
+
79
+ // 检查错误信息
80
+ if (this._mysql.error) {
81
+ console.log('错误信息:', this._mysql.error);
82
+ this._recordResult('无效表查询', true, `成功捕获错误: ${this._mysql.error.message}`);
83
+ return true;
84
+ } else {
85
+ this._recordResult('无效表查询', false, '未捕获到预期的错误');
86
+ return false;
87
+ }
88
+ } catch (error) {
89
+ this._recordResult('无效表查询', false, `异常错误: ${error.message}`);
90
+ return false;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * 测试无效SQL语法错误
96
+ * @returns {Promise<boolean>}
97
+ */
98
+ async testInvalidSyntax() {
99
+ try {
100
+ console.log('\n--- 测试2: 无效SQL语法 ---');
101
+
102
+ // 执行语法错误的SQL
103
+ const invalid_sql = 'SELECT FROM test_users';
104
+ const result = await this._mysql.run(invalid_sql);
105
+
106
+ // 检查错误信息
107
+ if (this._mysql.error) {
108
+ console.log('错误信息:', this._mysql.error);
109
+ this._recordResult('无效SQL语法', true, `成功捕获错误: ${this._mysql.error.message}`);
110
+ return true;
111
+ } else {
112
+ this._recordResult('无效SQL语法', false, '未捕获到预期的错误');
113
+ return false;
114
+ }
115
+ } catch (error) {
116
+ this._recordResult('无效SQL语法', false, `异常错误: ${error.message}`);
117
+ return false;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * 测试exec方法错误处理
123
+ * @returns {Promise<boolean>}
124
+ */
125
+ async testExecError() {
126
+ try {
127
+ console.log('\n--- 测试3: exec方法错误处理 ---');
128
+
129
+ // 执行无效INSERT语句
130
+ const invalid_sql = 'INSERT INTO non_existent_table (name) VALUES (?)';
131
+ const result = await this._mysql.exec(invalid_sql, ['test']);
132
+
133
+ // 检查错误信息
134
+ if (this._mysql.error) {
135
+ console.log('错误信息:', this._mysql.error);
136
+ this._recordResult('exec方法错误', true, `成功捕获错误: ${this._mysql.error.message}`);
137
+ return true;
138
+ } else {
139
+ this._recordResult('exec方法错误', false, '未捕获到预期的错误');
140
+ return false;
141
+ }
142
+ } catch (error) {
143
+ this._recordResult('exec方法错误', false, `异常错误: ${error.message}`);
144
+ return false;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * 测试DB类错误处理
150
+ * @returns {Promise<boolean>}
151
+ */
152
+ async testDbClassError() {
153
+ try {
154
+ console.log('\n--- 测试4: DB类错误处理 ---');
155
+
156
+ // 获取DB实例并尝试操作不存在的表
157
+ const db = this._mysql.db().new('non_existent_table_db', 'id');
158
+
159
+ // 尝试获取数据
160
+ const result = await db.get({ id: 1 });
161
+
162
+ // 检查错误信息
163
+ if (this._mysql.error) {
164
+ console.log('错误信息:', this._mysql.error);
165
+ this._recordResult('DB类错误', true, `成功捕获错误: ${this._mysql.error.message}`);
166
+ return true;
167
+ } else {
168
+ this._recordResult('DB类错误', false, '未捕获到预期的错误');
169
+ return false;
170
+ }
171
+ } catch (error) {
172
+ this._recordResult('DB类错误', false, `异常错误: ${error.message}`);
173
+ return false;
174
+ }
175
+ }
176
+
177
+ /**
178
+ * 测试连接失败错误(使用错误配置)
179
+ * @returns {Promise<boolean>}
180
+ */
181
+ async testConnectionError() {
182
+ try {
183
+ console.log('\n--- 测试5: 连接失败错误 ---');
184
+
185
+ // 使用错误配置创建连接
186
+ const bad_config = {
187
+ host: '127.0.0.1',
188
+ port: 3307, // 错误端口
189
+ user: 'root',
190
+ password: 'wrong_password',
191
+ database: 'test_db',
192
+ debug: true
193
+ };
194
+
195
+ const bad_mysql = new Mysql(bad_config);
196
+ const result = await bad_mysql.open();
197
+
198
+ // 连接应该失败
199
+ if (result === false) {
200
+ console.log('连接失败(预期行为)');
201
+ this._recordResult('连接失败错误', true, '成功检测到连接失败');
202
+ return true;
203
+ } else {
204
+ this._recordResult('连接失败错误', false, '连接意外成功,测试失败');
205
+ await bad_mysql.close();
206
+ return false;
207
+ }
208
+ } catch (error) {
209
+ console.log('捕获到异常:', error.message);
210
+ this._recordResult('连接失败错误', true, `成功捕获连接异常: ${error.message}`);
211
+ return true;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * 测试参数验证错误
217
+ * @returns {Promise<boolean>}
218
+ */
219
+ async testParameterValidation() {
220
+ try {
221
+ console.log('\n--- 测试6: 参数验证错误 ---');
222
+
223
+ // 测试无效参数类型
224
+ let error_count = 0;
225
+
226
+ try {
227
+ await this._mysql.run(null);
228
+ } catch (error) {
229
+ console.log('参数验证错误1:', error.message);
230
+ error_count++;
231
+ }
232
+
233
+ try {
234
+ await this._mysql.run('SELECT 1', 'invalid');
235
+ } catch (error) {
236
+ console.log('参数验证错误2:', error.message);
237
+ error_count++;
238
+ }
239
+
240
+ if (error_count === 2) {
241
+ this._recordResult('参数验证错误', true, '成功捕获2个参数验证错误');
242
+ return true;
243
+ } else {
244
+ this._recordResult('参数验证错误', false, `只捕获到 ${error_count} 个错误,预期2个`);
245
+ return false;
246
+ }
247
+ } catch (error) {
248
+ this._recordResult('参数验证错误', false, `异常错误: ${error.message}`);
249
+ return false;
250
+ }
251
+ }
252
+
253
+ /**
254
+ * 运行所有错误测试
255
+ * @returns {Promise<object>}
256
+ */
257
+ async runAllTests() {
258
+ console.log('\n=== 开始运行MySQL错误处理测试 ===\n');
259
+
260
+ // 初始化测试
261
+ const init_success = await this._init();
262
+ if (!init_success) {
263
+ console.log('测试初始化失败');
264
+ return this._getTestSummary();
265
+ }
266
+
267
+ // 定义测试用例
268
+ const test_cases = [
269
+ { name: '无效表查询', method: 'testInvalidTable' },
270
+ { name: '无效SQL语法', method: 'testInvalidSyntax' },
271
+ { name: 'exec方法错误', method: 'testExecError' },
272
+ { name: 'DB类错误', method: 'testDbClassError' },
273
+ { name: '连接失败错误', method: 'testConnectionError' },
274
+ { name: '参数验证错误', method: 'testParameterValidation' }
275
+ ];
276
+
277
+ // 执行测试
278
+ for (const test_case of test_cases) {
279
+ try {
280
+ console.log(`执行测试: ${test_case.name}`);
281
+ await this[test_case.method]();
282
+ } catch (error) {
283
+ console.error(`测试异常: ${test_case.name}`, error);
284
+ this._recordResult(test_case.name, false, `测试执行异常: ${error.message}`);
285
+ }
286
+ }
287
+
288
+ // 关闭连接
289
+ if (this._mysql) {
290
+ await this._mysql.close();
291
+ }
292
+
293
+ return this._getTestSummary();
294
+ }
295
+
296
+ /**
297
+ * 获取测试摘要
298
+ * @returns {object}
299
+ */
300
+ _getTestSummary() {
301
+ const total = this._test_results.length;
302
+ const passed = this._test_results.filter(r => r.success).length;
303
+ const failed = total - passed;
304
+
305
+ console.log('\n=== 测试结果摘要 ===');
306
+ console.log(`总测试数: ${total}`);
307
+ console.log(`通过: ${passed}`);
308
+ console.log(`失败: ${failed}`);
309
+ console.log(`通过率: ${((passed / total) * 100).toFixed(1)}%`);
310
+
311
+ // 显示失败的测试
312
+ const failed_tests = this._test_results.filter(r => !r.success);
313
+ if (failed_tests.length > 0) {
314
+ console.log('\n失败的测试:');
315
+ failed_tests.forEach(test => {
316
+ console.log(` ✗ ${test.test_name}: ${test.message}`);
317
+ });
318
+ }
319
+
320
+ return {
321
+ total,
322
+ passed,
323
+ failed,
324
+ results: this._test_results
325
+ };
326
+ }
327
+
328
+ /**
329
+ * 主测试函数
330
+ * @returns {Promise<void>}
331
+ */
332
+ async main() {
333
+ try {
334
+ const summary = await this.runAllTests();
335
+
336
+ if (summary.failed > 0) {
337
+ console.log('\n❌ 部分测试失败');
338
+ process.exit(1);
339
+ } else {
340
+ console.log('\n✅ 所有测试通过!');
341
+ process.exit(0);
342
+ }
343
+ } catch (error) {
344
+ console.error('测试执行异常:', error);
345
+ process.exit(1);
346
+ }
347
+ }
348
+ }
349
+
350
+ // 模块导出
351
+ exports.ErrorTestMysql = ErrorTestMysql;
352
+
353
+ /**
354
+ * 快速测试函数
355
+ * @param {object} config - 数据库配置
356
+ */
357
+ const quick_test = async function(config) {
358
+ const tester = new ErrorTestMysql(config);
359
+ await tester.main();
360
+ };
361
+
362
+ // 如果直接运行此文件,执行测试
363
+ if (require.main === module) {
364
+ const test_config = {
365
+ host: process.env.DB_HOST || '127.0.0.1',
366
+ port: parseInt(process.env.DB_PORT) || 3306,
367
+ user: process.env.DB_USER || 'root',
368
+ password: process.env.DB_PASSWORD || 'Asd159357',
369
+ database: process.env.DB_NAME || 'test_db',
370
+ debug: process.env.DEBUG === 'true'
371
+ };
372
+
373
+ console.log('使用配置:', {
374
+ ...test_config,
375
+ password: '***'
376
+ });
377
+
378
+ quick_test(test_config);
379
+ }
380
+
381
+ exports.quick_test = quick_test;