mm_sqlite 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +351 -1
- package/db/mm.db +0 -0
- package/db.js +583 -139
- package/index.js +687 -187
- package/package.json +16 -11
- package/sql.js +854 -125
- package/sql_builder.js +375 -0
- package/test.js +75 -648
- package/test_all_methods.js +115 -0
- package/db/test.db +0 -0
- package/index_/345/217/202/350/200/203.js +0 -299
package/sql.js
CHANGED
|
@@ -149,21 +149,24 @@ class Sql {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
|
-
* @description
|
|
152
|
+
* @description 清空查询条件
|
|
153
|
+
* @return {Object} 返回当前对象
|
|
153
154
|
*/
|
|
154
|
-
Sql.prototype.clear =
|
|
155
|
-
this.
|
|
156
|
-
this.
|
|
155
|
+
Sql.prototype.clear = function() {
|
|
156
|
+
this.where = "";
|
|
157
|
+
this.set = "";
|
|
158
|
+
this.order = "";
|
|
159
|
+
this.view = "";
|
|
157
160
|
this.sql = "";
|
|
158
|
-
this.error;
|
|
159
|
-
this.
|
|
160
|
-
this.
|
|
161
|
+
this.error = "";
|
|
162
|
+
this.like = true;
|
|
163
|
+
this.config = {};
|
|
164
|
+
this.param = {};
|
|
161
165
|
this.page = 0;
|
|
162
|
-
this.size =
|
|
163
|
-
this.
|
|
164
|
-
this.
|
|
165
|
-
this
|
|
166
|
-
this.count_ret = "false";
|
|
166
|
+
this.size = 0;
|
|
167
|
+
this.run = null;
|
|
168
|
+
this.exec = null;
|
|
169
|
+
return this;
|
|
167
170
|
};
|
|
168
171
|
|
|
169
172
|
/**
|
|
@@ -257,7 +260,7 @@ Sql.prototype.getSql = function(where, sort, view) {
|
|
|
257
260
|
* @param {String} set 修改的键值
|
|
258
261
|
* @return {Promise|Object} 执行结果
|
|
259
262
|
*/
|
|
260
|
-
Sql.prototype.addOrSetSql = async function(where, set) {
|
|
263
|
+
Sql.prototype.addOrSetSql = async function(where, set, like) {
|
|
261
264
|
if (!where || !set) {
|
|
262
265
|
return -1;
|
|
263
266
|
}
|
|
@@ -333,20 +336,20 @@ Sql.prototype.groupMathSql = async function(where, groupby, view, sort, method)
|
|
|
333
336
|
if (view.indexOf(",") !== -1) {
|
|
334
337
|
var arr = view.split(",");
|
|
335
338
|
for (var i = 0; i < arr.length; i++) {
|
|
336
|
-
var str =
|
|
339
|
+
var str = escapeId(arr[i]);
|
|
337
340
|
viewStr += "," + method.toUpperCase() + "(" + str + ") " + method.toLowerCase() + "_" + str.replace(
|
|
338
341
|
/`/g, "")
|
|
339
342
|
}
|
|
340
343
|
} else {
|
|
341
|
-
viewStr = "," + method.toUpperCase() + "(" +
|
|
344
|
+
viewStr = "," + method.toUpperCase() + "(" + escapeId(view) + ") " + method.toLowerCase() + "_" +
|
|
342
345
|
view.replace(/`/g, "")
|
|
343
346
|
}
|
|
344
|
-
var sql = "SELECT " + (groupby ?
|
|
347
|
+
var sql = "SELECT " + (groupby ? escapeId(groupby) : "") + viewStr + " FROM `" + this.table + "`";
|
|
345
348
|
if (where) {
|
|
346
349
|
sql += ' WHERE ' + where;
|
|
347
350
|
}
|
|
348
351
|
if (groupby) {
|
|
349
|
-
sql += " GROUP BY " +
|
|
352
|
+
sql += " GROUP BY " + escapeId(groupby);
|
|
350
353
|
}
|
|
351
354
|
if (sort) {
|
|
352
355
|
sql += " ORDER BY " + sort;
|
|
@@ -458,34 +461,49 @@ Sql.prototype.toWhere = function(obj, like) {
|
|
|
458
461
|
if (like) {
|
|
459
462
|
for (var k in obj) {
|
|
460
463
|
var val = obj[k];
|
|
464
|
+
if (val && typeof(val) === "string") {
|
|
465
|
+
val = val.trim("'");
|
|
466
|
+
}
|
|
467
|
+
val = escape(val);
|
|
461
468
|
if (k.endWith('_min')) {
|
|
462
|
-
where += " and " +
|
|
469
|
+
where += " and " + escapeId(k.replace('_min', '')) + " >= " + val;
|
|
463
470
|
} else if (k.endWith('_max')) {
|
|
464
|
-
where += " and " +
|
|
471
|
+
where += " and " + escapeId(k.replace('_max', '')) + " <= " + val;
|
|
465
472
|
} else if (k.endWith('_not')) {
|
|
466
|
-
where += " and " +
|
|
473
|
+
where += " and " + escapeId(k.replace('_not', '')) + " != " + val;
|
|
467
474
|
} else if (k.endWith('_has')) {
|
|
468
|
-
|
|
475
|
+
var vals = val.trim("'").split(',').map((o) => {
|
|
476
|
+
return "'" + o + "'"
|
|
477
|
+
});
|
|
478
|
+
where += " and " + escapeId(k.replace('_has', '')) + " in (" + vals.join(',') + ")";
|
|
479
|
+
} else if (k.endWith('_like')) {
|
|
480
|
+
where += " and " + escapeId(k.replace('_like', '')) + " LIKE '%" + val.trim("'") + "%'";
|
|
469
481
|
} else if (typeof(val) === "string" && !/^[0-9]+$/.test(val)) {
|
|
470
|
-
where += " and " +
|
|
482
|
+
where += " and " + escapeId(k) + " LIKE '%" + val.trim("'") + "%'"
|
|
471
483
|
} else {
|
|
472
|
-
where += " and " +
|
|
484
|
+
where += " and " + escapeId(k) + " = " + val;
|
|
473
485
|
}
|
|
474
486
|
}
|
|
475
487
|
} else {
|
|
476
488
|
for (var k in obj) {
|
|
477
489
|
var val = obj[k];
|
|
490
|
+
if (val && typeof(val) === "string") {
|
|
491
|
+
val = val.trim("'");
|
|
492
|
+
}
|
|
493
|
+
val = escape(val);
|
|
478
494
|
if (k.endWith('_min')) {
|
|
479
|
-
where += " and " +
|
|
480
|
-
''));
|
|
495
|
+
where += " and " + escapeId(k.replace('_min', '')) + " >= " + val;
|
|
481
496
|
} else if (k.endWith('_max')) {
|
|
482
|
-
where += " and " +
|
|
497
|
+
where += " and " + escapeId(k.replace('_max', '')) + " <= " + val;
|
|
483
498
|
} else if (k.endWith('_not')) {
|
|
484
|
-
where += " and " +
|
|
499
|
+
where += " and " + escapeId(k.replace('_not', '')) + " != " + val;
|
|
485
500
|
} else if (k.endWith('_has')) {
|
|
486
|
-
|
|
501
|
+
var vals = val.trim("'").split(',').map((o) => {
|
|
502
|
+
return "'" + o + "'"
|
|
503
|
+
});
|
|
504
|
+
where += " and " + escapeId(k.replace('_has', '')) + " in (" + vals.join(',') + ")";
|
|
487
505
|
} else {
|
|
488
|
-
where += " and " +
|
|
506
|
+
where += " and " + escapeId(k) + " = " + val;
|
|
489
507
|
}
|
|
490
508
|
}
|
|
491
509
|
}
|
|
@@ -500,15 +518,24 @@ Sql.prototype.toWhere = function(obj, like) {
|
|
|
500
518
|
Sql.prototype.toSet = function(obj) {
|
|
501
519
|
var set = "";
|
|
502
520
|
for (var k in obj) {
|
|
503
|
-
|
|
521
|
+
if (!Object.prototype.hasOwnProperty.call(obj, k)) continue;
|
|
522
|
+
|
|
523
|
+
var val = obj[k];
|
|
524
|
+
if (val === undefined || val === null) continue;
|
|
525
|
+
|
|
526
|
+
if (typeof val === "string") {
|
|
527
|
+
val = val.trim("'");
|
|
528
|
+
}
|
|
529
|
+
val = escape(val);
|
|
530
|
+
|
|
504
531
|
if (k.endWith('_add')) {
|
|
505
|
-
var k2 =
|
|
532
|
+
var k2 = escapeId(k.replace('_add', ''));
|
|
506
533
|
set += "," + k2 + " = " + k2 + " + " + val;
|
|
507
534
|
} else if (k.endWith('_del')) {
|
|
508
|
-
var k3 =
|
|
535
|
+
var k3 = escapeId(k.replace('_del', ''));
|
|
509
536
|
set += "," + k3 + " = " + k3 + " - " + val;
|
|
510
537
|
} else {
|
|
511
|
-
set += "," +
|
|
538
|
+
set += "," + escapeId(k) + " = " + val;
|
|
512
539
|
}
|
|
513
540
|
}
|
|
514
541
|
return set.replace(",", "");
|
|
@@ -520,11 +547,21 @@ Sql.prototype.toSet = function(obj) {
|
|
|
520
547
|
* @return {String} sql语句
|
|
521
548
|
*/
|
|
522
549
|
Sql.prototype.toAddSql = function(item) {
|
|
550
|
+
if (!this.table || !item || typeof item !== 'object') {
|
|
551
|
+
throw new Error('表名或数据未设置');
|
|
552
|
+
}
|
|
553
|
+
|
|
523
554
|
var key = "";
|
|
524
555
|
var val = "";
|
|
525
556
|
for (var k in item) {
|
|
526
|
-
|
|
527
|
-
|
|
557
|
+
if (!Object.prototype.hasOwnProperty.call(item, k)) continue;
|
|
558
|
+
|
|
559
|
+
key += "," + escapeId(k);
|
|
560
|
+
var value = item[k];
|
|
561
|
+
if (typeof value === "string") {
|
|
562
|
+
value = value.trim("'");
|
|
563
|
+
}
|
|
564
|
+
val += "," + escape(value);
|
|
528
565
|
}
|
|
529
566
|
var sql = "INSERT INTO `{0}` ({1}) VALUES ({2});";
|
|
530
567
|
return sql.replace("{0}", this.table).replace("{1}", key.replace(",", "")).replace("{2}", val.replace(",", ""));
|
|
@@ -533,10 +570,14 @@ Sql.prototype.toAddSql = function(item) {
|
|
|
533
570
|
/**
|
|
534
571
|
* @description 转删除sql语句
|
|
535
572
|
* @param {Object} query 查询键值
|
|
573
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
536
574
|
* @return {String} sql语句
|
|
537
575
|
*/
|
|
538
|
-
Sql.prototype.toDelSql = function(query) {
|
|
539
|
-
|
|
576
|
+
Sql.prototype.toDelSql = function(query, like) {
|
|
577
|
+
if (!this.table) {
|
|
578
|
+
throw new Error('表名未设置');
|
|
579
|
+
}
|
|
580
|
+
var where = this.toWhere(query, like);
|
|
540
581
|
var sql = "DELETE FROM `{0}` WHERE {1};";
|
|
541
582
|
return sql.replace("{0}", this.table).replace("{1}", where);
|
|
542
583
|
};
|
|
@@ -545,10 +586,14 @@ Sql.prototype.toDelSql = function(query) {
|
|
|
545
586
|
* @description 转修改sql语句
|
|
546
587
|
* @param {Object} query 查询的键值集合
|
|
547
588
|
* @param {Object} item 修改的键值集合
|
|
589
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
548
590
|
* @return {String} sql语句
|
|
549
591
|
*/
|
|
550
|
-
Sql.prototype.toSetSql = function(query, item) {
|
|
551
|
-
|
|
592
|
+
Sql.prototype.toSetSql = function(query, item, like) {
|
|
593
|
+
if (!this.table) {
|
|
594
|
+
throw new Error('表名未设置');
|
|
595
|
+
}
|
|
596
|
+
var where = this.toWhere(query, like);
|
|
552
597
|
var set = this.toSet(item);
|
|
553
598
|
var sql = "UPDATE `{0}` SET {1} WHERE {2};";
|
|
554
599
|
return sql.replace("{0}", this.table).replace("{1}", set).replace("{2}", where);
|
|
@@ -559,43 +604,110 @@ Sql.prototype.toSetSql = function(query, item) {
|
|
|
559
604
|
* @param {Object} query 查询键值集合
|
|
560
605
|
* @param {String} sort 排序规则
|
|
561
606
|
* @param {String} view 显示的字段
|
|
562
|
-
* @param {Boolean} like 是否使用like匹配,
|
|
607
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
563
608
|
* @return {String} sql语句
|
|
564
609
|
*/
|
|
565
|
-
Sql.prototype.toGetSql = function(query, sort, view, like
|
|
610
|
+
Sql.prototype.toGetSql = function(query, sort, view, like) {
|
|
566
611
|
var where = this.toWhere(query, like);
|
|
567
|
-
|
|
568
|
-
return sql;
|
|
612
|
+
return this.toQuery(where, sort, view);
|
|
569
613
|
};
|
|
570
614
|
/* === 传入对象操作 === */
|
|
571
615
|
/**
|
|
572
616
|
* @description 增加数据
|
|
573
|
-
* @param {Object}
|
|
617
|
+
* @param {Object} body 添加的对象
|
|
574
618
|
* @return {Promise|Object} 执行结果
|
|
575
619
|
*/
|
|
576
|
-
Sql.prototype.add = function(
|
|
577
|
-
|
|
578
|
-
|
|
620
|
+
Sql.prototype.add = async function(body) {
|
|
621
|
+
if (!this.table || !body || typeof body !== 'object') {
|
|
622
|
+
throw new Error('表名或数据未设置');
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
// 触发前置事件
|
|
626
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
627
|
+
await $.eventer.run("sqlite_add_before:" + this.table, { body });
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
var sql = this.toAddSql(body);
|
|
631
|
+
this.sql = sql;
|
|
632
|
+
var bl = await this.exec(sql);
|
|
633
|
+
|
|
634
|
+
// 触发后置事件
|
|
635
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
636
|
+
await $.eventer.run("sqlite_add_after:" + this.table, { body, sql: this.sql, error: this.error, bl });
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return bl;
|
|
640
|
+
} catch (err) {
|
|
641
|
+
this.error = err.message;
|
|
642
|
+
$.log.error(`添加数据失败: ${err.message}`);
|
|
643
|
+
throw err;
|
|
644
|
+
}
|
|
579
645
|
};
|
|
580
646
|
/**
|
|
581
647
|
* @description 删除数据
|
|
582
648
|
* @param {Object} query 查询条件集合
|
|
649
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
583
650
|
* @return {Promise|Object} 执行结果
|
|
584
651
|
*/
|
|
585
|
-
Sql.prototype.del = function(query) {
|
|
586
|
-
|
|
587
|
-
|
|
652
|
+
Sql.prototype.del = async function(query, like) {
|
|
653
|
+
if (!this.table) {
|
|
654
|
+
throw new Error('表名未设置');
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
657
|
+
// 触发前置事件
|
|
658
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
659
|
+
await $.eventer.run("sqlite_del_before:" + this.table, { query, like });
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
var sql = this.toDelSql(query, like);
|
|
663
|
+
this.sql = sql;
|
|
664
|
+
var bl = await this.exec(sql);
|
|
665
|
+
|
|
666
|
+
// 触发后置事件
|
|
667
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
668
|
+
await $.eventer.run("sqlite_del_after:" + this.table, { query, like, sql: this.sql, error: this.error, bl });
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return bl;
|
|
672
|
+
} catch (err) {
|
|
673
|
+
this.error = err.message;
|
|
674
|
+
$.log.error(`删除数据失败: ${err.message}`);
|
|
675
|
+
throw err;
|
|
676
|
+
}
|
|
588
677
|
};
|
|
589
678
|
|
|
590
679
|
/**
|
|
591
680
|
* @description 修改数据
|
|
592
681
|
* @param {Object} query 查询条件集合
|
|
593
|
-
* @param {Object}
|
|
682
|
+
* @param {Object} body 修改的键值集合
|
|
683
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
594
684
|
* @return {Promise|Object} 执行结果
|
|
595
685
|
*/
|
|
596
|
-
Sql.prototype.set = function(query,
|
|
597
|
-
|
|
598
|
-
|
|
686
|
+
Sql.prototype.set = async function(query, body, like) {
|
|
687
|
+
if (!this.table || !body || typeof body !== 'object') {
|
|
688
|
+
throw new Error('表名或数据未设置');
|
|
689
|
+
}
|
|
690
|
+
try {
|
|
691
|
+
// 触发前置事件
|
|
692
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
693
|
+
await $.eventer.run("sqlite_set_before:" + this.table, { query, body, like, page: this.page, size: this.size });
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
var sql = this.toSetSql(query, body, like);
|
|
697
|
+
this.sql = sql;
|
|
698
|
+
var bl = await this.exec(sql);
|
|
699
|
+
|
|
700
|
+
// 触发后置事件
|
|
701
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
702
|
+
await $.eventer.run("sqlite_set_after:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql, error: this.error, bl });
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return bl;
|
|
706
|
+
} catch (err) {
|
|
707
|
+
this.error = err.message;
|
|
708
|
+
$.log.error(`修改数据失败: ${err.message}`);
|
|
709
|
+
throw err;
|
|
710
|
+
}
|
|
599
711
|
};
|
|
600
712
|
|
|
601
713
|
/**
|
|
@@ -603,12 +715,81 @@ Sql.prototype.set = function(query, item) {
|
|
|
603
715
|
* @param {Object} query 查询条件
|
|
604
716
|
* @param {String} sort 排序
|
|
605
717
|
* @param {String} view 返回的字段
|
|
606
|
-
* @param {Boolean} like 是否使用like匹配,
|
|
718
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
719
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
607
720
|
* @return {Promise|Array} 查询结果
|
|
608
721
|
*/
|
|
609
|
-
Sql.prototype.get = function(query, sort, view, like =
|
|
610
|
-
|
|
611
|
-
|
|
722
|
+
Sql.prototype.get = async function(query, sort, view, like, timeout = 30000) {
|
|
723
|
+
if (!this.table) {
|
|
724
|
+
throw new Error('表名未设置');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
try {
|
|
728
|
+
// 添加超时控制的Promise
|
|
729
|
+
var timeoutPromise = new Promise((_, reject) => {
|
|
730
|
+
setTimeout(() => reject(new Error('查询操作超时')), timeout);
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
// 使用Promise.race实现超时控制
|
|
734
|
+
return await Promise.race([
|
|
735
|
+
(async () => {
|
|
736
|
+
// 安全触发事件,避免事件系统问题影响核心功能
|
|
737
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
738
|
+
try {
|
|
739
|
+
// 添加超时保护的事件触发
|
|
740
|
+
await Promise.race([
|
|
741
|
+
$.eventer.run("sqlite_get_before:" + this.table, {
|
|
742
|
+
query,
|
|
743
|
+
sort,
|
|
744
|
+
view,
|
|
745
|
+
like,
|
|
746
|
+
page: this.page,
|
|
747
|
+
size: this.size
|
|
748
|
+
}),
|
|
749
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
|
|
750
|
+
]);
|
|
751
|
+
} catch (eventError) {
|
|
752
|
+
$.log.warn(`事件处理失败,但不影响查询: ${eventError.message}`);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// 生成SQL并执行
|
|
757
|
+
var sql = this.toGetSql(query, sort, view, like);
|
|
758
|
+
this.sql = sql;
|
|
759
|
+
var list = await this.run(sql);
|
|
760
|
+
|
|
761
|
+
// 安全触发后置事件
|
|
762
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
763
|
+
try {
|
|
764
|
+
// 添加超时保护的事件触发
|
|
765
|
+
await Promise.race([
|
|
766
|
+
$.eventer.run("sqlite_get_after:" + this.table, {
|
|
767
|
+
query,
|
|
768
|
+
sort,
|
|
769
|
+
view,
|
|
770
|
+
like,
|
|
771
|
+
page: this.page,
|
|
772
|
+
size: this.size,
|
|
773
|
+
sql: this.sql,
|
|
774
|
+
error: this.error,
|
|
775
|
+
list
|
|
776
|
+
}),
|
|
777
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
|
|
778
|
+
]);
|
|
779
|
+
} catch (eventError) {
|
|
780
|
+
$.log.warn(`事件处理失败,但不影响查询返回: ${eventError.message}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return list;
|
|
785
|
+
})(),
|
|
786
|
+
timeoutPromise
|
|
787
|
+
]);
|
|
788
|
+
} catch (err) {
|
|
789
|
+
this.error = err.message;
|
|
790
|
+
$.log.error(`查询数据失败: ${err.message}`);
|
|
791
|
+
throw err;
|
|
792
|
+
}
|
|
612
793
|
};
|
|
613
794
|
|
|
614
795
|
/**
|
|
@@ -618,30 +799,172 @@ Sql.prototype.get = function(query, sort, view, like = true) {
|
|
|
618
799
|
* @param {Boolean} like 是否使用like匹配, 默认不使用
|
|
619
800
|
* @return {Promise|Object} 执行结果
|
|
620
801
|
*/
|
|
802
|
+
/**
|
|
803
|
+
* 添加或修改数据(存在则修改,不存在则添加)
|
|
804
|
+
* @param {Object|String} where 查询条件
|
|
805
|
+
* @param {Object|String} set 要设置的数据
|
|
806
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
807
|
+
* @return {Promise<Object>} 执行结果
|
|
808
|
+
*/
|
|
621
809
|
Sql.prototype.addOrSet = async function(where, set, like) {
|
|
622
|
-
|
|
810
|
+
if (!this.table || !where || !set) {
|
|
811
|
+
throw new Error('表名、条件或数据未设置');
|
|
812
|
+
}
|
|
813
|
+
try {
|
|
814
|
+
let query = where;
|
|
815
|
+
let body = set;
|
|
816
|
+
let whereStr;
|
|
817
|
+
|
|
818
|
+
if (typeof where === "object") {
|
|
819
|
+
whereStr = await this.toWhere(where, like);
|
|
820
|
+
} else {
|
|
821
|
+
whereStr = where;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const count = await this.countSql(whereStr);
|
|
825
|
+
|
|
826
|
+
if (count === 0) {
|
|
827
|
+
let key = "";
|
|
828
|
+
let value = "";
|
|
829
|
+
|
|
830
|
+
if (typeof set === "string") {
|
|
831
|
+
const arr = set.split(",");
|
|
832
|
+
for (const o of arr) {
|
|
833
|
+
const ar = o.split('=');
|
|
834
|
+
if (ar.length === 2) {
|
|
835
|
+
key += "," + ar[0];
|
|
836
|
+
value += "," + ar[1];
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
} else {
|
|
840
|
+
// 触发前置事件
|
|
841
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
|
|
842
|
+
await $.eventer.run("sqlite_add_before:" + this.table, { body });
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
for (const k in set) {
|
|
846
|
+
if (!Object.prototype.hasOwnProperty.call(set, k)) continue;
|
|
847
|
+
|
|
848
|
+
key += "," + this.escapeId(k);
|
|
849
|
+
let val = set[k];
|
|
850
|
+
if (typeof val === "string") {
|
|
851
|
+
val = val.trim("'");
|
|
852
|
+
}
|
|
853
|
+
value += "," + this.escape(val);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const bl = await this.addSql(key.replace(",", ""), value.replace(",", ""));
|
|
858
|
+
|
|
859
|
+
// 触发后置事件
|
|
860
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
|
|
861
|
+
await $.eventer.run("sqlite_add_after:" + this.table, { body, sql: this.sql, error: this.error, bl });
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return bl;
|
|
865
|
+
} else {
|
|
866
|
+
// 触发前置事件
|
|
867
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof set === "object") {
|
|
868
|
+
await $.eventer.run("sqlite_set_before:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql });
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
if (typeof set === "object") {
|
|
872
|
+
set = await this.toSet(set);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const bl1 = await this.setSql(whereStr, set);
|
|
876
|
+
|
|
877
|
+
// 触发后置事件
|
|
878
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
|
|
879
|
+
await $.eventer.run("sqlite_set_after:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql, error: this.error, bl: bl1 });
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
return bl1;
|
|
883
|
+
}
|
|
884
|
+
} catch (err) {
|
|
885
|
+
this.error = err.message;
|
|
886
|
+
$.log.error(`添加或修改数据失败: ${err.message}`);
|
|
887
|
+
throw err;
|
|
888
|
+
}
|
|
623
889
|
};
|
|
624
890
|
|
|
625
891
|
/**
|
|
626
|
-
*
|
|
627
|
-
* @param {Object} query
|
|
628
|
-
* @param {Boolean} like 是否使用like匹配,
|
|
629
|
-
* @
|
|
892
|
+
* 统计记录数
|
|
893
|
+
* @param {Object} query 查询条件
|
|
894
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
895
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
896
|
+
* @return {Promise|Number} 记录数
|
|
630
897
|
*/
|
|
631
|
-
Sql.prototype.count = function(query, like =
|
|
632
|
-
|
|
898
|
+
Sql.prototype.count = async function(query, like, timeout = 30000) {
|
|
899
|
+
if (!this.table) {
|
|
900
|
+
throw new Error('表名未设置');
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
try {
|
|
904
|
+
// 添加超时控制
|
|
905
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
906
|
+
setTimeout(() => reject(new Error('统计操作超时')), timeout);
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
return await Promise.race([
|
|
910
|
+
(async () => {
|
|
911
|
+
// 安全触发事件
|
|
912
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
913
|
+
try {
|
|
914
|
+
await Promise.race([
|
|
915
|
+
$.eventer.run("sqlite_count_before:" + this.table, { query, like }),
|
|
916
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
|
|
917
|
+
]);
|
|
918
|
+
} catch (eventError) {
|
|
919
|
+
$.log.warn(`事件处理失败,但不影响统计: ${eventError.message}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// 正确生成count SQL
|
|
924
|
+
const where = typeof query === 'string' ? query : await this.toWhere(query, like);
|
|
925
|
+
const sql = "SELECT COUNT(*) as num FROM `" + this.table + "`" + (where ? " WHERE " + where : "");
|
|
926
|
+
this.sql = sql;
|
|
927
|
+
const list = await this.run(sql);
|
|
928
|
+
const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
|
|
929
|
+
|
|
930
|
+
// 安全触发事件
|
|
931
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function') {
|
|
932
|
+
try {
|
|
933
|
+
await Promise.race([
|
|
934
|
+
$.eventer.run("sqlite_count_after:" + this.table, {
|
|
935
|
+
query,
|
|
936
|
+
like,
|
|
937
|
+
sql: this.sql,
|
|
938
|
+
error: this.error,
|
|
939
|
+
total
|
|
940
|
+
}),
|
|
941
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('事件处理超时')), 5000))
|
|
942
|
+
]);
|
|
943
|
+
} catch (eventError) {
|
|
944
|
+
$.log.warn(`事件处理失败,但不影响统计返回: ${eventError.message}`);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return total;
|
|
949
|
+
})(),
|
|
950
|
+
timeoutPromise
|
|
951
|
+
]);
|
|
952
|
+
} catch (err) {
|
|
953
|
+
this.error = err.message;
|
|
954
|
+
$.log.error(`统计记录数失败: ${err.message}`, { sql: this.sql });
|
|
955
|
+
throw err;
|
|
956
|
+
}
|
|
633
957
|
};
|
|
634
958
|
|
|
635
959
|
/**
|
|
636
|
-
*
|
|
960
|
+
* 查询数据并返回符合条件总数
|
|
637
961
|
* @param {Object} query 查询条件
|
|
638
|
-
* @param {
|
|
639
|
-
* @param {
|
|
640
|
-
* @
|
|
641
|
-
* @return {Promise|Object} 查询到的内容列表和符合条件总数
|
|
962
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
963
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
964
|
+
* @return {Promise<Number>} 记录数
|
|
642
965
|
*/
|
|
643
|
-
Sql.prototype.getCount = async function(query,
|
|
644
|
-
return this.
|
|
966
|
+
Sql.prototype.getCount = async function(query, like, timeout = 30000) {
|
|
967
|
+
return await this.count(query, like, timeout);
|
|
645
968
|
};
|
|
646
969
|
|
|
647
970
|
/* === 传入数组操作 === */
|
|
@@ -649,42 +972,278 @@ Sql.prototype.getCount = async function(query, sort, view, like = true) {
|
|
|
649
972
|
* @description 添加多条数据
|
|
650
973
|
* @param {Array} list 对象数组
|
|
651
974
|
* @param {Boolean} lock 是否锁定
|
|
975
|
+
* @param {Number} batchSize 批量大小,默认100
|
|
976
|
+
* @param {Number} timeout 超时时间,默认60000毫秒
|
|
652
977
|
* @return {Promise|Object} 执行结果
|
|
653
978
|
*/
|
|
654
|
-
Sql.prototype.addList = function(list, lock = true) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
for (var i = 0; i < len; i++) {
|
|
658
|
-
sql += this.toAddSql(list[i]) + "\r\n";
|
|
979
|
+
Sql.prototype.addList = async function(list, lock = true, batchSize = 100, timeout = 60000) {
|
|
980
|
+
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
981
|
+
throw new Error('表名或数据列表未设置');
|
|
659
982
|
}
|
|
660
|
-
|
|
661
|
-
|
|
983
|
+
try {
|
|
984
|
+
// 添加整体操作超时控制
|
|
985
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
986
|
+
setTimeout(() => reject(new Error('批量添加数据操作超时')), timeout);
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
return await Promise.race([
|
|
990
|
+
(async () => {
|
|
991
|
+
// 如果数据量较小,直接处理
|
|
992
|
+
if (list.length <= batchSize) {
|
|
993
|
+
// 使用批量插入语法,不使用事务包装
|
|
994
|
+
this.sql = this.toBatchAddSql(list);
|
|
995
|
+
return await this.exec(this.sql);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// 分批处理大数据量
|
|
999
|
+
const totalBatches = Math.ceil(list.length / batchSize);
|
|
1000
|
+
$.log.info(`开始分批添加数据,共${totalBatches}批,每批${batchSize}条`);
|
|
1001
|
+
|
|
1002
|
+
// 分批执行,每批一个单独的批量插入语句
|
|
1003
|
+
let finalResult = null;
|
|
1004
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
1005
|
+
const batch = list.slice(i * batchSize, (i + 1) * batchSize);
|
|
1006
|
+
$.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
|
|
1007
|
+
|
|
1008
|
+
// 生成批量插入SQL
|
|
1009
|
+
const batchSql = this.toBatchAddSql(batch);
|
|
1010
|
+
this.sql = batchSql;
|
|
1011
|
+
|
|
1012
|
+
// 为每批操作添加超时控制
|
|
1013
|
+
finalResult = await Promise.race([
|
|
1014
|
+
this.exec(batchSql),
|
|
1015
|
+
new Promise((_, reject) => {
|
|
1016
|
+
setTimeout(() => reject(new Error(`第${i + 1}批数据处理超时`)), timeout / totalBatches);
|
|
1017
|
+
})
|
|
1018
|
+
]);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
$.log.success(`批量添加数据完成,共${list.length}条`);
|
|
1022
|
+
return finalResult;
|
|
1023
|
+
})(),
|
|
1024
|
+
timeoutPromise
|
|
1025
|
+
]);
|
|
1026
|
+
} catch (error) {
|
|
1027
|
+
$.log.error(`[${this.constructor.name}] [addList]`, '批量添加数据失败', {
|
|
1028
|
+
error: error.message,
|
|
1029
|
+
table: this.table,
|
|
1030
|
+
list_length: list.length
|
|
1031
|
+
});
|
|
1032
|
+
throw error;
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* 生成批量插入SQL语句
|
|
1038
|
+
* @param {Array} list 数据列表
|
|
1039
|
+
* @return {String} 批量插入SQL语句
|
|
1040
|
+
*/
|
|
1041
|
+
Sql.prototype.toBatchAddSql = function(list) {
|
|
1042
|
+
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
1043
|
+
throw new Error('表名或数据列表未设置');
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// 获取第一个对象的键名作为列名
|
|
1047
|
+
const firstItem = list[0];
|
|
1048
|
+
if (!firstItem || typeof firstItem !== 'object') {
|
|
1049
|
+
throw new Error('数据格式错误');
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
let keys = [];
|
|
1053
|
+
for (const k in firstItem) {
|
|
1054
|
+
if (Object.prototype.hasOwnProperty.call(firstItem, k)) {
|
|
1055
|
+
keys.push(this.escapeId(k));
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// 构建列名部分
|
|
1060
|
+
const columns = keys.join(',');
|
|
1061
|
+
|
|
1062
|
+
// 构建值部分
|
|
1063
|
+
const valuesList = [];
|
|
1064
|
+
for (const item of list) {
|
|
1065
|
+
const values = [];
|
|
1066
|
+
for (const k of keys) {
|
|
1067
|
+
const unescapedKey = k.replace(/`/g, '');
|
|
1068
|
+
let val = item[unescapedKey];
|
|
1069
|
+
if (typeof val === "string") {
|
|
1070
|
+
val = val.trim("'");
|
|
1071
|
+
}
|
|
1072
|
+
values.push(this.escape(val));
|
|
1073
|
+
}
|
|
1074
|
+
valuesList.push(`(${values.join(',')})`);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// 生成最终SQL
|
|
1078
|
+
const sql = `INSERT INTO \`${this.table}\` (${columns}) VALUES ${valuesList.join(',')}`;
|
|
1079
|
+
return sql;
|
|
662
1080
|
};
|
|
1081
|
+
|
|
663
1082
|
/**
|
|
664
|
-
*
|
|
1083
|
+
* 删除多条数据
|
|
665
1084
|
* @param {Array} list 对象数组
|
|
666
|
-
* @
|
|
1085
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
1086
|
+
* @param {Number} batchSize 每批处理数量,默认100
|
|
1087
|
+
* @param {Number} timeout 超时时间(毫秒),默认60000
|
|
1088
|
+
* @return {Promise<Object>} 执行结果
|
|
667
1089
|
*/
|
|
668
|
-
Sql.prototype.delList = function(list) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
1090
|
+
Sql.prototype.delList = async function(list, like, batchSize = 100, timeout = 60000) {
|
|
1091
|
+
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
1092
|
+
throw new Error('表名或数据列表未设置');
|
|
1093
|
+
}
|
|
1094
|
+
try {
|
|
1095
|
+
// 添加整体操作超时控制
|
|
1096
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1097
|
+
setTimeout(() => reject(new Error('批量删除数据操作超时')), timeout);
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
return await Promise.race([
|
|
1101
|
+
(async () => {
|
|
1102
|
+
// 如果数据量较小,直接处理
|
|
1103
|
+
if (list.length <= batchSize) {
|
|
1104
|
+
let sql = "";
|
|
1105
|
+
for (const item of list) {
|
|
1106
|
+
sql += this.toDelSql(item.query, like);
|
|
1107
|
+
}
|
|
1108
|
+
this.sql = sql;
|
|
1109
|
+
return await this.exec(sql);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// 分批处理大数据量
|
|
1113
|
+
const totalBatches = Math.ceil(list.length / batchSize);
|
|
1114
|
+
$.log.info(`开始分批删除数据,共${totalBatches}批,每批${batchSize}条`);
|
|
1115
|
+
|
|
1116
|
+
// 使用事务包装整个操作以保证原子性
|
|
1117
|
+
let finalResult = null;
|
|
1118
|
+
try {
|
|
1119
|
+
// 开始事务
|
|
1120
|
+
await this.exec("BEGIN;", 15000);
|
|
1121
|
+
|
|
1122
|
+
// 分批处理
|
|
1123
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
1124
|
+
const batch = list.slice(i * batchSize, (i + 1) * batchSize);
|
|
1125
|
+
$.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
|
|
1126
|
+
|
|
1127
|
+
let batchSql = "";
|
|
1128
|
+
for (const item of batch) {
|
|
1129
|
+
batchSql += this.toDelSql(item.query, like);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// 为每批操作添加超时控制
|
|
1133
|
+
finalResult = await Promise.race([
|
|
1134
|
+
this.exec(batchSql),
|
|
1135
|
+
new Promise((_, reject) => {
|
|
1136
|
+
setTimeout(() => reject(new Error(`第${i + 1}批数据删除超时`)), timeout / totalBatches);
|
|
1137
|
+
})
|
|
1138
|
+
]);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// 提交事务
|
|
1142
|
+
await this.exec("COMMIT;", 15000);
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
// 发生错误时回滚事务
|
|
1145
|
+
try {
|
|
1146
|
+
await this.exec("ROLLBACK;", 15000);
|
|
1147
|
+
$.log.error(`批量删除数据失败,事务已回滚: ${error.message}`);
|
|
1148
|
+
} catch (rollbackError) {
|
|
1149
|
+
$.log.error(`批量删除数据失败,事务回滚也失败: ${rollbackError.message}`);
|
|
1150
|
+
}
|
|
1151
|
+
throw error;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
$.log.success(`批量删除数据完成,共${list.length}条`);
|
|
1155
|
+
return finalResult;
|
|
1156
|
+
})(),
|
|
1157
|
+
timeoutPromise
|
|
1158
|
+
]);
|
|
1159
|
+
} catch (err) {
|
|
1160
|
+
this.error = err.message;
|
|
1161
|
+
$.log.error(`批量删除数据失败: ${err.message}`);
|
|
1162
|
+
throw err;
|
|
673
1163
|
}
|
|
674
|
-
return this.exec(sql);
|
|
675
1164
|
};
|
|
676
1165
|
/**
|
|
677
|
-
*
|
|
1166
|
+
* 更新多条数据
|
|
678
1167
|
* @param {Array} list 对象数组
|
|
679
|
-
* @
|
|
1168
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
1169
|
+
* @param {Number} batchSize 每批处理数量,默认100
|
|
1170
|
+
* @param {Number} timeout 超时时间(毫秒),默认60000
|
|
1171
|
+
* @return {Promise<Object>} 执行结果
|
|
680
1172
|
*/
|
|
681
|
-
Sql.prototype.setList = function(list) {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
1173
|
+
Sql.prototype.setList = async function(list, like = false, batchSize = 100, timeout = 60000) {
|
|
1174
|
+
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
1175
|
+
throw new Error('表名或数据列表未设置');
|
|
1176
|
+
}
|
|
1177
|
+
try {
|
|
1178
|
+
// 添加整体操作超时控制
|
|
1179
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1180
|
+
setTimeout(() => reject(new Error('批量更新数据操作超时')), timeout);
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
return await Promise.race([
|
|
1184
|
+
(async () => {
|
|
1185
|
+
// 如果数据量较小,直接处理
|
|
1186
|
+
if (list.length <= batchSize) {
|
|
1187
|
+
let sql = "";
|
|
1188
|
+
for (const item of list) {
|
|
1189
|
+
sql += this.toSetSql(item.query, item.obj, like);
|
|
1190
|
+
}
|
|
1191
|
+
this.sql = sql;
|
|
1192
|
+
return await this.exec(sql);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// 分批处理大数据量
|
|
1196
|
+
const totalBatches = Math.ceil(list.length / batchSize);
|
|
1197
|
+
$.log.info(`开始分批更新数据,共${totalBatches}批,每批${batchSize}条`);
|
|
1198
|
+
|
|
1199
|
+
// 使用事务包装整个操作以保证原子性
|
|
1200
|
+
let finalResult = null;
|
|
1201
|
+
try {
|
|
1202
|
+
// 开始事务
|
|
1203
|
+
await this.exec("BEGIN;", 15000);
|
|
1204
|
+
|
|
1205
|
+
// 分批处理
|
|
1206
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
1207
|
+
const batch = list.slice(i * batchSize, (i + 1) * batchSize);
|
|
1208
|
+
$.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
|
|
1209
|
+
|
|
1210
|
+
let batchSql = "";
|
|
1211
|
+
for (const item of batch) {
|
|
1212
|
+
batchSql += this.toSetSql(item.query, item.obj, like);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// 为每批操作添加超时控制
|
|
1216
|
+
finalResult = await Promise.race([
|
|
1217
|
+
this.exec(batchSql),
|
|
1218
|
+
new Promise((_, reject) => {
|
|
1219
|
+
setTimeout(() => reject(new Error(`第${i + 1}批数据更新超时`)), timeout / totalBatches);
|
|
1220
|
+
})
|
|
1221
|
+
]);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// 提交事务
|
|
1225
|
+
await this.exec("COMMIT;", 15000);
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
// 发生错误时回滚事务
|
|
1228
|
+
try {
|
|
1229
|
+
await this.exec("ROLLBACK;", 15000);
|
|
1230
|
+
$.log.error(`批量更新数据失败,事务已回滚: ${error.message}`);
|
|
1231
|
+
} catch (rollbackError) {
|
|
1232
|
+
$.log.error(`批量更新数据失败,事务回滚也失败: ${rollbackError.message}`);
|
|
1233
|
+
}
|
|
1234
|
+
throw error;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
$.log.success(`批量更新数据完成,共${list.length}条`);
|
|
1238
|
+
return finalResult;
|
|
1239
|
+
})(),
|
|
1240
|
+
timeoutPromise
|
|
1241
|
+
]);
|
|
1242
|
+
} catch (err) {
|
|
1243
|
+
this.error = err.message;
|
|
1244
|
+
$.log.error(`批量更新数据失败: ${err.message}`);
|
|
1245
|
+
throw err;
|
|
686
1246
|
}
|
|
687
|
-
return this.exec(sql);
|
|
688
1247
|
};
|
|
689
1248
|
|
|
690
1249
|
/* 辅助类 */
|
|
@@ -694,7 +1253,7 @@ Sql.prototype.setList = function(list) {
|
|
|
694
1253
|
* @param {Object} sqlDt sql模板集合
|
|
695
1254
|
* @return {Bool} 有则返回true,没有则返回false
|
|
696
1255
|
*/
|
|
697
|
-
Sql.prototype.
|
|
1256
|
+
Sql.prototype.hasParam = function(paramDt, sqlDt) {
|
|
698
1257
|
var bl = false;
|
|
699
1258
|
for (var key in sqlDt) {
|
|
700
1259
|
var value = paramDt[key];
|
|
@@ -712,7 +1271,7 @@ Sql.prototype.has_param = function(paramDt, sqlDt) {
|
|
|
712
1271
|
* @param {Object} sqlDt sql模板集合
|
|
713
1272
|
* @return {Bool} 没有模板则返回名称,都有则返回undefined
|
|
714
1273
|
*/
|
|
715
|
-
Sql.prototype.
|
|
1274
|
+
Sql.prototype.notParam = function(paramDt, sqlDt) {
|
|
716
1275
|
var name;
|
|
717
1276
|
for (var key in paramDt) {
|
|
718
1277
|
if (!sqlDt[key]) {
|
|
@@ -729,7 +1288,7 @@ Sql.prototype.not_param = function(paramDt, sqlDt) {
|
|
|
729
1288
|
* @param {Object} sqlDt sql模板集合
|
|
730
1289
|
* @return {Object} 返回过滤后的参数集合
|
|
731
1290
|
*/
|
|
732
|
-
Sql.prototype.
|
|
1291
|
+
Sql.prototype.filterParam = function(paramDt, sqlDt) {
|
|
733
1292
|
var dt = [];
|
|
734
1293
|
for (var key in paramDt) {
|
|
735
1294
|
if (!sqlDt[key]) {
|
|
@@ -745,7 +1304,7 @@ Sql.prototype.filter_param = function(paramDt, sqlDt) {
|
|
|
745
1304
|
* @param {Object} sqlDt 模板集合
|
|
746
1305
|
* @return {String} 返回拼接的查询参数
|
|
747
1306
|
*/
|
|
748
|
-
Sql.prototype.
|
|
1307
|
+
Sql.prototype.tplQuery = function(paramDt, sqlDt) {
|
|
749
1308
|
var sql = "";
|
|
750
1309
|
if (sqlDt) {
|
|
751
1310
|
var l = this.config.separator;
|
|
@@ -829,7 +1388,7 @@ Sql.prototype.tpl_query = function(paramDt, sqlDt) {
|
|
|
829
1388
|
* @param {Object} sqlDt 模板集合
|
|
830
1389
|
* @return {String} 返回拼接的查询参数
|
|
831
1390
|
*/
|
|
832
|
-
Sql.prototype.
|
|
1391
|
+
Sql.prototype.tplBody = function(paramDt, sqlDt) {
|
|
833
1392
|
var sql = "";
|
|
834
1393
|
if (!sqlDt || sqlDt.length === 0) {
|
|
835
1394
|
for (var key in paramDt) {
|
|
@@ -884,37 +1443,207 @@ Sql.prototype.model = function(model) {
|
|
|
884
1443
|
};
|
|
885
1444
|
|
|
886
1445
|
/**
|
|
887
|
-
*
|
|
1446
|
+
* 查询单条数据
|
|
888
1447
|
* @param {Object} query 查询条件
|
|
889
1448
|
* @param {String} sort 排序
|
|
890
1449
|
* @param {String} view 返回的字段
|
|
891
|
-
* @param {Boolean} like
|
|
892
|
-
* @
|
|
1450
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
1451
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
1452
|
+
* @return {Promise|Object|null} 查询结果
|
|
893
1453
|
*/
|
|
894
|
-
Sql.prototype.getObj = async function(query, sort, view, like) {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1454
|
+
Sql.prototype.getObj = async function(query, sort, view, like, timeout = 30000) {
|
|
1455
|
+
try {
|
|
1456
|
+
// 保存当前分页设置
|
|
1457
|
+
const oldPage = this.page;
|
|
1458
|
+
const oldSize = this.size;
|
|
1459
|
+
|
|
1460
|
+
// 设置为只查询一条
|
|
1461
|
+
this.page = 1;
|
|
1462
|
+
this.size = 1;
|
|
1463
|
+
|
|
1464
|
+
// 使用优化后的get方法
|
|
1465
|
+
const list = await this.get(query, sort, view, like, timeout);
|
|
1466
|
+
|
|
1467
|
+
// 恢复分页设置
|
|
1468
|
+
this.page = oldPage;
|
|
1469
|
+
this.size = oldSize;
|
|
1470
|
+
|
|
1471
|
+
var obj = null;
|
|
1472
|
+
if (list.length > 0) {
|
|
1473
|
+
obj = list[0];
|
|
1474
|
+
if (this.key) {
|
|
1475
|
+
obj = this.model(obj);
|
|
1476
|
+
}
|
|
914
1477
|
}
|
|
915
|
-
|
|
916
|
-
return
|
|
1478
|
+
|
|
1479
|
+
return obj;
|
|
1480
|
+
} catch (err) {
|
|
1481
|
+
this.error = err.message;
|
|
1482
|
+
$.log.error(`查询单条数据失败: ${err.message}`, { sql: this.sql });
|
|
1483
|
+
throw err;
|
|
917
1484
|
}
|
|
918
1485
|
};
|
|
919
1486
|
|
|
1487
|
+
|
|
1488
|
+
|
|
1489
|
+
/**
|
|
1490
|
+
* 从SQL文件加载数据库
|
|
1491
|
+
* @param {String} file - SQL文件路径
|
|
1492
|
+
* @returns {Promise<boolean>} 是否加载成功
|
|
1493
|
+
*/
|
|
1494
|
+
Sql.prototype.load = async function (file) {
|
|
1495
|
+
try {
|
|
1496
|
+
// 记录操作日志
|
|
1497
|
+
if (this.config && this.config.debug) {
|
|
1498
|
+
$.log.debug(`[${this.constructor.name}] [load] 开始从文件加载数据库`, {
|
|
1499
|
+
file: file
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
// 检查文件是否存在
|
|
1504
|
+
if (!file.hasFile()) {
|
|
1505
|
+
throw new Error(`SQL文件不存在: ${file}`);
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// 读取SQL文件内容
|
|
1509
|
+
const sqlContent = await $.file.readText(file);
|
|
1510
|
+
|
|
1511
|
+
if (!sqlContent || sqlContent.trim() === '') {
|
|
1512
|
+
throw new Error(`SQL文件内容为空: ${file}`);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// 分割SQL语句(按分号分割,但需要注意处理字符串中的分号)
|
|
1516
|
+
const sqlStatements = this._splitSqlStatements(sqlContent);
|
|
1517
|
+
|
|
1518
|
+
// 开始事务执行SQL语句
|
|
1519
|
+
await this.exec('BEGIN TRANSACTION');
|
|
1520
|
+
|
|
1521
|
+
try {
|
|
1522
|
+
// 逐个执行SQL语句
|
|
1523
|
+
for (const sql of sqlStatements) {
|
|
1524
|
+
const trimmedSql = sql.trim();
|
|
1525
|
+
if (trimmedSql) {
|
|
1526
|
+
await this.exec(trimmedSql);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
// 提交事务
|
|
1531
|
+
await this.exec('COMMIT');
|
|
1532
|
+
|
|
1533
|
+
if (this.config && this.config.debug) {
|
|
1534
|
+
$.log.info(`[${this.constructor.name}] [load] 数据库加载成功`, {
|
|
1535
|
+
file: file,
|
|
1536
|
+
statementCount: sqlStatements.length
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
return true;
|
|
1541
|
+
} catch (err) {
|
|
1542
|
+
// 回滚事务
|
|
1543
|
+
await this.exec('ROLLBACK').catch(rollbackErr => {
|
|
1544
|
+
$.log.error(`[${this.constructor.name}] [load] 事务回滚失败`, {
|
|
1545
|
+
error: rollbackErr.message
|
|
1546
|
+
});
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
throw err;
|
|
1550
|
+
}
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
// 记录错误日志
|
|
1553
|
+
$.log.error(`[${this.constructor.name}] [load] 数据库加载失败`, {
|
|
1554
|
+
error: error.message,
|
|
1555
|
+
file: file
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
// 抛出错误
|
|
1559
|
+
throw error;
|
|
1560
|
+
}
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* 分割SQL语句
|
|
1565
|
+
* @private
|
|
1566
|
+
* @param {String} sqlContent - SQL内容
|
|
1567
|
+
* @returns {Array} SQL语句数组
|
|
1568
|
+
*/
|
|
1569
|
+
Sql.prototype._splitSqlStatements = function(sqlContent) {
|
|
1570
|
+
const statements = [];
|
|
1571
|
+
let inString = false;
|
|
1572
|
+
let stringChar = '';
|
|
1573
|
+
let inComment = false;
|
|
1574
|
+
let currentStatement = '';
|
|
1575
|
+
|
|
1576
|
+
for (let i = 0; i < sqlContent.length; i++) {
|
|
1577
|
+
const char = sqlContent[i];
|
|
1578
|
+
const nextChar = i + 1 < sqlContent.length ? sqlContent[i + 1] : '';
|
|
1579
|
+
|
|
1580
|
+
// 处理注释
|
|
1581
|
+
if (!inString && !inComment && char === '-' && nextChar === '-') {
|
|
1582
|
+
inComment = true;
|
|
1583
|
+
i++; // 跳过第二个'-'
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
if (inComment && char === '\n') {
|
|
1588
|
+
inComment = false;
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
if (inComment) {
|
|
1593
|
+
continue;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// 处理多行注释
|
|
1597
|
+
if (!inString && !inComment && char === '/' && nextChar === '*') {
|
|
1598
|
+
inComment = true;
|
|
1599
|
+
i++; // 跳过'*'
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
if (inComment && char === '*' && nextChar === '/') {
|
|
1604
|
+
inComment = false;
|
|
1605
|
+
i++; // 跳过'/'
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
// 处理字符串
|
|
1610
|
+
if (!inComment && (char === "'" || char === '"') && (!inString || stringChar === char)) {
|
|
1611
|
+
// 检查是否是转义的引号
|
|
1612
|
+
let escaped = false;
|
|
1613
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
1614
|
+
if (sqlContent[j] === '\\') {
|
|
1615
|
+
escaped = !escaped;
|
|
1616
|
+
} else {
|
|
1617
|
+
break;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
if (!escaped) {
|
|
1622
|
+
if (inString && stringChar === char) {
|
|
1623
|
+
inString = false;
|
|
1624
|
+
stringChar = '';
|
|
1625
|
+
} else if (!inString) {
|
|
1626
|
+
inString = true;
|
|
1627
|
+
stringChar = char;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// 分割语句
|
|
1633
|
+
if (!inString && !inComment && char === ';') {
|
|
1634
|
+
statements.push(currentStatement.trim());
|
|
1635
|
+
currentStatement = '';
|
|
1636
|
+
} else {
|
|
1637
|
+
currentStatement += char;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
// 添加最后一个语句(如果有)
|
|
1642
|
+
if (currentStatement.trim()) {
|
|
1643
|
+
statements.push(currentStatement.trim());
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
return statements;
|
|
1647
|
+
};
|
|
1648
|
+
|
|
920
1649
|
module.exports = Sql;
|