mm_mysql 2.0.1 → 2.0.3
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 +266 -234
- package/db.js +516 -286
- package/index.js +981 -394
- package/package.json +13 -13
- package/sql.js +904 -396
- package/config.json +0 -8
- package/link_model.js +0 -132
- package/sql.json +0 -56
- package/test.js +0 -846
- package/upgrade.sql +0 -34
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 (
|
|
487
|
-
|
|
488
|
-
|
|
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
|
-
|
|
498
|
+
const k2 = escapeId(k.replace('_add', ""));
|
|
494
499
|
set += "," + k2 + " = " + k2 + " + " + val;
|
|
495
500
|
} else if (k.endWith('_del')) {
|
|
496
|
-
|
|
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
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
516
|
-
if (
|
|
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
|
-
|
|
522
|
-
|
|
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
|
-
|
|
534
|
-
|
|
535
|
-
|
|
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
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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
|
-
|
|
562
|
-
|
|
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
|
-
|
|
573
|
-
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
sql
|
|
603
|
-
|
|
604
|
-
bl
|
|
605
|
-
|
|
606
|
-
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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
|
-
|
|
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
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
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
|
-
|
|
671
|
-
|
|
672
|
-
|
|
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
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
body
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
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
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
-
* @
|
|
870
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
871
|
+
* @return {Promise|Object|null} 查询结果
|
|
763
872
|
*/
|
|
764
|
-
Sql.prototype.getObj = async function(query, sort, view, like) {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
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
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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
|
-
* @
|
|
910
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
911
|
+
* @return {Promise|Number} 记录数
|
|
809
912
|
*/
|
|
810
|
-
Sql.prototype.
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
-
* @
|
|
978
|
+
* @param {Number} timeout 超时时间(毫秒),默认30000ms
|
|
979
|
+
* @return {Promise|Number} 记录数
|
|
849
980
|
*/
|
|
850
|
-
Sql.prototype.getCount = async function(query,
|
|
851
|
-
return this.
|
|
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
|
-
* @
|
|
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
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
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
|
-
* @
|
|
1101
|
+
* @param {Number} batchSize 每批处理数量,默认100
|
|
1102
|
+
* @param {Number} timeout 超时时间(毫秒),默认60000
|
|
1103
|
+
* @return {Promise<Object>} 执行结果
|
|
875
1104
|
*/
|
|
876
|
-
Sql.prototype.delList = function(list, like) {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
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
|
-
* @
|
|
1185
|
+
* @param {Number} batchSize 每批处理数量,默认100
|
|
1186
|
+
* @param {Number} timeout 超时时间(毫秒),默认60000
|
|
1187
|
+
* @return {Promise<Object>} 执行结果
|
|
889
1188
|
*/
|
|
890
|
-
Sql.prototype.setList = function(list, like) {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
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 {
|
|
1241
|
+
* @return {Boolean} 有则返回true,没有则返回false
|
|
905
1242
|
*/
|
|
906
|
-
Sql.prototype.has_param = function(paramDt, sqlDt) {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
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
|
-
|
|
912
|
-
break;
|
|
1251
|
+
return true;
|
|
913
1252
|
}
|
|
914
1253
|
}
|
|
915
|
-
return
|
|
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 {
|
|
1261
|
+
* @return {String|undefined} 没有模板则返回名称,都有则返回undefined
|
|
923
1262
|
*/
|
|
924
|
-
Sql.prototype.not_param = function(paramDt, sqlDt) {
|
|
925
|
-
|
|
926
|
-
|
|
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
|
-
|
|
929
|
-
break;
|
|
1270
|
+
return key;
|
|
930
1271
|
}
|
|
931
1272
|
}
|
|
932
|
-
return
|
|
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
|
-
|
|
943
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
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
|
-
|
|
979
|
-
sql += " && " + sl;
|
|
1326
|
+
conditions.push("(" + subConditions.join(" || ") + ")");
|
|
980
1327
|
} else {
|
|
981
|
-
|
|
982
|
-
|
|
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
|
-
|
|
990
|
-
|
|
991
|
-
|
|
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
|
-
|
|
999
|
-
sql += " && " + sl;
|
|
1338
|
+
conditions.push("(" + subConditions.join(" || ") + ")");
|
|
1000
1339
|
} else {
|
|
1001
|
-
|
|
1002
|
-
|
|
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
|
-
|
|
1010
|
-
|
|
1011
|
-
if (
|
|
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
|
-
|
|
1356
|
+
conditions.push(sqlDt[key].replaceAll("{0}", value.trim("'")));
|
|
1017
1357
|
} else {
|
|
1018
|
-
|
|
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
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
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
|
-
|
|
1038
|
-
sql += " && " + sl;
|
|
1378
|
+
conditions.push("(" + subConditions.join(" || ") + ")");
|
|
1039
1379
|
} else {
|
|
1040
|
-
|
|
1380
|
+
conditions.push(escapeId(key) + " = " + escape(value));
|
|
1041
1381
|
}
|
|
1042
1382
|
}
|
|
1383
|
+
sql = conditions.join(" && ");
|
|
1043
1384
|
} else {
|
|
1044
1385
|
// 直接拼接
|
|
1045
|
-
|
|
1046
|
-
|
|
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
|
|
1394
|
+
return sql;
|
|
1051
1395
|
};
|
|
1052
1396
|
|
|
1053
1397
|
/**
|
|
@@ -1056,63 +1400,227 @@ 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
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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 (
|
|
1067
|
-
|
|
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
|
-
|
|
1418
|
+
parts.push(" " + sqlDt[key].replace("{0}", value).replace(/\+ -/g, "- ").replace(/- -/g, "+ "));
|
|
1070
1419
|
} else {
|
|
1071
|
-
|
|
1420
|
+
parts.push(" " + escapeId(key) + " = " + value);
|
|
1072
1421
|
}
|
|
1073
1422
|
}
|
|
1074
1423
|
}
|
|
1075
|
-
return
|
|
1424
|
+
return parts.join(",").replace(", ", "");
|
|
1076
1425
|
};
|
|
1077
1426
|
|
|
1078
1427
|
/**
|
|
1079
|
-
*
|
|
1080
|
-
* @param {
|
|
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;
|
|
1585
|
+
};
|
|
1586
|
+
|
|
1587
|
+
/**
|
|
1588
|
+
* 模型监听函数
|
|
1589
|
+
* @param {Object} model - 模型对象
|
|
1081
1590
|
* @return {Object} 返回监听操作的对象
|
|
1082
1591
|
*/
|
|
1083
|
-
Sql.prototype.model = function(model) {
|
|
1084
|
-
|
|
1085
|
-
return new Proxy(model, {
|
|
1086
|
-
set: function(obj, prop, value) {
|
|
1087
|
-
if (_this.key) {
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
for (
|
|
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
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
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
|
-
|
|
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
|
|
1623
|
+
return true;
|
|
1116
1624
|
}
|
|
1117
1625
|
});
|
|
1118
1626
|
};
|