mm_sql 1.4.0 → 1.4.2
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 +6 -0
- package/admin_vs_direct_test.js +162 -0
- package/compatibility_test.js +320 -0
- package/comprehensive_test.js +304 -0
- package/db/mm.db +0 -0
- package/debug_error_test.js +127 -0
- package/debug_test.js +35 -0
- package/debug_test2.js +45 -0
- package/debug_test3.js +54 -0
- package/detailed_error_test.js +133 -0
- package/eslint.config.js +235 -0
- package/index.js +306 -297
- package/mysql_error_test.js +110 -0
- package/package.json +13 -5
- package/test.js +271 -222
- package/test2.js +53 -49
package/index.js
CHANGED
|
@@ -1,298 +1,307 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* @author <a href="http://qww.elins.cn">qww</a>
|
|
4
|
-
* @version 1.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
* @param {
|
|
78
|
-
* @param {
|
|
79
|
-
* @
|
|
80
|
-
* @
|
|
81
|
-
*/
|
|
82
|
-
Sql.prototype.
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
1
|
+
/**
|
|
2
|
+
* SQL通用类
|
|
3
|
+
* @author <a href="http://qww.elins.cn">qww</a>
|
|
4
|
+
* @version 1.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 数据库SQL类
|
|
9
|
+
* @class
|
|
10
|
+
* @description 提供统一的SQL操作接口,支持多种数据库类型
|
|
11
|
+
*/
|
|
12
|
+
class Sql {
|
|
13
|
+
/**
|
|
14
|
+
* 构造函数
|
|
15
|
+
* @class
|
|
16
|
+
* @param {object} config - 配置对象
|
|
17
|
+
*/
|
|
18
|
+
constructor(config) {
|
|
19
|
+
/**
|
|
20
|
+
* 配置信息
|
|
21
|
+
*/
|
|
22
|
+
this.config = {scope: 'sys',
|
|
23
|
+
db_type: 'mysql',
|
|
24
|
+
dir: '/db/',
|
|
25
|
+
host: 'localhost',
|
|
26
|
+
port: 3306,
|
|
27
|
+
database: '', ...config || {}};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* SQL适配器
|
|
31
|
+
*/
|
|
32
|
+
this._adapter = null;
|
|
33
|
+
|
|
34
|
+
// 初始化
|
|
35
|
+
this._init();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 初始化
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
Sql.prototype._init = function () {
|
|
44
|
+
this._createSqlAdapter();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 创建SQL适配器
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
Sql.prototype._createSqlAdapter = function () {
|
|
52
|
+
const adapter_mod = `mm_${this.config.db_type}`;
|
|
53
|
+
const adapter = require(adapter_mod);
|
|
54
|
+
|
|
55
|
+
// 根据数据库类型选择不同的初始化方式
|
|
56
|
+
if (this.config.db_type === 'mysql') {
|
|
57
|
+
// 创建MySQL实例
|
|
58
|
+
const admin = adapter.mysqlAdmin;
|
|
59
|
+
this._adapter = admin(this.config.scope, this.config);
|
|
60
|
+
} else if (this.config.db_type === 'sqlite') {
|
|
61
|
+
// SQLite应该有类似的结构
|
|
62
|
+
const admin = adapter.sqliteAdmin;
|
|
63
|
+
this._adapter = admin(this.config.scope, this.config);
|
|
64
|
+
} else {
|
|
65
|
+
// 其他数据库类型直接使用Sql类(如果存在)
|
|
66
|
+
const adapter_cls = adapter.Sql;
|
|
67
|
+
if (adapter_cls) {
|
|
68
|
+
this._adapter = new adapter_cls(this.config);
|
|
69
|
+
} else {
|
|
70
|
+
throw new Error(`不支持的数据库类型: ${this.config.db_type}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 验证SQL参数
|
|
77
|
+
* @param {string | object} sql - SQL语句或选项对象
|
|
78
|
+
* @param {Array} param - 参数数组
|
|
79
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
Sql.prototype._validateSqlParams = function (sql, param, timeout) {
|
|
83
|
+
if (typeof sql !== 'string' && typeof sql !== 'object') {
|
|
84
|
+
throw new TypeError('sql must be string or object');
|
|
85
|
+
}
|
|
86
|
+
if (!Array.isArray(param)) {
|
|
87
|
+
throw new TypeError('param must be array');
|
|
88
|
+
}
|
|
89
|
+
if (timeout !== null && typeof timeout !== 'number') {
|
|
90
|
+
throw new TypeError('timeout must be number or null');
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 执行查询操作
|
|
96
|
+
* @param {string | object} sql - SQL语句或选项对象
|
|
97
|
+
* @param {Array} param - 参数数组
|
|
98
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
99
|
+
* @returns {Promise} 查询结果
|
|
100
|
+
* @throws {TypeError} 当sql参数无效时
|
|
101
|
+
*/
|
|
102
|
+
Sql.prototype.run = function (sql, param = [], timeout = null) {
|
|
103
|
+
this._validateSqlParams(sql, param, timeout);
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
// 支持两种调用方式:run(sql, param, timeout) 或 run({sql: '', param: []})
|
|
107
|
+
let final_sql = sql;
|
|
108
|
+
let final_param = param;
|
|
109
|
+
let final_timeout = timeout;
|
|
110
|
+
if (typeof sql === 'object') {
|
|
111
|
+
final_param = sql.param || [];
|
|
112
|
+
final_timeout = sql.timeout || null;
|
|
113
|
+
final_sql = sql.sql || '';
|
|
114
|
+
}
|
|
115
|
+
return this._adapter.run(final_sql, final_param, final_timeout);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
this.log('error', 'SQL查询执行失败', error);
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 执行修改操作
|
|
124
|
+
* @param {string | object} sql - SQL语句或选项对象
|
|
125
|
+
* @param {Array} param - 参数数组
|
|
126
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
127
|
+
* @returns {Promise} 修改结果
|
|
128
|
+
* @throws {TypeError} 当sql参数无效时
|
|
129
|
+
*/
|
|
130
|
+
Sql.prototype.exec = function (sql, param = [], timeout = null) {
|
|
131
|
+
this._validateSqlParams(sql, param, timeout);
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
// 支持两种调用方式:exec(sql, param, timeout) 或 exec({sql: '', param: []})
|
|
135
|
+
let final_sql = sql;
|
|
136
|
+
let final_param = param;
|
|
137
|
+
let final_timeout = timeout;
|
|
138
|
+
if (typeof sql === 'object') {
|
|
139
|
+
final_param = sql.param || [];
|
|
140
|
+
final_timeout = sql.timeout || null;
|
|
141
|
+
final_sql = sql.sql || '';
|
|
142
|
+
}
|
|
143
|
+
return this._adapter.exec(final_sql, final_param, final_timeout);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
this.log('error', 'SQL修改执行失败', error);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 打开数据库连接
|
|
152
|
+
* @returns {Promise|null} 连接结果
|
|
153
|
+
*/
|
|
154
|
+
Sql.prototype.open = function () {
|
|
155
|
+
try {
|
|
156
|
+
return this._adapter.open();
|
|
157
|
+
} catch (error) {
|
|
158
|
+
this.log('error', '数据库连接打开失败', error);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 关闭数据库连接
|
|
165
|
+
* @returns {Promise|undefined} 关闭结果
|
|
166
|
+
*/
|
|
167
|
+
Sql.prototype.close = function () {
|
|
168
|
+
try {
|
|
169
|
+
return this._adapter.close();
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.log('error', '数据库连接关闭失败', error);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 设置配置
|
|
177
|
+
* @param {object} config - 配置对象
|
|
178
|
+
* @throws {TypeError} 当config参数无效时
|
|
179
|
+
*/
|
|
180
|
+
Sql.prototype.setConfig = function (config) {
|
|
181
|
+
// 参数校验
|
|
182
|
+
if (!config || typeof config !== 'object') {
|
|
183
|
+
throw new TypeError('config must be object');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
this.config = Object.assign(this.config, config);
|
|
188
|
+
this._init();
|
|
189
|
+
} catch (error) {
|
|
190
|
+
this.log('error', '配置设置失败', error);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 执行模板查询
|
|
196
|
+
* @param {object} param - 参数对象
|
|
197
|
+
* @param {object} sql_tpl - SQL模板对象
|
|
198
|
+
* @returns {string} 查询条件字符串
|
|
199
|
+
* @throws {TypeError} 当参数对象无效时
|
|
200
|
+
*/
|
|
201
|
+
Sql.prototype.tplQuery = function (param, sql_tpl) {
|
|
202
|
+
// 参数校验
|
|
203
|
+
if (!param || typeof param !== 'object') {
|
|
204
|
+
throw new TypeError('param must be object');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 如果sql_tpl为null或undefined,使用空对象
|
|
208
|
+
const template = sql_tpl || {};
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const segments = [];
|
|
212
|
+
|
|
213
|
+
for (const key in param) {
|
|
214
|
+
if (template[key]) {
|
|
215
|
+
// 替换占位符{0}为参数值
|
|
216
|
+
const seg = template[key].replace(/\{0\}/g, param[key]);
|
|
217
|
+
segments.push(seg);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
segments.push('`' + key + "` = '" + param[key] + "'");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return segments.join(' AND ');
|
|
225
|
+
} catch (error) {
|
|
226
|
+
this.log('error', '模板查询生成失败', error);
|
|
227
|
+
return '';
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* 执行模板查询(仅返回数据部分)
|
|
233
|
+
* @param {object} param - 参数对象
|
|
234
|
+
* @param {object} sql_tpl - SQL模板对象
|
|
235
|
+
* @returns {string} 数据部分字符串
|
|
236
|
+
* @throws {TypeError} 当参数对象无效时
|
|
237
|
+
*/
|
|
238
|
+
Sql.prototype.tplBody = function (param, sql_tpl) {
|
|
239
|
+
// 参数校验
|
|
240
|
+
if (!param || typeof param !== 'object') {
|
|
241
|
+
throw new TypeError('param must be object');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 如果sql_tpl为null或undefined,使用空对象
|
|
245
|
+
const template = sql_tpl || {};
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const segments = [];
|
|
249
|
+
|
|
250
|
+
for (const key in param) {
|
|
251
|
+
if (template[key]) {
|
|
252
|
+
// 替换占位符{0}为参数值
|
|
253
|
+
const seg = template[key].replace(/\{0\}/g, param[key]);
|
|
254
|
+
segments.push(seg);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
segments.push('`' + key + "` = '" + param[key] + "'");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return segments.join(' , ');
|
|
262
|
+
} catch (error) {
|
|
263
|
+
this.log('error', '模板数据生成失败', error);
|
|
264
|
+
return '';
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 过滤参数对象中的指定键
|
|
270
|
+
* @param {object} param - 参数对象
|
|
271
|
+
* @param {Array} arr - 过滤数组
|
|
272
|
+
* @returns {object} 过滤后的参数对象
|
|
273
|
+
* @throws {TypeError} 当参数对象无效时
|
|
274
|
+
*/
|
|
275
|
+
Sql.prototype.filter = function (param, arr) {
|
|
276
|
+
// 参数校验
|
|
277
|
+
if (!param || typeof param !== 'object') {
|
|
278
|
+
throw new TypeError('param must be object');
|
|
279
|
+
}
|
|
280
|
+
if (!Array.isArray(arr)) {
|
|
281
|
+
throw new TypeError('arr must be array');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
const result = {};
|
|
286
|
+
for (const key of arr) {
|
|
287
|
+
if (param[key] !== undefined) {
|
|
288
|
+
result[key] = param[key];
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
this.log('error', '参数过滤失败', error);
|
|
294
|
+
return {};
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* 获取新数据库管理器
|
|
300
|
+
* @returns {object} 新数据库管理器
|
|
301
|
+
*/
|
|
302
|
+
Sql.prototype.db = function () {
|
|
303
|
+
return this._adapter.db();
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// 导出模块
|
|
298
307
|
exports.Sql = Sql;
|