mm_mysql 2.2.4 → 2.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (8) hide show
  1. package/README.md +3 -4
  2. package/README_EN.md +478 -0
  3. package/db.js +497 -496
  4. package/eslint.config.js +235 -0
  5. package/index.js +601 -601
  6. package/package.json +12 -5
  7. package/sql.js +1390 -1276
  8. package/test.js +481 -485
package/db.js CHANGED
@@ -1,145 +1,145 @@
1
1
  const {
2
- Sql
2
+ Sql
3
3
  } = require('./sql');
4
4
 
5
5
  /**
6
6
  * @class 数据库操作类
7
- * @extends Sql
7
+ * @augments Sql
8
8
  */
9
9
  class DB extends Sql {
10
- /**
11
- * @description 数据库管理器
12
- * @param {Object} mysql - MySQL实例
13
- */
14
- constructor(mysql) {
15
- // 正确绑定run和exec方法的上下文
16
- super(
17
- mysql.run,
18
- mysql.exec
19
- );
20
- // 保存mysql实例引用
21
- this._mysql = mysql;
22
- // 事务中
23
- this.task = 0;
24
-
25
- // 事务SQL
26
- this.task_sql = "";
27
-
28
- /**
29
- * 获取上级
30
- * @return {Object} 返回上级管理器
31
- */
32
- this.parent = function () {
33
- return mysql;
34
- };
35
- }
10
+ /**
11
+ * @description 数据库管理器
12
+ * @param {object} mysql - MySQL实例
13
+ */
14
+ constructor(mysql) {
15
+ // 正确绑定run和exec方法的上下文
16
+ super(
17
+ mysql.run,
18
+ mysql.exec
19
+ );
20
+ // 保存mysql实例引用
21
+ this._mysql = mysql;
22
+ // 事务中
23
+ this.task = 0;
24
+
25
+ // 事务SQL
26
+ this.task_sql = '';
27
+
28
+ /**
29
+ * 获取上级
30
+ * @returns {object} 返回上级管理器
31
+ */
32
+ this.parent = function () {
33
+ return mysql;
34
+ };
35
+ }
36
36
  }
37
37
 
38
38
  /**
39
39
  * 创建超时Promise
40
40
  * @private
41
- * @param {Number} timeout - 超时时间(毫秒)
42
- * @param {String} message - 错误信息
41
+ * @param {number} timeout - 超时时间(毫秒)
42
+ * @param {string} message - 错误信息
43
43
  * @returns {Promise<Error>}
44
44
  */
45
45
  DB.prototype._createTimeoutPromise = function (timeout, message) {
46
- return new Promise((_, reject) => {
47
- setTimeout(() => {
48
- reject(new Error(message));
49
- }, timeout);
50
- });
46
+ return new Promise((_, reject) => {
47
+ setTimeout(() => {
48
+ reject(new Error(message));
49
+ }, timeout);
50
+ });
51
51
  };
52
52
 
53
53
  /**
54
54
  * 获取数据库名
55
- * @return {String} 数据库
55
+ * @returns {string} 数据库
56
56
  */
57
57
  DB.prototype.database = function () {
58
- return this.parent().config.database;
58
+ return this.parent().config.database;
59
59
  };
60
60
 
61
61
  /**
62
62
  * 构建新管理器
63
- * @param {String} table 表名
64
- * @param {String} key 键名
65
- * @return {Object} 返回管理器
63
+ * @param {string} table 表名
64
+ * @param {string} key 键名
65
+ * @returns {object} 返回管理器
66
66
  */
67
67
  DB.prototype.new = function (table, key) {
68
- const db = this.parent().db();
69
- db.table = table;
70
- if (key) {
71
- db.key = key;
72
- } else {
73
- const arr = table.split("_");
74
- db.key = arr[arr.length - 1] + "_id";
75
- }
76
- return db;
68
+ const db = this.parent().db();
69
+ db.table = table;
70
+ if (key) {
71
+ db.key = key;
72
+ } else {
73
+ const arr = table.split('_');
74
+ db.key = arr[arr.length - 1] + '_id';
75
+ }
76
+ return db;
77
77
  };
78
78
 
79
79
  /**
80
80
  * 获取数据库连接
81
- * @returns {Promise<Object>}
81
+ * @returns {Promise<object>}
82
82
  */
83
83
  DB.prototype.getConn = async function() {
84
- try {
85
- return await this._mysql.getConn();
86
- } catch (error) {
87
- this.logger('error', '获取连接失败', error);
88
- // 返回null作为默认值,保持返回值类型一致
89
- return null;
90
- }
84
+ try {
85
+ return await this._mysql.getConn();
86
+ } catch (error) {
87
+ this.log('error', '获取连接失败', error);
88
+ // 返回null作为默认值,保持返回值类型一致
89
+ return null;
90
+ }
91
91
  };
92
92
 
93
93
  /**
94
94
  * 开始事务
95
- * @returns {Promise<Object>}
95
+ * @returns {Promise<object>}
96
96
  */
97
97
  DB.prototype.start = async function() {
98
- try {
99
- return await this._mysql.beginTransaction();
100
- } catch (error) {
101
- this.logger('error', '开始事务失败', error);
102
- // 返回null作为默认值,保持返回值类型一致
103
- return null;
104
- }
98
+ try {
99
+ return await this._mysql.beginTransaction();
100
+ } catch (error) {
101
+ this.log('error', '开始事务失败', error);
102
+ // 返回null作为默认值,保持返回值类型一致
103
+ return null;
104
+ }
105
105
  };
106
106
 
107
107
  /**
108
108
  * 提交事务
109
- * @param {Object} transaction - 事务对象
109
+ * @param {object} transaction - 事务对象
110
110
  * @returns {Promise<void>}
111
111
  * @throws {TypeError} 当transaction参数无效时
112
112
  */
