mm_sqlite 1.5.7 → 1.6.0
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 +7 -7
- package/lib/query_error.js +22 -0
- package/lib/sqlite.js +7 -4
- package/lib/tools/index.js +16 -0
- package/lib/tools/sqlite/index.js +125 -0
- package/package.json +57 -56
- package/tool/sqlite/index.js +7 -0
- package/tool/sqlite/tool.json +82 -0
- 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/index.js
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
* @description 参考 mm_redis 结构,index.js 为薄包装,类定义在 lib/sqlite.js
|
|
4
4
|
*/
|
|
5
5
|
const SQLite = require('./lib/sqlite');
|
|
6
|
-
const
|
|
6
|
+
const { reg } = require('mm_admin');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* SQLite 管理器实例(Admin 工厂)
|
|
10
10
|
* 支持 os.js 调用:require('mm_sqlite').admin.setServer(os) -> admin.get('os', config)
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
const admin = reg('mm_sqlite');
|
|
13
13
|
admin.setClass(SQLite);
|
|
14
14
|
|
|
15
15
|
module.exports = {
|
|
16
16
|
SQLite,
|
|
17
17
|
admin,
|
|
18
18
|
sqliteAdmin(scope, config) {
|
|
19
|
-
|
|
20
|
-
scope = 'os';
|
|
21
|
-
}
|
|
22
|
-
return admin.get(scope, config);
|
|
19
|
+
return admin.get(scope || 'os', config);
|
|
23
20
|
}
|
|
24
|
-
};
|
|
21
|
+
};
|
|
22
|
+
/* mm-tool-logic-export 工具能力层:其它模块可 require("<pkg>").tools.<name> 直接引用 */
|
|
23
|
+
Object.defineProperty(module.exports, 'tools', { enumerable: true, configurable: true,
|
|
24
|
+
get: function () { return require('./lib/tools'); } });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 构造带上下文的数据层错误
|
|
5
|
+
*
|
|
6
|
+
* 独立函数而非实例方法:DB 包装层以 `super(sqlite.run, sqlite.exec)` 传递未绑定的方法引用,
|
|
7
|
+
* 调用时 this 指向 DB 实例而不是 SQLite 实例,任何 this.xxx 辅助方法都会失效。
|
|
8
|
+
* 用模块级函数可同时覆盖「SQLite 直接被调用」与「经 DB 包装调用」两条路径。
|
|
9
|
+
*
|
|
10
|
+
* @param {Error} cause 驱动抛出的原始异常
|
|
11
|
+
* @param {string} sql 出错的 SQL
|
|
12
|
+
* @param {Array} params 绑定参数
|
|
13
|
+
* @returns {Error} 携带 code / sql / params / cause 的错误对象
|
|
14
|
+
*/
|
|
15
|
+
module.exports = function makeQueryError(cause, sql, params) {
|
|
16
|
+
const error = new Error(`SQL执行失败: ${cause.message || cause}`);
|
|
17
|
+
error.code = cause.code || cause.errno;
|
|
18
|
+
error.sql = sql;
|
|
19
|
+
error.params = params;
|
|
20
|
+
error.cause = cause;
|
|
21
|
+
return error;
|
|
22
|
+
};
|
package/lib/sqlite.js
CHANGED
|
@@ -4,6 +4,7 @@ const {
|
|
|
4
4
|
const { Base } = require('mm_mod');
|
|
5
5
|
const { fullname, addDir } = require('mm_helper');
|
|
6
6
|
const SQLitePool = require('./pool');
|
|
7
|
+
const makeQueryError = require('./query_error');
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -189,13 +190,15 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
|
|
|
189
190
|
const stmt = conn.prepare(sql);
|
|
190
191
|
ret = params.length > 0 ? stmt.all(...params) : stmt.all();
|
|
191
192
|
} catch (error) {
|
|
192
|
-
|
|
193
|
+
// D-12:查询失败必须与「查到 0 条」区分。历史实现把异常吞成 [],
|
|
194
|
+
// 上层拿到空结果继续跑,最终以 TypeError / 空页面呈现,根因彻底丢失。
|
|
195
|
+
// 这里补齐上下文后抛出,由调用方决定降级或失败;同时不再直接 console.error(D-15)
|
|
193
196
|
this.sql = sql;
|
|
194
197
|
this.error = {
|
|
195
198
|
code: error.code || error.errno,
|
|
196
199
|
message: error.message
|
|
197
200
|
};
|
|
198
|
-
|
|
201
|
+
throw makeQueryError(error, sql, params);
|
|
199
202
|
} finally {
|
|
200
203
|
await releaseConn(conn);
|
|
201
204
|
}
|
|
@@ -250,13 +253,13 @@ SQLite.prototype.exec = async function (sql, params = [], timeout) {
|
|
|
250
253
|
}
|
|
251
254
|
ret = info.lastInsertRowid || info.changes || 1;
|
|
252
255
|
} catch (error) {
|
|
253
|
-
|
|
256
|
+
// 写操作失败同样不能伪装成「影响 0 行」:上层会把「没更新」当成正常结果
|
|
254
257
|
this.sql = sql;
|
|
255
258
|
this.error = {
|
|
256
259
|
code: error.code || error.errno,
|
|
257
260
|
message: error.message
|
|
258
261
|
};
|
|
259
|
-
|
|
262
|
+
throw makeQueryError(error, sql, params);
|
|
260
263
|
} finally {
|
|
261
264
|
await releaseConn(conn);
|
|
262
265
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
/** 模块能力层:懒加载工具实现,避免模块入口被 require 时加载全部实现 */
|
|
5
|
+
module.exports = new Proxy({}, {
|
|
6
|
+
get(_t, key) {
|
|
7
|
+
if (typeof key !== 'string') return undefined;
|
|
8
|
+
if (!fs.existsSync(path.join(__dirname, key, 'index.js'))) return undefined;
|
|
9
|
+
return require('./' + key);
|
|
10
|
+
},
|
|
11
|
+
has(_t, key) {
|
|
12
|
+
return typeof key === 'string' && fs.existsSync(path.join(__dirname, key, 'index.js'));
|
|
13
|
+
},
|
|
14
|
+
ownKeys() { return fs.readdirSync(__dirname, { withFileTypes: true }).filter(e => e.isDirectory()).map(e => e.name); },
|
|
15
|
+
getOwnPropertyDescriptor(_t, key) { return this.has(_t, key) ? { enumerable: true, configurable: true } : undefined; }
|
|
16
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite管理器
|
|
3
|
+
* 管理 SQLite 连接和操作(基于 mm_sqlite 连接池)
|
|
4
|
+
* SQL 方法: query/execute, ORM 方法: add/del/set/list/getObj/count
|
|
5
|
+
*/
|
|
6
|
+
async function main(params, ctx, options) {
|
|
7
|
+
const { sqliteAdmin } = require('mm_sqlite');
|
|
8
|
+
var action = params.action || '';
|
|
9
|
+
var table = params.table || '';
|
|
10
|
+
var sql = params.sql || '';
|
|
11
|
+
var sql_params = params.params || [];
|
|
12
|
+
var query = params.query || {};
|
|
13
|
+
var body = params.body || {};
|
|
14
|
+
|
|
15
|
+
var opts = this.getOptions();
|
|
16
|
+
|
|
17
|
+
let config = { ...opts };
|
|
18
|
+
|
|
19
|
+
var sqlite = sqliteAdmin('os', config);
|
|
20
|
+
await sqlite.open();
|
|
21
|
+
|
|
22
|
+
ctx.output = await dispatch(sqlite, action, table, sql, sql_params, query, body);
|
|
23
|
+
return ctx.output;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 分发 action 到对应的处理方法
|
|
28
|
+
*/
|
|
29
|
+
async function dispatch(sqlite, action, table, sql, sql_params, query, body) {
|
|
30
|
+
const SQL_METHODS = ['query', 'run', 'execute', 'exec', 'insert', 'update', 'delete'];
|
|
31
|
+
const ORM_METHODS = ['add', 'del', 'set', 'list', 'getObj', 'count'];
|
|
32
|
+
|
|
33
|
+
if (SQL_METHODS.indexOf(action) !== -1) {
|
|
34
|
+
return handleSql(sqlite, action, sql, sql_params);
|
|
35
|
+
}
|
|
36
|
+
if (ORM_METHODS.indexOf(action) !== -1) {
|
|
37
|
+
return handleOrm(sqlite, action, table, query, body);
|
|
38
|
+
}
|
|
39
|
+
if (action === 'runSql') {
|
|
40
|
+
return handleRunSql(sqlite, sql);
|
|
41
|
+
}
|
|
42
|
+
return { error: { code: 'MGR_UNKNOWN_ACTION', message: '不支持的操作: ' + action } };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 执行多语句 SQL 脚本(支持分号分隔的建表/插入语句)
|
|
47
|
+
* @param {object} sqlite 数据库实例
|
|
48
|
+
* @param {string} sql SQL 脚本内容
|
|
49
|
+
* @returns {object} { success, statements, affected_rows }
|
|
50
|
+
*/
|
|
51
|
+
async function handleRunSql(sqlite, sql) {
|
|
52
|
+
if (!sql) {
|
|
53
|
+
return _errorResult('MGR_SQL_EMPTY', 'SQL 语句不能为空');
|
|
54
|
+
}
|
|
55
|
+
var result = await sqlite.runSql(sql);
|
|
56
|
+
if (sqlite.error) {
|
|
57
|
+
return _errorResult('MGR_RUNSQL_ERROR', sqlite.error.message);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
success: result.success,
|
|
61
|
+
statements: result.statements,
|
|
62
|
+
affected_rows: result.affected_rows
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 处理 SQL 方法: query/run → SELECT, execute/exec → INSERT/UPDATE/DELETE
|
|
68
|
+
*/
|
|
69
|
+
async function handleSql(sqlite, action, sql, sql_params) {
|
|
70
|
+
var is_query = action === 'query' || action === 'run';
|
|
71
|
+
var result = is_query
|
|
72
|
+
? await sqlite.run(sql, sql_params)
|
|
73
|
+
: await sqlite.exec(sql, sql_params);
|
|
74
|
+
|
|
75
|
+
if (sqlite.error) {
|
|
76
|
+
return _errorResult('MGR_SQL_ERROR', sqlite.error.message);
|
|
77
|
+
}
|
|
78
|
+
return is_query
|
|
79
|
+
? { list: Array.isArray(result) ? result : [], count: Array.isArray(result) ? result.length : 0 }
|
|
80
|
+
: { affected: result || 0 };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 处理 ORM 方法: add/del/set/list/getObj/count
|
|
85
|
+
*/
|
|
86
|
+
async function handleOrm(sqlite, action, table, query, body) {
|
|
87
|
+
var db = sqlite.db();
|
|
88
|
+
db.table = table;
|
|
89
|
+
|
|
90
|
+
var result;
|
|
91
|
+
switch (action) {
|
|
92
|
+
case 'add':
|
|
93
|
+
result = await db.add(body);
|
|
94
|
+
break;
|
|
95
|
+
case 'del':
|
|
96
|
+
result = await db.del(query);
|
|
97
|
+
break;
|
|
98
|
+
case 'set':
|
|
99
|
+
result = await db.set(query, body);
|
|
100
|
+
break;
|
|
101
|
+
case 'list':
|
|
102
|
+
result = await db.list(query);
|
|
103
|
+
break;
|
|
104
|
+
case 'getObj':
|
|
105
|
+
result = await db.getObj(query);
|
|
106
|
+
break;
|
|
107
|
+
case 'count':
|
|
108
|
+
result = await db.count(query);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (db.error) {
|
|
113
|
+
return _errorResult('MGR_ORM_ERROR', db.error.message);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 构建错误结果对象
|
|
120
|
+
*/
|
|
121
|
+
function _errorResult(code, message) {
|
|
122
|
+
return { error: { code: code, message: message } };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = { main };
|
package/package.json
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mm_sqlite",
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"description": "高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口,支持异步操作、事务处理和批量操作",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test.js",
|
|
8
|
+
"dev": "nodemon test.js",
|
|
9
|
+
"lint": "eslint . --config eslint.config.js",
|
|
10
|
+
"lint:fix": "eslint . --config eslint.config.js --fix"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://gitee.com/qiuwenwu91/mm_sqlite.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mm_mod",
|
|
18
|
+
"mm_adapter",
|
|
19
|
+
"mm_persist",
|
|
20
|
+
"sqlite",
|
|
21
|
+
"node.js",
|
|
22
|
+
"async",
|
|
23
|
+
"await",
|
|
24
|
+
"promise",
|
|
25
|
+
"database",
|
|
26
|
+
"transaction",
|
|
27
|
+
"batch",
|
|
28
|
+
"sql",
|
|
29
|
+
"mm_mysql",
|
|
30
|
+
"compatible",
|
|
31
|
+
"node-sqlite3",
|
|
32
|
+
"async-await"
|
|
33
|
+
],
|
|
34
|
+
"layer": "infrastructure",
|
|
35
|
+
"group": "persistence",
|
|
36
|
+
"author": "邱文武",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://gitee.com/qiuwenwu91/mm_sqlite/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://gitee.com/qiuwenwu91/mm_sqlite#readme",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=22.13.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"mm_admin": "^1.1.0",
|
|
47
|
+
"mm_eslint": "^1.0.0",
|
|
48
|
+
"mm_helper": "^1.0.0",
|
|
49
|
+
"mm_mod": "^1.0.1",
|
|
50
|
+
"sqlstring": "^2.3.3"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"eslint": "^10.9.1",
|
|
54
|
+
"eslint-plugin-jsdoc": "^64.2.1",
|
|
55
|
+
"mm_eslint": "^1.7.7"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sqlite",
|
|
3
|
+
"handler": "manager",
|
|
4
|
+
"title": "SQLite管理器",
|
|
5
|
+
"description": "操作 SQLite 数据库,支持 SQL 与 ORM 两种方式。适用场景:本地单文件、嵌入式或轻量持久化时。工作流提示:action 必填(SQL 方法配 sql/params,ORM 方法配 table/query/body),db_path 指定库文件,读在 list+count、写在 affected。",
|
|
6
|
+
"type": "data",
|
|
7
|
+
"params": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"action": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "操作类型: SQL方法(query/execute/run/exec/runSql) + ORM方法(add/del/set/list/getObj/count)",
|
|
13
|
+
"enum": [
|
|
14
|
+
"query",
|
|
15
|
+
"execute",
|
|
16
|
+
"run",
|
|
17
|
+
"exec",
|
|
18
|
+
"runSql",
|
|
19
|
+
"add",
|
|
20
|
+
"del",
|
|
21
|
+
"set",
|
|
22
|
+
"list",
|
|
23
|
+
"getObj",
|
|
24
|
+
"count"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"sql": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "SQL语句(SQL方法需要,runSql 可传多条以分号分隔的建表/插入语句)"
|
|
30
|
+
},
|
|
31
|
+
"params": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"description": "SQL参数(可选)"
|
|
34
|
+
},
|
|
35
|
+
"table": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "表名(ORM方法需要)"
|
|
38
|
+
},
|
|
39
|
+
"query": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"description": "查询条件(ORM方法需要)"
|
|
42
|
+
},
|
|
43
|
+
"body": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"description": "数据对象(add/set 操作需要)"
|
|
46
|
+
},
|
|
47
|
+
"db_path": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "SQLite数据库文件路径(可选,优先于 options 配置)"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"required": [
|
|
53
|
+
"action"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"returns": {
|
|
57
|
+
"description": "管理操作结果,读操作返回 list+count,写操作返回 affected,异常时返回 error",
|
|
58
|
+
"type": "object",
|
|
59
|
+
"properties": {
|
|
60
|
+
"list": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"description": "查询结果列表(query/run 操作)"
|
|
63
|
+
},
|
|
64
|
+
"count": {
|
|
65
|
+
"type": "number",
|
|
66
|
+
"description": "列表条目数/统计数"
|
|
67
|
+
},
|
|
68
|
+
"affected": {
|
|
69
|
+
"type": "number",
|
|
70
|
+
"description": "受影响的行数(写操作)"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"options": {
|
|
75
|
+
"db_path": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"description": "SQLite数据库文件路径(默认值,params.db_path 优先级更高)",
|
|
78
|
+
"default": "./data/sqlite.db"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"group": "storage"
|
|
82
|
+
}
|
package/test_db/test.db
DELETED
|
Binary file
|
package/test_db/test_basic.db
DELETED
|
Binary file
|
|
Binary file
|