mm_sqlite 1.2.2 → 1.2.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/sql.js CHANGED
@@ -7,11 +7,11 @@ const SqlString = require('sqlstring');
7
7
  const { Base } = require('mm_expand');
8
8
 
9
9
  function escape(value, stringifyObjects, timeZone) {
10
- return SqlString.escape(value, stringifyObjects, timeZone);
10
+ return SqlString.escape(value, stringifyObjects, timeZone);
11
11
  }
12
12
 
13
13
  function escapeId(value, forbidQualified) {
14
- return SqlString.escapeId(value, forbidQualified);
14
+ return SqlString.escapeId(value, forbidQualified);
15
15
  }
16
16
 
17
17
  /**
@@ -19,1503 +19,1605 @@ function escapeId(value, forbidQualified) {
19
19
  * @property {Function} filter 设置并过滤参数
20
20
  */
21
21
  class Sql extends Base {
22
- /**
23
- * @description 数据库管理器
24
- * @param {Function} run 查询函数
25
- * @param {Function} exec 更改函数
26
- */
27
- constructor(run, exec) {
28
- super();
29
- /**
30
- * 查询函数
31
- */
32
- this.run = run;
33
- /**
34
- * 更改函数 用于增删改
35
- */
36
- this.exec = exec;
37
- /**
38
- * 规避SQL注入函数
39
- * @param {Object} value 值
40
- * @return {String} 返回执行结果
41
- */
42
- this.escape = function (value) {
43
- return escape(value);
44
- };
45
-
46
- /**
47
- * 规避排序、SQL注入函数
48
- * @param {String} key 键
49
- * @return {String} 返回执行结果
50
- */
51
- this.escapeId = function (key) {
52
- return escapeId(key);
53
- };
54
-
55
- /**
56
- * sql语句
57
- */
58
- this.sql = "";
59
- /**
60
- * 错误提示
61
- */
62
- this.error;
63
- /**
64
- * 查询结果
65
- */
66
- this.results = [];
67
-
68
- /**
69
- * 表名
70
- */
71
- this.table = "";
72
- /**
73
- * 显示页
74
- */
75
- this.page = 0;
76
- /**
77
- * 显示条数
78
- */
79
- this.size = 30;
80
- /**
81
- * 请求方式 add、del、set、get、import、export等,跟函数名一致
82
- */
83
- this.method = "";
84
-
85
- /**
86
- * 显示的字段
87
- */
88
- this.field = "";
89
-
90
- /**
91
- * 排序方式
92
- */
93
- this.orderby = "";
94
-
95
- /**
96
- * 查询分组
97
- */
98
- this.groupby = "";
99
-
100
- /**
101
- * 是否统计查询结果数
102
- */
103
- this.count_ret = "false";
104
-
105
- /**
106
- * 过滤查询参数字典
107
- */
108
- this.config = {
109
- /**
110
- * 分隔符 用于查询时的多条件处理
111
- */
112
- "separator": "|",
113
- /**
114
- * 过滤
115
- */
116
- "filter": {
117
- /**
118
- * 表名
119
- */
120
- "table": "table",
121
- /**
122
- * 查询的页码
123
- */
124
- "page": "page",
125
- /**
126
- * 查询每页条数
127
- */
128
- "size": "size",
129
- /**
130
- * 操作方式: 传入参数method=add, 支持参数 add增、del删、set改、get查,为空则为get
131
- */
132
- "method": "method",
133
- /**
134
- * 排序
135
- */
136
- "orderby": "orderby",
137
- /**
138
- * 查询显示的字段
139
- */
140
- "field": "field",
141
- /**
142
- * 统计结果: 统计符合条件的结果数,只有当page等于1或0时才会统计
143
- */
144
- "count_ret": "count_ret"
145
- }
146
- };
147
-
148
- this.like = false;
149
- }
22
+ /**
23
+ * @description 数据库管理器
24
+ * @param {Function} run 查询函数
25
+ * @param {Function} exec 更改函数
26
+ */
27
+ constructor(run, exec) {
28
+ super();
29
+ /**
30
+ * 查询函数
31
+ */
32
+ this.run = run;
33
+ /**
34
+ * 更改函数 用于增删改
35
+ */
36
+ this.exec = exec;
37
+ /**
38
+ * 规避SQL注入函数
39
+ * @param {object} value 值
40
+ * @returns {string} 返回执行结果
41
+ */
42
+ this.escape = function (value) {
43
+ return escape(value);
44
+ };
45
+
46
+ /**
47
+ * 规避排序、SQL注入函数
48
+ * @param {string} key 键
49
+ * @returns {string} 返回执行结果
50
+ */
51
+ this.escapeId = function (key) {
52
+ return escapeId(key);
53
+ };
54
+
55
+ /**
56
+ * sql语句
57
+ */
58
+ this.sql = '';
59
+ /**
60
+ * 错误提示
61
+ */
62
+ this.error;
63
+ /**
64
+ * 查询结果
65
+ */
66
+ this.results = [];
67
+
68
+ /**
69
+ * 表名
70
+ */
71
+ this.table = '';
72
+ /**
73
+ * 显示页
74
+ */
75
+ this.page = 0;
76
+ /**
77
+ * 显示条数
78
+ */
79
+ this.size = 30;
80
+ /**
81
+ * 请求方式 add、del、set、get、import、export等,跟函数名一致
82
+ */
83
+ this.method = '';
84
+
85
+ /**
86
+ * 显示的字段
87
+ */
88
+ this.field = '';
89
+
90
+ /**
91
+ * 排序方式
92
+ */
93
+ this.orderby = '';
94
+
95
+ /**
96
+ * 查询分组
97
+ */
98
+ this.groupby = '';
99
+
100
+ /**
101
+ * 是否统计查询结果数
102
+ */
103
+ this.count_ret = 'false';
104
+
105
+ /**
106
+ * 过滤查询参数字典
107
+ */
108
+ this.config = {
109
+ /**
110
+ * 分隔符 用于查询时的多条件处理
111
+ */
112
+ 'separator': '|',
113
+ /**
114
+ * 过滤
115
+ */
116
+ 'filter': {
117
+ /**
118
+ * 表名
119
+ */
120
+ 'table': 'table',
121
+ /**
122
+ * 查询的页码
123
+ */
124
+ 'page': 'page',
125
+ /**
126
+ * 查询每页条数
127
+ */
128
+ 'size': 'size',
129
+ /**
130
+ * 操作方式: 传入参数method=add, 支持参数 add增、del删、set改、get查,为空则为get
131
+ */
132
+ 'method': 'method',
133
+ /**
134
+ * 排序
135
+ */
136
+ 'orderby': 'orderby',
137
+ /**
138
+ * 查询显示的字段
139
+ */
140
+ 'field': 'field',
141
+ /**
142
+ * 统计结果: 统计符合条件的结果数,只有当page等于1或0时才会统计
143
+ */
144
+ 'count_ret': 'count_ret'
145
+ }
146
+ };
147
+
148
+ this.like = false;
149
+ }
150
150
  }
151
151
 
152
152
  /**
153
153
  * @description 清空查询条件
154
- * @return {Object} 返回当前对象
154
+ * @returns {object} 返回当前对象
155
155
  */
156
156
  Sql.prototype.clear = function () {
157
- this.where = "";
158
- this.set = "";
159
- this.order = "";
160
- this.view = "";
161
- this.sql = "";
162
- this.error = "";
163
- this.like = true;
164
- this.config = {};
165
- this.param = {};
166
- this.page = 0;
167
- this.size = 0;
168
- this.run = null;
169
- this.exec = null;
170
- return this;
157
+ this.where = '';
158
+ this.set = '';
159
+ this.order = '';
160
+ this.view = '';
161
+ this.sql = '';
162
+ this.error = '';
163
+ this.like = true;
164
+ this.config = {};
165
+ this.param = {};
166
+ this.page = 0;
167
+ this.size = 0;
168
+ this.run = null;
169
+ this.exec = null;
170
+ return this;
171
171
  };
172
172
 
173
173
  /**
174
174
  * @description 过滤查询参数
175
- * @param {Object} query 查询参数
175
+ * @param {object} query 查询参数
176
176
  */
177
177
  Sql.prototype.filter = function (query) {
178
- var m = this.config.filter;
179
- for (var k in m) {
180
- var key = m[k];
181
- if (query[key]) {
182
- this[k] = query[key];
183
- delete query[key];
184
- }
185
- }
178
+ var m = this.config.filter;
179
+ for (var k in m) {
180
+ var key = m[k];
181
+ if (query[key]) {
182
+ this[k] = query[key];
183
+ delete query[key];
184
+ }
185
+ }
186
186
  };
187
187
 
188
188
  /**
189
189
  * @description 查询条件拼接
190
- * @param {String} where 查询条件
191
- * @param {String} sort 排序
192
- * @param {String} view 返回的字段
193
- * @return {String} 返回查询条件语句
190
+ * @param {string} where 查询条件
191
+ * @param {string} sort 排序
192
+ * @param {string} view 返回的字段
193
+ * @returns {string} 返回查询条件语句
194
194
  */
195
195
  Sql.prototype.toQuery = function (where, sort, view) {
196
- var sql = "SELECT {1} FROM `{0}`";
197
- if (!view) {
198
- view = "*";
199
- }
200
- if (where) {
201
- sql += " WHERE " + where;
202
- }
203
- if (sort) {
204
- sql += " ORDER BY " + sort.replace(/;/, '');
205
- }
206
- sql = sql.replace("{0}", this.table).replace("{1}", view);
207
- if (this.size && this.page) {
208
- var start = this.size * (this.page - 1);
209
- sql += " limit " + start + ',' + this.size;
210
- }
211
- return sql;
196
+ var sql = 'SELECT {1} FROM `{0}`';
197
+ if (!view) {
198
+ view = '*';
199
+ }
200
+ if (where) {
201
+ sql += ' WHERE ' + where;
202
+ }
203
+ if (sort) {
204
+ sql += ' ORDER BY ' + sort.replace(/;/, '');
205
+ }
206
+ sql = sql.replace('{0}', this.table).replace('{1}', view);
207
+ if (this.size && this.page) {
208
+ var start = this.size * (this.page - 1);
209
+ sql += ' limit ' + start + ',' + this.size;
210
+ }
211
+ return sql;
212
212
  };
213
213
  /* === 传字符串参数 === */
214
214
  /**
215
215
  * @description 增加数据
216
- * @param {String} key 用作增加的键集合
217
- * @param {String} val 用作增加的值集合
218
- * @return {Promise|Object} 执行结果
216
+ * @param {string} key 用作增加的键集合
217
+ * @param {string} val 用作增加的值集合
218
+ * @returns {Promise | object} 执行结果
219
219
  */
220
220
  Sql.prototype.addSql = function (key, val) {
221
- var sql = "INSERT INTO `{0}` ({1}) VALUES ({2});";
222
- sql = sql.replace("{0}", this.table).replace("{1}", key).replace("{2}", val);
223
- return this.exec(sql);
221
+ var sql = 'INSERT INTO `{0}` ({1}) VALUES ({2});';
222
+ sql = sql.replace('{0}', this.table).replace('{1}', key).replace('{2}', val);
223
+ return this.exec(sql);
224
224
  };
225
225
  /**
226
226
  * @description 删除数据
227
- * @param {String} where 删除条件
228
- * @return {Promise|Object} 执行结果
227
+ * @param {string} where 删除条件
228
+ * @returns {Promise | object} 执行结果
229
229
  */
230
230
  Sql.prototype.delSql = function (where) {
231
- var sql = "DELETE FROM `{0}` WHERE {1};";
232
- sql = sql.replace("{0}", this.table).replace("{1}", where);
233
- return this.exec(sql);
231
+ var sql = 'DELETE FROM `{0}` WHERE {1};';
232
+ sql = sql.replace('{0}', this.table).replace('{1}', where);
233
+ return this.exec(sql);
234
234
  };
235
235
  /**
236
236
  * 修改数据
237
- * @param {String} where 查询条件
238
- * @param {String} set 修改的键值
239
- * @return {Promise|Object} 执行结果
237
+ * @param {string} where 查询条件
238
+ * @param {string} set 修改的键值
239
+ * @returns {Promise | object} 执行结果
240
240
  */
241
241
  Sql.prototype.setSql = function (where, set) {
242
- var sql = "UPDATE `{0}` SET {1} WHERE {2};";
243
- sql = sql.replace("{0}", this.table).replace("{1}", set).replace("{2}", where);
244
- return this.exec(sql);
242
+ var sql = 'UPDATE `{0}` SET {1} WHERE {2};';
243
+ sql = sql.replace('{0}', this.table).replace('{1}', set).replace('{2}', where);
244
+ return this.exec(sql);
245
245
  };
246
246
  /**
247
247
  * @description 查询数据
248
- * @param {String} where 查询条件
249
- * @param {String} sort 排序
250
- * @param {String} view 显示的字段
251
- * @return {Promise|Array} 查询结果数组
248
+ * @param {string} where 查询条件
249
+ * @param {string} sort 排序
250
+ * @param {string} view 显示的字段
251
+ * @returns {Promise|Array} 查询结果数组
252
252
  */