113
113
  DB.prototype.commit = async function(transaction) {
114
- // 参数校验
115
- if (!transaction || typeof transaction !== 'object') {
116
- throw new TypeError('transaction must be object');
117
- }
114
+ // 参数校验
115
+ if (!transaction || typeof transaction !== 'object') {
116
+ throw new TypeError('transaction must be object');
117
+ }
118
118
 
119
- try {
120
- await transaction.commit();
121
- } catch (error) {
122
- this.logger('error', '提交事务失败', error);
123
- }
119
+ try {
120
+ await transaction.commit();
121
+ } catch (error) {
122
+ this.log('error', '提交事务失败', error);
123
+ }
124
124
  };
125
125
 
126
126
  /**
127
127
  * 回滚事务
128
- * @param {Object} transaction - 事务对象
128
+ * @param {object} transaction - 事务对象
129
129
  * @returns {Promise<void>}
130
130
  * @throws {TypeError} 当transaction参数无效时
131
131
  */
132
132
  DB.prototype.back = async function(transaction) {
133
- // 参数校验
134
- if (!transaction || typeof transaction !== 'object') {
135
- throw new TypeError('transaction must be object');
136
- }
133
+ // 参数校验
134
+ if (!transaction || typeof transaction !== 'object') {
135
+ throw new TypeError('transaction must be object');
136
+ }
137
137
 
138
- try {
139
- await transaction.rollback();
140
- } catch (error) {
141
- this.logger('error', '回滚事务失败', error);
142
- }
138
+ try {
139
+ await transaction.rollback();
140
+ } catch (error) {
141
+ this.log('error', '回滚事务失败', error);
142
+ }
143
143
  };
144
144
 
145
145
  /**
@@ -149,522 +149,523 @@ DB.prototype.back = async function(transaction) {
149
149
  * @throws {TypeError} 当callback参数无效时
150
150
  */
151
151
  DB.prototype.transaction = async function(callback) {
152
- // 参数校验
153
- if (typeof callback !== 'function') {
154
- throw new TypeError('callback must be function');
155
- }
152
+ // 参数校验
153
+ if (typeof callback !== 'function') {
154
+ throw new TypeError('callback must be function');
155
+ }
156
156
 
157
- try {
158
- return await this._mysql.transaction(callback);
159
- } catch (error) {
160
- this.logger('error', '事务执行失败', error);
161
- // 返回null作为默认值,保持返回值类型一致
162
- return null;
163
- }
157
+ try {
158
+ return await this._mysql.transaction(callback);
159
+ } catch (error) {
160
+ this.log('error', '事务执行失败', error);
161
+ // 返回null作为默认值,保持返回值类型一致
162
+ return null;
163
+ }
164
164
  };
165
165
 
166
166
  /**
167
167
  * @description 获取所有表名
168
- * @param {String} table 表名关键词, 可以 *table*包含、*table后缀、table*前缀 查询
169
- * @param {Number} timeout 超时时间(毫秒)
170
- * @return {Promise|Array} 表名数组
168
+ * @param {string} table 表名关键词, 可以 *table*包含、*table后缀、table*前缀 查询
169
+ * @param {number} timeout 超时时间(毫秒)
170
+ * @returns {Promise|Array} 表名数组
171
171
  */
172
172
  DB.prototype.tables = async function (table, timeout = 15000) {
173
- try {
174
- const list = await this.run("show tables", [], timeout);
175
- const key = 'Tables_in_' + this.database();
176
- if (table) {
177
- // 简单的过滤实现
178
- const filtered = [];
179
- for (const item of list) {
180
- const value = item[key];
181
- if (value && value.includes(table)) {
182
- filtered.push(item);
183
- }
184
- }
185
- return filtered.map(item => item[key]);
186
- }
187
- // 使用原生方法提取表名
188
- return list.map(item => item[key]);
189
- } catch (err) {
190
- this.logger('error', '获取表名失败', err);
191
- return [];
192
- }
173
+ try {
174
+ const list = await this.run('show tables', [], timeout);
175
+ const key = 'Tables_in_' + this.database();
176
+ if (table) {
177
+ // 简单的过滤实现
178
+ const filtered = [];
179
+ for (const item of list) {
180
+ const value = item[key];
181
+ if (value && value.includes(table)) {
182
+ filtered.push(item);
183
+ }
184
+ }
185
+ return filtered.map(item => item[key]);
186
+ }
187
+ // 使用原生方法提取表名
188
+ return list.map(item => item[key]);
189
+ } catch (err) {
190
+ this.log('error', '获取表名失败', err);
191
+ return [];
192
+ }
193
193
  };
194
194
 
195
195
  /**
196
196
  * @description 获取所有表字段
197
- * @param {String} table 表名
198
- * @param {String} field_name 字段名,可选
199
- * @param {Number} timeout 超时时间(毫秒)
200
- * @return {Promise|Array} 字段信息列表
197
+ * @param {string} table 表名
198
+ * @param {string} field_name 字段名,可选
199
+ * @param {number} timeout 超时时间(毫秒)
200
+ * @returns {Promise|Array} 字段信息列表
201
201
  */
