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