253
253
  Sql.prototype.getSql = function (where, sort, view) {
254
- var sql = this.toQuery(where, sort, view);
255
- return this.run(sql);
254
+ var sql = this.toQuery(where, sort, view);
255
+ return this.run(sql);
256
256
  };
257
257
 
258
258
  /**
259
259
  * @description 添加或修改
260
- * @param {String} where 查询条件
261
- * @param {String} set 修改的键值
262
- * @return {Promise|Object} 执行结果
260
+ * @param {string} where 查询条件
261
+ * @param {string} set 修改的键值
262
+ * @returns {Promise | object} 执行结果
263
263
  */
264
264
  Sql.prototype.addOrSetSql = async function (where, set) {
265
- if (!where || !set) {
266
- return -1;
267
- }
268
- var count = await this.countSql(where);
269
- if (count === 0) {
270
- var arr = set.split(',');
271
- var key = "";
272
- var value = "";
273
- for (var i = 0; i < arr.length; i++) {
274
- var o = arr[i];
275
- var ar = o.split('=');
276
- if (ar.length === 2) {
277
- key += "," + ar[0];
278
- value += "," + ar[1];
279
- }
280
- }
281
- return await this.addSql(key.replace(',', ''), value.replace(',', ''));
282
- }
283
- return await this.setSql(where, set);
265
+ if (!where || !set) {
266
+ return -1;
267
+ }
268
+ var count = await this.countSql(where);
269
+ if (count === 0) {
270
+ var arr = set.split(',');
271
+ var key = '';
272
+ var value = '';
273
+ for (var i = 0; i < arr.length; i++) {
274
+ var o = arr[i];
275
+ var ar = o.split('=');
276
+ if (ar.length === 2) {
277
+ key += ',' + ar[0];
278
+ value += ',' + ar[1];
279
+ }
280
+ }
281
+ return await this.addSql(key.replace(',', ''), value.replace(',', ''));
282
+ }
283
+ return await this.setSql(where, set);
284
284
  };
285
285
 
286
286
  /**
287
287
  * @description 查询符合结果总数
288
- * @param {String} where 查询条件
289
- * @return {Promise|Number} 返回结果总数
288
+ * @param {string} where 查询条件
289
+ * @returns {Promise | number} 返回结果总数
290
290
  */
291
291
  Sql.prototype.countSql = async function (where) {
292
- var sql = "SELECT count(*) count FROM `" + this.table + "`";
293
- if (where) {
294
- sql += ' WHERE ' + where;
295
- }
296
- var n = 0;
297
- var arr = await this.run(sql);
298
- if (arr.length) {
299
- n = arr[0].count;
300
- }
301
- return n;
292
+ var sql = 'SELECT count(*) count FROM `' + this.table + '`';
293
+ if (where) {
294
+ sql += ' WHERE ' + where;
295
+ }
296
+ var n = 0;
297
+ var arr = await this.run(sql);
298
+ if (arr.length) {
299
+ n = arr[0].count;
300
+ }
301
+ return n;
302
302
  };
303
303
 
304
304
  /**
305
305
  * @description 查询数据并返回符合条件总数
306
- * @param {String} where 查询条件
307
- * @param {String} sort 排序
308
- * @param {String} view 返回的字段
309
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
306
+ * @param {string} where 查询条件
307
+ * @param {string} sort 排序
308
+ * @param {string} view 返回的字段
309
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
310
310
  */
311
311
  Sql.prototype.getCountSql = async function (where, sort, view) {
312
- var list = [];
313
- var count = await this.countSql(where);
314
- if (count > 0) {
315
- list = await this.getSql(where, sort, view);
316
- }
317
- var ret = {
318
- list: list,
319
- count: count
320
- };
321
- return ret;
312
+ var list = [];
313
+ var count = await this.countSql(where);
314
+ if (count > 0) {
315
+ list = await this.getSql(where, sort, view);
316
+ }
317
+ var ret = {
318
+ list: list,
319
+ count: count
320
+ };
321
+ return ret;
322
322
  };
323
323
 
324
324
  /**
325
325
  * @description 统计学
326
- * @param {String} where 查询条件
327
- * @param {String} groupby 分组的字段
328
- * @param {String} view 返回的字段
329
- * @param {String} sort 排序方式
330
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
326
+ * @param {string} where 查询条件
327
+ * @param {string} groupby 分组的字段
328
+ * @param {string} view 返回的字段
329
+ * @param {string} sort 排序方式
330
+ * @param method
331
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
331
332
  */
