mm_sqlite 1.4.8 → 1.4.9
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/index.js +28 -100
- package/package.json +6 -6
- package/pool.js +31 -38
- package/sql.js +16 -2
- package/test_db/test_basic.db +0 -0
- package/test_db/test_core_methods.db +0 -0
package/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const sqlite3 = require('sqlite3').verbose();
|
|
2
1
|
const {
|
|
3
2
|
DB
|
|
4
3
|
} = require('./db');
|
|
@@ -184,40 +183,19 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
|
|
|
184
183
|
try {
|
|
185
184
|
// 获取连接
|
|
186
185
|
conn = await this.getConn(query_timeout);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
timeout_id = setTimeout(() => {
|
|
192
|
-
reject(new Error(`SQL查询超时: ${timeout}ms`));
|
|
193
|
-
}, timeout);
|
|
194
|
-
|
|
195
|
-
// 执行SQL查询
|
|
196
|
-
conn.all(sql, params || [], (error, rows) => {
|
|
197
|
-
// 清除超时定时器
|
|
198
|
-
if (timeout_id) {
|
|
199
|
-
clearTimeout(timeout_id);
|
|
200
|
-
timeout_id = null;
|
|
201
|
-
}
|
|
202
|
-
if (error) {
|
|
203
|
-
reject(error);
|
|
204
|
-
resolve([]);
|
|
205
|
-
} else {
|
|
206
|
-
// 保持与MySQL兼容的返回值格式,始终返回数组
|
|
207
|
-
resolve(rows);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
});
|
|
186
|
+
|
|
187
|
+
// better-sqlite3 同步查询,无需 Promise 包装
|
|
188
|
+
const stmt = conn.prepare(sql);
|
|
189
|
+
ret = params.length > 0 ? stmt.all(params) : stmt.all();
|
|
211
190
|
} catch (error) {
|
|
212
191
|
console.error('SQL执行失败', error);
|
|
213
192
|
this.sql = sql;
|
|
214
193
|
this.error = {
|
|
215
|
-
code: error.errno,
|
|
194
|
+
code: error.code || error.errno,
|
|
216
195
|
message: error.message
|
|
217
196
|
};
|
|
218
197
|
ret = [];
|
|
219
|
-
}
|
|
220
|
-
finally {
|
|
198
|
+
} finally {
|
|
221
199
|
await releaseConn(conn);
|
|
222
200
|
}
|
|
223
201
|
return ret;
|
|
@@ -252,40 +230,28 @@ SQLite.prototype.exec = async function (sql, params, timeout) {
|
|
|
252
230
|
// 获取连接
|
|
253
231
|
conn = await this.getConn(timeout);
|
|
254
232
|
this.sql = sql;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
conn.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
timeout_id = null;
|
|
269
|
-
}
|
|
270
|
-
if (error) {
|
|
271
|
-
reject(error);
|
|
272
|
-
} else {
|
|
273
|
-
resolve(this.lastID || this.changes || 1);
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
});
|
|
233
|
+
|
|
234
|
+
const trimmed = sql.trim().toUpperCase().replace(/;+$/, '');
|
|
235
|
+
let info;
|
|
236
|
+
// 事务命令不能作为预编译语句,需用 exec() 直接执行
|
|
237
|
+
if (trimmed === 'BEGIN' || trimmed === 'BEGIN TRANSACTION' ||
|
|
238
|
+
trimmed === 'COMMIT' || trimmed === 'ROLLBACK') {
|
|
239
|
+
conn.exec(sql);
|
|
240
|
+
info = { changes: 0, lastInsertRowid: 0 };
|
|
241
|
+
} else {
|
|
242
|
+
const stmt = conn.prepare(sql);
|
|
243
|
+
info = params && params.length > 0 ? stmt.run(params) : stmt.run();
|
|
244
|
+
}
|
|
245
|
+
ret = info.lastInsertRowid || info.changes || 1;
|
|
277
246
|
} catch (error) {
|
|
278
247
|
console.error('SQL执行失败', error);
|
|
279
248
|
this.sql = sql;
|
|
280
249
|
this.error = {
|
|
281
|
-
code: error.errno,
|
|
250
|
+
code: error.code || error.errno,
|
|
282
251
|
message: error.message
|
|
283
252
|
};
|
|
284
|
-
// 简化错误处理:SQLite不需要复杂的连接错误处理
|
|
285
|
-
// 返回0,保持与MySQL一致的错误处理行为
|
|
286
253
|
ret = 0;
|
|
287
|
-
}
|
|
288
|
-
finally {
|
|
254
|
+
} finally {
|
|
289
255
|
await releaseConn(conn);
|
|
290
256
|
}
|
|
291
257
|
return ret;
|
|
@@ -417,18 +383,8 @@ SQLite.prototype.beginTransaction = async function () {
|
|
|
417
383
|
// 标记连接为事务中
|
|
418
384
|
conn._in_transaction = true;
|
|
419
385
|
|
|
420
|
-
//
|
|
421
|
-
|
|
422
|
-
conn.run('BEGIN TRANSACTION', (error) => {
|
|
423
|
-
if (error) {
|
|
424
|
-
// 事务开始失败,清除事务标记
|
|
425
|
-
conn._in_transaction = false;
|
|
426
|
-
reject(error);
|
|
427
|
-
} else {
|
|
428
|
-
resolve();
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
});
|
|
386
|
+
// 开始事务(better-sqlite3 同步执行)
|
|
387
|
+
conn.exec('BEGIN TRANSACTION');
|
|
432
388
|
|
|
433
389
|
if (this.config.debug) {
|
|
434
390
|
this.log('debug', '事务开始');
|
|
@@ -438,15 +394,7 @@ SQLite.prototype.beginTransaction = async function () {
|
|
|
438
394
|
return {
|
|
439
395
|
conn,
|
|
440
396
|
commit: async () => {
|
|
441
|
-
|
|
442
|
-
conn.run('COMMIT', (error) => {
|
|
443
|
-
if (error) {
|
|
444
|
-
reject(error);
|
|
445
|
-
} else {
|
|
446
|
-
resolve();
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
});
|
|
397
|
+
conn.exec('COMMIT');
|
|
450
398
|
if (this.config.debug) {
|
|
451
399
|
this.log('debug', '事务提交');
|
|
452
400
|
}
|
|
@@ -456,15 +404,7 @@ SQLite.prototype.beginTransaction = async function () {
|
|
|
456
404
|
await releaseConn(conn);
|
|
457
405
|
},
|
|
458
406
|
rollback: async () => {
|
|
459
|
-
|
|
460
|
-
conn.run('ROLLBACK', (error) => {
|
|
461
|
-
if (error) {
|
|
462
|
-
reject(error);
|
|
463
|
-
} else {
|
|
464
|
-
resolve();
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
});
|
|
407
|
+
conn.exec('ROLLBACK');
|
|
468
408
|
if (this.config.debug) {
|
|
469
409
|
this.log('debug', '事务回滚');
|
|
470
410
|
}
|
|
@@ -474,21 +414,9 @@ SQLite.prototype.beginTransaction = async function () {
|
|
|
474
414
|
},
|
|
475
415
|
exec: async (sql, params) => {
|
|
476
416
|
// 在事务中执行SQL
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
this.sql = error.sql;
|
|
481
|
-
this.error = {
|
|
482
|
-
code: error.errno,
|
|
483
|
-
message: error.message
|
|
484
|
-
};
|
|
485
|
-
reject(error);
|
|
486
|
-
resolve(0);
|
|
487
|
-
} else {
|
|
488
|
-
resolve(this.lastID || this.changes || 1);
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
});
|
|
417
|
+
const stmt = conn.prepare(sql);
|
|
418
|
+
const info = params && params.length > 0 ? stmt.run(params) : stmt.run();
|
|
419
|
+
return info.lastInsertRowid || info.changes || 1;
|
|
492
420
|
}
|
|
493
421
|
};
|
|
494
422
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_sqlite",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.9",
|
|
4
4
|
"description": "高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口,支持异步操作、事务处理和批量操作",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"node": ">=14.0.0"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"
|
|
42
|
-
"
|
|
41
|
+
"better-sqlite3": "^13.0.2",
|
|
42
|
+
"mm_expand": "^2.4.5",
|
|
43
43
|
"sqlstring": "^2.3.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"eslint": "^10.
|
|
47
|
-
"eslint-plugin-jsdoc": "^63.
|
|
46
|
+
"eslint": "^10.8.0",
|
|
47
|
+
"eslint-plugin-jsdoc": "^63.3.2",
|
|
48
48
|
"mm_eslint": "^1.7.5"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|
package/pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const Database = require('better-sqlite3');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* SQLite连接池类
|
|
@@ -33,9 +33,9 @@ class SQLitePool {
|
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// 创建最小连接数(better-sqlite3是同步的,无需await)
|
|
37
37
|
for (let i = 0; i < this.config.pool_min; i++) {
|
|
38
|
-
const conn =
|
|
38
|
+
const conn = this._createConnection();
|
|
39
39
|
this._pool_connections.push(conn);
|
|
40
40
|
this._pool_available.push(conn);
|
|
41
41
|
}
|
|
@@ -86,18 +86,16 @@ class SQLitePool {
|
|
|
86
86
|
|
|
87
87
|
// 检查是否可以创建新连接
|
|
88
88
|
if (this._pool_connections.length < this.config.pool_max) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
reject(err);
|
|
100
|
-
});
|
|
89
|
+
try {
|
|
90
|
+
const conn = this._createConnection();
|
|
91
|
+
this._pool_connections.push(conn);
|
|
92
|
+
conn._last_used = Date.now();
|
|
93
|
+
cleanup();
|
|
94
|
+
resolve(conn);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
cleanup();
|
|
97
|
+
reject(err);
|
|
98
|
+
}
|
|
101
99
|
return;
|
|
102
100
|
}
|
|
103
101
|
|
|
@@ -159,14 +157,10 @@ class SQLitePool {
|
|
|
159
157
|
this._pool_reaper = null;
|
|
160
158
|
}
|
|
161
159
|
|
|
162
|
-
//
|
|
160
|
+
// 关闭所有连接(better-sqlite3的close是同步的)
|
|
163
161
|
this._pool_connections.forEach(conn => {
|
|
164
162
|
try {
|
|
165
|
-
conn.close(
|
|
166
|
-
if (err) {
|
|
167
|
-
this.log('error', '关闭连接池连接失败', err);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
163
|
+
conn.close();
|
|
170
164
|
} catch (error) {
|
|
171
165
|
this.log('error', '关闭连接池连接异常', error);
|
|
172
166
|
}
|
|
@@ -192,21 +186,20 @@ class SQLitePool {
|
|
|
192
186
|
}
|
|
193
187
|
|
|
194
188
|
/**
|
|
195
|
-
* 创建SQLite
|
|
189
|
+
* 创建SQLite连接(better-sqlite3,同步创建)
|
|
196
190
|
* @private
|
|
197
|
-
* @returns {
|
|
191
|
+
* @returns {object} 数据库连接对象
|
|
198
192
|
*/
|
|
199
193
|
_createConnection() {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (err) {
|
|
203
|
-
reject(err);
|
|
204
|
-
} else {
|
|
205
|
-
db.release = () => this.releaseConn(db);
|
|
206
|
-
resolve(db);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
194
|
+
const db = new Database(this._getDbFilename(), {
|
|
195
|
+
timeout: this.config.connect_timeout || 5000
|
|
209
196
|
});
|
|
197
|
+
// 启用WAL模式,提升并发读取性能
|
|
198
|
+
db.pragma('journal_mode = WAL');
|
|
199
|
+
// 添加release方法,兼容原有API
|
|
200
|
+
db.release = () => this.releaseConn(db);
|
|
201
|
+
db._last_used = Date.now();
|
|
202
|
+
return db;
|
|
210
203
|
}
|
|
211
204
|
|
|
212
205
|
/**
|
|
@@ -221,11 +214,11 @@ class SQLitePool {
|
|
|
221
214
|
const conn = this._pool_available[i];
|
|
222
215
|
if (conn._last_used && now - conn._last_used > idle_timeout) {
|
|
223
216
|
// 关闭并移除空闲连接
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
217
|
+
try {
|
|
218
|
+
conn.close();
|
|
219
|
+
} catch (error) {
|
|
220
|
+
this.log('error', '关闭空闲连接失败', error);
|
|
221
|
+
}
|
|
229
222
|
|
|
230
223
|
// 从连接池中移除
|
|
231
224
|
const conn_idx = this._pool_connections.indexOf(conn);
|
|
@@ -238,4 +231,4 @@ class SQLitePool {
|
|
|
238
231
|
}
|
|
239
232
|
}
|
|
240
233
|
|
|
241
|
-
module.exports = SQLitePool;
|
|
234
|
+
module.exports = SQLitePool;
|
package/sql.js
CHANGED
|
@@ -7,6 +7,10 @@ const SqlString = require('sqlstring');
|
|
|
7
7
|
const { Base } = require('mm_expand');
|
|
8
8
|
|
|
9
9
|
function escape(value, stringifyObjects, timeZone) {
|
|
10
|
+
if (typeof value === 'string') {
|
|
11
|
+
// SQLite使用双单引号('')转义,不使用反斜杠转义
|
|
12
|
+
return "'" + value.replace(/'/g, "''") + "'";
|
|
13
|
+
}
|
|
10
14
|
return SqlString.escape(value, stringifyObjects, timeZone);
|
|
11
15
|
}
|
|
12
16
|
|
|
@@ -705,6 +709,11 @@ Sql.prototype.toWhere = function (obj, like) {
|
|
|
705
709
|
if (like) {
|
|
706
710
|
for (var k in obj) {
|
|
707
711
|
var val = obj[k];
|
|
712
|
+
if (Array.isArray(val)) {
|
|
713
|
+
var vals = val.map(function(o) { return escape(o); });
|
|
714
|
+
where += ' and ' + escapeId(k) + ' in (' + vals.join(', ') + ')';
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
708
717
|
val = escape(val);
|
|
709
718
|
if (k.endsWith('_min')) {
|
|
710
719
|
where += ' and ' + escapeId(k.replace('_min', '')) + ' >= ' + val;
|
|
@@ -713,7 +722,7 @@ Sql.prototype.toWhere = function (obj, like) {
|
|
|
713
722
|
} else if (k.endsWith('_not')) {
|
|
714
723
|
where += ' and ' + escapeId(k.replace('_not', '')) + ' != ' + val;
|
|
715
724
|
} else if (k.endsWith('_has')) {
|
|
716
|
-
var vals = val.trim("'").split(',').map((o)
|
|
725
|
+
var vals = val.trim("'").split(',').map(function(o) {
|
|
717
726
|
return escape(o);
|
|
718
727
|
});
|
|
719
728
|
where += ' and ' + escapeId(k.replace('_has', '')) + ' in (' + vals.join(',') + ')';
|
|
@@ -728,6 +737,11 @@ Sql.prototype.toWhere = function (obj, like) {
|
|
|
728
737
|
} else {
|
|
729
738
|
for (var k in obj) {
|
|
730
739
|
var val = obj[k];
|
|
740
|
+
if (Array.isArray(val)) {
|
|
741
|
+
var vals = val.map(function(o) { return escape(o); });
|
|
742
|
+
where += ' and ' + escapeId(k) + ' in (' + vals.join(', ') + ')';
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
731
745
|
val = escape(val);
|
|
732
746
|
if (k.endsWith('_min')) {
|
|
733
747
|
where += ' and ' + escapeId(k.replace('_min', '')) + ' >= ' + val;
|
|
@@ -736,7 +750,7 @@ Sql.prototype.toWhere = function (obj, like) {
|
|
|
736
750
|
} else if (k.endsWith('_not')) {
|
|
737
751
|
where += ' and ' + escapeId(k.replace('_not', '')) + ' != ' + val;
|
|
738
752
|
} else if (k.endsWith('_has')) {
|
|
739
|
-
var vals = val.trim("'").split(',').map((o)
|
|
753
|
+
var vals = val.trim("'").split(',').map(function(o) {
|
|
740
754
|
return escape(o);
|
|
741
755
|
});
|
|
742
756
|
where += ' and ' + escapeId(k.replace('_has', '')) + ' in (' + vals.join(',') + ')';
|
package/test_db/test_basic.db
CHANGED
|
Binary file
|
|
Binary file
|