jj.js 0.18.0 → 0.20.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/README.md +243 -173
- package/jj.js +14 -14
- package/lib/app.js +53 -15
- package/lib/cache.js +96 -30
- package/lib/config.js +21 -6
- package/lib/context.js +18 -22
- package/lib/controller.js +36 -5
- package/lib/cookie.js +11 -15
- package/lib/ctx.js +28 -28
- package/lib/db/mongodb.js +564 -0
- package/lib/db/mysql.js +294 -0
- package/lib/db/sql.js +116 -0
- package/lib/db/sqlite.js +292 -0
- package/lib/db.js +261 -331
- package/lib/loader.js +79 -44
- package/lib/logger.js +124 -126
- package/lib/middleware.js +39 -6
- package/lib/model.js +23 -9
- package/lib/{run.js → mvc.js} +29 -22
- package/lib/pagination.js +68 -14
- package/lib/request.js +6 -3
- package/lib/response.js +70 -6
- package/lib/router.js +4 -3
- package/lib/types.js +363 -196
- package/lib/upload.js +15 -15
- package/lib/url.js +10 -2
- package/lib/utils/error.js +9 -5
- package/lib/utils/utils.js +2 -0
- package/lib/utils/validate.js +13 -0
- package/lib/view.js +54 -8
- package/logo.png +0 -0
- package/package.json +10 -3
- package/types.js +181 -84
- package/CHANGELOG.md +0 -53
- package/jsdoc.conf.js +0 -17
package/lib/db/mysql.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
const Sql = require('./sql');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import('../../types').Pool} Pool
|
|
5
|
+
* @typedef {import('../../types').PoolConfig} PoolConfig
|
|
6
|
+
* @typedef {import('../../types').PoolConnection} PoolConnection
|
|
7
|
+
* @typedef {import('../../types').FieldInfo} FieldInfo
|
|
8
|
+
* @typedef {Map<any, Pool>} PoolMap
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
//连接池
|
|
12
|
+
/**
|
|
13
|
+
* @type {PoolMap}
|
|
14
|
+
*/
|
|
15
|
+
const pool = new Map();
|
|
16
|
+
//事务连接
|
|
17
|
+
const trans = new Map();
|
|
18
|
+
//事务嵌套
|
|
19
|
+
const nest = new Map();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @extends Sql
|
|
23
|
+
*/
|
|
24
|
+
class Mysql extends Sql
|
|
25
|
+
{
|
|
26
|
+
/**
|
|
27
|
+
* 连接数据库连接池
|
|
28
|
+
* @public
|
|
29
|
+
* @param {PoolConfig} config - 数据库配置标识或连接参数
|
|
30
|
+
* @returns {Promise<this>}
|
|
31
|
+
}
|
|
32
|
+
*/
|
|
33
|
+
async connect(config={}) {
|
|
34
|
+
this._config = config;
|
|
35
|
+
|
|
36
|
+
if(!pool.has(this._config)) {
|
|
37
|
+
const cur_pool = require('mysql').createPool(this._config);
|
|
38
|
+
pool.set(this._config, cur_pool);
|
|
39
|
+
this.logger.sql(`MYSQL连接池创建成功:{all: ${pool.size}}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 关闭数据库连接池
|
|
47
|
+
* @public
|
|
48
|
+
* @returns {Promise<this>}
|
|
49
|
+
*/
|
|
50
|
+
async close() {
|
|
51
|
+
const that = this;
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
if(pool.has(this._config)) {
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
pool.get(this._config).end(err => {
|
|
56
|
+
if(err) {
|
|
57
|
+
const message = 'MYSQL连接池销毁失败:' + err.message;
|
|
58
|
+
that.logger.sql(message);
|
|
59
|
+
that.logger.error(message);
|
|
60
|
+
reject(new Error('DbError: ' + message));
|
|
61
|
+
} else {
|
|
62
|
+
pool.delete(this._config);
|
|
63
|
+
that.logger.sql(`MYSQL连接池销毁成功:{poolTotal: ${pool.size}}`);
|
|
64
|
+
resolve(that);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
resolve(that);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 释放数据库连接
|
|
75
|
+
* @public
|
|
76
|
+
* @param {PoolConnection} conn - 数据库连接
|
|
77
|
+
*/
|
|
78
|
+
release(conn) {
|
|
79
|
+
try {
|
|
80
|
+
conn.release();
|
|
81
|
+
this.logger.sql('释放数据库连接!');
|
|
82
|
+
} catch(e) {
|
|
83
|
+
const message = '释放数据库出错:' + (e instanceof Error && e.message || String(e));
|
|
84
|
+
this.logger.sql(message);
|
|
85
|
+
this.logger.error(message);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 获取数据库连接
|
|
91
|
+
* @private
|
|
92
|
+
* @param {Pool} p
|
|
93
|
+
* @returns {Promise<PoolConnection>}
|
|
94
|
+
*/
|
|
95
|
+
async _creatConnect(p) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
p.getConnection((err, connection) => {
|
|
98
|
+
if(err) {
|
|
99
|
+
const message = '获取数据库连接失败:' + err.message;
|
|
100
|
+
this.logger.sql(message);
|
|
101
|
+
this.logger.error(message);
|
|
102
|
+
reject(new Error('DbError: ' + message));
|
|
103
|
+
} else {
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
this.logger.sql(`获取数据库连接:{limit: ${p.config.connectionLimit}, all: ${p._allConnections.length}, acquiring: ${p._acquiringConnections.length}, free: ${p._freeConnections.length}, queue: ${p._connectionQueue.length}}`);
|
|
106
|
+
resolve(connection);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 获取数据库连接
|
|
114
|
+
* @private
|
|
115
|
+
* @returns {Promise<PoolConnection>}
|
|
116
|
+
*/
|
|
117
|
+
async _getConnect() {
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
return trans.get(this.ctx) || await this._creatConnect(pool.get(this._config));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 开启事务
|
|
124
|
+
* @public
|
|
125
|
+
* @param {function} fun
|
|
126
|
+
* @returns {Promise<string>}
|
|
127
|
+
*/
|
|
128
|
+
async startTrans(fun) {
|
|
129
|
+
const conn = await this._getConnect();
|
|
130
|
+
trans.set(this.ctx, conn);
|
|
131
|
+
let trans_nest = nest.get(conn) || 0;
|
|
132
|
+
nest.set(conn, ++trans_nest);
|
|
133
|
+
if(trans_nest > 1) {
|
|
134
|
+
const message = `开启事务成功:{nest:${trans_nest}}`;
|
|
135
|
+
this.logger.sql(message);
|
|
136
|
+
if(typeof fun === 'function') {
|
|
137
|
+
try {
|
|
138
|
+
await fun();
|
|
139
|
+
await this.commit();
|
|
140
|
+
} catch(e) {
|
|
141
|
+
await this.rollback();
|
|
142
|
+
throw e;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return message;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
conn.beginTransaction(async err => {
|
|
150
|
+
if(err) {
|
|
151
|
+
const message = '开启事务失败:' + err.message;
|
|
152
|
+
this.logger.sql(message);
|
|
153
|
+
this.logger.error(message);
|
|
154
|
+
reject(new Error('DbError: ' + message));
|
|
155
|
+
} else {
|
|
156
|
+
const message = '开启事务成功!';
|
|
157
|
+
this.logger.sql(message);
|
|
158
|
+
if(typeof fun === 'function') {
|
|
159
|
+
try {
|
|
160
|
+
await fun();
|
|
161
|
+
await this.commit();
|
|
162
|
+
resolve('事务执行成功!');
|
|
163
|
+
} catch(e) {
|
|
164
|
+
await this.rollback();
|
|
165
|
+
reject(e);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
resolve(message);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 事务回滚
|
|
176
|
+
* @public
|
|
177
|
+
* @returns {Promise<string>}
|
|
178
|
+
*/
|
|
179
|
+
async rollback() {
|
|
180
|
+
const conn = await this._getConnect();
|
|
181
|
+
const trans_nest = nest.get(conn) || 0;
|
|
182
|
+
if(trans_nest > 1) {
|
|
183
|
+
nest.set(conn, trans_nest - 1);
|
|
184
|
+
const message = `事务回滚成功:{nest:${trans_nest}}`;
|
|
185
|
+
this.logger.sql(message);
|
|
186
|
+
return message;
|
|
187
|
+
} else {
|
|
188
|
+
nest.delete(conn);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return new Promise((resolve, reject) => {
|
|
192
|
+
conn.rollback(err => {
|
|
193
|
+
if(err) {
|
|
194
|
+
reject(new Error('DbError: ' + err.message));
|
|
195
|
+
} else {
|
|
196
|
+
trans.delete(this.ctx);
|
|
197
|
+
const message = '事务回滚成功!';
|
|
198
|
+
this.logger.sql(message);
|
|
199
|
+
this.release(conn);
|
|
200
|
+
resolve(message);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 提交事务
|
|
208
|
+
* @public
|
|
209
|
+
* @returns {Promise<string>}
|
|
210
|
+
*/
|
|
211
|
+
async commit() {
|
|
212
|
+
const conn = await this._getConnect();
|
|
213
|
+
const trans_nest = nest.get(conn) || 0;
|
|
214
|
+
if(trans_nest > 1) {
|
|
215
|
+
nest.set(conn, trans_nest - 1);
|
|
216
|
+
const message = `事务提交成功:{nest:${trans_nest}}`;
|
|
217
|
+
this.logger.sql(message);
|
|
218
|
+
return message;
|
|
219
|
+
} else {
|
|
220
|
+
nest.delete(conn);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return new Promise((resolve, reject) => {
|
|
224
|
+
conn.commit(err => {
|
|
225
|
+
if(err) {
|
|
226
|
+
const message = '事务提交失败:' + err.message;
|
|
227
|
+
this.logger.sql(message);
|
|
228
|
+
this.logger.error(message);
|
|
229
|
+
this.rollback();
|
|
230
|
+
reject(new Error('DbError: ' + message));
|
|
231
|
+
} else {
|
|
232
|
+
trans.delete(this.ctx);
|
|
233
|
+
const message = '事务提交成功!';
|
|
234
|
+
this.logger.sql(message);
|
|
235
|
+
this.release(conn);
|
|
236
|
+
resolve(message);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* 执行sql查询
|
|
244
|
+
* @public
|
|
245
|
+
* @param {string} sql - sql语句或参数
|
|
246
|
+
* @param {*} params - sql参数
|
|
247
|
+
* @returns {Promise<*>}
|
|
248
|
+
*/
|
|
249
|
+
async query(sql, params) {
|
|
250
|
+
params || (params = []);
|
|
251
|
+
const conn = await this._getConnect();
|
|
252
|
+
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
conn.query(sql, params, (err, data) => {
|
|
255
|
+
if(err) {
|
|
256
|
+
const message = '数据操作失败,' + err.message + "\nSQL:" + this.format(sql, params);
|
|
257
|
+
this.logger.sql(message);
|
|
258
|
+
this.logger.error(message);
|
|
259
|
+
reject(new Error('DbError: ' + message));
|
|
260
|
+
} else {
|
|
261
|
+
this.logger.sql('数据操作成功,SQL:' + this.format(sql, params));
|
|
262
|
+
resolve(data);
|
|
263
|
+
}
|
|
264
|
+
if(!trans.has(this.ctx)) {
|
|
265
|
+
this.release(conn);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* 序列化sql语句
|
|
273
|
+
* @public
|
|
274
|
+
* @param {string} sql - sql语句或参数
|
|
275
|
+
* @param {*} params - sql参数
|
|
276
|
+
* @returns {string}
|
|
277
|
+
*/
|
|
278
|
+
format(sql, params) {
|
|
279
|
+
params || (params = []);
|
|
280
|
+
return require('mysql').format(sql, params);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* 获取数据表信息
|
|
285
|
+
* @public
|
|
286
|
+
* @param {string} tableName - 表名字
|
|
287
|
+
* @returns {Promise<FieldInfo[]>}
|
|
288
|
+
*/
|
|
289
|
+
async tableInfo(tableName) {
|
|
290
|
+
return await this.query(`show columns from ?`, [tableName]);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
module.exports = Mysql;
|
package/lib/db/sql.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('../../types').Logger} Logger
|
|
3
|
+
* @typedef {import('../../types').FieldInfo} FieldInfo
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class Sql
|
|
7
|
+
{
|
|
8
|
+
/**
|
|
9
|
+
* @public
|
|
10
|
+
* @param {object} ctx
|
|
11
|
+
* @param {Logger} logger
|
|
12
|
+
*/
|
|
13
|
+
constructor(ctx, logger) {
|
|
14
|
+
this.ctx = ctx;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 连接数据库
|
|
20
|
+
* @public
|
|
21
|
+
* @param {object} config - 数据库连接参数
|
|
22
|
+
* @returns {Promise<this>}
|
|
23
|
+
*/
|
|
24
|
+
async connect(config={}) {
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 关闭数据库
|
|
30
|
+
* @public
|
|
31
|
+
* @returns {Promise<this>}
|
|
32
|
+
*/
|
|
33
|
+
async close() {
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 释放数据库连接
|
|
39
|
+
* @public
|
|
40
|
+
* @param {object} conn - 数据库连接
|
|
41
|
+
*/
|
|
42
|
+
release(conn) {
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 开启事务
|
|
47
|
+
* @public
|
|
48
|
+
* @param {function} [fun]
|
|
49
|
+
* @returns {Promise<string>}
|
|
50
|
+
*/
|
|
51
|
+
async startTrans(fun) {
|
|
52
|
+
return '开启事务成功';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 事务回滚
|
|
57
|
+
* @public
|
|
58
|
+
* @returns {Promise<string>}
|
|
59
|
+
*/
|
|
60
|
+
async rollback() {
|
|
61
|
+
return '事务回滚成功';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 提交事务
|
|
66
|
+
* @public
|
|
67
|
+
* @returns {Promise<string>}
|
|
68
|
+
*/
|
|
69
|
+
async commit() {
|
|
70
|
+
return '事务提交成功';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 执行sql查询
|
|
75
|
+
* @public
|
|
76
|
+
* @param {string} sql - sql语句或参数
|
|
77
|
+
* @param {*} params - sql参数
|
|
78
|
+
* @returns {Promise<*>}
|
|
79
|
+
*/
|
|
80
|
+
async query(sql, params) {
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 序列化sql语句
|
|
85
|
+
* @public
|
|
86
|
+
* @param {string} sql - sql语句或参数
|
|
87
|
+
* @param {*} params - sql参数
|
|
88
|
+
* @returns {string}
|
|
89
|
+
*/
|
|
90
|
+
format(sql, params) {
|
|
91
|
+
params || (params = []);
|
|
92
|
+
return `${sql} ${params.map((/** @type {any[]} */ item) => item.join('=')).join(', ')}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 获取数据表信息
|
|
97
|
+
* @public
|
|
98
|
+
* @param {string} tableName - 表名字
|
|
99
|
+
* @returns {Promise<FieldInfo[]>}
|
|
100
|
+
*/
|
|
101
|
+
async tableInfo(tableName) {
|
|
102
|
+
return await this.query(`show columns from ?`, [tableName]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 设置日志器
|
|
107
|
+
* @param {Logger} logger
|
|
108
|
+
* @returns {this}
|
|
109
|
+
*/
|
|
110
|
+
setLogger(logger) {
|
|
111
|
+
this.logger = logger;
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = Sql;
|
package/lib/db/sqlite.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
const {app: cfg_app} = require('../config');
|
|
2
|
+
const Sql = require('./sql');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('../../types').DbConfigItem} DbConfigItem
|
|
6
|
+
* @typedef {import('sqlite3').Database} Database
|
|
7
|
+
* @typedef {import('../../types').FieldInfo} FieldInfo
|
|
8
|
+
* @typedef {Map<any, Database>} ConnectionMap
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
//数据库连接
|
|
12
|
+
/**
|
|
13
|
+
* @type {ConnectionMap}
|
|
14
|
+
*/
|
|
15
|
+
const connections = new Map();
|
|
16
|
+
//事务连接
|
|
17
|
+
const trans = new Map();
|
|
18
|
+
//事务嵌套
|
|
19
|
+
const nest = new Map();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @extends Sql
|
|
23
|
+
*/
|
|
24
|
+
class Sqlite extends Sql
|
|
25
|
+
{
|
|
26
|
+
/**
|
|
27
|
+
* 连接数据库
|
|
28
|
+
* @public
|
|
29
|
+
* @param {DbConfigItem} config - 数据库配置标识或连接参数
|
|
30
|
+
* @returns {Promise<this>}
|
|
31
|
+
*/
|
|
32
|
+
async connect(config) {
|
|
33
|
+
this._config = config;
|
|
34
|
+
|
|
35
|
+
let connection = connections.get(this._config);
|
|
36
|
+
if(!connection) {
|
|
37
|
+
const sqlite3 = cfg_app.app_debug ? require('sqlite3').verbose() : require('sqlite3');
|
|
38
|
+
connection = new sqlite3.Database(this._config.database);
|
|
39
|
+
connections.set(this._config, connection);
|
|
40
|
+
this.logger.sql(`SQLITE数据库连接创建成功:{all: ${connections.size}}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 关闭数据库连接
|
|
48
|
+
* @public
|
|
49
|
+
* @returns {Promise<this>}
|
|
50
|
+
*/
|
|
51
|
+
async close() {
|
|
52
|
+
const that = this;
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
if(connections.has(this._config)) {
|
|
55
|
+
const connection = connections.get(this._config);
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
connection.close(err => {
|
|
58
|
+
if(err) {
|
|
59
|
+
const message = 'SQLITE数据库连接关闭失败:' + err.message;
|
|
60
|
+
this.logger.sql(message);
|
|
61
|
+
this.logger.error(message);
|
|
62
|
+
reject(new Error('DbError: ' + message));
|
|
63
|
+
} else {
|
|
64
|
+
connections.delete(this._config);
|
|
65
|
+
this.logger.sql(`SQLITE数据库连接关闭成功:{connectionTotal: ${connections.size}}`);
|
|
66
|
+
resolve(that);
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
resolve(that);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 获取数据库连接
|
|
78
|
+
* @private
|
|
79
|
+
* @returns {Promise<Database>}
|
|
80
|
+
*/
|
|
81
|
+
async _getConnect() {
|
|
82
|
+
return trans.get(this.ctx) || connections.get(this._config);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 开启事务
|
|
87
|
+
* @public
|
|
88
|
+
* @param {function} fun
|
|
89
|
+
* @returns {Promise<string>}
|
|
90
|
+
*/
|
|
91
|
+
async startTrans(fun) {
|
|
92
|
+
const conn = await this._getConnect();
|
|
93
|
+
trans.set(this.ctx, conn);
|
|
94
|
+
let trans_nest = nest.get(conn) || 0;
|
|
95
|
+
nest.set(conn, ++trans_nest);
|
|
96
|
+
if(trans_nest > 1) {
|
|
97
|
+
const message = `开启事务成功:{nest:${trans_nest}}`;
|
|
98
|
+
this.logger.sql(message);
|
|
99
|
+
if(typeof fun === 'function') {
|
|
100
|
+
try {
|
|
101
|
+
await fun();
|
|
102
|
+
await this.commit();
|
|
103
|
+
} catch(e) {
|
|
104
|
+
await this.rollback();
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return message;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
conn.run('BEGIN TRANSACTION;', async err => {
|
|
113
|
+
if(err) {
|
|
114
|
+
const message = '开启事务失败:' + err.message;
|
|
115
|
+
this.logger.sql(message);
|
|
116
|
+
this.logger.error(message);
|
|
117
|
+
reject(new Error('DbError: ' + message));
|
|
118
|
+
} else {
|
|
119
|
+
const message = '开启事务成功!';
|
|
120
|
+
this.logger.sql(message);
|
|
121
|
+
if(typeof fun === 'function') {
|
|
122
|
+
try {
|
|
123
|
+
await fun();
|
|
124
|
+
await this.commit();
|
|
125
|
+
resolve('事务执行成功!');
|
|
126
|
+
} catch(e) {
|
|
127
|
+
await this.rollback();
|
|
128
|
+
reject(e);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
resolve(message);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 事务回滚
|
|
139
|
+
* @public
|
|
140
|
+
* @returns {Promise<string>}
|
|
141
|
+
*/
|
|
142
|
+
async rollback() {
|
|
143
|
+
const conn = await this._getConnect();
|
|
144
|
+
const trans_nest = nest.get(conn) || 0;
|
|
145
|
+
if(trans_nest > 1) {
|
|
146
|
+
nest.set(conn, trans_nest - 1);
|
|
147
|
+
const message = `事务回滚成功:{nest:${trans_nest}}`;
|
|
148
|
+
this.logger.sql(message);
|
|
149
|
+
return message;
|
|
150
|
+
} else {
|
|
151
|
+
nest.delete(conn);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
conn.run('ROLLBACK;', err => {
|
|
156
|
+
if(err) {
|
|
157
|
+
reject(new Error('DbError: ' + err.message));
|
|
158
|
+
} else {
|
|
159
|
+
trans.delete(this.ctx);
|
|
160
|
+
const message = '事务回滚成功!';
|
|
161
|
+
this.logger.sql(message);
|
|
162
|
+
resolve(message);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 提交事务
|
|
170
|
+
* @public
|
|
171
|
+
* @returns {Promise<string>}
|
|
172
|
+
*/
|
|
173
|
+
async commit() {
|
|
174
|
+
const conn = await this._getConnect();
|
|
175
|
+
const trans_nest = nest.get(conn) || 0;
|
|
176
|
+
if(trans_nest > 1) {
|
|
177
|
+
nest.set(conn, trans_nest - 1);
|
|
178
|
+
const message = `事务提交成功:{nest:${trans_nest}}`;
|
|
179
|
+
this.logger.sql(message);
|
|
180
|
+
return message;
|
|
181
|
+
} else {
|
|
182
|
+
nest.delete(conn);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return new Promise((resolve, reject) => {
|
|
186
|
+
conn.run('COMMIT;', err => {
|
|
187
|
+
if(err) {
|
|
188
|
+
const message = '事务提交失败:' + err.message;
|
|
189
|
+
this.logger.sql(message);
|
|
190
|
+
this.logger.error(message);
|
|
191
|
+
this.rollback();
|
|
192
|
+
reject(new Error('DbError: ' + message));
|
|
193
|
+
} else {
|
|
194
|
+
trans.delete(this.ctx);
|
|
195
|
+
const message = '事务提交成功!';
|
|
196
|
+
this.logger.sql(message);
|
|
197
|
+
resolve(message);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 执行sql查询
|
|
205
|
+
* @public
|
|
206
|
+
* @param {string} sql - sql语句或参数
|
|
207
|
+
* @param {*} [params] - sql参数
|
|
208
|
+
* @returns {Promise<*>}
|
|
209
|
+
*/
|
|
210
|
+
async query(sql, params) {
|
|
211
|
+
params || (params = []);
|
|
212
|
+
const conn = await this._getConnect();
|
|
213
|
+
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
// 判断是SELECT查询还是其他操作
|
|
216
|
+
const isSelect = /^\s*select /i.test(sql);
|
|
217
|
+
const isTableInfo = /^\s*PRAGMA table_info/i.test(sql);
|
|
218
|
+
|
|
219
|
+
const that = this;
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
conn[isSelect || isTableInfo ? 'all' : 'run'](sql, params, function(err, rows) {
|
|
222
|
+
if(err) {
|
|
223
|
+
const message = '数据操作失败,' + err.message + "\nSQL:" + that.format(sql, params);
|
|
224
|
+
that.logger.sql(message);
|
|
225
|
+
that.logger.error(message);
|
|
226
|
+
reject(new Error('DbError: ' + message));
|
|
227
|
+
} else {
|
|
228
|
+
that.logger.sql('数据操作成功,SQL:' + that.format(sql, params));
|
|
229
|
+
if(isSelect || isTableInfo) {
|
|
230
|
+
resolve(rows);
|
|
231
|
+
} else {
|
|
232
|
+
resolve({
|
|
233
|
+
// @ts-ignore - sqlite3 run 回调中的 this 包含 changes 和 lastID
|
|
234
|
+
affectedRows: this.changes,
|
|
235
|
+
// @ts-ignore - sqlite3 run 回调中的 this 包含 changes 和 lastID
|
|
236
|
+
insertId: this.lastID
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if(!trans.has(that.ctx)) {
|
|
241
|
+
// SQLite不需要显式释放连接
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 序列化sql语句
|
|
249
|
+
* @public
|
|
250
|
+
* @param {string} sql - sql语句或参数
|
|
251
|
+
* @param {*} params - sql参数
|
|
252
|
+
* @returns {string}
|
|
253
|
+
*/
|
|
254
|
+
format(sql, params) {
|
|
255
|
+
params || (params = []);
|
|
256
|
+
|
|
257
|
+
let formatted = sql;
|
|
258
|
+
for(let i = 0; i < params.length; i++) {
|
|
259
|
+
let value = params[i];
|
|
260
|
+
if (typeof value === 'string') {
|
|
261
|
+
value = "'" + value.replace(/'/g, "''") + "'";
|
|
262
|
+
} else if (value === null) {
|
|
263
|
+
value = 'NULL';
|
|
264
|
+
}
|
|
265
|
+
formatted = formatted.replace(/\?/, value);
|
|
266
|
+
}
|
|
267
|
+
return formatted;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 获取数据表信息
|
|
272
|
+
* @public
|
|
273
|
+
* @param {string} tableName - 表名字
|
|
274
|
+
* @returns {Promise<FieldInfo[]>}
|
|
275
|
+
*/
|
|
276
|
+
async tableInfo(tableName) {
|
|
277
|
+
const columns = await this.query(`PRAGMA table_info(${tableName})`);
|
|
278
|
+
// @ts-ignore
|
|
279
|
+
return columns.map(col => {
|
|
280
|
+
return {
|
|
281
|
+
Field: col.name,
|
|
282
|
+
Type: col.type,
|
|
283
|
+
Null: col.notnull === 1 ? 'NO' : 'YES',
|
|
284
|
+
Key: col.pk === 1 ? 'PRI' : '',
|
|
285
|
+
Default: col.dflt_value,
|
|
286
|
+
Extra: col.pk === 1 ? 'auto_increment' : '',
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = Sqlite;
|