mm_sqlite 1.3.9 → 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/db.js +200 -264
- package/index.js +128 -509
- package/package.json +1 -1
- package/pool.js +241 -0
- package/sql.js +311 -414
- package/test_db/test.db +0 -0
- package/test_db/test_basic.db +0 -0
- package/test_db/test_core_methods.db +0 -0
package/db.js
CHANGED
|
@@ -75,21 +75,15 @@ DB.prototype.new = function (table = '', key = '') {
|
|
|
75
75
|
* @returns {Promise<object>} 数据库连接对象
|
|
76
76
|
*/
|
|
77
77
|
DB.prototype.getConn = async function (timeout = 15000) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return await this.getParent().getConn(timeout);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
this.log('error', '获取连接失败', error);
|
|
83
|
-
// 重新抛出异常,因为调用方需要连接对象
|
|
84
|
-
throw error;
|
|
85
|
-
}
|
|
78
|
+
// 直接使用SQLite实例的getConn方法,避免Promise.race导致的死锁
|
|
79
|
+
return await this.getParent().getConn(timeout);
|
|
86
80
|
};
|
|
87
81
|
|
|
88
82
|
/**
|
|
89
83
|
* 开始事务
|
|
90
84
|
* @returns {Promise<object>}
|
|
91
85
|
*/
|
|
92
|
-
DB.prototype.start = async function() {
|
|
86
|
+
DB.prototype.start = async function () {
|
|
93
87
|
this.task = 1;
|
|
94
88
|
try {
|
|
95
89
|
await this.exec('BEGIN;');
|
|
@@ -116,17 +110,17 @@ DB.prototype.start = async function() {
|
|
|
116
110
|
* @returns {Promise<void>}
|
|
117
111
|
* @throws {TypeError} 当transaction参数无效时
|
|
118
112
|
*/
|
|
119
|
-
DB.prototype.commit = async function(transaction) {
|
|
113
|
+
DB.prototype.commit = async function (transaction) {
|
|
120
114
|
// 参数校验
|
|
121
115
|
if (!transaction || typeof transaction !== 'object') {
|
|
122
116
|
throw new TypeError('transaction must be object');
|
|
123
117
|
}
|
|
124
|
-
|
|
118
|
+
|
|
125
119
|
if (this.task !== 1) {
|
|
126
120
|
this.log('warn', '没有活跃的事务可提交');
|
|
127
121
|
return;
|
|
128
122
|
}
|
|
129
|
-
|
|
123
|
+
|
|
130
124
|
try {
|
|
131
125
|
await this.exec('COMMIT;', [], 15000);
|
|
132
126
|
this.task = 0;
|
|
@@ -158,17 +152,17 @@ DB.prototype.end = function () {
|
|
|
158
152
|
* @returns {Promise<void>}
|
|
159
153
|
* @throws {TypeError} 当transaction参数无效时
|
|
160
154
|
*/
|
|
161
|
-
DB.prototype.back = async function(transaction) {
|
|
155
|
+
DB.prototype.back = async function (transaction) {
|
|
162
156
|
// 参数校验
|
|
163
157
|
if (!transaction || typeof transaction !== 'object') {
|
|
164
158
|
throw new TypeError('transaction must be object');
|
|
165
159
|
}
|
|
166
|
-
|
|
160
|
+
|
|
167
161
|
if (this.task !== 1) {
|
|
168
162
|
this.log('warn', '没有活跃的事务可回滚');
|
|
169
163
|
return;
|
|
170
164
|
}
|
|
171
|
-
|
|
165
|
+
|
|
172
166
|
try {
|
|
173
167
|
await this.exec('ROLLBACK;', [], 15000);
|
|
174
168
|
this.task = 0;
|
|
@@ -186,22 +180,22 @@ DB.prototype.back = async function(transaction) {
|
|
|
186
180
|
* @returns {Promise<*>}
|
|
187
181
|
* @throws {TypeError} 当callback参数无效时
|
|
188
182
|
*/
|
|
189
|
-
DB.prototype.transaction = async function(callback) {
|
|
183
|
+
DB.prototype.transaction = async function (callback) {
|
|
190
184
|
// 参数校验
|
|
191
185
|
if (typeof callback !== 'function') {
|
|
192
186
|
throw new TypeError('callback must be function');
|
|
193
187
|
}
|
|
194
|
-
|
|
188
|
+
|
|
195
189
|
try {
|
|
196
190
|
// 开始事务
|
|
197
191
|
await this.start();
|
|
198
|
-
|
|
192
|
+
|
|
199
193
|
// 执行回调函数
|
|
200
194
|
const result = await callback();
|
|
201
|
-
|
|
195
|
+
|
|
202
196
|
// 提交事务
|
|
203
197
|
await this.commit({});
|
|
204
|
-
|
|
198
|
+
|
|
205
199
|
return result;
|
|
206
200
|
} catch (err) {
|
|
207
201
|
// 回滚事务
|
|
@@ -219,25 +213,20 @@ DB.prototype.transaction = async function(callback) {
|
|
|
219
213
|
* @returns {Promise|Array} 表名数组
|
|
220
214
|
*/
|
|
221
215
|
DB.prototype.tables = async function (table, timeout = 15000) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
filtered.push(item);
|
|
231
|
-
}
|
|
216
|
+
const list = await this.run("SELECT `name` FROM sqlite_master WHERE type='table';", [], timeout);
|
|
217
|
+
if (table) {
|
|
218
|
+
// 简单的过滤实现
|
|
219
|
+
const filtered = [];
|
|
220
|
+
for (const item of list) {
|
|
221
|
+
const value = item.name;
|
|
222
|
+
if (value && value.includes(table)) {
|
|
223
|
+
filtered.push(item);
|
|
232
224
|
}
|
|
233
|
-
return filtered.map(item => item.name);
|
|
234
225
|
}
|
|
235
|
-
|
|
236
|
-
return list.map(item => item.name);
|
|
237
|
-
} catch (err) {
|
|
238
|
-
this.log('error', '获取表名失败', err);
|
|
239
|
-
return [];
|
|
226
|
+
return filtered.map(item => item.name);
|
|
240
227
|
}
|
|
228
|
+
// 使用原生方法提取表名
|
|
229
|
+
return list.map(item => item.name);
|
|
241
230
|
};
|
|
242
231
|
|
|
243
232
|
/**
|
|
@@ -247,38 +236,33 @@ DB.prototype.tables = async function (table, timeout = 15000) {
|
|
|
247
236
|
* @returns {Promise|Array} 字段信息列表
|
|
248
237
|
*/
|
|
249
238
|
DB.prototype.fields = async function (table, field_name, timeout = 15000) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
throw new TypeError('table must be specified');
|
|
254
|
-
}
|
|
255
|
-
var sql = 'PRAGMA table_info(`{0}`);'.replace('{0}', targetTable);
|
|
256
|
-
var list = await this.run(sql, [], timeout);
|
|
257
|
-
var len = list.length;
|
|
258
|
-
for (var i = 0; i < len; i++) {
|
|
259
|
-
list[i].pk = list[i].pk ? true : false;
|
|
260
|
-
list[i].not_null = list[i].not_null ? true : false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// 如果指定了字段名,过滤结果
|
|
264
|
-
if (field_name) {
|
|
265
|
-
list = list.filter(field => field.name === field_name);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return list.map(item => ({
|
|
269
|
-
name: item.name,
|
|
270
|
-
cid: item.cid,
|
|
271
|
-
default_value: item.dflt_value,
|
|
272
|
-
not_null: item.notnull,
|
|
273
|
-
type: item.type,
|
|
274
|
-
pk: item.pk,
|
|
275
|
-
auto: item.auto,
|
|
276
|
-
note: item.note
|
|
277
|
-
}));
|
|
278
|
-
} catch (err) {
|
|
279
|
-
this.log('error', '获取字段信息失败', err);
|
|
280
|
-
return [];
|
|
239
|
+
const targetTable = table || this.table;
|
|
240
|
+
if (!targetTable) {
|
|
241
|
+
throw new TypeError('table must be specified');
|
|
281
242
|
}
|
|
243
|
+
var sql = 'PRAGMA table_info(`{0}`);'.replace('{0}', targetTable);
|
|
244
|
+
var list = await this.run(sql, [], timeout);
|
|
245
|
+
var len = list.length;
|
|
246
|
+
for (var i = 0; i < len; i++) {
|
|
247
|
+
list[i].pk = list[i].pk ? true : false;
|
|
248
|
+
list[i].not_null = list[i].not_null ? true : false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 如果指定了字段名,过滤结果
|
|
252
|
+
if (field_name) {
|
|
253
|
+
list = list.filter(field => field.name === field_name);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return list.map(item => ({
|
|
257
|
+
name: item.name,
|
|
258
|
+
cid: item.cid,
|
|
259
|
+
default_value: item.dflt_value,
|
|
260
|
+
not_null: item.notnull,
|
|
261
|
+
type: item.type,
|
|
262
|
+
pk: item.pk,
|
|
263
|
+
auto: item.auto,
|
|
264
|
+
note: item.note
|
|
265
|
+
}));
|
|
282
266
|
};
|
|
283
267
|
|
|
284
268
|
/**
|
|
@@ -424,42 +408,37 @@ DB.prototype.setType = function (field, type, value, not_null, auto) {
|
|
|
424
408
|
* @returns {Promise | number} 创建成功返回1,失败返回0
|
|
425
409
|
*/
|
|
426
410
|
DB.prototype.addTable = async function (table, field, type = 'int', auto = true, commit = '', timeout = 15000) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
return bl;
|
|
459
|
-
} catch (err) {
|
|
460
|
-
this.log('error', '创建表失败', err);
|
|
461
|
-
return 0;
|
|
462
|
-
}
|
|
411
|
+
if (!table || typeof table !== 'string') {
|
|
412
|
+
throw new TypeError('table must be non-empty string');
|
|
413
|
+
}
|
|
414
|
+
if (!field) {
|
|
415
|
+
field = 'id';
|
|
416
|
+
}
|
|
417
|
+
// SQLite的自增主键要求字段类型必须是INTEGER(大写且不带长度)
|
|
418
|
+
let fieldType;
|
|
419
|
+
if (auto) {
|
|
420
|
+
// 自增字段使用简单的INTEGER类型,由后面的PRIMARY KEY AUTOINCREMENT决定自增行为
|
|
421
|
+
fieldType = 'INTEGER';
|
|
422
|
+
} else {
|
|
423
|
+
// 非自增字段使用正常的类型设置
|
|
424
|
+
fieldType = this.setType(field, type, null, true, auto);
|
|
425
|
+
}
|
|
426
|
+
// 根据是否自增来构造不同的SQL语句
|
|
427
|
+
let sqlTemplate;
|
|
428
|
+
if (auto) {
|
|
429
|
+
// 自增字段:使用INTEGER PRIMARY KEY AUTOINCREMENT语法
|
|
430
|
+
sqlTemplate = 'CREATE TABLE IF NOT EXISTS `{0}` (`{1}` {2} PRIMARY KEY AUTOINCREMENT)';
|
|
431
|
+
} else {
|
|
432
|
+
// 非自增字段:使用正常的字段类型和主键定义
|
|
433
|
+
sqlTemplate = 'CREATE TABLE IF NOT EXISTS `{0}` (`{1}` {2} PRIMARY KEY)';
|
|
434
|
+
}
|
|
435
|
+
var sql = sqlTemplate.replace('{0}', table).replace(
|
|
436
|
+
'{1}', field).replace('{2}', fieldType) + ';';
|
|
437
|
+
// SQLite不支持表级COMMENT语法,所以忽略commit参数
|
|
438
|
+
var bl = await this.exec(sql, [], timeout);
|
|
439
|
+
// 设置实例的表名属性,以便后续操作使用
|
|
440
|
+
this.table = table;
|
|
441
|
+
return bl;
|
|
463
442
|
};
|
|
464
443
|
|
|
465
444
|
/**
|
|
@@ -488,36 +467,32 @@ DB.prototype.emptyTable = function (table, timeout = 15000) {
|
|
|
488
467
|
* @returns {Promise | number} 添加成功返回1,失败返回0
|
|
489
468
|
*/
|
|
490
469
|
DB.prototype.addField = async function (field, type, value = '', not_null = true, auto = false, comment = '', timeout = 15000) {
|
|
491
|
-
try {
|
|
492
|
-
// 确保表名已设置
|
|
493
|
-
if (!this.table || !field || !type) {
|
|
494
|
-
throw new TypeError('table, field, and type must be specified');
|
|
495
|
-
}
|
|
496
470
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
var fieldExists = false;
|
|
502
|
-
for (var i = 0; i < columns.length; i++) {
|
|
503
|
-
if (columns[i].name === field) {
|
|
504
|
-
fieldExists = true;
|
|
505
|
-
break;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
471
|
+
// 确保表名已设置
|
|
472
|
+
if (!this.table || !field || !type) {
|
|
473
|
+
throw new TypeError('table, field, and type must be specified');
|
|
474
|
+
}
|
|
508
475
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
476
|
+
// 在SQLite中,使用PRAGMA table_info检查表中是否已存在字段
|
|
477
|
+
var sql = 'PRAGMA table_info(`{0}`)';
|
|
478
|
+
sql = sql.replace('{0}', this.table);
|
|
479
|
+
var columns = await this.run(sql, [], timeout);
|
|
480
|
+
var fieldExists = false;
|
|
481
|
+
for (var i = 0; i < columns.length; i++) {
|
|
482
|
+
if (columns[i].name === field) {
|
|
483
|
+
fieldExists = true;
|
|
484
|
+
break;
|
|
515
485
|
}
|
|
516
|
-
return 0;
|
|
517
|
-
} catch (err) {
|
|
518
|
-
this.log('error', '添加字段失败', err);
|
|
519
|
-
return 0;
|
|
520
486
|
}
|
|
487
|
+
|
|
488
|
+
if (!fieldExists) {
|
|
489
|
+
var fieldType = this.setType(field, type, value, not_null, auto);
|
|
490
|
+
var sql = 'ALTER Table `{0}` ADD `{1}` {2}';
|
|
491
|
+
sql = sql.replace('{0}', this.table).replace('{1}', field).replace('{2}', fieldType) + ';';
|
|
492
|
+
// SQLite不支持字段级COMMENT语法,所以忽略comment参数
|
|
493
|
+
return await this.exec(sql, [], timeout);
|
|
494
|
+
}
|
|
495
|
+
return 0;
|
|
521
496
|
};
|
|
522
497
|
|
|
523
498
|
/**
|
|
@@ -533,53 +508,49 @@ DB.prototype.addField = async function (field, type, value = '', not_null = true
|
|
|
533
508
|
* @returns {Promise | number} 修改成功返回1,失败返回0
|
|
534
509
|
*/
|
|
535
510
|
DB.prototype.setField = async function (field, type, value = '', not_null = true, auto = false, isKey = false, new_name = '', timeout = 15000) {
|
|
536
|
-
try {
|
|
537
|
-
if (!field || !type || !this.table) {
|
|
538
|
-
throw new TypeError('field, type, and table must be specified');
|
|
539
|
-
}
|
|
540
511
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
var arr = await this.run(sql, [], timeout);
|
|
545
|
-
if (arr && arr.length > 0) {
|
|
546
|
-
if (arr[0].count == 0) {
|
|
547
|
-
return 0;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
512
|
+
if (!field || !type || !this.table) {
|
|
513
|
+
throw new TypeError('field, type, and table must be specified');
|
|
514
|
+
}
|
|
550
515
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
516
|
+
var sql =
|
|
517
|
+
"select count(*) as `count` from sqlite_master where `type` = 'table' and `name` = '{1}' and `sql` like '%{2}%'";
|
|
518
|
+
sql = sql.replace('{1}', this.table).replace('{2}', field);
|
|
519
|
+
var arr = await this.run(sql, [], timeout);
|
|
520
|
+
if (arr && arr.length > 0) {
|
|
521
|
+
if (arr[0].count == 0) {
|
|
522
|
+
return 0;
|
|
554
523
|
}
|
|
524
|
+
}
|
|
555
525
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
526
|
+
var field_type = this.setType(field, type, value, not_null, auto);
|
|
527
|
+
if (field_type.has('text')) {
|
|
528
|
+
field_type = field_type.replace('NOT NULL', '').replace("DEFAULT ''", '');
|
|
529
|
+
}
|
|
559
530
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
sql += ', DROP PRIMARY KEY, ADD PRIMARY KEY (' + new_name + ') USING BTREE;';
|
|
564
|
-
} else {
|
|
565
|
-
sql += ';';
|
|
566
|
-
}
|
|
567
|
-
await this.exec(sql, [], timeout);
|
|
531
|
+
if (!new_name) {
|
|
532
|
+
new_name = field;
|
|
533
|
+
}
|
|
568
534
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
535
|
+
sql = 'ALTER TABLE `{0}` ADD COLUMN `{2}` {3}';
|
|
536
|
+
sql = sql.replace('{0}', this.table).replace('{2}', new_name).replace('{3}', field_type);
|
|
537
|
+
if (isKey) {
|
|
538
|
+
sql += ', DROP PRIMARY KEY, ADD PRIMARY KEY (' + new_name + ') USING BTREE;';
|
|
539
|
+
} else {
|
|
540
|
+
sql += ';';
|
|
541
|
+
}
|
|
542
|
+
await this.exec(sql, [], timeout);
|
|
572
543
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
this.
|
|
581
|
-
return 0;
|
|
544
|
+
sql = 'UPDATE TABLE `{0}` SET `{2}` = `{1}`;';
|
|
545
|
+
sql = sql.replace('{0}', this.table).replace('{1}', field).replace('{2}', new_name);
|
|
546
|
+
var ret = await this.exec(sql, [], timeout);
|
|
547
|
+
|
|
548
|
+
if (field !== new_name) {
|
|
549
|
+
// sql = "ALTER TABLE `{0}` DROP COLUMN `{1}`;";
|
|
550
|
+
// sql = sql.replace('{0}', this.table).replace('{1}', field);
|
|
551
|
+
// ret = await this.exec(sql);
|
|
582
552
|
}
|
|
553
|
+
return ret;
|
|
583
554
|
};
|
|
584
555
|
|
|
585
556
|
/**
|
|
@@ -590,18 +561,13 @@ DB.prototype.setField = async function (field, type, value = '', not_null = true
|
|
|
590
561
|
* @returns {Promise | number} 删除成功返回1,失败返回0
|
|
591
562
|
*/
|
|
592
563
|
DB.prototype.delField = async function (table, field, timeout = 15000) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
throw new TypeError('table and field must be specified');
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
var sql = 'ALTER TABLE {0} DROP COLUMN {1};';
|
|
599
|
-
sql = sql.replace('{0}', table).replace('{1}', field);
|
|
600
|
-
return await this.exec(sql, [], timeout);
|
|
601
|
-
} catch (err) {
|
|
602
|
-
this.log('error', '删除字段失败', err);
|
|
603
|
-
return 0;
|
|
564
|
+
if (!table || !field) {
|
|
565
|
+
throw new TypeError('table and field must be specified');
|
|
604
566
|
}
|
|
567
|
+
|
|
568
|
+
var sql = 'ALTER TABLE {0} DROP COLUMN {1};';
|
|
569
|
+
sql = sql.replace('{0}', table).replace('{1}', field);
|
|
570
|
+
return await this.exec(sql, [], timeout);
|
|
605
571
|
};
|
|
606
572
|
|
|
607
573
|
/**
|
|
@@ -650,18 +616,13 @@ DB.prototype.sqlField = function (fd) {
|
|
|
650
616
|
* @returns {Promise | number} 重命名成功返回1,失败返回0
|
|
651
617
|
*/
|
|
652
618
|
DB.prototype.renameField = async function (table, field, new_field, type, timeout = 15000) {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
throw new TypeError('table, field, and new_field must be specified');
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
var sql = 'ALTER TABLE {0} RENAME COLUMN {1} TO {2};';
|
|
659
|
-
sql = sql.replace('{0}', table).replace('{1}', field).replace('{2}', new_field);
|
|
660
|
-
return await this.exec(sql, [], timeout);
|
|
661
|
-
} catch (err) {
|
|
662
|
-
this.log('error', '重命名字段失败', err);
|
|
663
|
-
return 0;
|
|
619
|
+
if (!table || !field || !new_field) {
|
|
620
|
+
throw new TypeError('table, field, and new_field must be specified');
|
|
664
621
|
}
|
|
622
|
+
|
|
623
|
+
var sql = 'ALTER TABLE {0} RENAME COLUMN {1} TO {2};';
|
|
624
|
+
sql = sql.replace('{0}', table).replace('{1}', field).replace('{2}', new_field);
|
|
625
|
+
return await this.exec(sql, [], timeout);
|
|
665
626
|
};
|
|
666
627
|
|
|
667
628
|
/**
|
|
@@ -731,16 +692,11 @@ DB.prototype.emptyTable = function (table, timeout = 15000) {
|
|
|
731
692
|
* @returns {Promise | boolean} 存在返回true,不存在返回false
|
|
732
693
|
*/
|
|
733
694
|
DB.prototype.hasTable = async function (table, timeout = 15000) {
|
|
734
|
-
|
|
735
|
-
if (!table) {
|
|
736
|
-
return false;
|
|
737
|
-
}
|
|
738
|
-
var list = await this.run("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", [table], timeout);
|
|
739
|
-
return list && list.length > 0;
|
|
740
|
-
} catch (err) {
|
|
741
|
-
this.log('error', '检查表是否存在失败', err);
|
|
695
|
+
if (!table) {
|
|
742
696
|
return false;
|
|
743
697
|
}
|
|
698
|
+
var list = await this.run("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", [table], timeout);
|
|
699
|
+
return list && list.length > 0;
|
|
744
700
|
};
|
|
745
701
|
|
|
746
702
|
/**
|
|
@@ -751,16 +707,11 @@ DB.prototype.hasTable = async function (table, timeout = 15000) {
|
|
|
751
707
|
* @returns {Promise | boolean} 存在返回true,不存在返回false
|
|
752
708
|
*/
|
|
753
709
|
DB.prototype.hasField = async function (table, field, timeout = 15000) {
|
|
754
|
-
|
|
755
|
-
if (!table || !field) {
|
|
756
|
-
return false;
|
|
757
|
-
}
|
|
758
|
-
var fields = await this.fields(table, field, timeout);
|
|
759
|
-
return fields && fields.some(f => f.name === field);
|
|
760
|
-
} catch (err) {
|
|
761
|
-
this.log('error', '检查字段是否存在失败', err);
|
|
710
|
+
if (!table || !field) {
|
|
762
711
|
return false;
|
|
763
712
|
}
|
|
713
|
+
var fields = await this.fields(table, field, timeout);
|
|
714
|
+
return fields && fields.some(f => f.name === field);
|
|
764
715
|
};
|
|
765
716
|
|
|
766
717
|
/**
|
|
@@ -788,16 +739,11 @@ DB.prototype.getCreateTable = async function (table, timeout = 15000) {
|
|
|
788
739
|
if (!table) {
|
|
789
740
|
throw new TypeError('table must be specified');
|
|
790
741
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
return list[0].sql || '';
|
|
795
|
-
}
|
|
796
|
-
return '';
|
|
797
|
-
} catch (err) {
|
|
798
|
-
this.log('error', '获取表结构失败', err);
|
|
799
|
-
return '';
|
|
742
|
+
const list = await this.run("SELECT sql FROM sqlite_master WHERE type='table' AND name=?;", [table], timeout);
|
|
743
|
+
if (list && list.length > 0) {
|
|
744
|
+
return list[0].sql || '';
|
|
800
745
|
}
|
|
746
|
+
return '';
|
|
801
747
|
};
|
|
802
748
|
|
|
803
749
|
/**
|
|
@@ -811,51 +757,46 @@ DB.prototype.getTableData = async function (table, batch_size = 100, timeout = 6
|
|
|
811
757
|
if (!table) {
|
|
812
758
|
throw new TypeError('table must be specified');
|
|
813
759
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
this.log('error', '处理行数据失败', rowErr);
|
|
849
|
-
}
|
|
760
|
+
// 获取表数据
|
|
761
|
+
const rows = await this.run(`SELECT * FROM \`${table}\``, [], timeout);
|
|
762
|
+
let sql = '';
|
|
763
|
+
|
|
764
|
+
if (rows && rows.length > 0) {
|
|
765
|
+
sql += `-- 表数据: ${table}\n`;
|
|
766
|
+
|
|
767
|
+
// 批量处理大数据量
|
|
768
|
+
for (let j = 0; j < rows.length; j += batch_size) {
|
|
769
|
+
const batch = rows.slice(j, j + batch_size);
|
|
770
|
+
for (const row of batch) {
|
|
771
|
+
try {
|
|
772
|
+
const row_data = Object.values(row)
|
|
773
|
+
.map(value => {
|
|
774
|
+
if (value === null) return 'NULL';
|
|
775
|
+
if (typeof value === 'boolean') return value ? 1 : 0;
|
|
776
|
+
if (typeof value === 'number') return value;
|
|
777
|
+
if (value instanceof Date) {
|
|
778
|
+
return "'" + value.toISOString().slice(0, 19).replace('T', ' ') + "'";
|
|
779
|
+
}
|
|
780
|
+
// 处理字符串,转义特殊字符
|
|
781
|
+
if (typeof value === 'string') {
|
|
782
|
+
return "'" + value
|
|
783
|
+
.replace(/[\\']/g, '\\$&')
|
|
784
|
+
.replace(/\n/g, '\\n')
|
|
785
|
+
.replace(/\r/g, '\\r')
|
|
786
|
+
.replace(/\t/g, '\\t')
|
|
787
|
+
.replace(/\u0000/g, '\\0') + "'";
|
|
788
|
+
}
|
|
789
|
+
return "'" + String(value || '') + "'";
|
|
790
|
+
}).join(',');
|
|
791
|
+
sql += `INSERT INTO \`${table}\` VALUES (${row_data});\n`;
|
|
792
|
+
} catch (rowErr) {
|
|
793
|
+
this.log('error', '处理行数据失败', rowErr);
|
|
850
794
|
}
|
|
851
795
|
}
|
|
852
|
-
sql += '\n';
|
|
853
796
|
}
|
|
854
|
-
|
|
855
|
-
} catch (err) {
|
|
856
|
-
this.log('error', '获取表数据失败', err);
|
|
857
|
-
return '';
|
|
797
|
+
sql += '\n';
|
|
858
798
|
}
|
|
799
|
+
return sql;
|
|
859
800
|
};
|
|
860
801
|
|
|
861
802
|
/**
|
|
@@ -866,15 +807,10 @@ DB.prototype.getTableData = async function (table, batch_size = 100, timeout = 6
|
|
|
866
807
|
* @returns {Promise | number} 操作结果
|
|
867
808
|
*/
|
|
868
809
|
DB.prototype.backup = function (table, backup, timeout = 60000) {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
throw new TypeError('table and backup must be specified');
|
|
872
|
-
}
|
|
873
|
-
return this.backupTable(table, backup, timeout);
|
|
874
|
-
} catch (err) {
|
|
875
|
-
this.log('error', '备份表失败', err);
|
|
876
|
-
return 0;
|
|
810
|
+
if (!table || !backup) {
|
|
811
|
+
throw new TypeError('table and backup must be specified');
|
|
877
812
|
}
|
|
813
|
+
return this.backupTable(table, backup, timeout);
|
|
878
814
|
};
|
|
879
815
|
|
|
880
816
|
/**
|