202
202
  DB.prototype.fields = async function (table, field_name, timeout = 15000) {
203
- try {
204
- const targetTable = table || this.table;
205
- if (!targetTable) {
206
- throw new TypeError('table must be specified');
207
- }
208
- const field = 'COLUMN_NAME as `name`,ORDINAL_POSITION as `cid`,COLUMN_DEFAULT as `dflt_value`,IS_NULLABLE as `notnull`,COLUMN_TYPE as `type`,COLUMN_KEY as `pk`,EXTRA as `auto`,COLUMN_COMMENT as `note`';
209
- let sql = "select " + field + " from information_schema.COLUMNS where `table_name` = '" + targetTable +
203
+ try {
204
+ const targetTable = table || this.table;
205
+ if (!targetTable) {
206
+ throw new TypeError('table must be specified');
207
+ }
208
+ const field = 'COLUMN_NAME as `name`,ORDINAL_POSITION as `cid`,COLUMN_DEFAULT as `dflt_value`,IS_NULLABLE as `notnull`,COLUMN_TYPE as `type`,COLUMN_KEY as `pk`,EXTRA as `auto`,COLUMN_COMMENT as `note`';
209
+ let sql = 'select ' + field + " from information_schema.COLUMNS where `table_name` = '" + targetTable +
210
210
  "' and `table_schema` = '" + this.database() + "'";
211
- if (field_name) {
212
- sql += " AND COLUMN_NAME='" + field_name + "'";
213
- }
214
- const list = await this.run(sql, [], timeout);
215
- const len = list.length;
216
- for (let i = 0; i < len; i++) {
217
- list[i].pk = !!list[i].pk;
218
- list[i].notnull = list[i].notnull === 'NO';
219
- }
220
- return list;
221
- } catch (err) {
222
- this.logger('error', '获取字段信息失败', err);
223
- return [];
224
- }
211
+ if (field_name) {
212
+ sql += " AND COLUMN_NAME='" + field_name + "'";
213
+ }
214
+ const list = await this.run(sql, [], timeout);
215
+ const len = list.length;
216
+ for (let i = 0; i < len; i++) {
217
+ list[i].pk = !!list[i].pk;
218
+ list[i].notnull = list[i].notnull === 'NO';
219
+ }
220
+ return list;
221
+ } catch (err) {
222
+ this.log('error', '获取字段信息失败', err);
223
+ return [];
224
+ }
225
225
  };
226
226
 
227
227
  /**
228
228
  * @description 创建数据表
229
- * @param {String} table 表名
230
- * @param {String} field 主键字段名
231
- * @param {String} type 类型名,常用类型 mediumint, int, varchar
232
- * @param {Boolean} auto 是否自增字段, 默认为自增字段
233
- * @param {String} commit 注释
234
- * @param {Number} timeout 超时时间(毫秒)
235
- * @return {Promise|Number} 创建成功返回1,失败返回0
229
+ * @param {string} table 表名
230
+ * @param {string} field 主键字段名
231
+ * @param {string} type 类型名,常用类型 mediumint, int, varchar
232
+ * @param {boolean} auto 是否自增字段, 默认为自增字段
233
+ * @param {string} commit 注释
234
+ * @param {number} timeout 超时时间(毫秒)
235
+ * @returns {Promise | number} 创建成功返回1,失败返回0
236
236
  */
237
237
  DB.prototype.addTable = async function (table, field, type = 'int', auto = true, commit = '', timeout = 15000) {
238
- try {
239
- if (!table || typeof table !== 'string') {
240
- throw new TypeError('table must be a valid string');
241
- }
242
- if (!field) {
243
- field = "id";
244
- }
245
- // 构建完整的字段定义
246
- let fieldDef = `\`${field}\` ${type}(11)`;
247
- fieldDef += " NOT NULL";
248
- if (auto) {
249
- fieldDef += " AUTO_INCREMENT";
250
- }
251
- if (commit) {
252
- fieldDef += " COMMENT '" + commit + "'";
253
- }
254
- fieldDef += " PRIMARY KEY";
255
-
256
- let sql = "CREATE TABLE IF NOT EXISTS \`" + table + "\` (" + fieldDef + ")";
257
- sql += " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
258
-
259
- // 执行SQL并设置表名
260
- const result = await this.exec(sql, timeout);
261
- // 设置实例的表名属性,以便后续操作使用
262
- this.table = table;
263
- return result;
264
- } catch (err) {
265
- this.logger('error', '创建表失败', err);
266
- return 0;
267
- }
238
+ try {
239
+ if (!table || typeof table !== 'string') {
240
+ throw new TypeError('table must be a valid string');
241
+ }
242
+ if (!field) {
243
+ field = 'id';
244
+ }
245
+ // 构建完整的字段定义
246
+ let fieldDef = `\`${field}\` ${type}(11)`;
247
+ fieldDef += ' NOT NULL';
248
+ if (auto) {
249
+ fieldDef += ' AUTO_INCREMENT';
250
+ }
251
+ if (commit) {
252
+ fieldDef += " COMMENT '" + commit + "'";
253
+ }
254
+ fieldDef += ' PRIMARY KEY';
255
+
256
+ let sql = 'CREATE TABLE IF NOT EXISTS \`' + table + '\` (' + fieldDef + ')';
257
+ sql += ' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';
258
+
259
+ // 执行SQL并设置表名
260
+ const result = await this.exec(sql, timeout);
261
+ // 设置实例的表名属性,以便后续操作使用
262
+ this.table = table;
263
+ return result;
264
+ } catch (err) {
265
+ this.log('error', '创建表失败', err);
266
+ return 0;
267
+ }
268
268
  };
269
269
 
270
270
  /**
271
271
  * @description 删除表
272
- * @param {String} table 表名
273
- * @param {Number} timeout 超时时间(毫秒)
274
- * @return {Promise|Number} 操作结果
272
+ * @param {string} table 表名
273
+ * @param {number} timeout 超时时间(毫秒)
274
+ * @returns {Promise | number} 操作结果
275
275
  */