332
333
  Sql.prototype.groupMathSql = async function (where, groupby, view, sort, method) {
333
- if (!view) {
334
- view = "*"
335
- }
336
- var viewStr = "";
337
- if (view.indexOf(",") !== -1) {
338
- var arr = view.split(",");
339
- for (var i = 0; i < arr.length; i++) {
340
- var str = escapeId(arr[i]);
341
- viewStr += "," + method.toUpperCase() + "(" + str + ") " + method.toLowerCase() + "_" + str.replace(
342
- /`/g, "")
343
- }
344
- } else {
345
- viewStr = "," + method.toUpperCase() + "(" + escapeId(view) + ") " + method.toLowerCase() + "_" +
346
- view.replace(/`/g, "")
347
- }
348
- var sql = "SELECT " + (groupby ? escapeId(groupby) : "") + viewStr + " FROM `" + this.table + "`";
349
- if (where) {
350
- sql += ' WHERE ' + where;
351
- }
352
- if (groupby) {
353
- sql += " GROUP BY " + escapeId(groupby);
354
- }
355
- if (sort) {
356
- sql += " ORDER BY " + sort;
357
- }
358
- if (this.size && this.page) {
359
- var start = this.size * (this.page - 1);
360
- sql += " limit " + start + ',' + this.size;
361
- }
362
- return await this.run(sql);
363
- }
334
+ if (!view) {
335
+ view = '*';
336
+ }
337
+ var viewStr = '';
338
+ if (view.indexOf(',') !== -1) {
339
+ var arr = view.split(',');
340
+ for (var i = 0; i < arr.length; i++) {
341
+ var str = escapeId(arr[i]);
342
+ viewStr += ',' + method.toUpperCase() + '(' + str + ') ' + method.toLowerCase() + '_' + str.replace(
343
+ /`/g, '');
344
+ }
345
+ } else {
346
+ viewStr = ',' + method.toUpperCase() + '(' + escapeId(view) + ') ' + method.toLowerCase() + '_' +
347
+ view.replace(/`/g, '');
348
+ }
349
+ var sql = 'SELECT ' + (groupby ? escapeId(groupby) : '') + viewStr + ' FROM `' + this.table + '`';
350
+ if (where) {
351
+ sql += ' WHERE ' + where;
352
+ }
353
+ if (groupby) {
354
+ sql += ' GROUP BY ' + escapeId(groupby);
355
+ }
356
+ if (sort) {
357
+ sql += ' ORDER BY ' + sort;
358
+ }
359
+ if (this.size && this.page) {
360
+ var start = this.size * (this.page - 1);
361
+ sql += ' limit ' + start + ',' + this.size;
362
+ }
363
+ return await this.run(sql);
364
+ };
364
365
 
365
366
 
366
367
  /**
367
368
  * @description 分组求平均值
368
- * @param {String} where 查询条件
369
- * @param {String} groupby 分组的字段
370
- * @param {String} view 返回的字段
371
- * @param {String} sort 排序方式
372
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
369
+ * @param {string} where 查询条件
370
+ * @param {string} groupby 分组的字段
371
+ * @param {string} view 返回的字段
372
+ * @param {string} sort 排序方式
373
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
373
374
  */
374
- Sql.prototype.groupAvgSql = async function (where, groupby, view, sort = "") {
375
- return await this.groupMathSql(where, groupby, view, sort, "AVG");
375
+ Sql.prototype.groupAvgSql = async function (where, groupby, view, sort = '') {
376
+ return await this.groupMathSql(where, groupby, view, sort, 'AVG');
376
377
  };
377
378
 
378
379
  /**
379
380
  * @description 分组合计数值
380
- * @param {String} where 查询条件
381
- * @param {String} groupby 分组的字段
382
- * @param {String} view 返回的字段
383
- * @param {String} sort 排序方式
384
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
381
+ * @param {string} where 查询条件
382
+ * @param {string} groupby 分组的字段
383
+ * @param {string} view 返回的字段
384
+ * @param {string} sort 排序方式
385
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
385
386
  */
386
- Sql.prototype.groupSumSql = async function (where, groupby, view, sort = "") {
387
- return await this.groupMathSql(where, groupby, view, sort, "SUM");
387
+ Sql.prototype.groupSumSql = async function (where, groupby, view, sort = '') {
388
+ return await this.groupMathSql(where, groupby, view, sort, 'SUM');
388
389
  };
389
390
 
390
391
  /**
391
392
  * @description 分组合计不同条数
392
- * @param {String} where 查询条件
393
- * @param {String} groupby 分组的字段
394
- * @param {String} view 返回的字段
395
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
393
+ * @param {string} where 查询条件
394
+ * @param {string} groupby 分组的字段
395
+ * @param {string} view 返回的字段
396
+ * @param sort
397
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
396
398
  */
397
- Sql.prototype.groupCountSql = async function (where, groupby, view, sort = "") {
398
- return await this.groupMathSql(where, groupby, view, sort, "COUNT");
399
+ Sql.prototype.groupCountSql = async function (where, groupby, view, sort = '') {
400
+ return await this.groupMathSql(where, groupby, view, sort, 'COUNT');
399
401
  };
400
402
 
401
403
 
402
404
  /**
403
405
  * @description 统计学
404
- * @param {Object} query 查询条件
405
- * @param {String} groupby 分组的字段
406
- * @param {String} view 返回的字段
407
- * @param {String} sort 排序方式
408
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
406
+ * @param {object} query 查询条件
407
+ * @param {string} groupby 分组的字段
408
+ * @param {string} view 返回的字段
409
+ * @param {string} sort 排序方式
410
+ * @param method
411
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
409
412
  */
410
413
  Sql.prototype.groupMath = async function (query, groupby, view, sort, method) {
411
- var where = this.toWhere(query, this.like);
412
- return await this.groupMathSql(where, groupby, view, sort, method);
414
+ var where = this.toWhere(query, this.like);
415
+ return await this.groupMathSql(where, groupby, view, sort, method);
413
416
  };
414
417
 
415
418
  /**
416
419
  * @description 分组求平均值
417
- * @param {Object} query 查询条件
418
- * @param {String} groupby 分组的字段
419
- * @param {String} view 返回的字段
420
- * @param {String} sort 排序方式
421
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
420
+ * @param {object} query 查询条件
421
+ * @param {string} groupby 分组的字段
422
+ * @param {string} view 返回的字段
423
+ * @param {string} sort 排序方式
424
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
422
425
  */
423
426
  Sql.prototype.groupAvg = async function (query, groupby, view, sort) {
424
- return await this.groupMath(query, groupby, view, sort, "AVG");
427
+ return await this.groupMath(query, groupby, view, sort, 'AVG');
425
428
  };
426
429
 
427
430
  /**
428
431
  * @description 分组合计数值
429
- * @param {Object} query 查询条件
430
- * @param {String} groupby 分组的字段
431
- * @param {String} view 返回的字段
432
- * @param {String} sort 排序方式
433
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
432
+ * @param {object} query 查询条件
433
+ * @param {string} groupby 分组的字段
434
+ * @param {string} view 返回的字段
435
+ * @param {string} sort 排序方式
436
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
434
437
  */
435
438
  Sql.prototype.groupSum = async function (query, groupby, view, sort) {
436
- return await this.groupMath(query, groupby, view, sort, "SUM");
439
+ return await this.groupMath(query, groupby, view, sort, 'SUM');
437
440
  };
438
441
 
439
442
  /**
440
443
  * @description 分组合计不同条数
441
- * @param {Object} query 查询条件
442
- * @param {String} groupby 分组的字段
443
- * @param {String} view 返回的字段
444
- * @return {Promise|Object} 查询到的内容列表和符合条件总数
444
+ * @param {object} query 查询条件
445
+ * @param {string} groupby 分组的字段
446
+ * @param {string} view 返回的字段
447
+ * @param sort
448
+ * @returns {Promise | object} 查询到的内容列表和符合条件总数
445
449
  */
446
450
  Sql.prototype.groupCount = async function (query, groupby, view, sort) {
447
- return await this.groupMath(query, groupby, view, sort, "COUNT");
451
+ return await this.groupMath(query, groupby, view, sort, 'COUNT');
452
+ };
453
+
454
+ /* === 聚合函数 === */
455
+ /**
456
+ * @description 求和函数
457
+ * @param {string} field 字段名
458
+ * @param {object} query 查询条件
459
+ * @returns {number} 求和结果
460
+ */
461
+ Sql.prototype.sum = async function (field, query) {
462
+ if (!field || typeof field !== 'string') {
463
+ throw new TypeError('字段名必须为字符串');
464
+ }
465
+
466
+ if (!this.table) {
467
+ throw new TypeError('表名未设置');
468
+ }
469
+
470
+ const result = await this.groupSum(query, '', field, '');
471
+ const fieldKey = 'sum_' + field.replace(/`/g, '');
472
+ return result && result.length > 0 ? Number(result[0][fieldKey] || result[0].sum_age) : 0;
473
+ };
474
+
475
+ /**
476
+ * @description 最大值函数
477
+ * @param {string} field 字段名
478
+ * @param {object} query 查询条件
479
+ * @returns {number} 最大值结果
480
+ */
481
+ Sql.prototype.max = async function (field, query) {
482
+ if (!field || typeof field !== 'string') {
483
+ throw new TypeError('字段名必须为字符串');
484
+ }
485
+
486
+ if (!this.table) {
487
+ throw new TypeError('表名未设置');
488
+ }
489
+
490
+ const result = await this.groupMath(query, '', field, '', 'MAX');
491
+ const fieldKey = 'max_' + field.replace(/`/g, '');
492
+ return result && result.length > 0 ? Number(result[0][fieldKey] || result[0].max_age) : 0;
493
+ };
494
+
495
+ /**
496
+ * @description 最小值函数
497
+ * @param {string} field 字段名
498
+ * @param {object} query 查询条件
499
+ * @returns {number} 最小值结果
500
+ */
501
+ Sql.prototype.min = async function (field, query) {
502
+ if (!field || typeof field !== 'string') {
503
+ throw new TypeError('字段名必须为字符串');
504
+ }
505
+
506
+ if (!this.table) {
507
+ throw new TypeError('表名未设置');
508
+ }
509
+
510
+ const result = await this.groupMath(query, '', field, '', 'MIN');
511
+ const fieldKey = 'min_' + field.replace(/`/g, '');
512
+ return result && result.length > 0 ? Number(result[0][fieldKey] || result[0].min_age) : 0;
513
+ };
514
+
515
+ /**
516
+ * @description 平均值函数
517
+ * @param {string} field 字段名
518
+ * @param {object} query 查询条件
519
+ * @returns {number} 平均值结果
520
+ */
521
+ Sql.prototype.avg = async function (field, query) {
522
+ if (!field || typeof field !== 'string') {
523
+ throw new TypeError('字段名必须为字符串');
524
+ }
525
+
526
+ if (!this.table) {
527
+ throw new TypeError('表名未设置');
528
+ }
529
+
530
+ const result = await this.groupMath(query, '', field, '', 'AVG');
531
+ const fieldKey = 'avg_' + field.replace(/`/g, '');
532
+ return result && result.length > 0 ? Number(result[0][fieldKey] || result[0].avg_age) : 0;
533
+ };
534
+
535
+ /* === 字符串操作函数 === */
536
+ /**
537
+ * @description 字符串连接函数
538
+ * @param {...string} args 要连接的字符串参数
539
+ * @returns {string} 连接后的字符串
540
+ */
541
+ Sql.prototype.toStr = function (...args) {
542
+ // 如果没有参数,返回空字符串
543
+ if (args.length === 0) {
544
+ return '';
545
+ }
546
+
547
+ // 将所有参数转换为字符串并用空格连接
548
+ return args.map(arg => String(arg)).join(' ');
448
549
  };
449
550
 
450
551
  /* === sql语句拼接函数 === */
451
552
  /**
452
553
  * @description 转为where语句
453
- * @param {Object} obj 用作拼接的对象
454
- * @param {Boolean} like 是否使用like匹配, 默认不使用
455
- * @return {String} where格式sql语句字符串
554
+ * @param {object} obj 用作拼接的对象
555
+ * @param {boolean} like 是否使用like匹配, 默认不使用
556
+ * @returns {string} where格式sql语句字符串
456
557
  */
457
558
  Sql.prototype.toWhere = function (obj, like) {
458
- var where = "";
459
- if (like === undefined) {
460
- like = this.like;
461
- }
462
- if (like) {
463
- for (var k in obj) {
464
- var val = obj[k];
465
- if (val && typeof (val) === "string") {
466
- val = val.trim("'");
467
- }
468
- val = escape(val);
469
- if (k.endsWith('_min')) {
470
- where += " and " + escapeId(k.replace('_min', '')) + " >= " + val;
471
- } else if (k.endsWith('_max')) {
472
- where += " and " + escapeId(k.replace('_max', '')) + " <= " + val;
473
- } else if (k.endsWith('_not')) {
474
- where += " and " + escapeId(k.replace('_not', '')) + " != " + val;
475
- } else if (k.endsWith('_has')) {
476
- var vals = val.trim("'").split(',').map((o) => {
477
- return "'" + o + "'"
478
- });
479
- where += " and " + escapeId(k.replace('_has', '')) + " in (" + vals.join(',') + ")";
480
- } else if (k.endsWith('_like')) {
481
- where += " and " + escapeId(k.replace('_like', '')) + " LIKE '%" + val.trim("'") + "%'";
482
- } else if (typeof (val) === "string" && !/^[0-9]+$/.test(val)) {
483
- where += " and " + escapeId(k) + " LIKE '%" + val.trim("'") + "%'"
484
- } else {
485
- where += " and " + escapeId(k) + " = " + val;
486
- }
487
- }
488
- } else {
489
- for (var k in obj) {
490
- var val = obj[k];
491
- if (val && typeof (val) === "string") {
492
- val = val.trim("'");
493
- }
494
- val = escape(val);
495
- if (k.endsWith('_min')) {
496
- where += " and " + escapeId(k.replace('_min', '')) + " >= " + val;
497
- } else if (k.endsWith('_max')) {
498
- where += " and " + escapeId(k.replace('_max', '')) + " <= " + val;
499
- } else if (k.endsWith('_not')) {
500
- where += " and " + escapeId(k.replace('_not', '')) + " != " + val;
501
- } else if (k.endsWith('_has')) {
502
- var vals = val.trim("'").split(',').map((o) => {
503
- return "'" + o + "'"
504
- });
505
- where += " and " + escapeId(k.replace('_has', '')) + " in (" + vals.join(',') + ")";
506
- } else {
507
- where += " and " + escapeId(k) + " = " + val;
508
- }
509
- }
510
- }
511
- return where.replace(" and ", "");
559
+ var where = '';
560
+ if (like === undefined) {
561
+ like = this.like;
562
+ }
563
+ if (like) {
564
+ for (var k in obj) {
565
+ var val = obj[k];
566
+ if (val && typeof (val) === 'string') {
567
+ val = val.trim("'");
568
+ }
569
+ val = escape(val);
570
+ if (k.endsWith('_min')) {
571
+ where += ' and ' + escapeId(k.replace('_min', '')) + ' >= ' + val;
572
+ } else if (k.endsWith('_max')) {
573
+ where += ' and ' + escapeId(k.replace('_max', '')) + ' <= ' + val;
574
+ } else if (k.endsWith('_not')) {
575
+ where += ' and ' + escapeId(k.replace('_not', '')) + ' != ' + val;
576
+ } else if (k.endsWith('_has')) {
577
+ var vals = val.trim("'").split(',').map((o) => {
578
+ return "'" + o + "'";
579
+ });
580
+ where += ' and ' + escapeId(k.replace('_has', '')) + ' in (' + vals.join(',') + ')';
581
+ } else if (k.endsWith('_like')) {
582
+ where += ' and ' + escapeId(k.replace('_like', '')) + " LIKE '%" + val.trim("'") + "%'";
583
+ } else if (typeof (val) === 'string' && !/^[0-9]+$/.test(val)) {
584
+ where += ' and ' + escapeId(k) + " LIKE '%" + val.trim("'") + "%'";
585
+ } else {
586
+ where += ' and ' + escapeId(k) + ' = ' + val;
587
+ }
588
+ }
589
+ } else {
590
+ for (var k in obj) {
591
+ var val = obj[k];
592
+ if (val && typeof (val) === 'string') {
593
+ val = val.trim("'");
594
+ }
595
+ val = escape(val);
596
+ if (k.endsWith('_min')) {
597
+ where += ' and ' + escapeId(k.replace('_min', '')) + ' >= ' + val;
598
+ } else if (k.endsWith('_max')) {
599
+ where += ' and ' + escapeId(k.replace('_max', '')) + ' <= ' + val;
600
+ } else if (k.endsWith('_not')) {
601
+ where += ' and ' + escapeId(k.replace('_not', '')) + ' != ' + val;
602
+ } else if (k.endsWith('_has')) {
603
+ var vals = val.trim("'").split(',').map((o) => {
604
+ return "'" + o + "'";
605
+ });
606
+ where += ' and ' + escapeId(k.replace('_has', '')) + ' in (' + vals.join(',') + ')';
607
+ } else {
608
+ where += ' and ' + escapeId(k) + ' = ' + val;
609
+ }
610
+ }
611
+ }
612
+ return where.replace(' and ', '');
512
613
  };
513
614
 
514
615
  /**
515
616
  * @description 转为set语句
516
- * @param {Object} obj 用作拼接的对象
517
- * @return {String} set格式sql语句字符串
617
+ * @param {object} obj 用作拼接的对象
618
+ * @returns {string} set格式sql语句字符串
518
619
  */
519
620
  Sql.prototype.toSet = function (obj) {
520
- var set = "";
521
- for (var k in obj) {
522
- if (!Object.prototype.hasOwnProperty.call(obj, k)) continue;
523
-
524
- var val = obj[k];
525
- if (val === undefined || val === null) continue;
526
-
527
- if (typeof val === "string") {
528
- val = val.trim("'");
529
- }
530
- val = escape(val);
531
-
532
- if (k.endsWith('_add')) {
533
- var k2 = escapeId(k.replace('_add', ''));
534
- set += "," + k2 + " = " + k2 + " + " + val;
535
- } else if (k.endsWith('_del')) {
536
- var k3 = escapeId(k.replace('_del', ''));
537
- set += "," + k3 + " = " + k3 + " - " + val;
538
- } else {
539
- set += "," + escapeId(k) + " = " + val;
540
- }
541
- }
542
- return set.replace(",", "");
621
+ var set = '';
622
+ for (var k in obj) {
623
+ if (!Object.prototype.hasOwnProperty.call(obj, k)) continue;
624
+
625
+ var val = obj[k];
626
+ if (val === undefined || val === null) continue;
627
+
628
+ if (typeof val === 'string') {
629
+ val = val.trim("'");
630
+ }
631
+ val = escape(val);
632
+
633
+ if (k.endsWith('_add')) {
634
+ var k2 = escapeId(k.replace('_add', ''));
635
+ set += ',' + k2 + ' = ' + k2 + ' + ' + val;
636
+ } else if (k.endsWith('_del')) {
637
+ var k3 = escapeId(k.replace('_del', ''));
638
+ set += ',' + k3 + ' = ' + k3 + ' - ' + val;
639
+ } else {
640
+ set += ',' + escapeId(k) + ' = ' + val;
641
+ }
642
+ }
643
+ return set.replace(',', '');
543
644
  };
544
645
 
545
646
  /**
546
647
  * @description 转添加sql语句
547
- * @param {Object} item 用作添加的键值
548
- * @return {String} sql语句
648
+ * @param {object} item 用作添加的键值
649
+ * @returns {string} sql语句
549
650
  */
550
651
  Sql.prototype.toAddSql = function (item) {
551
- if (!this.table || !item || typeof item !== 'object') {
552
- throw new Error('表名或数据未设置');
553
- }
554
-
555
- var key = "";
556
- var val = "";
557
- for (var k in item) {
558
- if (!Object.prototype.hasOwnProperty.call(item, k)) continue;
559
-
560
- key += "," + escapeId(k);
561
- var value = item[k];
562
- if (typeof value === "string") {
563
- value = value.trim("'");
564
- }
565
- val += "," + escape(value);
566
- }
567
- var sql = "INSERT INTO `{0}` ({1}) VALUES ({2});";
568
- return sql.replace("{0}", this.table).replace("{1}", key.replace(",", "")).replace("{2}", val.replace(",", ""));
652
+ if (!this.table || !item || typeof item !== 'object') {
653
+ throw new Error('表名或数据未设置');
654
+ }
655
+
656
+ var key = '';
657
+ var val = '';
658
+ for (var k in item) {
659
+ if (!Object.prototype.hasOwnProperty.call(item, k)) continue;
660
+
661
+ key += ',' + escapeId(k);
662
+ var value = item[k];
663
+ if (typeof value === 'string') {
664
+ value = value.trim("'");
665
+ }
666
+ val += ',' + escape(value);
667
+ }
668
+ var sql = 'INSERT INTO `{0}` ({1}) VALUES ({2});';
669
+ return sql.replace('{0}', this.table).replace('{1}', key.replace(',', '')).replace('{2}', val.replace(',', ''));
569
670
  };
570
671
 
571
672
  /**
572
673
  * @description 转删除sql语句
573
- * @param {Object} query 查询键值
574
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
575
- * @return {String} sql语句
674
+ * @param {object} query 查询键值
675
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
676
+ * @returns {string} sql语句
576
677
  */
577
678
  Sql.prototype.toDelSql = function (query, like) {
578
- if (!this.table) {
579
- throw new Error('表名未设置');
580
- }
581
- var where = this.toWhere(query, like);
582
- var sql = "DELETE FROM `{0}` WHERE {1};";
583
- return sql.replace("{0}", this.table).replace("{1}", where);
679
+ if (!this.table) {
680
+ throw new Error('表名未设置');
681
+ }
682
+ var where = this.toWhere(query, like);
683
+ var sql = 'DELETE FROM `{0}` WHERE {1};';
684
+ return sql.replace('{0}', this.table).replace('{1}', where);
584
685
  };
585
686
 
586
687
  /**
587
688
  * @description 转修改sql语句
588
- * @param {Object} query 查询的键值集合
589
- * @param {Object} item 修改的键值集合
590
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
591
- * @return {String} sql语句
689
+ * @param {object} query 查询的键值集合
690
+ * @param {object} item 修改的键值集合
691
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
692
+ * @returns {string} sql语句
592
693
  */
593
694
  Sql.prototype.toSetSql = function (query, item, like) {
594
- if (!this.table) {
595
- throw new Error('表名未设置');
596
- }
597
- var where = this.toWhere(query, like);
598
- var set = this.toSet(item);
599
- var sql = "UPDATE `{0}` SET {1} WHERE {2};";
600
- return sql.replace("{0}", this.table).replace("{1}", set).replace("{2}", where);
695
+ if (!this.table) {
696
+ throw new Error('表名未设置');
697
+ }
698
+ var where = this.toWhere(query, like);
699
+ var set = this.toSet(item);
700
+ var sql = 'UPDATE `{0}` SET {1} WHERE {2};';
701
+ return sql.replace('{0}', this.table).replace('{1}', set).replace('{2}', where);
601
702
  };
602
703
 
603
704
  /**
604
705
  * @description 转查询sql语句
605
- * @param {Object} query 查询键值集合
606
- * @param {String} sort 排序规则
607
- * @param {String} view 显示的字段
608
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
609
- * @return {String} sql语句
706
+ * @param {object} query 查询键值集合
707
+ * @param {string} sort 排序规则
708
+ * @param {string} view 显示的字段
709
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
710
+ * @returns {string} sql语句
610
711
  */
611
712
  Sql.prototype.toGetSql = function (query, sort, view, like) {
612
- var where = this.toWhere(query, like);
613
- return this.toQuery(where, sort, view);
713
+ var where = this.toWhere(query, like);
714
+ return this.toQuery(where, sort, view);
614
715
  };
615
716
  /* === 传入对象操作 === */
616
717
  /**
617
718
  * @description 增加数据
618
- * @param {Object} body 添加的对象
619
- * @return {Promise|Object} 执行结果
719
+ * @param {object} body 添加的对象
720
+ * @returns {Promise | object} 执行结果
620
721
  */
621
722
  Sql.prototype.add = async function (body) {
622
- if (!this.table || !body || typeof body !== 'object') {
623
- throw new Error('表名或数据未设置');
624
- }
625
- try {
626
- var sql = this.toAddSql(body);
627
- this.sql = sql;
628
- var bl = await this.exec(sql);
629
-
630
- return bl;
631
- } catch (err) {
632
- this.error = err.message;
633
- this.logger('error', '添加数据失败', err);
634
- // 返回默认操作结果对象,保持返回值类型一致
635
- return 0;
636
- }
723
+ if (!this.table || !body || typeof body !== 'object') {
724
+ throw new Error('表名或数据未设置');
725
+ }
726
+ try {
727
+ var sql = this.toAddSql(body);
728
+ this.sql = sql;
729
+ var bl = await this.exec(sql);
730
+
731
+ return bl;
732
+ } catch (err) {
733
+ this.error = err.message;
734
+ this.log('error', '添加数据失败', err);
735
+ // 返回默认操作结果对象,保持返回值类型一致
736
+ return 0;
737
+ }
637
738
  };
638
739
  /**
639
740
  * @description 删除数据
640
- * @param {Object} query 查询条件集合
641
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
642
- * @return {Promise|Object} 执行结果
741
+ * @param {object} query 查询条件集合
742
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
743
+ * @returns {Promise | object} 执行结果
643
744
  */
644
745
  Sql.prototype.del = async function (query, like) {
645
- if (!this.table) {
646
- throw new Error('表名未设置');
647
- }
648
- try {
649
- var sql = this.toDelSql(query, like);
650
- this.sql = sql;
651
- var bl = await this.exec(sql);
652
-
653
- return bl;
654
- } catch (err) {
655
- this.error = err.message;
656
- this.logger('error', '删除数据失败', err);
657
- // 返回默认操作结果对象,保持返回值类型一致
658
- return 0;
659
- }
746
+ if (!this.table) {
747
+ throw new Error('表名未设置');
748
+ }
749
+ try {
750
+ var sql = this.toDelSql(query, like);
751
+ this.sql = sql;
752
+ var bl = await this.exec(sql);
753
+
754
+ return bl;
755
+ } catch (err) {
756
+ this.error = err.message;
757
+ this.log('error', '删除数据失败', err);
758
+ // 返回默认操作结果对象,保持返回值类型一致
759
+ return 0;
760
+ }
660
761
  };
661
762
 
662
763
  /**
663
764
  * @description 修改数据
664
- * @param {Object} query 查询条件集合
665
- * @param {Object} body 修改的键值集合
666
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
667
- * @return {Promise|Object} 执行结果
765
+ * @param {object} query 查询条件集合
766
+ * @param {object} body 修改的键值集合
767
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
768
+ * @returns {Promise | object} 执行结果
668
769
  */
669
770
  Sql.prototype.set = async function (query, body, like) {
670
- if (!this.table || !body || typeof body !== 'object') {
671
- throw new Error('表名或数据未设置');
672
- }
673
- try {
674
- var sql = this.toSetSql(query, body, like);
675
- this.sql = sql;
676
- var bl = await this.exec(sql);
677
- return bl;
678
- } catch (err) {
679
- this.error = err.message;
680
- this.logger('error', '修改数据失败', err);
681
- // 返回默认操作结果对象,保持返回值类型一致
682
- return 0;
683
- }
771
+ if (!this.table || !body || typeof body !== 'object') {
772
+ throw new Error('表名或数据未设置');
773
+ }
774
+ try {
775
+ var sql = this.toSetSql(query, body, like);
776
+ this.sql = sql;
777
+ var bl = await this.exec(sql);
778
+ return bl;
779
+ } catch (err) {
780
+ this.error = err.message;
781
+ this.log('error', '修改数据失败', err);
782
+ // 返回默认操作结果对象,保持返回值类型一致
783
+ return 0;
784
+ }
684
785
  };
685
786
 
686
787
  /**
687
788
  * @description 查询数据
688
- * @param {Object} query 查询条件
689
- * @param {String} sort 排序
690
- * @param {String} view 返回的字段
691
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
692
- * @param {Number} timeout 超时时间(毫秒),默认30000ms
693
- * @return {Promise|Array} 查询结果
789
+ * @param {object} query 查询条件
790
+ * @param {string} sort 排序
791
+ * @param {string} view 返回的字段
792
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
793
+ * @param {number} timeout 超时时间(毫秒),默认30000ms
794
+ * @returns {Promise|Array} 查询结果
694
795
  */
695
796
  Sql.prototype.get = async function (query, sort, view, like, timeout = 30000) {
696
- if (!this.table) {
697
- throw new Error('表名未设置');
698
- }
699
-
700
- try {
701
- // 添加超时控制的Promise
702
- var timeoutPromise = new Promise((_, reject) => {
703
- setTimeout(() => reject(new Error('查询操作超时')), timeout);
704
- });
705
-
706
- // 使用Promise.race实现超时控制
707
- return await Promise.race([
708
- (async () => {
709
- // 生成SQL并执行
710
- var sql = this.toGetSql(query, sort, view, like);
711
- var list = await this.run(sql);
712
- return list;
713
- })(),
714
- timeoutPromise
715
- ]);
716
- } catch (err) {
717
- this.error = err.message;
718
- this.logger('error', '查询数据失败', err);
719
- // 返回空数组作为默认值,保持返回值类型一致
720
- return [];
721
- }
797
+ if (!this.table) {
798
+ throw new Error('表名未设置');
799
+ }
800
+
801
+ try {
802
+ // 使用Promise.race实现超时控制
803
+ const timeout_promise = new Promise((unused_resolve, reject) => {
804
+ setTimeout(() => reject(new Error('查询操作超时')), timeout);
805
+ });
806
+
807
+ return await Promise.race([
808
+ (async () => {
809
+ // 生成SQL并执行
810
+ var sql = this.toGetSql(query, sort, view, like);
811
+ var list = await this.run(sql);
812
+ return list;
813
+ })(),
814
+ timeout_promise
815
+ ]);
816
+ } catch (err) {
817
+ this.error = err.message;
818
+ this.log('error', '查询数据失败', err);
819
+ // 返回空数组作为默认值,保持返回值类型一致
820
+ return [];
821
+ }
722
822
  };
723
823
 
724
824
  /**
725
825
  * @description 添加或修改
726
- * @param {Object} where 查询条件集合
727
- * @param {Object} set 修改的键值
728
- * @param {Boolean} like 是否使用like匹配, 默认不使用
729
- * @return {Promise|Object} 执行结果
826
+ * @param {object} where 查询条件集合
827
+ * @param {object} set 修改的键值
828
+ * @param {boolean} like 是否使用like匹配, 默认不使用
829
+ * @returns {Promise | object} 执行结果
730
830
  */
731
831
  /**
732
832
  * 添加或修改数据(存在则修改,不存在则添加)
733
- * @param {Object|String} where 查询条件
734
- * @param {Object|String} set 要设置的数据
735
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
736
- * @return {Promise<Object>} 执行结果
833
+ * @param {object | string} where 查询条件
834
+ * @param {object | string} set 要设置的数据
835
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
836
+ * @returns {Promise<object>} 执行结果
737
837
  */
738
838
  Sql.prototype.addOrSet = async function (where, set, like) {
739
- if (!this.table || !where || !set) {
740
- throw new Error('表名、条件或数据未设置');
741
- }
742
- try {
743
- let query = where;
744
- let body = set;
745
- let whereStr;
746
-
747
- if (typeof where === "object") {
748
- whereStr = await this.toWhere(where, like);
749
- } else {
750
- whereStr = where;
751
- }
752
-
753
- const count = await this.countSql(whereStr);
754
-
755
- if (count === 0) {
756
- let key = "";
757
- let value = "";
758
-
759
- if (typeof set === "string") {
760
- const arr = set.split(",");
761
- for (const o of arr) {
762
- const ar = o.split('=');
763
- if (ar.length === 2) {
764
- key += "," + ar[0];
765
- value += "," + ar[1];
766
- }
767
- }
768
- } else {
769
- for (const k in set) {
770
- if (!Object.prototype.hasOwnProperty.call(set, k)) continue;
771
-
772
- key += "," + this.escapeId(k);
773
- let val = set[k];
774
- if (typeof val === "string") {
775
- val = val.trim("'");
776
- }
777
- value += "," + this.escape(val);
778
- }
779
- }
780
-
781
- const bl = await this.addSql(key.replace(",", ""), value.replace(",", ""));
782
-
783
- return bl;
784
- } else {
785
- if (typeof set === "object") {
786
- set = await this.toSet(set);
787
- }
788
-
789
- const bl1 = await this.setSql(whereStr, set);
790
-
791
- return bl1;
792
- }
793
- } catch (err) {
794
- this.error = err.message;
795
- this.logger('error', '添加或修改数据失败', err);
796
- // 返回默认操作结果对象,保持返回值类型一致
797
- return 0;
798
- }
839
+ if (!this.table || !where || !set) {
840
+ throw new Error('表名、条件或数据未设置');
841
+ }
842
+ try {
843
+ let where_str;
844
+
845
+ if (typeof where === 'object') {
846
+ where_str = await this.toWhere(where, like);
847
+ } else {
848
+ where_str = where;
849
+ }
850
+
851
+ const count = await this.countSql(whereStr);
852
+
853
+ if (count === 0) {
854
+ let key = '';
855
+ let value = '';
856
+
857
+ if (typeof set === 'string') {
858
+ const arr = set.split(',');
859
+ for (const o of arr) {
860
+ const ar = o.split('=');
861
+ if (ar.length === 2) {
862
+ key += ',' + ar[0];
863
+ value += ',' + ar[1];
864
+ }
865
+ }
866
+ } else {
867
+ for (const k in set) {
868
+ if (!Object.prototype.hasOwnProperty.call(set, k)) continue;
869
+
870
+ key += ',' + this.escapeId(k);
871
+ let val = set[k];
872
+ if (typeof val === 'string') {
873
+ val = val.trim("'");
874
+ }
875
+ value += ',' + this.escape(val);
876
+ }
877
+ }
878
+
879
+ const bl = await this.addSql(key.replace(',', ''), value.replace(',', ''));
880
+
881
+ return bl;
882
+ } else {
883
+ let set_vals = set;
884
+ if (typeof set === 'object') {
885
+ set_vals = await this.toSet(set);
886
+ }
887
+
888
+ const bl1 = await this.setSql(where_str, set_vals);
889
+
890
+ return bl1;
891
+ }
892
+ } catch (err) {
893
+ this.error = err.message;
894
+ this.log('error', '添加或修改数据失败', err);
895
+ // 返回默认操作结果对象,保持返回值类型一致
896
+ return 0;
897
+ }
799
898
  };
800
899
 
801
900
  /**
802
901
  * 统计记录数
803
- * @param {Object} query 查询条件
804
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
805
- * @param {Number} timeout 超时时间(毫秒),默认30000ms
806
- * @return {Promise|Number} 记录数
902
+ * @param {object} query 查询条件
903
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
904
+ * @param {number} timeout 超时时间(毫秒),默认30000ms
905
+ * @returns {Promise | number} 记录数
807
906
  */
808
907
  Sql.prototype.count = async function (query, like, timeout = 30000) {
809
- if (!this.table) {
810
- throw new Error('表名未设置');
811
- }
812
-
813
- try {
814
- // 添加超时控制
815
- const timeoutPromise = new Promise((_, reject) => {
816
- setTimeout(() => reject(new Error('统计操作超时')), timeout);
817
- });
818
-
819
- return await Promise.race([
820
- (async () => {
821
- // 正确生成count SQL
822
- const where = typeof query === 'string' ? query : await this.toWhere(query, like);
823
- const sql = "SELECT COUNT(*) as num FROM `" + this.table + "`" + (where ? " WHERE " + where : "");
824
- this.sql = sql;
825
- const list = await this.run(sql);
826
- const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
827
-
828
- return total;
829
- })(),
830
- timeoutPromise
831
- ]);
832
- } catch (err) {
833
- this.error = err.message;
834
- this.logger('error', '统计记录数失败', err);
835
- // 返回0作为默认统计值,保持返回值类型一致
836
- return 0;
837
- }
908
+ if (!this.table) {
909
+ throw new Error('表名未设置');
910
+ }
911
+
912
+ try {
913
+ // 添加超时控制
914
+ const timeout_promise = new Promise((unused_resolve, reject) => {
915
+ setTimeout(() => reject(new Error('统计操作超时')), timeout);
916
+ });
917
+
918
+ return await Promise.race([
919
+ (async () => {
920
+ // 正确生成count SQL
921
+ const where = typeof query === 'string' ? query : await this.toWhere(query, like);
922
+ const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
923
+ this.sql = sql;
924
+ const list = await this.run(sql);
925
+ const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
926
+
927
+ return total;
928
+ })(),
929
+ timeout_promise
930
+ ]);
931
+ } catch (err) {
932
+ this.error = err.message;
933
+ this.log('error', '统计记录数失败', err);
934
+ // 返回0作为默认统计值,保持返回值类型一致
935
+ return 0;
936
+ }
838
937
  };
839
938
 
840
939
  /**
841
940
  * 查询数据并返回符合条件总数
842
- * @param {Object} query 查询条件
843
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
844
- * @param {Number} timeout 超时时间(毫秒),默认30000ms
845
- * @return {Promise<Number>} 记录数
941
+ * @param {object} query 查询条件
942
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
943
+ * @param {number} timeout 超时时间(毫秒),默认30000ms
944
+ * @returns {Promise<number>} 记录数
846
945
  */
847
946
  Sql.prototype.getCount = async function (query, like, timeout = 30000) {
848
- return await this.count(query, like, timeout);
947
+ return await this.count(query, like, timeout);
849
948
  };
850
949
 
851
950
  /* === 传入数组操作 === */
852
951
  /**
853
- * @description 添加多条数据
952
+ * 添加多条数据
854
953
  * @param {Array} list 对象数组
855
- * @param {Number} batch_size 批量大小,默认100
856
- * @param {Number} timeout 超时时间,默认60000毫秒
857
- * @return {Promise|Object} 执行结果
954
+ * @param {number} batch_size 批量大小,默认100
955
+ * @param {number} timeout 超时时间,默认60000毫秒
956
+ * @returns {Promise | object} 执行结果
858
957
  */
859
958
  Sql.prototype.addList = async function (list, batch_size = 100, timeout = 60000) {
860
- if (!this.table || !Array.isArray(list) || list.length === 0) {
861
- throw new Error('表名或数据列表未设置');
862
- }
863
- try {
864
- // 添加整体操作超时控制
865
- const timeoutPromise = new Promise((_, reject) => {
866
- setTimeout(() => reject(new Error('批量添加数据操作超时')), timeout);
867
- });
868
-
869
- return await Promise.race([
870
- (async () => {
871
- // 如果数据量较小,直接处理
872
- if (list.length <= batch_size) {
873
- // 使用批量插入语法,不使用事务包装
874
- this.sql = this.toBatchAddSql(list);
875
- return await this.exec(this.sql);
876
- }
877
-
878
- // 分批处理大数据量
879
- const totalBatches = Math.ceil(list.length / batch_size);
880
- $.log.info(`开始分批添加数据,共${totalBatches}批,每批${batch_size}条`);
881
-
882
- // 分批执行,每批一个单独的批量插入语句
883
- let finalResult = null;
884
- for (let i = 0; i < totalBatches; i++) {
885
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
886
- $.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
887
-
888
- // 生成批量插入SQL
889
- const batchSql = this.toBatchAddSql(batch);
890
- this.sql = batchSql;
891
-
892
- // 为每批操作添加超时控制
893
- finalResult = await Promise.race([
894
- this.exec(batchSql),
895
- new Promise((_, reject) => {
896
- setTimeout(() => reject(new Error(`第${i + 1}批数据处理超时`)), timeout / totalBatches);
897
- })
898
- ]);
899
- }
900
-
901
- $.log.success(`批量添加数据完成,共${list.length}条`);
902
- return finalResult;
903
- })(),
904
- timeoutPromise
905
- ]);
906
- } catch (error) {
907
- this.logger('error', '批量添加数据失败', error);
908
- // 返回默认操作结果对象,保持返回值类型一致
909
- return 0;
910
- }
959
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
960
+ throw new Error('表名或数据列表未设置');
961
+ }
962
+ try {
963
+ // 添加整体操作超时控制
964
+ const timeout_promise = new Promise((unused_resolve, reject) => {
965
+ setTimeout(() => reject(new Error('批量添加数据操作超时')), timeout);
966
+ });
967
+
968
+ return await Promise.race([
969
+ (async () => {
970
+ // 如果数据量较小,直接处理
971
+ if (list.length <= batch_size) {
972
+ // 使用批量插入语法,不使用事务包装
973
+ this.sql = this.toBatchAddSql(list);
974
+ return await this.exec(this.sql);
975
+ }
976
+
977
+ // 分批处理大数据量
978
+ const total = Math.ceil(list.length / batch_size);
979
+ $.log.info(`开始分批添加数据,共${total}批,每批${batch_size}条`);
980
+
981
+ // 分批执行,每批一个单独的批量插入语句
982
+ let final_res = null;
983
+ for (let i = 0; i < total; i++) {
984
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
985
+ $.log.debug(`处理第${i + 1}/${total}批数据,${batch.length}条`);
986
+
987
+ // 生成批量插入SQL
988
+ const batch_sql = this.toBatchAddSql(batch);
989
+ this.sql = batch_sql;
990
+
991
+ // 为每批操作添加超时控制
992
+ final_res = await Promise.race([
993
+ this.exec(batch_sql),
994
+ new Promise((unused_resolve, reject) => {
995
+ setTimeout(() => reject(new Error(`第${i + 1}批数据处理超时`)), timeout / total);
996
+ })
997
+ ]);
998
+ }
999
+
1000
+ $.log.success(`批量添加数据完成,共${list.length}条`);
1001
+ return final_res;
1002
+ })(),
1003
+ timeout_promise
1004
+ ]);
1005
+ } catch (error) {
1006
+ this.log('error', '批量添加数据失败', error);
1007
+ // 返回默认操作结果对象,保持返回值类型一致
1008
+ return 0;
1009
+ }
911
1010
  };
912
1011
 
913
1012
  /**
914
1013
  * 生成批量插入SQL语句
915
1014
  * @param {Array} list 数据列表
916
- * @return {String} 批量插入SQL语句
1015
+ * @returns {string} 批量插入SQL语句
917
1016
  */
918
1017
  Sql.prototype.toBatchAddSql = function (list) {
919
- if (!this.table || !Array.isArray(list) || list.length === 0) {
920
- throw new Error('表名或数据列表未设置');
921
- }
922
-
923
- // 获取第一个对象的键名作为列名
924
- const firstItem = list[0];
925
- if (!firstItem || typeof firstItem !== 'object') {
926
- throw new Error('数据格式错误');
927
- }
928
-
929
- let keys = [];
930
- for (const k in firstItem) {
931
- if (Object.prototype.hasOwnProperty.call(firstItem, k)) {
932
- keys.push(this.escapeId(k));
933
- }
934
- }
935
-
936
- // 构建列名部分
937
- const columns = keys.join(',');
938
-
939
- // 构建值部分
940
- const values = [];
941
- for (const item of list) {
942
- const values = [];
943
- for (const k of keys) {
944
- const unescapedKey = k.replace(/`/g, '');
945
- let val = item[unescapedKey];
946
- if (typeof val === "string") {
947
- val = val.trim("'");
948
- }
949
- values.push(this.escape(val));
950
- }
951
- values.push(`(${values.join(',')})`);
952
- }
953
-
954
- // 生成最终SQL
955
- const sql = `INSERT INTO \`${this.table}\` (${columns}) VALUES ${values.join(',')}`;
956
- return sql;
1018
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
1019
+ throw new Error('表名或数据列表未设置');
1020
+ }
1021
+
1022
+ // 获取第一个对象的键名作为列名
1023
+ const first_obj = list[0];
1024
+ if (!first_obj || typeof first_obj !== 'object') {
1025
+ throw new Error('数据格式错误');
1026
+ }
1027
+
1028
+ let keys = [];
1029
+ for (const k in first_obj) {
1030
+ if (Object.prototype.hasOwnProperty.call(first_obj, k)) {
1031
+ keys.push(this.escapeId(k));
1032
+ }
1033
+ }
1034
+
1035
+ // 构建列名部分
1036
+ const columns = keys.join(',');
1037
+
1038
+ // 构建值部分
1039
+ const values = [];
1040
+ for (const item of list) {
1041
+ const values = [];
1042
+ for (const k of keys) {
1043
+ const key = k.replace(/`/g, '');
1044
+ let val = item[key];
1045
+ if (typeof val === 'string') {
1046
+ val = val.trim("'");
1047
+ }
1048
+ values.push(this.escape(val));
1049
+ }
1050
+ values.push(`(${values.join(',')})`);
1051
+ }
1052
+
1053
+ // 生成最终SQL
1054
+ const sql = `INSERT INTO \`${this.table}\` (${columns}) VALUES ${values.join(',')}`;
1055
+ return sql;
957
1056
  };
958
1057
 
959
1058
  /**
960
1059
  * 删除多条数据
961
1060
  * @param {Array} list 对象数组
962
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
963
- * @param {Number} batch_size 每批处理数量,默认100
964
- * @param {Number} timeout 超时时间(毫秒),默认60000
965
- * @return {Promise<Object>} 执行结果
1061
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
1062
+ * @param {number} batch_size 每批处理数量,默认100
1063
+ * @param {number} timeout 超时时间(毫秒),默认60000
1064
+ * @returns {Promise<object>} 执行结果
966
1065
  */
967
1066
  Sql.prototype.delList = async function (list, like, batch_size = 100, timeout = 60000) {
968
- if (!this.table || !Array.isArray(list) || list.length === 0) {
969
- throw new Error('表名或数据列表未设置');
970
- }
971
- try {
972
- // 添加整体操作超时控制
973
- const timeoutPromise = new Promise((_, reject) => {
974
- setTimeout(() => reject(new Error('批量删除数据操作超时')), timeout);
975
- });
976
-
977
- return await Promise.race([
978
- (async () => {
979
- // 如果数据量较小,直接处理
980
- if (list.length <= batch_size) {
981
- let sql = "";
982
- for (const item of list) {
983
- sql += this.toDelSql(item.query, like);
984
- }
985
- this.sql = sql;
986
- return await this.exec(sql);
987
- }
988
-
989
- // 分批处理大数据量
990
- const totalBatches = Math.ceil(list.length / batch_size);
991
- $.log.info(`开始分批删除数据,共${totalBatches}批,每批${batch_size}条`);
992
-
993
- // 使用事务包装整个操作以保证原子性
994
- let finalResult = null;
995
- try {
996
- // 开始事务
997
- await this.exec("BEGIN;", 15000);
998
-
999
- // 分批处理
1000
- for (let i = 0; i < totalBatches; i++) {
1001
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1002
- $.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
1003
-
1004
- let batchSql = "";
1005
- for (const item of batch) {
1006
- batchSql += this.toDelSql(item.query, like);
1007
- }
1008
-
1009
- // 为每批操作添加超时控制
1010
- finalResult = await Promise.race([
1011
- this.exec(batchSql),
1012
- new Promise((_, reject) => {
1013
- setTimeout(() => reject(new Error(`第${i + 1}批数据删除超时`)), timeout / totalBatches);
1014
- })
1015
- ]);
1016
- }
1017
-
1018
- // 提交事务
1019
- await this.exec("COMMIT;", 15000);
1020
- } catch (error) {
1021
- // 发生错误时回滚事务
1022
- try {
1023
- await this.exec("ROLLBACK;", 15000);
1024
- this.logger('error', '批量删除数据失败,事务已回滚', error);
1025
- } catch (rollbackError) {
1026
- this.logger('error', '批量删除数据失败,事务回滚也失败', rollbackError);
1027
- }
1028
- // 记录错误日志
1029
- this.logger('error', 'SQL语句执行失败', error);
1030
- }
1031
-
1032
- $.log.success(`批量删除数据完成,共${list.length}条`);
1033
- return finalResult;
1034
- })(),
1035
- timeoutPromise
1036
- ]);
1037
- } catch (err) {
1038
- this.logger('error', '批量删除数据失败', err);
1039
- // 返回默认操作结果对象,保持返回值类型一致
1040
- return 0;
1041
- }
1067
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
1068
+ throw new Error('表名或数据列表未设置');
1069
+ }
1070
+ try {
1071
+ // 添加整体操作超时控制
1072
+ const timeout_promise = new Promise((unused_resolve, reject) => {
1073
+ setTimeout(() => reject(new Error('批量删除数据操作超时')), timeout);
1074
+ });
1075
+
1076
+ return await Promise.race([
1077
+ (async () => {
1078
+ // 如果数据量较小,直接处理
1079
+ if (list.length <= batch_size) {
1080
+ let sql = '';
1081
+ for (const item of list) {
1082
+ sql += this.toDelSql(item.query, like);
1083
+ }
1084
+ this.sql = sql;
1085
+ return await this.exec(sql);
1086
+ }
1087
+
1088
+ // 分批处理大数据量
1089
+ const total = Math.ceil(list.length / batch_size);
1090
+ $.log.info(`开始分批删除数据,共${total}批,每批${batch_size}条`);
1091
+
1092
+ // 使用事务包装整个操作以保证原子性
1093
+ let final_res = null;
1094
+ try {
1095
+ // 开始事务
1096
+ await this.exec('BEGIN;', 15000);
1097
+
1098
+ // 分批处理
1099
+ for (let i = 0; i < total; i++) {
1100
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1101
+ $.log.debug(`处理第${i + 1}/${total}批数据,${batch.length}条`);
1102
+
1103
+ let batch_sql = '';
1104
+ for (const item of batch) {
1105
+ batch_sql += this.toDelSql(item.query, like);
1106
+ }
1107
+
1108
+ // 为每批操作添加超时控制
1109
+ final_res = await Promise.race([
1110
+ this.exec(batch_sql),
1111
+ new Promise((unused_resolve, reject) => {
1112
+ setTimeout(() => reject(new Error(`第${i + 1}批数据删除超时`)), timeout / total);
1113
+ })
1114
+ ]);
1115
+ }
1116
+
1117
+ // 提交事务
1118
+ await this.exec('COMMIT;', 15000);
1119
+ } catch (error) {
1120
+ // 发生错误时回滚事务
1121
+ try {
1122
+ await this.exec('ROLLBACK;', 15000);
1123
+ this.log('error', '批量删除数据失败,事务已回滚', error);
1124
+ } catch (rollback_err) {
1125
+ this.log('error', '批量删除数据失败,事务回滚也失败', rollback_err);
1126
+ }
1127
+ // 记录错误日志
1128
+ this.log('error', 'SQL语句执行失败', error);
1129
+ }
1130
+
1131
+ $.log.success(`批量删除数据完成,共${list.length}条`);
1132
+ return final_res;
1133
+ })(),
1134
+ timeout_promise
1135
+ ]);
1136
+ } catch (err) {
1137
+ this.log('error', '批量删除数据失败', err);
1138
+ // 返回默认操作结果对象,保持返回值类型一致
1139
+ return 0;
1140
+ }
1042
1141
  };
1043
1142
  /**
1044
1143
  * 更新多条数据
1045
1144
  * @param {Array} list 对象数组
1046
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
1047
- * @param {Number} batch_size 每批处理数量,默认100
1048
- * @param {Number} timeout 超时时间(毫秒),默认60000
1049
- * @return {Promise<Object>} 执行结果
1145
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
1146
+ * @param {number} batch_size 每批处理数量,默认100
1147
+ * @param {number} timeout 超时时间(毫秒),默认60000
1148
+ * @returns {Promise<object>} 执行结果
1050
1149
  */
1051
1150
  Sql.prototype.setList = async function (list, like = false, batch_size = 100, timeout = 60000) {
1052
- if (!this.table || !Array.isArray(list) || list.length === 0) {
1053
- throw new Error('表名或数据列表未设置');
1054
- }
1055
- try {
1056
- // 添加整体操作超时控制
1057
- const timeoutPromise = new Promise((_, reject) => {
1058
- setTimeout(() => reject(new Error('批量更新数据操作超时')), timeout);
1059
- });
1060
-
1061
- return await Promise.race([
1062
- (async () => {
1063
- // 如果数据量较小,直接处理
1064
- if (list.length <= batch_size) {
1065
- let sql = "";
1066
- for (const item of list) {
1067
- sql += this.toSetSql(item.query, item.obj, like);
1068
- }
1069
- this.sql = sql;
1070
- return await this.exec(sql);
1071
- }
1072
-
1073
- // 分批处理大数据量
1074
- const totalBatches = Math.ceil(list.length / batch_size);
1075
- $.log.info(`开始分批更新数据,共${totalBatches}批,每批${batch_size}条`);
1076
-
1077
- // 使用事务包装整个操作以保证原子性
1078
- let finalResult = null;
1079
- try {
1080
- // 开始事务
1081
- await this.exec("BEGIN;", 15000);
1082
-
1083
- // 分批处理
1084
- for (let i = 0; i < totalBatches; i++) {
1085
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1086
- $.log.debug(`处理第${i + 1}/${totalBatches}批数据,${batch.length}条`);
1087
-
1088
- let batchSql = "";
1089
- for (const item of batch) {
1090
- batchSql += this.toSetSql(item.query, item.obj, like);
1091
- }
1092
-
1093
- // 为每批操作添加超时控制
1094
- finalResult = await Promise.race([
1095
- this.exec(batchSql),
1096
- new Promise((_, reject) => {
1097
- setTimeout(() => reject(new Error(`第${i + 1}批数据更新超时`)), timeout / totalBatches);
1098
- })
1099
- ]);
1100
- }
1101
-
1102
- // 提交事务
1103
- await this.exec("COMMIT;", 15000);
1104
- } catch (error) {
1105
- // 发生错误时回滚事务
1106
- try {
1107
- await this.exec("ROLLBACK;", 15000);
1108
- this.logger('error', '批量更新数据失败,事务已回滚', error);
1109
- } catch (rollbackError) {
1110
- this.logger('error', '批量更新数据失败,事务回滚也失败', rollbackError);
1111
- }
1112
- }
1113
-
1114
- $.log.success(`批量更新数据完成,共${list.length}条`);
1115
- return finalResult;
1116
- })(),
1117
- timeoutPromise
1118
- ]);
1119
- } catch (err) {
1120
- this.logger('error', '批量更新数据失败', err);
1121
- // 返回默认操作结果对象,保持返回值类型一致
1122
- return 0;
1123
- }
1151
+ if (!this.table || !Array.isArray(list) || list.length === 0) {
1152
+ throw new Error('表名或数据列表未设置');
1153
+ }
1154
+ try {
1155
+ // 添加整体操作超时控制
1156
+ const timeout_promise = new Promise((unused_resolve, reject) => {
1157
+ setTimeout(() => reject(new Error('批量更新数据操作超时')), timeout);
1158
+ });
1159
+
1160
+ return await Promise.race([
1161
+ (async () => {
1162
+ // 如果数据量较小,直接处理
1163
+ if (list.length <= batch_size) {
1164
+ let sql = '';
1165
+ for (const item of list) {
1166
+ sql += this.toSetSql(item.query, item.obj, like);
1167
+ }
1168
+ this.sql = sql;
1169
+ return await this.exec(sql);
1170
+ }
1171
+
1172
+ // 分批处理大数据量
1173
+ const total = Math.ceil(list.length / batch_size);
1174
+ $.log.info(`开始分批更新数据,共${total}批,每批${batch_size}条`);
1175
+
1176
+ // 使用事务包装整个操作以保证原子性
1177
+ let final_res = null;
1178
+ try {
1179
+ // 开始事务
1180
+ await this.exec('BEGIN;', 15000);
1181
+
1182
+ // 分批处理
1183
+ for (let i = 0; i < total; i++) {
1184
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1185
+ $.log.debug(`处理第${i + 1}/${total}批数据,${batch.length}条`);
1186
+
1187
+ let batch_sql = '';
1188
+ for (const item of batch) {
1189
+ batch_sql += this.toSetSql(item.query, item.obj, like);
1190
+ }
1191
+
1192
+ // 为每批操作添加超时控制
1193
+ final_res = await Promise.race([
1194
+ this.exec(batch_sql),
1195
+ new Promise((unused_resolve, reject) => {
1196
+ setTimeout(() => reject(new Error(`第${i + 1}批数据更新超时`)), timeout / total);
1197
+ })
1198
+ ]);
1199
+ }
1200
+
1201
+ // 提交事务
1202
+ await this.exec('COMMIT;', 15000);
1203
+ } catch (error) {
1204
+ // 发生错误时回滚事务
1205
+ try {
1206
+ await this.exec('ROLLBACK;', 15000);
1207
+ this.log('error', '批量更新数据失败,事务已回滚', error);
1208
+ } catch (rollback_err) {
1209
+ this.log('error', '批量更新数据失败,事务回滚也失败', rollback_err);
1210
+ }
1211
+ }
1212
+
1213
+ $.log.success(`批量更新数据完成,共${list.length}条`);
1214
+ return final_res;
1215
+ })(),
1216
+ timeout_promise
1217
+ ]);
1218
+ } catch (err) {
1219
+ this.log('error', '批量更新数据失败', err);
1220
+ // 返回默认操作结果对象,保持返回值类型一致
1221
+ return 0;
1222
+ }
1124
1223
  };
1125
1224
 
1126
1225
  /* 辅助类 */
1127
1226
  /**
1128
- * @description 判断SQL模板是否包含某些参数
1129
- * @param {Object} paramDt 参数集合
1130
- * @param {Object} sqlDt sql模板集合
1131
- * @return {Bool} 有则返回true,没有则返回false
1227
+ * 判断SQL模板是否包含某些参数
1228
+ * @param {object} param_dt 参数集合
1229
+ * @param {object} sql_dt sql模板集合
1230
+ * @returns {boolean} 有则返回true,没有则返回false
1132
1231
  */
1133
- Sql.prototype.hasParam = function (paramDt, sqlDt) {
1134
- var bl = false;
1135
- for (var key in sqlDt) {
1136
- var value = paramDt[key];
1137
- if (value !== undefined && value !== null && value !== '') {
1138
- bl = true;
1139
- break;
1140
- }
1141
- }
1142
- return bl;
1232
+ Sql.prototype.hasPrm = function (param_dt, sql_dt) {
1233
+ var bl = false;
1234
+ for (var key in sql_dt) {
1235
+ if (Object.prototype.hasOwnProperty.call(sql_dt, key)) {
1236
+ var value = param_dt[key];
1237
+ if (value !== undefined && value !== null && value !== '') {
1238
+ bl = true;
1239
+ break;
1240
+ }
1241
+ }
1242
+ }
1243
+ return bl;
1143
1244
  };
1144
1245
 
1145
1246
  /**
1146
- * @description 判断某些参数是否没有SQL模板
1147
- * @param {Object} paramDt 参数集合
1148
- * @param {Object} sqlDt sql模板集合
1149
- * @return {Bool} 没有模板则返回名称,都有则返回undefined
1247
+ * 判断某些参数是否没有SQL模板
1248
+ * @param {object} param_dt 参数集合
1249
+ * @param {object} sql_dt sql模板集合
1250
+ * @returns {string|undefined} 没有模板则返回名称,都有则返回undefined
1150
1251
  */
1151
- Sql.prototype.notParam = function (paramDt, sqlDt) {
1152
- var name;
1153
- for (var key in paramDt) {
1154
- if (!sqlDt[key]) {
1155
- name = key;
1156
- break;
1157
- }
1158
- }
1159
- return name;
1252
+ Sql.prototype.noPrm = function (param_dt, sql_dt) {
1253
+ var name;
1254
+ for (var key in param_dt) {
1255
+ if (!sql_dt[key]) {
1256
+ name = key;
1257
+ break;
1258
+ }
1259
+ }
1260
+ return name;
1160
1261
  };
1161
1262
 
1162
1263
  /**
1163
- * @description 过滤参数,仅保留没有sql模板的参数
1164
- * @param {Object} paramDt 参数集合
1165
- * @param {Object} sqlDt sql模板集合
1166
- * @return {Object} 返回过滤后的参数集合
1264
+ * 过滤参数,仅保留没有sql模板的参数
1265
+ * @param {object} param_dt 参数集合
1266
+ * @param {object} sql_dt sql模板集合
1267
+ * @returns {object} 返回过滤后的参数集合
1167
1268
  */
1168
- Sql.prototype.filterParam = function (paramDt, sqlDt) {
1169
- var dt = [];
1170
- for (var key in paramDt) {
1171
- if (!sqlDt[key]) {
1172
- dt.Add(key, o.Value);
1173
- }
1174
- }
1175
- return dt;
1269
+ Sql.prototype.filtPrm = function (param_dt, sql_dt) {
1270
+ var dt = [];
1271
+ for (var key in param_dt) {
1272
+ if (!sql_dt[key]) {
1273
+ dt.Add(key, o.Value);
1274
+ }
1275
+ }
1276
+ return dt;
1176
1277
  };
1177
1278
 
1178
1279
  /**
1179
- * @description 通过模板拼接查询参数
1180
- * @param {Object} paramDt 参数集合
1181
- * @param {Object} sqlDt 模板集合
1182
- * @return {String} 返回拼接的查询参数
1280
+ * 通过模板拼接查询参数
1281
+ * @param {object} param_dt 参数集合
1282
+ * @param {object} sql_dt 模板集合
1283
+ * @returns {string} 返回拼接的查询参数
1183
1284
  */
1184
- Sql.prototype.tplQuery = function (paramDt, sqlDt) {
1185
- var sql = "";
1186
- if (sqlDt) {
1187
- var l = this.config.separator;
1188
- if (l) {
1189
- for (var key in paramDt) {
1190
- var value = paramDt[key] + '';
1191
- var arr = value.split(l);
1192
- var tpl = sqlDt[key];
1193
- if (tpl) {
1194
- if (arr.length > 1) {
1195
- // 如果数量大于0,则增加多条件
1196
- var sl = "(";
1197
- var len = arr.length;
1198
- for (var i = 0; i < len; i++) {
1199
- sl += " || " + tpl.replaceAll("{0}", this.escape(arr[i]).trim("'"));
1200
- }
1201
- sl = sl.replace(" || ", "") + ")";
1202
- sql += " && " + sl;
1203
- } else {
1204
- sql += " && " + tpl.replaceAll("{0}", this.escape(value).trim("'"));
1205
- }
1206
- } else {
1207
- if (arr.length > 1) {
1208
- // 如果数量大于0,则增加多条件
1209
- var sl = "(";
1210
- var len = arr.length;
1211
- for (var i = 0; i < len; i++) {
1212
- sl += " || " + this.escapeId(key) + " = " + this.escape(arr[i]);
1213
- }
1214
- sl = sl.replace(" || ", "") + ")";
1215
- sql += " && " + sl;
1216
- } else {
1217
- sql += " && " + this.escapeId(key) + " = " + this.escape(value);
1218
- }
1219
- }
1220
- }
1221
- } else {
1222
- for (var key in paramDt) {
1223
- var value = this.escape(paramDt[key]);
1224
- if (sqlDt[key]) {
1225
- sql += " && " + sqlDt[key].replaceAll("{0}", value.trim("'"));
1226
- } else {
1227
- sql += " && " + this.escapeId(key) + " = " + value;
1228
- }
1229
- }
1230
- }
1231
- } else {
1232
- // 如果没有模板,则直接拼接参数
1233
- var l = this.config.separator;
1234
- if (l) {
1235
- // 使用分隔数组拼接
1236
- for (var key in paramDt) {
1237
- var value = paramDt[key];
1238
- var arr = value.split(l);
1239
- if (arr.length > 1) {
1240
- // 如果数量大于0,则增加多条件
1241
- var sl = "(";
1242
- var len = arr.length;
1243
- for (var i = 0; i < len; i++) {
1244
- sl += " || " + this.escapeId(key) + " = " + this.escape(arr[i]);
1245
- }
1246
- sl = sl.replace(" || ", "") + ")";
1247
- sql += " && " + sl;
1248
- } else {
1249
- sql += " && " + this.escapeId(key) + " = " + this.escape(value);
1250
- }
1251
- }
1252
- } else {
1253
- // 直接拼接
1254
- for (var key in paramDt) {
1255
- sql += " && " + this.escapeId(key) + " = " + this.escape(paramDt[key]);
1256
- }
1257
- }
1258
- }
1259
- return sql.replace(" && ", "");
1285
+ Sql.prototype.tplQuery = function (param_dt, sql_dt) {
1286
+ var sql = '';
1287
+ if (sql_dt) {
1288
+ var l = this.config.separator;
1289
+ if (l) {
1290
+ for (var key in param_dt) {
1291
+ var value = param_dt[key] + '';
1292
+ var arr = value.split(l);
1293
+ var tpl = sql_dt[key];
1294
+ if (tpl) {
1295
+ if (arr.length > 1) {
1296
+ // 如果数量大于0,则增加多条件
1297
+ var sl = '(';
1298
+ var len = arr.length;
1299
+ for (var i = 0; i < len; i++) {
1300
+ sl += ' || ' + tpl.replaceAll('{0}', this.escape(arr[i]).trim("'"));
1301
+ }
1302
+ sl = sl.replace(' || ', '') + ')';
1303
+ sql += ' && ' + sl;
1304
+ } else {
1305
+ sql += ' && ' + tpl.replaceAll('{0}', this.escape(value).trim("'"));
1306
+ }
1307
+ } else {
1308
+ if (arr.length > 1) {
1309
+ // 如果数量大于0,则增加多条件
1310
+ var sl = '(';
1311
+ var len = arr.length;
1312
+ for (var i = 0; i < len; i++) {
1313
+ sl += ' || ' + this.escapeId(key) + ' = ' + this.escape(arr[i]);
1314
+ }
1315
+ sl = sl.replace(' || ', '') + ')';
1316
+ sql += ' && ' + sl;
1317
+ } else {
1318
+ sql += ' && ' + this.escapeId(key) + ' = ' + this.escape(value);
1319
+ }
1320
+ }
1321
+ }
1322
+ } else {
1323
+ for (var key in param_dt) {
1324
+ var value = this.escape(param_dt[key]);
1325
+ if (sql_dt[key]) {
1326
+ sql += ' && ' + sql_dt[key].replaceAll('{0}', value.trim("'"));
1327
+ } else {
1328
+ sql += ' && ' + this.escapeId(key) + ' = ' + value;
1329
+ }
1330
+ }
1331
+ }
1332
+ } else {
1333
+ // 如果没有模板,则直接拼接参数
1334
+ var l = this.config.separator;
1335
+ if (l) {
1336
+ // 使用分隔数组拼接
1337
+ for (var key in param_dt) {
1338
+ var value = param_dt[key];
1339
+ var arr = value.split(l);
1340
+ if (arr.length > 1) {
1341
+ // 如果数量大于0,则增加多条件
1342
+ var sl = '(';
1343
+ var len = arr.length;
1344
+ for (var i = 0; i < len; i++) {
1345
+ sl += ' || ' + this.escapeId(key) + ' = ' + this.escape(arr[i]);
1346
+ }
1347
+ sl = sl.replace(' || ', '') + ')';
1348
+ sql += ' && ' + sl;
1349
+ } else {
1350
+ sql += ' && ' + this.escapeId(key) + ' = ' + this.escape(value);
1351
+ }
1352
+ }
1353
+ } else {
1354
+ // 直接拼接
1355
+ for (var key in param_dt) {
1356
+ sql += ' && ' + this.escapeId(key) + ' = ' + this.escape(param_dt[key]);
1357
+ }
1358
+ }
1359
+ }
1360
+ return sql.replace(' && ', '');
1260
1361
  };
1261
1362
 
1262
1363
  /**
1263
- * @description 通过模板拼接修改参数
1264
- * @param {Object} paramDt 参数集合
1265
- * @param {Object} sqlDt 模板集合
1266
- * @return {String} 返回拼接的查询参数
1364
+ * 通过模板拼接修改参数
1365
+ * @param {object} param_dt 参数集合
1366
+ * @param {object} sql_dt 模板集合
1367
+ * @returns {string} 返回拼接的查询参数
1267
1368
  */
1268
- Sql.prototype.tplBody = function (paramDt, sqlDt) {
1269
- var sql = "";
1270
- if (!sqlDt || sqlDt.length === 0) {
1271
- for (var key in paramDt) {
1272
- sql += " , " + this.escapeId(key) + " = " + this.escape(val[key]);
1273
- }
1274
- } else {
1275
- for (var key in paramDt) {
1276
- var value = this.escape(paramDt[key]);
1277
- if (sqlDt[key]) {
1278
- sql += " , " + sqlDt[key].replace("{0}", value).replace('+ -', '- ').replace('- -', '+ ');
1279
- } else {
1280
- sql += " , " + this.escapeId(key) + " = " + value;
1281
- }
1282
- }
1283
- }
1284
- return sql.replace(" , ", "");
1369
+ Sql.prototype.tplBody = function (param_dt, sql_dt) {
1370
+ var sql = '';
1371
+ if (!sql_dt || sql_dt.length === 0) {
1372
+ for (var key in param_dt) {
1373
+ sql += ' , ' + this.escapeId(key) + ' = ' + this.escape(val[key]);
1374
+ }
1375
+ } else {
1376
+ for (var key in param_dt) {
1377
+ var value = this.escape(param_dt[key]);
1378
+ if (sql_dt[key]) {
1379
+ sql += ' , ' + sql_dt[key].replace('{0}', value).replace('+ -', '- ').replace('- -', '+ ');
1380
+ } else {
1381
+ sql += ' , ' + this.escapeId(key) + ' = ' + value;
1382
+ }
1383
+ }
1384
+ }
1385
+ return sql.replace(' , ', '');
1285
1386
  };
1286
1387
 
1287
1388
  /**
1288
- * @description 构建实体模型
1289
- * @param {Object} obj 模型对象
1290
- * @return {Object} 返回监听操作的对象
1389
+ * 构建实体模型
1390
+ * @param {object} model 模型对象
1391
+ * @returns {object} 返回监听操作的对象
1291
1392
  */
1292
1393
  Sql.prototype.model = function (model) {
1293
- var _this = this;
1294
- return new Proxy(model, {
1295
- set: function (obj, prop, value) {
1296
- if (typeof (value) === "number") {
1297
- var n = obj[prop];
1298
- var cha = value - n;
1299
- if (cha > 0) {
1300
- _this.setSql("`" + _this.key + "`=" + obj[_this.key], "`" + prop + "`=`" +
1301
- prop + "` + " + cha);
1302
- } else if (cha < 0) {
1303
- _this.setSql("`" + _this.key + "`=" + obj[_this.key], "`" + prop + "`=`" +
1304
- prop + "` - " + (-cha));
1305
- } else {
1306
- _this.setSql("`" + _this.key + "`=" + obj[_this.key], "`" + prop + "`=" +
1307
- value);
1308
- }
1309
- } else {
1310
- var query = {};
1311
- query[_this.key] = obj[_this.key];
1312
- var set = {};
1313
- set[prop] = value;
1314
- _this.set(query, set);
1315
- }
1316
- obj[prop] = value;
1317
- return obj;
1318
- }
1319
- });
1394
+ var self = this;
1395
+ return new Proxy(model, {
1396
+ set: function (obj, prop, value) {
1397
+ var modified_obj = { ...obj };
1398
+ if (typeof (value) === 'number') {
1399
+ var n = obj[prop];
1400
+ var cha = value - n;
1401
+ if (cha > 0) {
1402
+ self.setSql('`' + self.key + '`=' + obj[self.key], '`' + prop + '`=`' +
1403
+ prop + '` + ' + cha);
1404
+ } else if (cha < 0) {
1405
+ self.setSql('`' + self.key + '`=' + obj[self.key], '`' + prop + '`=`' +
1406
+ prop + '` - ' + (-cha));
1407
+ } else {
1408
+ self.setSql('`' + self.key + '`=' + obj[self.key], '`' + prop + '`=' +
1409
+ value);
1410
+ }
1411
+ } else {
1412
+ var query = {};
1413
+ query[self.key] = obj[self.key];
1414
+ var set = {};
1415
+ set[prop] = value;
1416
+ self.set(query, set);
1417
+ }
1418
+ modified_obj[prop] = value;
1419
+ return modified_obj;
1420
+ }
1421
+ });
1320
1422
  };
1321
1423
 
1322
1424
  /**
1323
1425
  * 查询单条数据
1324
- * @param {Object} query 查询条件
1325
- * @param {String} sort 排序
1326
- * @param {String} view 返回的字段
1327
- * @param {Boolean} like 是否使用like匹配, 为空使用默认方式
1328
- * @param {Number} timeout 超时时间(毫秒),默认30000ms
1329
- * @return {Promise|Object|null} 查询结果
1426
+ * @param {object} query 查询条件
1427
+ * @param {string} sort 排序
1428
+ * @param {string} view 返回的字段
1429
+ * @param {boolean} like 是否使用like匹配, 为空使用默认方式
1430
+ * @param {number} timeout 超时时间(毫秒),默认30000ms
1431
+ * @returns {Promise | object | null} 查询结果
1330
1432
  */
1331
1433
  Sql.prototype.getObj = async function (query, sort, view, like, timeout = 30000) {
1332
- try {
1333
- // 保存当前分页设置
1334
- const oldPage = this.page;
1335
- const oldSize = this.size;
1336
-
1337
- // 设置为只查询一条
1338
- this.page = 1;
1339
- this.size = 1;
1340
-
1341
- // 使用优化后的get方法
1342
- const list = await this.get(query, sort, view, like, timeout);
1343
-
1344
- // 恢复分页设置
1345
- this.page = oldPage;
1346
- this.size = oldSize;
1347
-
1348
- var obj = null;
1349
- if (list.length > 0) {
1350
- obj = list[0];
1351
- if (this.key) {
1352
- obj = this.model(obj);
1353
- }
1354
- }
1355
-
1356
- return obj;
1357
- } catch (err) {
1358
- this.error = err.message;
1359
- this.logger('error', '查询单条数据失败', err);
1360
- }
1361
- return null;
1434
+ try {
1435
+ // 保存当前分页设置
1436
+ const old_page = this.page;
1437
+ const size = this.size;
1438
+
1439
+ // 设置为只查询一条
1440
+ this.page = 1;
1441
+ this.size = 1;
1442
+
1443
+ // 使用优化后的get方法
1444
+ const list = await this.get(query, sort, view, like, timeout);
1445
+
1446
+ // 恢复分页设置
1447
+ this.page = old_page;
1448
+ this.size = size;
1449
+
1450
+ var obj = null;
1451
+ if (list.length > 0) {
1452
+ obj = list[0];
1453
+ if (this.key) {
1454
+ obj = this.model(obj);
1455
+ }
1456
+ }
1457
+
1458
+ return obj;
1459
+ } catch (err) {
1460
+ this.error = err.message;
1461
+ this.log('error', '查询单条数据失败', err);
1462
+ }
1463
+ return null;
1362
1464
  };
1363
1465
 
1364
1466
 
1365
1467
 
1366
1468
  /**
1367
1469
  * 从SQL文件加载数据库
1368
- * @param {String} file - SQL文件路径
1470
+ * @param {string} file - SQL文件路径
1369
1471
  * @returns {Promise<boolean>} 是否加载成功
1370
1472
  */
1371
1473
  Sql.prototype.load = async function (file) {
1372
- try {
1373
- // 记录操作日志
1374
- if (this.config && this.config.debug) {
1375
- $.log.debug(`[${this.constructor.name}] [load] 开始从文件加载数据库`, {
1376
- file: file
1377
- });
1378
- }
1379
-
1380
- // 检查文件是否存在
1381
- if (!file.hasFile()) {
1382
- throw new Error(`SQL文件不存在: ${file}`);
1383
- }
1384
-
1385
- // 读取SQL文件内容
1386
- const sqlContent = await $.file.readText(file);
1387
-
1388
- if (!sqlContent || sqlContent.trim() === '') {
1389
- throw new Error(`SQL文件内容为空: ${file}`);
1390
- }
1391
-
1392
- // 分割SQL语句(按分号分割,但需要注意处理字符串中的分号)
1393
- const sqlStatements = this._splitSqlStatements(sqlContent);
1394
-
1395
- // 开始事务执行SQL语句
1396
- await this.exec('BEGIN TRANSACTION');
1397
-
1398
- try {
1399
- // 逐个执行SQL语句
1400
- for (const sql of sqlStatements) {
1401
- const trimmedSql = sql.trim();
1402
- if (trimmedSql) {
1403
- await this.exec(trimmedSql);
1404
- }
1405
- }
1406
-
1407
- // 提交事务
1408
- await this.exec('COMMIT');
1409
-
1410
- if (this.config && this.config.debug) {
1411
- $.log.info(`[${this.constructor.name}] [load] 数据库加载成功`, {
1412
- file: file,
1413
- statementCount: sqlStatements.length
1414
- });
1415
- }
1416
-
1417
- return true;
1418
- } catch (err) {
1419
- // 回滚事务
1420
- await this.exec('ROLLBACK').catch(rollbackErr => {
1421
- this.logger('error', '事务回滚失败', rollbackErr);
1422
- });
1423
-
1424
- // 记录错误日志
1425
- this.logger('error', 'SQL语句执行失败', err);
1426
- }
1427
- } catch (error) {
1428
- // 记录错误日志
1429
- this.logger('error', '数据库加载失败', error);
1430
- }
1474
+ try {
1475
+ // 记录操作日志
1476
+ if (this.config && this.config.debug) {
1477
+ $.log.debug(`[${this.constructor.name}] [load] 开始从文件加载数据库`, {
1478
+ file: file
1479
+ });
1480
+ }
1481
+
1482
+ // 检查文件是否存在
1483
+ if (!file.hasFile()) {
1484
+ throw new Error(`SQL文件不存在: ${file}`);
1485
+ }
1486
+
1487
+ // 读取SQL文件内容
1488
+ const sql_content = await $.file.readText(file);
1489
+
1490
+ if (!sql_content || sql_content.trim() === '') {
1491
+ throw new Error(`SQL文件内容为空: ${file}`);
1492
+ }
1493
+
1494
+ // 分割SQL语句(按分号分割,但需要注意处理字符串中的分号)
1495
+ const sql_stmts = this._splitSqlStatements(sql_content);
1496
+
1497
+ // 开始事务执行SQL语句
1498
+ await this.exec('BEGIN TRANSACTION');
1499
+
1500
+ try {
1501
+ // 逐个执行SQL语句
1502
+ for (const sql of sql_stmts) {
1503
+ const trim_sql = sql.trim();
1504
+ if (trim_sql) {
1505
+ await this.exec(trim_sql);
1506
+ }
1507
+ }
1508
+
1509
+ // 提交事务
1510
+ await this.exec('COMMIT');
1511
+
1512
+ if (this.config && this.config.debug) {
1513
+ $.log.info(`[${this.constructor.name}] [load] 数据库加载成功`, {
1514
+ file: file,
1515
+ stmt_num: sqlStatements.length
1516
+ });
1517
+ }
1518
+
1519
+ return true;
1520
+ } catch (err) {
1521
+ // 回滚事务
1522
+ await this.exec('ROLLBACK').catch(rollback_err => {
1523
+ this.log('error', '事务回滚失败', rollback_err);
1524
+ });
1525
+
1526
+ // 记录错误日志
1527
+ this.log('error', 'SQL语句执行失败', err);
1528
+ }
1529
+ } catch (error) {
1530
+ // 记录错误日志
1531
+ this.log('error', '数据库加载失败', error);
1532
+ }
1431
1533
  };
1432
1534
 
1433
1535
  /**
1434
1536
  * 分割SQL语句
1435
1537
  * @private
1436
- * @param {String} sqlContent - SQL内容
1538
+ * @param {string} sql_content - SQL内容
1437
1539
  * @returns {Array} SQL语句数组
1438
1540
  */
1439
- Sql.prototype._splitSqlStatements = function (sqlContent) {
1440
- const statements = [];
1441
- let inString = false;
1442
- let stringChar = '';
1443
- let inComment = false;
1444
- let currentStatement = '';
1445
-
1446
- for (let i = 0; i < sqlContent.length; i++) {
1447
- const char = sqlContent[i];
1448
- const nextChar = i + 1 < sqlContent.length ? sqlContent[i + 1] : '';
1449
-
1450
- // 处理注释
1451
- if (!inString && !inComment && char === '-' && nextChar === '-') {
1452
- inComment = true;
1453
- i++; // 跳过第二个'-'
1454
- continue;
1455
- }
1456
-
1457
- if (inComment && char === '\n') {
1458
- inComment = false;
1459
- continue;
1460
- }
1461
-
1462
- if (inComment) {
1463
- continue;
1464
- }
1465
-
1466
- // 处理多行注释
1467
- if (!inString && !inComment && char === '/' && nextChar === '*') {
1468
- inComment = true;
1469
- i++; // 跳过'*'
1470
- continue;
1471
- }
1472
-
1473
- if (inComment && char === '*' && nextChar === '/') {
1474
- inComment = false;
1475
- i++; // 跳过'/'
1476
- continue;
1477
- }
1478
-
1479
- // 处理字符串
1480
- if (!inComment && (char === "'" || char === '"') && (!inString || stringChar === char)) {
1481
- // 检查是否是转义的引号
1482
- let escaped = false;
1483
- for (let j = i - 1; j >= 0; j--) {
1484
- if (sqlContent[j] === '\\') {
1485
- escaped = !escaped;
1486
- } else {
1487
- break;
1488
- }
1489
- }
1490
-
1491
- if (!escaped) {
1492
- if (inString && stringChar === char) {
1493
- inString = false;
1494
- stringChar = '';
1495
- } else if (!inString) {
1496
- inString = true;
1497
- stringChar = char;
1498
- }
1499
- }
1500
- }
1501
-
1502
- // 分割语句
1503
- if (!inString && !inComment && char === ';') {
1504
- statements.push(currentStatement.trim());
1505
- currentStatement = '';
1506
- } else {
1507
- currentStatement += char;
1508
- }
1509
- }
1510
-
1511
- // 添加最后一个语句(如果有)
1512
- if (currentStatement.trim()) {
1513
- statements.push(currentStatement.trim());
1514
- }
1515
-
1516
- return statements;
1541
+ Sql.prototype._splitSqlStatements = function (sql_content) {
1542
+ const stmts = [];
1543
+ let in_str = false;
1544
+ let str_char = '';
1545
+ let in_cmt = false;
1546
+ let cur_stmt = '';
1547
+
1548
+ for (let i = 0; i < sql_content.length; i++) {
1549
+ const char = sql_content[i];
1550
+ const next_char = i + 1 < sql_content.length ? sql_content[i + 1] : '';
1551
+
1552
+ // 处理注释
1553
+ if (!in_str && !in_cmt && char === '-' && next_char === '-') {
1554
+ in_cmt = true;
1555
+ i++; // 跳过第二个'-'
1556
+ continue;
1557
+ }
1558
+
1559
+ if (in_cmt && char === '\n') {
1560
+ in_cmt = false;
1561
+ continue;
1562
+ }
1563
+
1564
+ if (in_cmt) {
1565
+ continue;
1566
+ }
1567
+
1568
+ // 处理多行注释
1569
+ if (!in_str && !in_cmt && char === '/' && next_char === '*') {
1570
+ in_cmt = true;
1571
+ i++; // 跳过'*'
1572
+ continue;
1573
+ }
1574
+
1575
+ if (in_cmt && char === '*' && next_char === '/') {
1576
+ in_cmt = false;
1577
+ i++; // 跳过'/'
1578
+ continue;
1579
+ }
1580
+
1581
+ // 处理字符串
1582
+ if (!in_cmt && (char === "'" || char === '"') && (!in_str || str_char === char)) {
1583
+ // 检查是否是转义的引号
1584
+ let escaped = false;
1585
+ for (let j = i - 1; j >= 0; j--) {
1586
+ if (sql_content[j] === '\\') {
1587
+ escaped = !escaped;
1588
+ } else {
1589
+ break;
1590
+ }
1591
+ }
1592
+
1593
+ if (!escaped) {
1594
+ if (in_str && str_char === char) {
1595
+ in_str = false;
1596
+ str_char = '';
1597
+ } else if (!in_str) {
1598
+ in_str = true;
1599
+ str_char = char;
1600
+ }
1601
+ }
1602
+ }
1603
+
1604
+ // 分割语句
1605
+ if (!in_str && !in_cmt && char === ';') {
1606
+ stmts.push(cur_stmt.trim());
1607
+ cur_stmt = '';
1608
+ } else {
1609
+ cur_stmt += char;
1610
+ }
1611
+ }
1612
+
1613
+ // 添加最后一个语句(如果有)
1614
+ if (cur_stmt.trim()) {
1615
+ stmts.push(cur_stmt.trim());
1616
+ }
1617
+
1618
+ return stmts;
1517
1619
  };
1518
1620
 
1519
1621
  module.exports = {
1520
- Sql
1622
+ Sql
1521
1623
  };