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.
- package/README.md +3 -4
- package/README_EN.md +478 -0
- package/db.js +497 -496
- package/eslint.config.js +235 -0
- package/index.js +601 -601
- package/package.json +12 -5
- package/sql.js +1390 -1276
- 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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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 {
|
|
171
|
+
* @param {object} query 查询参数
|
|
167
172
|
*/
|
|
168
173
|
Sql.prototype.filter = function (query) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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 {
|
|
182
|
-
* @param {
|
|
183
|
-
* @param {
|
|
184
|
-
* @
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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 {
|
|
208
|
-
* @param {
|
|
209
|
-
* @
|
|
212
|
+
* @param {string} key 用作增加的键集合
|
|
213
|
+
* @param {string} val 用作增加的值集合
|
|
214
|
+
* @returns {Promise | object} 执行结果
|
|
210
215
|
*/
|
|
211
216
|
Sql.prototype.addSql = function (key, val) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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 {
|
|
219
|
-
* @
|
|
223
|
+
* @param {string} where 删除条件
|
|
224
|
+
* @returns {Promise | object} 执行结果
|
|
220
225
|
*/
|
|
221
226
|
Sql.prototype.delSql = function (where) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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 {
|
|
229
|
-
* @param {
|
|
230
|
-
* @
|
|
233
|
+
* @param {string} where 查询条件
|
|
234
|
+
* @param {string} set 修改的键值
|
|
235
|
+
* @returns {Promise | object} 执行结果
|
|
231
236
|
*/
|
|
232
237
|
Sql.prototype.setSql = function (where, set) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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 {
|
|
240
|
-
* @param {
|
|
241
|
-
* @param {
|
|
242
|
-
* @
|
|
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
|
-
|
|
246
|
-
|
|
250
|
+
var sql = this.toQuery(where, sort, view);
|
|
251
|
+
return this.run(sql);
|
|
247
252
|
};
|
|
248
253
|
|
|
249
254
|
/**
|
|
250
255
|
* 查询符合结果总数
|
|
251
|
-
* @param {
|
|
252
|
-
* @
|
|
256
|
+
* @param {string} where 查询条件
|
|
257
|
+
* @returns {Promise | number} 返回结果总数
|
|
253
258
|
*/
|
|
254
259
|
Sql.prototype.countSql = async function (where) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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 {
|
|
270
|
-
* @param {
|
|
271
|
-
* @param {
|
|
272
|
-
* @
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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 {
|
|
290
|
-
* @param {
|
|
291
|
-
* @param {
|
|
292
|
-
* @param {
|
|
293
|
-
* @
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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 {
|
|
332
|
-
* @param {
|
|
333
|
-
* @param {
|
|
334
|
-
* @param {
|
|
335
|
-
* @
|
|
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
|
-
|
|
342
|
+
return await this.groupMathSql(where, groupby, view, sort, 'AVG');
|
|
339
343
|
};
|
|
340
344
|
|
|
341
345
|
/**
|
|
342
346
|
* 分组合计数值
|
|
343
|
-
* @param {
|
|
344
|
-
* @param {
|
|
345
|
-
* @param {
|
|
346
|
-
* @param {
|
|
347
|
-
* @
|
|
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
|
-
|
|
354
|
+
return await this.groupMathSql(where, groupby, view, sort, 'SUM');
|
|
351
355
|
};
|
|
352
356
|
|
|
353
357
|
/**
|
|
354
358
|
* 分组合计不同条数
|
|
355
|
-
* @param {
|
|
356
|
-
* @param {
|
|
357
|
-
* @param {
|
|
358
|
-
* @
|
|
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
|
-
|
|
366
|
+
return await this.groupMathSql(where, groupby, view, sort, 'COUNT');
|
|
362
367
|
};
|
|
363
368
|
|
|
364
369
|
/**
|
|
365
370
|
* 统计学
|
|
366
|
-
* @param {
|
|
367
|
-
* @param {
|
|
368
|
-
* @param {
|
|
369
|
-
* @param {
|
|
370
|
-
* @param
|
|
371
|
-
* @
|
|
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
|
-
|
|
375
|
-
|
|
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 {
|
|
381
|
-
* @param {
|
|
382
|
-
* @param {
|
|
383
|
-
* @param {
|
|
384
|
-
* @
|
|
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
|
-
|
|
393
|
+
return await this.groupMath(query, groupby, view, sort, 'AVG');
|
|
388
394
|
};
|
|
389
395
|
|
|
390
396
|
/**
|
|
391
397
|
* 分组合计数值
|
|
392
|
-
* @param {
|
|
393
|
-
* @param {
|
|
394
|
-
* @param {
|
|
395
|
-
* @param {
|
|
396
|
-
* @
|
|
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
|
-
|
|
405
|
+
return await this.groupMath(query, groupby, view, sort, 'SUM');
|
|
400
406
|
};
|
|
401
407
|
|
|
402
408
|
/**
|
|
403
409
|
* 分组合计不同条数
|
|
404
|
-
* @param {
|
|
405
|
-
* @param {
|
|
406
|
-
* @param {
|
|
407
|
-
* @
|
|
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
|
-
|
|
417
|
+
return await this.groupMath(query, groupby, view, sort, 'COUNT');
|
|
411
418
|
};
|
|
412
419
|
|
|
413
420
|
/* === sql语句拼接函数 === */
|
|
414
421
|
/**
|
|
415
422
|
* 转为where语句
|
|
416
|
-
* @param {
|
|
417
|
-
* @param {
|
|
418
|
-
* @
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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 {
|
|
482
|
-
* @
|
|
498
|
+
* @param {object} obj 用作拼接的对象
|
|
499
|
+
* @returns {string} set格式sql语句字符串
|
|
483
500
|
*/
|
|
484
501
|
Sql.prototype.toSet = function (obj) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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 {
|
|
514
|
-
* @
|
|
530
|
+
* @param {object} item 用作添加的键值
|
|
531
|
+
* @returns {string} sql语句
|
|
515
532
|
*/
|
|
516
533
|
Sql.prototype.toAddSql = function (item) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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 {
|
|
546
|
-
* @param {
|
|
547
|
-
* @
|
|
562
|
+
* @param {object} query 查询键值
|
|
563
|
+
* @param {boolean} like 是否使用like匹配, 为空使用默认方式
|
|
564
|
+
* @returns {string} sql语句
|
|
548
565
|
*/
|
|
549
566
|
Sql.prototype.toDelSql = function (query, like) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
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 {
|
|
563
|
-
* @param {
|
|
564
|
-
* @param {
|
|
565
|
-
* @
|
|
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
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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 {
|
|
583
|
-
* @param {
|
|
584
|
-
* @param {
|
|
585
|
-
* @param {
|
|
586
|
-
* @
|
|
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
|
-
|
|
590
|
-
|
|
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 {
|
|
597
|
-
* @
|
|
613
|
+
* @param {object} body 添加的对象
|
|
614
|
+
* @returns {Promise | object} 执行结果
|
|
598
615
|
*/
|
|
599
616
|
Sql.prototype.add = async function (body) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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 {
|
|
617
|
-
* @param {
|
|
618
|
-
* @
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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 {
|
|
639
|
-
* @param {
|
|
640
|
-
* @param {
|
|
641
|
-
* @
|
|
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
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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 {
|
|
662
|
-
* @param {
|
|
663
|
-
* @param {
|
|
664
|
-
* @
|
|
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
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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 {
|
|
731
|
-
* @param {
|
|
732
|
-
* @param {
|
|
733
|
-
* @param {
|
|
734
|
-
* @param {
|
|
735
|
-
* @
|
|
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
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
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 {
|
|
769
|
-
* @param {
|
|
770
|
-
* @param {
|
|
771
|
-
* @param {
|
|
772
|
-
* @param {
|
|
773
|
-
* @
|
|
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
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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 {
|
|
811
|
-
* @param {
|
|
812
|
-
* @param {
|
|
813
|
-
* @
|
|
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
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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 {
|
|
848
|
-
* @param {
|
|
849
|
-
* @param {
|
|
850
|
-
* @
|
|
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
|
-
|
|
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 {
|
|
861
|
-
* @param {
|
|
862
|
-
* @param {
|
|
863
|
-
* @
|
|
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,
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
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
|
-
* @
|
|
945
|
+
* @returns {string} 批量插入SQL语句
|
|
922
946
|
*/
|
|
923
947
|
Sql.prototype.toBatchAddSql = function (list) {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
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 {
|
|
968
|
-
* @param {
|
|
969
|
-
* @param {
|
|
970
|
-
* @
|
|
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
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
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 {
|
|
1051
|
-
* @param {
|
|
1052
|
-
* @param {
|
|
1053
|
-
* @
|
|
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
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
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 {
|
|
1106
|
-
* @param {
|
|
1107
|
-
* @
|
|
1132
|
+
* @param {object} param_dt 参数集合
|
|
1133
|
+
* @param {object} sql_dt sql模板集合
|
|
1134
|
+
* @returns {boolean} 有则返回true,没有则返回false
|
|
1108
1135
|
*/
|
|
1109
|
-
Sql.prototype.
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
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 {
|
|
1126
|
-
* @param {
|
|
1127
|
-
* @
|
|
1152
|
+
* @param {object} param_dt 参数集合
|
|
1153
|
+
* @param {object} sql_dt sql模板集合
|
|
1154
|
+
* @returns {string | undefined} 没有模板则返回名称,都有则返回undefined
|
|
1128
1155
|
*/
|
|
1129
|
-
Sql.prototype.
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
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 {
|
|
1145
|
-
* @param {
|
|
1146
|
-
* @
|
|
1171
|
+
* @param {object} param_dt 参数集合
|
|
1172
|
+
* @param {object} sql_dt sql模板集合
|
|
1173
|
+
* @returns {object} 返回过滤后的参数集合
|
|
1147
1174
|
*/
|
|
1148
|
-
Sql.prototype.
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
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 {
|
|
1165
|
-
* @param {
|
|
1166
|
-
* @
|
|
1298
|
+
* @param {object} param_dt 参数集合
|
|
1299
|
+
* @param {object} sql_dt 模板集合
|
|
1300
|
+
* @returns {string} 返回拼接的查询参数
|
|
1167
1301
|
*/
|
|
1168
|
-
Sql.prototype.tplQuery = function (
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
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 {
|
|
1266
|
-
* @param {
|
|
1267
|
-
* @
|
|
1326
|
+
* @param {object} param_dt 参数集合
|
|
1327
|
+
* @param {object} sql_dt 模板集合
|
|
1328
|
+
* @returns {string} 返回拼接的查询参数
|
|
1268
1329
|
*/
|
|
1269
|
-
Sql.prototype.tplBody = function (
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
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 {
|
|
1356
|
+
* @param {string} file - SQL文件路径
|
|
1296
1357
|
* @returns {Promise<boolean>} 是否加载成功
|
|
1297
1358
|
*/
|
|
1298
1359
|
Sql.prototype.load = async function (file) {
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
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 {
|
|
1543
|
+
* @param {string} sql_content - SQL内容
|
|
1364
1544
|
* @returns {Array} SQL语句数组
|
|
1365
1545
|
*/
|
|
1366
|
-
Sql.prototype._splitSqlStatements = function (
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
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 {
|
|
1449
|
-
* @
|
|
1602
|
+
* @param {object} model - 模型对象
|
|
1603
|
+
* @returns {object} 返回监听操作的对象
|
|
1450
1604
|
*/
|
|
1451
1605
|
Sql.prototype.model = function (model) {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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 {
|
|
1490
|
-
* @param {
|
|
1491
|
-
* @param {
|
|
1492
|
-
* @
|
|
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
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
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
|
-
|
|
1670
|
+
Sql
|
|
1557
1671
|
};
|