276
276
  DB.prototype.dropTable = function (table, timeout = 15000) {
277
- if (!table || typeof table !== 'string') {
278
- throw new TypeError('table must be a valid string');
279
- }
280
- return this.exec("DROP TABLE IF EXISTS \`" + table + "\`;", timeout);
277
+ if (!table || typeof table !== 'string') {
278
+ throw new TypeError('table must be a valid string');
279
+ }
280
+ return this.exec('DROP TABLE IF EXISTS \`' + table + '\`;', timeout);
281
281
  };
282
282
 
283
283
  /**
284
284
  * @description 修改表名
285
- * @param {String} table 旧表名
286
- * @param {String} new_table 新表名
287
- * @param {Number} timeout 超时时间(毫秒)
288
- * @return {Promise|Number} 操作结果
285
+ * @param {string} table 旧表名
286
+ * @param {string} new_table 新表名
287
+ * @param {number} timeout 超时时间(毫秒)
288
+ * @returns {Promise | number} 操作结果
289
289
  */
290
290
  DB.prototype.renameTable = function (table, new_table, timeout = 15000) {
291
- if (!table || !new_table) {
292
- throw new TypeError('table and new_table must be specified');
293
- }
294
- return this.exec("RENAME TABLE \`" + table + "\` TO \`" + new_table + "\`;", timeout);
291
+ if (!table || !new_table) {
292
+ throw new TypeError('table and new_table must be specified');
293
+ }
294
+ return this.exec('RENAME TABLE \`' + table + '\` TO \`' + new_table + '\`;', timeout);
295
295
  };
296
296
 
297
297
  /**
298
298
  * @description 添加字段
299
- * @param {String} field 字段名
300
- * @param {String} type 类型名
301
- * @param {String} value 默认值
302
- * @param {Boolean} not_null 是否非空
303
- * @param {Boolean} auto 是否自增
304
- * @param {String} comment 注释
305
- * @param {Number} timeout 超时时间(毫秒)
306
- * @return {Promise|Number} 添加成功返回1,失败返回0
299
+ * @param {string} field 字段名
300
+ * @param {string} type 类型名
301
+ * @param {string} value 默认值
302
+ * @param {boolean} not_null 是否非空
303
+ * @param {boolean} auto 是否自增
304
+ * @param {string} comment 注释
305
+ * @param {number} timeout 超时时间(毫秒)
306
+ * @returns {Promise | number} 添加成功返回1,失败返回0
307
307
  */
308
308
  DB.prototype.addField = async function (field, type, value = '', not_null = true, auto = false, comment = '', timeout = 15000) {
309
- try {
310
- // 确保表名已设置
311
- if (!this.table || !field || !type) {
312
- throw new TypeError('table, field, and type must be specified');
313
- }
314
-
315
- // 构建字段定义
316
- let fieldDef = `\`${field}\` ${type}`;
317
-
318
- // 添加非空约束
319
- if (not_null) {
320
- fieldDef += " NOT NULL";
321
- }
322
-
323
- // 添加自增属性
324
- if (auto) {
325
- fieldDef += " AUTO_INCREMENT";
326
- }
327
-
328
- // 添加默认值
329
- if (value !== undefined && value !== null && value !== '') {
330
- if (typeof value === 'string') {
331
- fieldDef += " DEFAULT '" + value + "'";
332
- } else {
333
- fieldDef += " DEFAULT " + value;
334
- }
335
- }
336
-
337
- // 添加注释
338
- if (comment) {
339
- fieldDef += " COMMENT '" + comment + "'";
340
- }
341
-
342
- // 使用ADD COLUMN而不是CHANGE COLUMN
343
- const sql = `ALTER TABLE \`${this.table}\` ADD COLUMN ${fieldDef};`;
344
- const result = await this.exec(sql, timeout);
345
- return result
346
- } catch (err) {
347
- this.logger('error', '添加字段失败', err);
348
- return 0;
349
- }
309
+ try {
310
+ // 确保表名已设置
311
+ if (!this.table || !field || !type) {
312
+ throw new TypeError('table, field, and type must be specified');
313
+ }
314
+
315
+ // 构建字段定义
316
+ let fieldDef = `\`${field}\` ${type}`;
317
+
318
+ // 添加非空约束
319
+ if (not_null) {
320
+ fieldDef += ' NOT NULL';
321
+ }
322
+
323
+ // 添加自增属性
324
+ if (auto) {
325
+ fieldDef += ' AUTO_INCREMENT';
326
+ }
327
+
328
+ // 添加默认值
329
+ if (value !== undefined && value !== null && value !== '') {
330
+ if (typeof value === 'string') {
331
+ fieldDef += " DEFAULT '" + value + "'";
332
+ } else {
333
+ fieldDef += ' DEFAULT ' + value;
334
+ }
335
+ }
336
+
337
+ // 添加注释
338
+ if (comment) {
339
+ fieldDef += " COMMENT '" + comment + "'";
340
+ }
341
+
342
+ // 使用ADD COLUMN而不是CHANGE COLUMN
343
+ const sql = `ALTER TABLE \`${this.table}\` ADD COLUMN ${fieldDef};`;
344
+ const result = await this.exec(sql, timeout);
345
+ return result;
346
+ } catch (err) {
347
+ this.log('error', '添加字段失败', err);
348
+ return 0;
349
+ }
350
350
  };
351
351
 
