mm_mysql 2.2.4 → 2.2.6

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