jj.js 0.18.0 → 0.19.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/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # v0.19.0 / 2025-12-11
2
+ 1. 修改app.listen监听逻辑
3
+ 2. 新增支持sqlite数据库
4
+ 3. 新增test代码
5
+
1
6
  # v0.18.0 / 2025-03-20
2
7
  1. 升级依赖koa版本到v2.16.0
3
8
  2. 修复模板路径解析bug
package/lib/app.js CHANGED
@@ -12,11 +12,17 @@ const pjson = require('../package.json');
12
12
  */
13
13
  class App extends Koa
14
14
  {
15
- /**
16
- * @override
17
- * @param {...any} args - listen(port, ip, callback(err){})
18
- */
19
- listen(...args) {
15
+ constructor(beforeUse, options) {
16
+ if(typeof beforeUse === 'function') {
17
+ super(options);
18
+ this.use(beforeUse);
19
+ } else {
20
+ super(beforeUse);
21
+ }
22
+ this._init();
23
+ }
24
+
25
+ _init() {
20
26
  // storage
21
27
  this.use(async (ctx, next) => {
22
28
  await storage.run({}, async() => {
@@ -63,9 +69,6 @@ class App extends Koa
63
69
  const jsconfigFile = path.join(cfg_app.base_dir, 'jsconfig.json');
64
70
  isFileSync(jsconfigFile) && require('./types')();
65
71
  }
66
-
67
- // server
68
- return super.listen(...args);
69
72
  }
70
73
  }
71
74
 
package/lib/config.js CHANGED
@@ -34,9 +34,14 @@ const db = {
34
34
  user : 'root', // 数据库用户名
35
35
  password : '', // 数据库密码
36
36
  port : '', // 数据库连接端口
37
- charset : 'utf8', // 数据库编码默认采用utf8
37
+ charset : 'utf8mb4', // 数据库编码默认采用utf8mb4
38
38
  prefix : 'jj_' // 数据库表前缀
39
- }
39
+ },
40
+ sqlite: {
41
+ type : 'sqlite', // 数据库类型
42
+ database : ':memory:', // 数据库文件绝对地址,支持:memory:内存数据库
43
+ prefix : 'jj_' // 数据库表前缀
44
+ },
40
45
  }
41
46
 
42
47
  const log = {
@@ -0,0 +1,290 @@
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}
49
+ */
50
+ async close() {
51
+ return new Promise((resolve, reject) => {
52
+ if(pool.has(this._config)) {
53
+ pool.get(this._config).end(err => {
54
+ if(err) {
55
+ const message = 'MYSQL连接池销毁失败:' + err.message;
56
+ this.$logger.sql(message);
57
+ this.$logger.error(message);
58
+ reject(new Error('DbError: ' + message));
59
+ } else {
60
+ pool.delete(this._config);
61
+ this.$logger.sql(`MYSQL连接池销毁成功:{poolTotal: ${pool.size}}`);
62
+ resolve(this);
63
+ }
64
+ });
65
+ } else {
66
+ resolve(this);
67
+ }
68
+ });
69
+ }
70
+
71
+ /**
72
+ * 释放数据库连接
73
+ * @public
74
+ * @param {PoolConnection} conn - 数据库连接
75
+ */
76
+ release(conn) {
77
+ try {
78
+ conn.release();
79
+ this.$logger.sql('释放数据库连接!');
80
+ } catch(e) {
81
+ const message = '释放数据库出错:' + e.message;
82
+ this.$logger.sql(message);
83
+ this.$logger.error(message);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * 获取数据库连接
89
+ * @private
90
+ * @param {Pool} p
91
+ * @returns {Promise<PoolConnection>}
92
+ */
93
+ async _creatConnect(p) {
94
+ return new Promise((resolve, reject) => {
95
+ p.getConnection((err, connection) => {
96
+ if(err) {
97
+ const message = '获取数据库连接失败:' + err.message;
98
+ this.$logger.sql(message);
99
+ this.$logger.error(message);
100
+ reject(new Error('DbError: ' + message));
101
+ } else {
102
+ this.$logger.sql(`获取数据库连接:{limit: ${p.config.connectionLimit}, all: ${p._allConnections.length}, acquiring: ${p._acquiringConnections.length}, free: ${p._freeConnections.length}, queue: ${p._connectionQueue.length}}`);
103
+ resolve(connection);
104
+ }
105
+ });
106
+ });
107
+ }
108
+
109
+ /**
110
+ * 获取数据库连接
111
+ * @private
112
+ * @returns {Promise<PoolConnection>}
113
+ */
114
+ async _getConnect() {
115
+ return trans.get(this.ctx) || await this._creatConnect(pool.get(this._config));
116
+ }
117
+
118
+ /**
119
+ * 开启事务
120
+ * @public
121
+ * @param {function} fun
122
+ * @returns {Promise<string>}
123
+ */
124
+ async startTrans(fun) {
125
+ const conn = await this._getConnect();
126
+ trans.set(this.ctx, conn);
127
+ let trans_nest = nest.get(conn) || 0;
128
+ nest.set(conn, ++trans_nest);
129
+ if(trans_nest > 1) {
130
+ const message = `开启事务成功:{nest:${trans_nest}}`;
131
+ this.$logger.sql(message);
132
+ if(typeof fun === 'function') {
133
+ try {
134
+ await fun();
135
+ await this.commit();
136
+ } catch(e) {
137
+ await this.rollback();
138
+ throw e;
139
+ }
140
+ }
141
+ return message;
142
+ }
143
+
144
+ return new Promise((resolve, reject) => {
145
+ conn.beginTransaction(async err => {
146
+ if(err) {
147
+ const message = '开启事务失败:' + err.message;
148
+ this.$logger.sql(message);
149
+ this.$logger.error(message);
150
+ reject(new Error('DbError: ' + message));
151
+ } else {
152
+ const message = '开启事务成功!';
153
+ this.$logger.sql(message);
154
+ if(typeof fun === 'function') {
155
+ try {
156
+ await fun();
157
+ await this.commit();
158
+ resolve('事务执行成功!');
159
+ } catch(e) {
160
+ await this.rollback();
161
+ reject(e);
162
+ }
163
+ }
164
+ resolve(message);
165
+ }
166
+ });
167
+ });
168
+ }
169
+
170
+ /**
171
+ * 事务回滚
172
+ * @public
173
+ * @returns {Promise<string>}
174
+ */
175
+ async rollback() {
176
+ const conn = await this._getConnect();
177
+ const trans_nest = nest.get(conn) || 0;
178
+ if(trans_nest > 1) {
179
+ nest.set(conn, trans_nest - 1);
180
+ const message = `事务回滚成功:{nest:${trans_nest}}`;
181
+ this.$logger.sql(message);
182
+ return message;
183
+ } else {
184
+ nest.delete(conn);
185
+ }
186
+
187
+ return new Promise((resolve, reject) => {
188
+ conn.rollback(err => {
189
+ if(err) {
190
+ reject(new Error('DbError: ' + err.message));
191
+ } else {
192
+ trans.delete(this.ctx);
193
+ const message = '事务回滚成功!';
194
+ this.$logger.sql(message);
195
+ this.release(conn);
196
+ resolve(message);
197
+ }
198
+ });
199
+ });
200
+ }
201
+
202
+ /**
203
+ * 提交事务
204
+ * @public
205
+ * @returns {Promise<string>}
206
+ */
207
+ async commit() {
208
+ const conn = await this._getConnect();
209
+ const trans_nest = nest.get(conn) || 0;
210
+ if(trans_nest > 1) {
211
+ nest.set(conn, trans_nest - 1);
212
+ const message = `事务提交成功:{nest:${trans_nest}}`;
213
+ this.$logger.sql(message);
214
+ return message;
215
+ } else {
216
+ nest.delete(conn);
217
+ }
218
+
219
+ return new Promise((resolve, reject) => {
220
+ conn.commit(err => {
221
+ if(err) {
222
+ const message = '事务提交失败:' + err.message;
223
+ this.$logger.sql(message);
224
+ this.$logger.error(message);
225
+ this.rollback();
226
+ reject(new Error('DbError: ' + message));
227
+ } else {
228
+ trans.delete(this.ctx);
229
+ const message = '事务提交成功!';
230
+ this.$logger.sql(message);
231
+ this.release(conn);
232
+ resolve(message);
233
+ }
234
+ });
235
+ });
236
+ }
237
+
238
+ /**
239
+ * 执行sql查询
240
+ * @public
241
+ * @param {string} sql - sql语句或参数
242
+ * @param {*} params - sql参数
243
+ * @returns {Promise}
244
+ */
245
+ async query(sql, params) {
246
+ params || (params = []);
247
+ const conn = await this._getConnect();
248
+
249
+ return new Promise((resolve, reject) => {
250
+ conn.query(sql, params, (err, data) => {
251
+ if(err) {
252
+ const message = '数据操作失败,' + err.message + "\nSQL:" + this.format(sql, params);
253
+ this.$logger.sql(message);
254
+ this.$logger.error(message);
255
+ reject(new Error('DbError: ' + message));
256
+ } else {
257
+ this.$logger.sql('数据操作成功,SQL:' + this.format(sql, params));
258
+ resolve(data);
259
+ }
260
+ if(!trans.has(this.ctx)) {
261
+ this.release(conn);
262
+ }
263
+ });
264
+ });
265
+ }
266
+
267
+ /**
268
+ * 序列化sql语句
269
+ * @public
270
+ * @param {string} sql - sql语句或参数
271
+ * @param {*} params - sql参数
272
+ * @returns {string}
273
+ */
274
+ format(sql, params) {
275
+ params || (params = []);
276
+ return require('mysql').format(sql, params);
277
+ }
278
+
279
+ /**
280
+ * 获取数据表信息
281
+ * @public
282
+ * @param {string} tableName - 表名字
283
+ * @returns {Promise<FieldInfo[]>}
284
+ */
285
+ async tableInfo(tableName) {
286
+ return await this.query(`show columns from ?`, [tableName]);
287
+ }
288
+ }
289
+
290
+ module.exports = Mysql;
package/lib/db/sql.js ADDED
@@ -0,0 +1,106 @@
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(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
+ module.exports = Sql;
@@ -0,0 +1,284 @@
1
+ const {app: cfg_app} = require('../config');
2
+ const Sql = require('./sql');
3
+
4
+ /**
5
+ * @typedef {import('sqlite3').Database} Database
6
+ * @typedef {import('../../types').FieldInfo} FieldInfo
7
+ * @typedef {Map<any, Database>} ConnectionMap
8
+ */
9
+
10
+ //数据库连接
11
+ /**
12
+ * @type {ConnectionMap}
13
+ */
14
+ const connections = new Map();
15
+ //事务连接
16
+ const trans = new Map();
17
+ //事务嵌套
18
+ const nest = new Map();
19
+
20
+ /**
21
+ * @extends Sql
22
+ */
23
+ class Sqlite extends Sql
24
+ {
25
+ /**
26
+ * 连接数据库
27
+ * @public
28
+ * @param {object} config - 数据库配置标识或连接参数
29
+ * @returns {Promise<this>}
30
+ */
31
+ async connect(config={}) {
32
+ this._config = config;
33
+
34
+ let connection = connections.get(this._config);
35
+ if(!connection) {
36
+ const sqlite3 = cfg_app.app_debug ? require('sqlite3').verbose() : require('sqlite3');
37
+ connection = new sqlite3.Database(this._config.database);
38
+ connections.set(this._config, connection);
39
+ this.$logger.sql(`SQLITE数据库连接创建成功:{all: ${connections.size}}`);
40
+ }
41
+
42
+ return this;
43
+ }
44
+
45
+ /**
46
+ * 关闭数据库连接
47
+ * @public
48
+ * @returns {Promise}
49
+ */
50
+ async close() {
51
+ return new Promise((resolve, reject) => {
52
+ if(connections.has(this._config)) {
53
+ const connection = connections.get(this._config);
54
+ connection.close(err => {
55
+ if(err) {
56
+ const message = 'SQLITE数据库连接关闭失败:' + err.message;
57
+ this.$logger.sql(message);
58
+ this.$logger.error(message);
59
+ reject(new Error('DbError: ' + message));
60
+ } else {
61
+ connections.delete(this._config);
62
+ this.$logger.sql(`SQLITE数据库连接关闭成功:{connectionTotal: ${connections.size}}`);
63
+ resolve(this);
64
+ }
65
+ });
66
+ } else {
67
+ resolve(this);
68
+ }
69
+ });
70
+ }
71
+
72
+ /**
73
+ * 获取数据库连接
74
+ * @private
75
+ * @returns {Promise<Database>}
76
+ */
77
+ async _getConnect() {
78
+ return trans.get(this.ctx) || connections.get(this._config);
79
+ }
80
+
81
+ /**
82
+ * 开启事务
83
+ * @public
84
+ * @param {function} fun
85
+ * @returns {Promise<string>}
86
+ */
87
+ async startTrans(fun) {
88
+ const conn = await this._getConnect();
89
+ trans.set(this.ctx, conn);
90
+ let trans_nest = nest.get(conn) || 0;
91
+ nest.set(conn, ++trans_nest);
92
+ if(trans_nest > 1) {
93
+ const message = `开启事务成功:{nest:${trans_nest}}`;
94
+ this.$logger.sql(message);
95
+ if(typeof fun === 'function') {
96
+ try {
97
+ await fun();
98
+ await this.commit();
99
+ } catch(e) {
100
+ await this.rollback();
101
+ throw e;
102
+ }
103
+ }
104
+ return message;
105
+ }
106
+
107
+ return new Promise((resolve, reject) => {
108
+ conn.run('BEGIN TRANSACTION;', async err => {
109
+ if(err) {
110
+ const message = '开启事务失败:' + err.message;
111
+ this.$logger.sql(message);
112
+ this.$logger.error(message);
113
+ reject(new Error('DbError: ' + message));
114
+ } else {
115
+ const message = '开启事务成功!';
116
+ this.$logger.sql(message);
117
+ if(typeof fun === 'function') {
118
+ try {
119
+ await fun();
120
+ await this.commit();
121
+ resolve('事务执行成功!');
122
+ } catch(e) {
123
+ await this.rollback();
124
+ reject(e);
125
+ }
126
+ }
127
+ resolve(message);
128
+ }
129
+ });
130
+ });
131
+ }
132
+
133
+ /**
134
+ * 事务回滚
135
+ * @public
136
+ * @returns {Promise<string>}
137
+ */
138
+ async rollback() {
139
+ const conn = await this._getConnect();
140
+ const trans_nest = nest.get(conn) || 0;
141
+ if(trans_nest > 1) {
142
+ nest.set(conn, trans_nest - 1);
143
+ const message = `事务回滚成功:{nest:${trans_nest}}`;
144
+ this.$logger.sql(message);
145
+ return message;
146
+ } else {
147
+ nest.delete(conn);
148
+ }
149
+
150
+ return new Promise((resolve, reject) => {
151
+ conn.run('ROLLBACK;', err => {
152
+ if(err) {
153
+ reject(new Error('DbError: ' + err.message));
154
+ } else {
155
+ trans.delete(this.ctx);
156
+ const message = '事务回滚成功!';
157
+ this.$logger.sql(message);
158
+ resolve(message);
159
+ }
160
+ });
161
+ });
162
+ }
163
+
164
+ /**
165
+ * 提交事务
166
+ * @public
167
+ * @returns {Promise<string>}
168
+ */
169
+ async commit() {
170
+ const conn = await this._getConnect();
171
+ const trans_nest = nest.get(conn) || 0;
172
+ if(trans_nest > 1) {
173
+ nest.set(conn, trans_nest - 1);
174
+ const message = `事务提交成功:{nest:${trans_nest}}`;
175
+ this.$logger.sql(message);
176
+ return message;
177
+ } else {
178
+ nest.delete(conn);
179
+ }
180
+
181
+ return new Promise((resolve, reject) => {
182
+ conn.run('COMMIT;', err => {
183
+ if(err) {
184
+ const message = '事务提交失败:' + err.message;
185
+ this.$logger.sql(message);
186
+ this.$logger.error(message);
187
+ this.rollback();
188
+ reject(new Error('DbError: ' + message));
189
+ } else {
190
+ trans.delete(this.ctx);
191
+ const message = '事务提交成功!';
192
+ this.$logger.sql(message);
193
+ resolve(message);
194
+ }
195
+ });
196
+ });
197
+ }
198
+
199
+ /**
200
+ * 执行sql查询
201
+ * @public
202
+ * @param {string} sql - sql语句或参数
203
+ * @param {*} params - sql参数
204
+ * @returns {Promise}
205
+ */
206
+ async query(sql, params) {
207
+ params || (params = []);
208
+ const conn = await this._getConnect();
209
+
210
+ return new Promise((resolve, reject) => {
211
+ // 判断是SELECT查询还是其他操作
212
+ const isSelect = /^\s*select /i.test(sql);
213
+ const isTableInfo = /^\s*PRAGMA table_info/i.test(sql);
214
+
215
+ const that = this;
216
+ conn[isSelect || isTableInfo ? 'all' : 'run'](sql, params, function(err, rows) {
217
+ if(err) {
218
+ const message = '数据操作失败,' + err.message + "\nSQL:" + that.format(sql, params);
219
+ that.$logger.sql(message);
220
+ that.$logger.error(message);
221
+ reject(new Error('DbError: ' + message));
222
+ } else {
223
+ that.$logger.sql('数据操作成功,SQL:' + that.format(sql, params));
224
+ if(isSelect || isTableInfo) {
225
+ resolve(rows);
226
+ } else {
227
+ resolve({
228
+ affectedRows: this.changes,
229
+ insertId: this.lastID
230
+ });
231
+ }
232
+ }
233
+ if(!trans.has(that.ctx)) {
234
+ // SQLite不需要显式释放连接
235
+ }
236
+ });
237
+ });
238
+ }
239
+
240
+ /**
241
+ * 序列化sql语句
242
+ * @public
243
+ * @param {string} sql - sql语句或参数
244
+ * @param {*} params - sql参数
245
+ * @returns {string}
246
+ */
247
+ format(sql, params) {
248
+ params || (params = []);
249
+
250
+ let formatted = sql;
251
+ for(let i = 0; i < params.length; i++) {
252
+ let value = params[i];
253
+ if (typeof value === 'string') {
254
+ value = "'" + value.replace(/'/g, "''") + "'";
255
+ } else if (value === null) {
256
+ value = 'NULL';
257
+ }
258
+ formatted = formatted.replace(/\?/, value);
259
+ }
260
+ return formatted;
261
+ }
262
+
263
+ /**
264
+ * 获取数据表信息
265
+ * @public
266
+ * @param {string} tableName - 表名字
267
+ * @returns {Promise<FieldInfo[]>}
268
+ */
269
+ async tableInfo(tableName) {
270
+ const columns = await this.query(`PRAGMA table_info(${tableName})`);
271
+ return columns.map(col => {
272
+ return {
273
+ Field: col.name,
274
+ Type: col.type,
275
+ Null: col.notnull === 1 ? 'NO' : 'YES',
276
+ Key: col.pk === 1 ? 'PRI' : '',
277
+ Default: col.dflt_value,
278
+ Extra: col.pk === 1 ? 'auto_increment' : '',
279
+ };
280
+ });
281
+ }
282
+ }
283
+
284
+ module.exports = Sqlite;
package/lib/db.js CHANGED
@@ -3,29 +3,16 @@ const md5 = require('./utils/md5');
3
3
  const Context = require('./context');
4
4
 
5
5
  /**
6
+ * @typedef {import('../types').KoaCtx} KoaCtx
6
7
  * @typedef {import('../types').Pagination} Pagination
7
8
  * @typedef {import('../types').PaginationInstance} PaginationInstance
8
- * @typedef {import('../types').Pool} Pool
9
- * @typedef {import('../types').PoolConfig} PoolConfig
10
- * @typedef {import('../types').PoolConnection} PoolConnection
11
- * @typedef {import('../types').QueryOptions} QueryOptions
12
9
  * @typedef {import('../types').OkPacket} OkPacket
13
10
  * @typedef {import('../types').RowData} RowData
14
11
  * @typedef {import('../types').ListData} ListData
15
12
  * @typedef {import('../types').FieldInfo} FieldInfo
16
- * @typedef {import('../types').PoolMap} PoolMap
13
+ * @typedef {import('../types').SqlInstance} SqlInstance
17
14
  */
18
15
 
19
- //连接池
20
- /**
21
- * @type {PoolMap}
22
- */
23
- const pool = new Map();
24
- //事务连接
25
- const trans = new Map();
26
- //事务嵌套
27
- const nest = new Map();
28
-
29
16
  /**
30
17
  * @extends Context
31
18
  */
@@ -34,8 +21,8 @@ class Db extends Context
34
21
  /**
35
22
  * Initialize a new `Db`
36
23
  * @public
37
- * @param {import('../types').KoaCtx} [ctx]
38
- * @param {(string|PoolConfig)} [options] - 数据库配置标识或连接参数
24
+ * @param {(object|KoaCtx)} [ctx]
25
+ * @param {(string|object)} [options] - 数据库配置标识或连接参数
39
26
  */
40
27
  constructor(ctx, options) {
41
28
  ctx = ctx || {};
@@ -48,6 +35,10 @@ class Db extends Context
48
35
  */
49
36
  this._queryStr = '';
50
37
  this._tableField = {};
38
+ /**
39
+ * @type {SqlInstance}
40
+ */
41
+ this._sql = null;
51
42
  this.connect(options);
52
43
  }
53
44
 
@@ -78,28 +69,20 @@ class Db extends Context
78
69
  /**
79
70
  * 连接数据库连接池
80
71
  * @public
81
- * @param {(string|PoolConfig)} options - 数据库配置标识或连接参数
72
+ * @param {(string|object)} config - 数据库配置标识或连接参数
82
73
  * @returns {this}
83
74
  */
84
- connect(options='default') {
85
- this._config = typeof options === 'string' ? cfg_db[options] : options;
75
+ connect(config='default') {
76
+ this._config = typeof config === 'string' ? cfg_db[config] : config;
86
77
  this.reset();
87
78
 
88
- /**
89
- * @type {Pool}
90
- */
91
- let cur_pool = pool.get(this._config);
92
- if(!cur_pool) {
93
- switch(this._config.type) {
94
- case 'mysql':
95
- cur_pool = require('mysql').createPool(this._config);
96
- break;
97
- default:
98
- //other database, please provide database driver and implement the connection method
99
- cur_pool = this._config.connect(this._config);
100
- }
101
- pool.set(this._config, cur_pool);
102
- this.$logger.sql(`连接池创建成功:{all: ${pool.size}}`);
79
+ if(this._config.connect) {
80
+ this._sql = this._config.connect(this._config);
81
+ } else {
82
+ const sqltype = this._config.type;
83
+ const Sql = require(`./db/${sqltype}.js`);
84
+ this._sql = new Sql(this.ctx, this.$logger);
85
+ this._sql.connect(this._config);
103
86
  }
104
87
 
105
88
  return this;
@@ -111,67 +94,7 @@ class Db extends Context
111
94
  * @returns {Promise}
112
95
  */
113
96
  async close() {
114
- return new Promise((resolve, reject) => {
115
- pool.has(this._config) && pool.get(this._config).end(err => {
116
- if(err) {
117
- const message = '连接池销毁失败:' + err.message;
118
- this.$logger.sql(message);
119
- this.$logger.error(message);
120
- reject(new Error('DbError: ' + message));
121
- } else {
122
- pool.delete(this._config);
123
- this.$logger.sql(`连接池销毁成功:{poolTotal: ${pool.size}}`);
124
- resolve(this);
125
- }
126
- });
127
- });
128
- }
129
-
130
- /**
131
- * 释放数据库连接
132
- * @public
133
- * @param {PoolConnection} conn - 数据库连接
134
- */
135
- release(conn) {
136
- try {
137
- conn.release();
138
- this.$logger.sql('释放数据库连接!');
139
- } catch(e) {
140
- const message = '释放数据库出错:' + e.message;
141
- this.$logger.sql(message);
142
- this.$logger.error(message);
143
- }
144
- }
145
-
146
- /**
147
- * 获取数据库连接
148
- * @private
149
- * @param {Pool} p
150
- * @returns {Promise}
151
- */
152
- async _creatConnect(p) {
153
- return new Promise((resolve, reject) => {
154
- p.getConnection((err, connection) => {
155
- if(err) {
156
- const message = '获取数据库连接失败:' + err.message;
157
- this.$logger.sql(message);
158
- this.$logger.error(message);
159
- reject(new Error('DbError: ' + message));
160
- } else {
161
- this.$logger.sql(`获取数据库连接:{limit: ${p.config.connectionLimit}, all: ${p._allConnections.length}, acquiring: ${p._acquiringConnections.length}, free: ${p._freeConnections.length}, queue: ${p._connectionQueue.length}}`);
162
- resolve(connection);
163
- }
164
- });
165
- });
166
- }
167
-
168
- /**
169
- * 获取数据库连接
170
- * @private
171
- * @returns {Promise<PoolConnection>}
172
- */
173
- async _getConnect() {
174
- return trans.get(this.ctx) || await this._creatConnect(pool.get(this._config));
97
+ return await this._sql.close();
175
98
  }
176
99
 
177
100
  /**
@@ -181,49 +104,7 @@ class Db extends Context
181
104
  * @returns {Promise<string>}
182
105
  */
183
106
  async startTrans(fun) {
184
- const conn = await this._getConnect();
185
- trans.set(this.ctx, conn);
186
- let trans_nest = nest.get(conn) || 0;
187
- nest.set(conn, ++trans_nest);
188
- if(trans_nest > 1) {
189
- const message = `开启事务成功:{nest:${trans_nest}}`;
190
- this.$logger.sql(message);
191
- if(typeof fun === 'function') {
192
- try {
193
- await fun();
194
- await this.commit();
195
- } catch(e) {
196
- await this.rollback();
197
- throw e;
198
- }
199
- }
200
- return message;
201
- }
202
-
203
- return new Promise((resolve, reject) => {
204
- conn.beginTransaction(async (err) => {
205
- if(err) {
206
- const message = '开启事务失败:' + err.message;
207
- this.$logger.sql(message);
208
- this.$logger.error(message);
209
- reject(new Error('DbError: ' + message));
210
- } else {
211
- const message = '开启事务成功!';
212
- this.$logger.sql(message);
213
- if(typeof fun === 'function') {
214
- try {
215
- await fun();
216
- await this.commit();
217
- resolve('事务执行成功!');
218
- } catch(e) {
219
- await this.rollback();
220
- reject(e);
221
- }
222
- }
223
- resolve(message);
224
- }
225
- });
226
- });
107
+ return await this._sql.startTrans(fun);
227
108
  }
228
109
 
229
110
  /**
@@ -232,26 +113,7 @@ class Db extends Context
232
113
  * @returns {Promise<string>}
233
114
  */
234
115
  async rollback() {
235
- const conn = await this._getConnect();
236
- const trans_nest = nest.get(conn) || 0;
237
- if(trans_nest > 1) {
238
- nest.set(conn, trans_nest - 1);
239
- const message = `事务回滚成功:{nest:${trans_nest}}`;
240
- this.$logger.sql(message);
241
- return message;
242
- } else {
243
- nest.delete(conn);
244
- }
245
-
246
- return new Promise((resolve) => {
247
- conn.rollback(() => {
248
- trans.delete(this.ctx);
249
- const message = '事务回滚成功!';
250
- this.$logger.sql(message);
251
- this.release(conn);
252
- resolve(message);
253
- });
254
- });
116
+ return await this._sql.rollback();
255
117
  }
256
118
 
257
119
  /**
@@ -260,34 +122,7 @@ class Db extends Context
260
122
  * @returns {Promise<string>}
261
123
  */
262
124
  async commit() {
263
- const conn = await this._getConnect();
264
- const trans_nest = nest.get(conn) || 0;
265
- if(trans_nest > 1) {
266
- nest.set(conn, trans_nest - 1);
267
- const message = `事务提交成功:{nest:${trans_nest}}`;
268
- this.$logger.sql(message);
269
- return message;
270
- } else {
271
- nest.delete(conn);
272
- }
273
-
274
- return new Promise((resolve, reject) => {
275
- conn.commit((err) => {
276
- if(err) {
277
- const message = '事务提交失败:' + err.message;
278
- this.$logger.sql(message);
279
- this.$logger.error(message);
280
- this.rollback();
281
- reject(new Error('DbError: ' + message));
282
- } else {
283
- trans.delete(this.ctx);
284
- const message = '事务提交成功!';
285
- this.$logger.sql(message);
286
- this.release(conn);
287
- resolve(message);
288
- }
289
- });
290
- });
125
+ return await this._sql.commit();
291
126
  }
292
127
 
293
128
  /**
@@ -302,27 +137,7 @@ class Db extends Context
302
137
  params !== false && reset !== false && this.reset();
303
138
  params || (params = []);
304
139
 
305
- /**
306
- * @type {PoolConnection}
307
- */
308
- const conn = await this._getConnect();
309
-
310
- return new Promise((resolve, reject) => {
311
- conn.query(sql, params, (err, data) => {
312
- if(err) {
313
- const message = '数据操作失败,' + err.message + "\r\nSQL:" + this.format(sql, params);
314
- this.$logger.sql(message);
315
- this.$logger.error(message);
316
- reject(new Error('DbError: ' + message));
317
- } else {
318
- this.$logger.sql('数据操作成功,SQL:' + this.format(sql, params));
319
- resolve(data);
320
- }
321
- if(!trans.has(this.ctx)) {
322
- this.release(conn);
323
- }
324
- });
325
- });
140
+ return await this._sql.query(sql, params);
326
141
  }
327
142
 
328
143
  /**
@@ -531,7 +346,7 @@ class Db extends Context
531
346
  * 获取多条数据
532
347
  * @public
533
348
  * @param {object} condition - 查询条件
534
- * @returns {Promise<ListData>}
349
+ * @returns {Promise<string|ListData>}
535
350
  */
536
351
  async select(condition) {
537
352
  condition && (this._options.where = [], this._options.where.push([condition]));
@@ -555,12 +370,12 @@ class Db extends Context
555
370
 
556
371
  if(this._options.getSql) {
557
372
  this._options.getSql = false;
558
- return this.format(this._queryStr, params);
373
+ return this._sql.format(this._queryStr, params);
559
374
  }
560
375
 
561
376
  if(this._options.cache_time) {
562
377
  const cache_time = this._options.cache_time;
563
- const cache_key = md5(this.format(this._queryStr, params));
378
+ const cache_key = md5(this._sql.format(this._queryStr, params));
564
379
  if(this.getCache(cache_key)) {
565
380
  this.reset();
566
381
  return this.getCache(cache_key);
@@ -675,6 +490,9 @@ class Db extends Context
675
490
  return await this.select();
676
491
  }
677
492
 
493
+ /**
494
+ * @type {ListData}
495
+ */
678
496
  const rows = await this.select();
679
497
  const result = key ? {} : [];
680
498
  rows.forEach(row => {
@@ -723,23 +541,19 @@ class Db extends Context
723
541
  * 插入一条数据
724
542
  * @public
725
543
  * @param {object} data - 待插入数据
726
- * @returns {Promise<OkPacket>}
544
+ * @returns {Promise<string|OkPacket>}
727
545
  */
728
546
  async insert(data) {
729
547
  data && (this._options.data = data);
730
548
 
731
- let params = [];
732
549
  const table = this._parseTable();
733
-
734
550
  await this._filterData();
551
+ const [sql, params] = this._parseInsertData();
735
552
 
736
- data = this._parseData();
737
- params = params.concat(data[1]);
738
-
739
- this._queryStr = `insert into ${table} set ${data[0]}`;
553
+ this._queryStr = `insert into ${table} ${sql}`;
740
554
  if(this._options.getSql) {
741
555
  this._options.getSql = false;
742
- return this.format(this._queryStr, params);
556
+ return this._sql.format(this._queryStr, params);
743
557
  }
744
558
  return await this.query(this._queryStr, params);
745
559
  }
@@ -749,32 +563,28 @@ class Db extends Context
749
563
  * @public
750
564
  * @param {object} data - 更新数据
751
565
  * @param {object} condition - 更新条件
752
- * @returns {Promise<OkPacket>}
566
+ * @returns {Promise<string|OkPacket>}
753
567
  */
754
568
  async update(data, condition) {
755
569
  data && (this._options.data = data);
756
570
  condition && (this._options.where = [], this._options.where.push([condition]));
757
571
 
758
- let params = [];
759
572
  const table = this._parseTable();
760
-
761
573
  await this._filterData();
574
+ const [sql, dataParams] = this._parseUpdateData();
762
575
 
763
- data = this._parseData();
764
- params = params.concat(data[1]);
765
-
766
- const where = this._parseWhere();
576
+ const [where, whereParams] = this._parseWhere();
767
577
  if(!where[0]) {
768
578
  const message = 'update方法必须传入where参数';
769
579
  this.$logger.sql(message);
770
580
  throw new Error('DbError: ' + message);
771
581
  }
772
- params = params.concat(where[1]);
582
+ const params = [...dataParams, ...whereParams];
773
583
 
774
- this._queryStr = `update ${table} set ${data[0]} ${where[0]}`;
584
+ this._queryStr = `update ${table} set ${sql} ${where}`;
775
585
  if(this._options.getSql) {
776
586
  this._options.getSql = false;
777
- return this.format(this._queryStr, params);
587
+ return this._sql.format(this._queryStr, params);
778
588
  }
779
589
  return await this.query(this._queryStr, params);
780
590
  }
@@ -784,7 +594,7 @@ class Db extends Context
784
594
  * @public
785
595
  * @param {string} field - 字段
786
596
  * @param {number} [step=1] - 增加值,默认1
787
- * @returns {Promise<OkPacket>}
597
+ * @returns {Promise<string|OkPacket>}
788
598
  */
789
599
  async inc(field, step) {
790
600
  return await this.update({[field]: ['inc', step]});
@@ -795,7 +605,7 @@ class Db extends Context
795
605
  * @public
796
606
  * @param {string} field - 字段
797
607
  * @param {number} [step=1] - 减少值,默认1
798
- * @returns {Promise<OkPacket>}
608
+ * @returns {Promise<string|OkPacket>}
799
609
  */
800
610
  async dec(field, step) {
801
611
  return await this.update({[field]: ['dec', step]});
@@ -806,7 +616,7 @@ class Db extends Context
806
616
  * @public
807
617
  * @param {string} field - 字段
808
618
  * @param {string} value - 自定义表达式
809
- * @returns {Promise<OkPacket>}
619
+ * @returns {Promise<string|OkPacket>}
810
620
  */
811
621
  async exp(field, value) {
812
622
  return await this.update({[field]: ['exp', value]});
@@ -815,8 +625,8 @@ class Db extends Context
815
625
  /**
816
626
  * 删除数据
817
627
  * @public
818
- * @param {object} condition - 山粗条件
819
- * @returns {Promise<OkPacket>}
628
+ * @param {object} condition - 删除条件
629
+ * @returns {Promise<string|OkPacket>}
820
630
  */
821
631
  async delete(condition) {
822
632
  condition && (this._options.where = [], this._options.where.push([condition]));
@@ -834,7 +644,7 @@ class Db extends Context
834
644
  this._queryStr = `delete from ${table} ${where[0]}`;
835
645
  if(this._options.getSql) {
836
646
  this._options.getSql = false;
837
- return this.format(this._queryStr, params);
647
+ return this._sql.format(this._queryStr, params);
838
648
  }
839
649
  return await this.query(this._queryStr, params);
840
650
  }
@@ -845,18 +655,18 @@ class Db extends Context
845
655
  * @param {string} sql - sql语句或参数
846
656
  * @param {*} params - sql参数
847
657
  * @param {*} [reset=true] - 是否重置参数
848
- * @returns {Promise<(OkPacket|ListData|RowData)>}
658
+ * @returns {Promise<string|OkPacket|ListData|RowData>}
849
659
  */
850
660
  async execute(sql, params, reset=true) {
851
661
  this._queryStr = sql;
852
662
  if(this._options.getSql) {
853
663
  this._options.getSql = false;
854
- return this.format(this._queryStr, params);
664
+ return this._sql.format(this._queryStr, params);
855
665
  }
856
666
 
857
667
  if(this._options.cache_time) {
858
668
  const cache_time = this._options.cache_time;
859
- const cache_key = md5(this.format(this._queryStr, params));
669
+ const cache_key = md5(this._sql.format(this._queryStr, params));
860
670
  if(this.getCache(cache_key)) {
861
671
  return this.getCache(cache_key);
862
672
  }
@@ -876,7 +686,7 @@ class Db extends Context
876
686
  async tableInfo(table) {
877
687
  const get_sql = this._options.getSql;
878
688
  this._options.getSql = false;
879
- const table_info = await this.table(table).execute(`show columns from ${this._parseTable()}`, false);
689
+ const table_info = await this.table(table)._sql.tableInfo(this._parseTable());
880
690
  this._options.getSql = get_sql;
881
691
  return table_info;
882
692
  }
@@ -892,18 +702,6 @@ class Db extends Context
892
702
  return table_info.map(item => item.Field);
893
703
  }
894
704
 
895
- /**
896
- * 序列化sql语句
897
- * @public
898
- * @param {string} sql - sql语句或参数
899
- * @param {*} params - sql参数
900
- * @returns {string}
901
- */
902
- format(sql, params) {
903
- params || (params = []);
904
- return require('mysql').format(sql, params);
905
- }
906
-
907
705
  _parseTable() {
908
706
  const table = this._table.replace(' ', '` `');
909
707
  return `\`${this._options.prefix}${table}\``;
@@ -1004,7 +802,21 @@ class Db extends Context
1004
802
  return order;
1005
803
  }
1006
804
 
1007
- _parseData() {
805
+ _parseInsertData() {
806
+ const fields = [];
807
+ const values = [];
808
+ const params = [];
809
+ Object.keys(this._options.data).forEach(key => {
810
+ const field = '`' + key.replace('.', '`.`') + '`';
811
+ fields.push(field);
812
+ values.push('?');
813
+ const value = this._options.data[key];
814
+ params.push(value);
815
+ });
816
+ return [`(${fields.join(', ')}) values (${values.join(', ')})`, params];
817
+ }
818
+
819
+ _parseUpdateData() {
1008
820
  let data = '';
1009
821
  const params = [];
1010
822
  Object.keys(this._options.data).forEach(key => {
package/lib/request.js CHANGED
@@ -61,6 +61,9 @@ class Request extends Context
61
61
  * @returns {*}
62
62
  */
63
63
  post(key, default_value='') {
64
+ if(!this.$config.app.koa_body && key !== 'is_ajax') {
65
+ this.$logger.error('请先在app配置中开启koa_body');
66
+ }
64
67
  return this._post[key] || default_value;
65
68
  }
66
69
 
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "jj.js",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "A super simple lightweight NodeJS MVC framework(一个超级简单轻量的NodeJS MVC框架)",
5
5
  "main": "jj.js",
6
- "scripts": {},
6
+ "scripts": {
7
+ "test": "node ./test/server.js"
8
+ },
7
9
  "repository": {
8
10
  "type": "git",
9
11
  "url": "git+https://github.com/yafoo/jj.js.git"
@@ -28,6 +30,7 @@
28
30
  "koa-body": "^6.0.1",
29
31
  "koa-static": "^5.0.0",
30
32
  "mysql": "^2.18.1",
33
+ "sqlite3": "^5.1.7",
31
34
  "watch": "^1.0.2"
32
35
  },
33
36
  "engines": {
package/types.js CHANGED
@@ -210,7 +210,10 @@
210
210
  * @property {string} Key
211
211
  * @property {string} Default
212
212
  * @property {string} Extra
213
- * @typedef {Map<Pool>} PoolMap
213
+ */
214
+
215
+ /**
216
+ * @typedef {import('./lib/db/sql').prototype} SqlInstance - Sql实例
214
217
  */
215
218
 
216
219