352
352
  /**
353
353
  * @description 修改字段
354
- * @param {String} field 字段名
355
- * @param {String} type 类型名
356
- * @param {String} value 默认值
357
- * @param {Boolean} not_null 是否非空
358
- * @param {Boolean} auto 是否自增
359
- * @param {Boolean} isKey 是否主键
360
- * @param {String} new_name 新字段名
361
- * @param {Number} timeout 超时时间(毫秒)
362
- * @return {Promise|Number} 修改成功返回1,失败返回0
354
+ * @param {string} field 字段名
355
+ * @param {string} type 类型名
356
+ * @param {string} value 默认值
357
+ * @param {boolean} not_null 是否非空
358
+ * @param {boolean} auto 是否自增
359
+ * @param {boolean} isKey 是否主键
360
+ * @param {string} new_name 新字段名
361
+ * @param {number} timeout 超时时间(毫秒)
362
+ * @returns {Promise | number} 修改成功返回1,失败返回0
363
363
  */
364
364
  DB.prototype.setField = async function (field, type, value = '', not_null = true, auto = false, isKey = false, new_name = '', timeout = 15000) {
365
- try {
366
- if (!field || !type || !this.table) {
367
- throw new TypeError('field, type, and table must be specified');
368
- }
369
- const targetName = new_name || field;
370
- let fieldDef = `\`${targetName}\` ${type}`;
371
- if (not_null) {
372
- fieldDef += " NOT NULL";
373
- }
374
- if (auto) {
375
- fieldDef += " AUTO_INCREMENT";
376
- }
377
- if (value !== undefined && value !== null && value !== '') {
378
- if (typeof value === 'string') {
379
- fieldDef += " DEFAULT '" + value + "'";
380
- } else {
381
- fieldDef += " DEFAULT " + value;
382
- }
383
- }
384
- let sql = `ALTER TABLE \`${this.table}\` CHANGE COLUMN \`${field}\` ${fieldDef}`;
385
- if (isKey) {
386
- sql += ", ADD PRIMARY KEY (\`" + targetName + "\`)";
387
- }
388
- sql += ";";
389
- const result = await this.exec(sql, timeout);
390
- return result;
391
- } catch (err) {
392
- this.logger('error', '修改字段失败', err);
393
- return 0;
394
- }
365
+ try {
366
+ if (!field || !type || !this.table) {
367
+ throw new TypeError('field, type, and table must be specified');
368
+ }
369
+ const targetName = new_name || field;
370
+ let fieldDef = `\`${targetName}\` ${type}`;
371
+ if (not_null) {
372
+ fieldDef += ' NOT NULL';
373
+ }
374
+ if (auto) {
375
+ fieldDef += ' AUTO_INCREMENT';
376
+ }
377
+ if (value !== undefined && value !== null && value !== '') {
378
+ if (typeof value === 'string') {
379
+ fieldDef += " DEFAULT '" + value + "'";
380
+ } else {
381
+ fieldDef += ' DEFAULT ' + value;
382
+ }
383
+ }
384
+ let sql = `ALTER TABLE \`${this.table}\` CHANGE COLUMN \`${field}\` ${fieldDef}`;
385
+ if (isKey) {
386
+ sql += ', ADD PRIMARY KEY (\`' + targetName + '\`)';
387
+ }
388
+ sql += ';';
389
+ const result = await this.exec(sql, timeout);
390
+ return result;
391
+ } catch (err) {
392
+ this.log('error', '修改字段失败', err);
393
+ return 0;
394
+ }
395
395
  };
396
396
 
397
397
  /**
398
398
  * @description 修改字段类型
399
- * @param {String} table 表名
400
- * @param {String} field 字段名
401
- * @param {String} type 字段类型
402
- * @param {Number} timeout 超时时间(毫秒)
403
- * @return {Promise|Number} 操作结果
399
+ * @param {string} table 表名
400
+ * @param {string} field 字段名
401
+ * @param {string} type 字段类型
402
+ * @param {number} timeout 超时时间(毫秒)
403
+ * @returns {Promise | number} 操作结果
404
404
  */
405
405
  DB.prototype.editField = function (table, field, type, timeout = 15000) {
406
- if (!table || !field || !type) {
407
- throw new TypeError('table, field, and type must be specified');
408
- }
409
- return this.exec("ALTER TABLE \`" + table + "\` MODIFY COLUMN \`" + field + "\` " + type + ";", timeout);
406
+ if (!table || !field || !type) {
407
+ throw new TypeError('table, field, and type must be specified');
408
+ }
409
+ return this.exec('ALTER TABLE \`' + table + '\` MODIFY COLUMN \`' + field + '\` ' + type + ';', timeout);
410
410
  };
411
411
 
412
412
  /**
413
413
  * @description 删除字段
414
- * @param {String} table 表名
415
- * @param {String} field 字段名
416
- * @param {Number} timeout 超时时间(毫秒)
417
- * @return {Promise|Number} 操作结果
414
+ * @param {string} table 表名
415
+ * @param {string} field 字段名
416
+ * @param {number} timeout 超时时间(毫秒)
417
+ * @returns {Promise | number} 操作结果
418
418
  */
419
419
  DB.prototype.delField = function (table, field, timeout = 15000) {
420
- if (!table || !field) {
421
- throw new TypeError('table and field must be specified');
422
- }
423
- return this.exec("ALTER TABLE \`" + table + "\` DROP COLUMN \`" + field + "\`;", timeout);
420
+ if (!table || !field) {
421
+ throw new TypeError('table and field must be specified');
422
+ }
423
+ return this.exec('ALTER TABLE \`' + table + '\` DROP COLUMN \`' + field + '\`;', timeout);
424
424
  };
425
425
 
426
426
  /**
427
427
  * @description 修改字段名
428
- * @param {String} table 表名
429
- * @param {String} field 旧字段名
430
- * @param {String} new_field 新字段名
431
- * @param {String} type 字段类型
432
- * @param {Number} timeout 超时时间(毫秒)
433
- * @return {Promise|Number} 操作结果
428
+ * @param {string} table 表名
429
+ * @param {string} field 旧字段名
430
+ * @param {string} new_field 新字段名
431
+ * @param {string} type 字段类型
432
+ * @param {number} timeout 超时时间(毫秒)
433
+ * @returns {Promise | number} 操作结果
434
434
  */
435
435
  DB.prototype.renameField = function (table, field, new_field, type, timeout = 15000) {
436
- if (!table || !field || !new_field) {
437
- throw new TypeError('table, field, and new_field must be specified');
438
- }
439
- return this.exec("ALTER TABLE \`" + table + "\` CHANGE \`" + field + "\` \`" + new_field + "\` " + type + ";", timeout);
436
+ if (!table || !field || !new_field) {
437
+ throw new TypeError('table, field, and new_field must be specified');
438
+ }
439
+ return this.exec('ALTER TABLE \`' + table + '\` CHANGE \`' + field + '\` \`' + new_field + '\` ' + type + ';', timeout);
440
440
  };
441
441
 
442
442
  /**
443
443
  * @description 获取表创建语句
444
- * @param {String} table 表名
445
- * @param {Number} timeout 超时时间(毫秒)
446
- * @return {Promise|String} 创建语句
444
+ * @param {string} table 表名
445
+ * @param {number} timeout 超时时间(毫秒)
446
+ * @returns {Promise | string} 创建语句
447
447
  */
448
448
  DB.prototype.getCreateTable = async function (table, timeout = 15000) {
449
- if (!table) {
450
- throw new TypeError('table must be specified');
451
- }
452
- try {
453
- const list = await this.run("SHOW CREATE TABLE \`" + table + "\`;", [], timeout);
454
- if (list && list.length > 0) {
455
- return list[0]["Create Table"] || list[0]["create table"];
456
- }
457
- return '';
458
- } catch (err) {
459
- this.logger('error', '获取表结构失败', err);
460
- return '';
461
- }
449
+ if (!table) {
450
+ throw new TypeError('table must be specified');
451
+ }
452
+ try {
453
+ const list = await this.run('SHOW CREATE TABLE \`' + table + '\`;', [], timeout);
454
+ if (list && list.length > 0) {
455
+ return list[0]['Create Table'] || list[0]['create table'];
456
+ }
457
+ return '';
458
+ } catch (err) {
459
+ this.log('error', '获取表结构失败', err);
460
+ return '';
461
+ }
462
462
  };
463
463
 
464
464
  /**
465
465
  * @description 获取表数据的SQL插入语句
466
- * @param {String} table 表名
467
- * @param {Number} batchSize 批量处理大小
468
- * @param {Number} timeout 超时时间(毫秒)
469
- * @return {Promise|String} SQL插入语句
466
+ * @param {string} table 表名
467
+ * @param {number} batchSize 批量处理大小
468
+ * @param {number} timeout 超时时间(毫秒)
469
+ * @returns {Promise | string} SQL插入语句
470
470
  */
471
471
  DB.prototype.getTableData = async function (table, batchSize = 100, timeout = 60000) {
472
- if (!table) {
473
- throw new TypeError('table must be specified');
474
- }
475
- try {
476
- // 获取表数据
477
- const rows = await this.run(`SELECT * FROM \`${table}\``, [], timeout);
478
- let sql = '';
479
-
480
- if (rows && rows.length > 0) {
481
- sql += `-- 表数据: ${table}\n`;
482
-
483
- // 批量处理大数据量
484
- for (let j = 0; j < rows.length; j += batchSize) {
485
- const batch = rows.slice(j, j + batchSize);
486
- for (const row of batch) {
487
- try {
488
- const rowValues = Object.values(row)
489
- .map(value => {
490
- if (value === null) return 'NULL';
491
- if (typeof value === 'boolean') return value ? 1 : 0;
492
- if (typeof value === 'number') return value;
493
- if (value instanceof Date) {
494
- return "'" + value.toISOString().slice(0, 19).replace('T', ' ') + "'";
495
- }
496
- // 处理字符串,转义特殊字符
497
- if (typeof value === 'string') {
498
- return "'" + value
499
- .replace(/[\\']/g, '\\$&')
500
- .replace(/\n/g, '\\n')
501
- .replace(/\r/g, '\\r')
502
- .replace(/\t/g, '\\t')
503
- .replace(/\u0000/g, '\\0') + "'";
504
- }
505
- return "'" + String(value || '') + "'";
506
- }).join(',');
507
- sql += `INSERT INTO \`${table}\` VALUES (${rowValues});\n`;
508
- } catch (rowErr) {
509
- this.logger('error', '处理行数据失败', rowErr);
510
- }
511
- }
512
- }
513
- sql += '\n';
514
- }
515
- return sql;
516
- } catch (err) {
517
- this.logger('error', '获取表数据失败', err);
518
- return '';
519
- }
472
+ if (!table) {
473
+ throw new TypeError('table must be specified');
474
+ }
475
+ try {
476
+ // 获取表数据
477
+ const rows = await this.run(`SELECT * FROM \`${table}\``, [], timeout);
478
+ let sql = '';
479
+
480
+ if (rows && rows.length > 0) {
481
+ sql += `-- 表数据: ${table}\n`;
482
+
483
+ // 批量处理大数据量
484
+ for (let j = 0; j < rows.length; j += batchSize) {
485
+ const batch = rows.slice(j, j + batchSize);
486
+ for (const row of batch) {
487
+ try {
488
+ const rowValues = Object.values(row)
489
+ .map(value => {
490
+ if (value === null) return 'NULL';
491
+ if (typeof value === 'boolean') return value ? 1 : 0;
492
+ if (typeof value === 'number') return value;
493
+ if (value instanceof Date) {
494
+ return "'" + value.toISOString().slice(0, 19).replace('T', ' ') + "'";
495
+ }
496
+ // 处理字符串,转义特殊字符
497
+ if (typeof value === 'string') {
498
+ return "'" + value
499
+ .replace(/[\\']/g, '\\$&')
500
+ .replace(/\n/g, '\\n')
501
+ .replace(/\r/g, '\\r')
502
+ .replace(/\t/g, '\\t')
503
+ .replace(/\u0000/g, '\\0') + "'";
504
+ }
505
+ return "'" + String(value || '') + "'";
506
+ }).join(',');
507
+ sql += `INSERT INTO \`${table}\` VALUES (${rowValues});\n`;
508
+ } catch (rowErr) {
509
+ this.log('error', '处理行数据失败', rowErr);
510
+ }
511
+ }
512
+ }
513
+ sql += '\n';
514
+ }
515
+ return sql;
516
+ } catch (err) {
517
+ this.log('error', '获取表数据失败', err);
518
+ return '';
519
+ }
520
520
  };
521
521
 
522
522
  /**
523
523
  * @description 清空表数据
524
- * @param {String} table 表名
525
- * @param {Number} timeout 超时时间(毫秒)
526
- * @return {Promise|Number} 操作结果
524
+ * @param {string} table 表名
525
+ * @param {number} timeout 超时时间(毫秒)
526
+ * @returns {Promise | number} 操作结果
527
527
  */
528
528
  DB.prototype.emptyTable = function (table, timeout = 15000) {
529
- if (!table || typeof table !== 'string') {
530
- throw new TypeError('table must be a valid string');
531
- }
532
- return this.exec("TRUNCATE TABLE \`" + table + "\`;", timeout);
529
+ if (!table || typeof table !== 'string') {
530
+ throw new TypeError('table must be a valid string');
531
+ }
532
+ return this.exec('TRUNCATE TABLE \`' + table + '\`;', timeout);
533
533
  };
534
534
 
535
535
  /**
536
536
  * @description 检查表是否存在
537
- * @param {String} table 表名
538
- * @param {Number} timeout 超时时间(毫秒)
539
- * @return {Promise|Boolean} 是否存在
537
+ * @param {string} table 表名
538
+ * @param {number} timeout 超时时间(毫秒)
539
+ * @returns {Promise | boolean} 是否存在
540
540
  */
541
541
  DB.prototype.hasTable = async function (table, timeout = 15000) {
542
- if (!table || typeof table !== 'string') {
543
- return false;
544
- }
545
- try {
546
- const list = await this.run("SHOW TABLES LIKE '" + table + "'", [], timeout);
547
- return list && list.length > 0;
548
- } catch (err) {
549
- this.logger('error', '检查表是否存在失败', err);
550
- return false;
551
- }
542
+ if (!table || typeof table !== 'string') {
543
+ return false;
544
+ }
545
+ try {
546
+ const list = await this.run("SHOW TABLES LIKE '" + table + "'", [], timeout);
547
+ return list && list.length > 0;
548
+ } catch (err) {
549
+ this.log('error', '检查表是否存在失败', err);
550
+ return false;
551
+ }
552
552
  };
553
553
 
554
554
  /**
555
555
  * @description 检查字段是否存在
556
- * @param {String} table 表名
557
- * @param {String} field 字段名
558
- * @param {Number} timeout 超时时间(毫秒)
559
- * @return {Promise|Boolean} 是否存在
556
+ * @param {string} table 表名
557
+ * @param {string} field 字段名
558
+ * @param {number} timeout 超时时间(毫秒)
559
+ * @returns {Promise | boolean} 是否存在
560
560
  */
561
561
  DB.prototype.hasField = async function (table, field, timeout = 15000) {
562
- if (!table || !field) {
563
- return false;
564
- }
565
- try {
566
- const list = await this.fields(table, field, timeout);
567
- return list && list.length > 0;
568
- } catch (err) {
569
- this.logger('error', '检查字段是否存在失败', err);
570
- return false;
571
- }
562
+ if (!table || !field) {
563
+ return false;
564
+ }
565
+ try {
566
+ const list = await this.fields(table, field, timeout);
567
+ return list && list.length > 0;
568
+ } catch (err) {
569
+ this.log('error', '检查字段是否存在失败', err);
570
+ return false;
571
+ }
572
572
  };
573
573
 
574
574
  /**
575
575
  * @description 备份表
576
- * @param {String} table 表名
577
- * @param {String} backup 备份表名
578
- * @param {Number} timeout 超时时间(毫秒)
579
- * @return {Promise|Number} 操作结果
576
+ * @param {string} table 表名
577
+ * @param {string} backup 备份表名
578
+ * @param {number} timeout 超时时间(毫秒)
579
+ * @returns {Promise | number} 操作结果
580
580
  */
581
581
  DB.prototype.backupTable = function (table, backup, timeout = 60000) {
582
- if (!table || !backup) {
583
- throw new TypeError('table and backup must be specified');
584
- }
585
- return this.exec("CREATE TABLE \`" + backup + "\` LIKE \`" + table + "\`; INSERT INTO \`" + backup + "\` SELECT * FROM \`" + table + "\`;", timeout);
582
+ if (!table || !backup) {
583
+ throw new TypeError('table and backup must be specified');
584
+ }
585
+ return this.exec('CREATE TABLE \`' + backup + '\` LIKE \`' + table + '\`; INSERT INTO \`' + backup + '\` SELECT * FROM \`' + table + '\`;', timeout);
586
586
  };
587
587
 
588
588
 
589
589
  /**
590
590
  * @description 创建表
591
- * @param {String} table 表名
592
- * @param {Object} model 表模型,键值对,根据值类型创建字段类型,根据键名创建字段名
593
- * @param {String} key 主键
594
- * @return {Promise|Number} 操作结果
591
+ * @param {string} table 表名
592
+ * @param {object} model 表模型,键值对,根据值类型创建字段类型,根据键名创建字段名
593
+ * @param {string} key 主键
594
+ * @param timeout
595
+ * @returns {Promise | number} 操作结果
595
596
  */
596
597
  DB.prototype.createTable = function (table, model, key = 'id', timeout = 15000) {
597
- if (!table || !model || !model.fields) {
598
- throw new TypeError('table, model, and model.fields must be specified');
599
- }
600
- var fields = '';
601
- for (const field in model.fields) {
602
- const value = model.fields[field];
603
- let type = '';
604
- if (field === key) {
605
- type = 'INT AUTO_INCREMENT PRIMARY KEY';
606
- } else if (typeof value === 'number') {
607
- if (value % 1 === 0) {
608
- // 判断是否时间戳(10位或13位数字)
609
- const now = Date.now();
610
- const isTimestamp = (value >= 1000000000 && value <= now * 1.1); // 10位或13位时间戳
611
- if (isTimestamp) {
612
- type = 'DATETIME';
613
- } else {
614
- type = 'INT';
615
- }
616
- } else {
617
- type = 'FLOAT';
618
- }
619
- } else if (typeof value === 'string') {
620
- type = 'TEXT';
621
- if (value.length <= 255) {
622
- // 正则判断是否日期时间型
623
- if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value)) {
624
- type = 'DATETIME';
625
- }
626
- // 正则判断是否日期型
627
- else if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
628
- type = 'DATE';
629
- }
630
- // 正则判断是否时间型
631
- else if (/^\d{2}:\d{2}:\d{2}$/.test(value)) {
632
- type = 'TIME';
633
- }
634
- // 正则判断是否JSON字符串
635
- else if (/^[{[]/.test(value) && /[}]]$/.test(value)) {
636
- type = 'TEXT';
637
- }
638
- // 正则判断是否html
639
- else if (/^<[a-z][\s\S]*>/i.test(value)) {
640
- type = 'TEXT';
641
- }
642
- // 正则判断是否xml
643
- else if (/^<\?xml[\s\S]*\?>/.test(value)) {
644
- type = 'TEXT';
645
- }
646
- else {
647
- type = 'VARCHAR(255)';
648
- }
649
- }
650
- }
651
- else if (typeof value === 'boolean') {
652
- type = 'tinyint(1)';
653
- }
654
- else if (value instanceof Date) {
655
- // 判断是否Date对象,类型为datetime
656
- type = 'DATETIME';
657
- }
658
- else {
659
- type = 'BLOB';
660
- }
661
- fields += `\`${field}\` ${type}, `;
662
- }
663
- fields = fields.slice(0, -2);
664
- var sql = `CREATE TABLE IF NOT EXISTS \`${table}\` (${fields});`;
665
- return this.exec(sql, [], timeout);
666
- }
598
+ if (!table || !model) {
599
+ throw new TypeError('table, model must be specified');
600
+ }
601
+ var fields = '';
602
+ for (const field in model) {
603
+ const value = model[field];
604
+ let type = '';
605
+ if (field === key) {
606
+ type = 'INT AUTO_INCREMENT PRIMARY KEY';
607
+ } else if (typeof value === 'number') {
608
+ if (value % 1 === 0) {
609
+ // 判断是否时间戳(10位或13位数字)
610
+ const now = Date.now();
611
+ const isTimestamp = (value >= 1000000000 && value <= now * 1.1); // 10位或13位时间戳
612
+ if (isTimestamp) {
613
+ type = 'DATETIME';
614
+ } else {
615
+ type = 'INT';
616
+ }
617
+ } else {
618
+ type = 'FLOAT';
619
+ }
620
+ } else if (typeof value === 'string') {
621
+ type = 'TEXT';
622
+ if (value.length <= 255) {
623
+ // 正则判断是否日期时间型
624
+ if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value)) {
625
+ type = 'DATETIME';
626
+ }
627
+ // 正则判断是否日期型
628
+ else if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
629
+ type = 'DATE';
630
+ }
631
+ // 正则判断是否时间型
632
+ else if (/^\d{2}:\d{2}:\d{2}$/.test(value)) {
633
+ type = 'TIME';
634
+ }
635
+ // 正则判断是否JSON字符串
636
+ else if (/^[{[]/.test(value) && /[}]]$/.test(value)) {
637
+ type = 'TEXT';
638
+ }
639
+ // 正则判断是否html
640
+ else if (/^<[a-z][\s\S]*>/i.test(value)) {
641
+ type = 'TEXT';
642
+ }
643
+ // 正则判断是否xml
644
+ else if (/^<\?xml[\s\S]*\?>/.test(value)) {
645
+ type = 'TEXT';
646
+ }
647
+ else {
648
+ type = 'VARCHAR(255)';
649
+ }
650
+ }
651
+ }
652
+ else if (typeof value === 'boolean') {
653
+ type = 'tinyint(1)';
654
+ }
655
+ else if (value instanceof Date) {
656
+ // 判断是否Date对象,类型为datetime
657
+ type = 'DATETIME';
658
+ }
659
+ else {
660
+ type = 'BLOB';
661
+ }
662
+ fields += `\`${field}\` ${type}, `;
663
+ }
664
+ fields = fields.slice(0, -2);
665
+ var sql = `CREATE TABLE IF NOT EXISTS \`${table}\` (${fields});`;
666
+ return this.exec(sql, [], timeout);
667
+ };
667
668
 
668
669
  module.exports = {
669
- DB
670
+ DB
670
671
  };