jj.js 0.6.1 → 0.7.3
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 +316 -1
- package/lib/cache.js +13 -20
- package/lib/config.js +2 -2
- package/lib/cookie.js +8 -1
- package/lib/db.js +78 -82
- package/lib/upload.js +1 -1
- package/lib/utils/fs.js +7 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,2 +1,317 @@
|
|
|
1
|
-
# jj.js
|
|
1
|
+
# jj.js
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
2
5
|
A simple and lightweight MVC framework built on nodejs+koa2(一个基于nodejs+koa2构建的简单轻量级MVC框架)
|
|
6
|
+
|
|
7
|
+
## 项目介绍
|
|
8
|
+
|
|
9
|
+
> 框架依赖koa2、koa-router、art-template、mysql,基于proxy实现了代码自动加载及懒加载技术,最低依赖仅仅为koa和koa-router,非常轻量。系统架构类似Thinkphp5,很容易上手。支持类库自动加载、手工引入两种开发模式。支持应用、路由、控制器三级中间件,方便插件及二次开发。支持单应用和多应用两种运行模式。
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
项目地址:[https://github.com/yafoo/jj.js](https://github.com/yafoo/jj.js "https://github.com/yafoo/jj.js")
|
|
13
|
+
|
|
14
|
+
码云镜像:[https://gitee.com/yafu/jj.js](https://gitee.com/yafu/jj.js "https://gitee.com/yafu/jj.js")
|
|
15
|
+
|
|
16
|
+
官网地址:[https://me.i-i.me/jjjs/](https://me.i-i.me/jjjs/ "https://me.i-i.me/jjjs/")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i jj.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Hello world !
|
|
26
|
+
|
|
27
|
+
1、创建文件 `./app/controller/index.js`
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const {Controller} = require('jj.js');
|
|
31
|
+
|
|
32
|
+
class Index extends Controller
|
|
33
|
+
{
|
|
34
|
+
async index() {
|
|
35
|
+
this.$show('Hello jj.js, hello world !');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = Index;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2、创建文件 `./server.js`
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
const {app, Logger} = require('jj.js');
|
|
46
|
+
|
|
47
|
+
app.run(3000, '127.0.0.1', function(err){
|
|
48
|
+
!err && Logger.info('http server is ready on 3000');
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
3、运行命令
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node server.js
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
4、浏览器访问 `http://127.0.0.1:3000`,页面输出 `Hello jj.js, hello world !`
|
|
59
|
+
|
|
60
|
+
5、或者执行命令 `npm test`,快速打开测试程序。
|
|
61
|
+
|
|
62
|
+
## 应用结构
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
├── app //应用目录 (非必需,可改名)
|
|
66
|
+
│ ├── controller //控制器目录 (非必需,可改名)
|
|
67
|
+
│ │ └── index.js //控制器
|
|
68
|
+
│ ├── view //模板目录 (非必需,可改名)
|
|
69
|
+
│ │ └── index //index控制器模板目录 (非必需,可改名)
|
|
70
|
+
│ │ └── index.htm //模板
|
|
71
|
+
│ ├── middleware //中间件目录 (非必需,不可改名)
|
|
72
|
+
│ ├── model //模型目录 (非必需,可改名)
|
|
73
|
+
│ ├── pagination //分页目录 (非必需,可改名)
|
|
74
|
+
│ ├── logic //逻辑目录 (非必需,可改名)
|
|
75
|
+
│ └── **** //其他目录 (非必需,可改名)
|
|
76
|
+
├── app2 //应用2目录 (非必需,可改名)
|
|
77
|
+
├── common //公共应用目录 (非必需,可改名)
|
|
78
|
+
├── config //配置目录 (非必需,不可改名)
|
|
79
|
+
│ ├── app.js //APP配置 (非必需,不可改名)
|
|
80
|
+
│ ├── db.js //数据库配置 (非必需,不可改名)
|
|
81
|
+
│ ├── routes.js //路由配置 (非必需,不可改名)
|
|
82
|
+
│ ├── view.js //模版配置 (非必需,不可改名)
|
|
83
|
+
│ ├── cache.js //缓存配置 (非必需,不可改名)
|
|
84
|
+
│ └── **** //其他配置 (非必需,可改名)
|
|
85
|
+
├── public //静态访问目录 (非必需,可改名)
|
|
86
|
+
│ └── static //css image文件目录 (非必需,可改名)
|
|
87
|
+
├── node_modules //nodejs模块目录
|
|
88
|
+
├── server.js //应用入口文件 (必需,可改名)
|
|
89
|
+
└── package.json //npm package.json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 系统类库
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
const {app, Controller, Db, Model, Pagination, View, Logger, Cookie, Response, Upload, Url, Middleware, Context} = require('jj.js');
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 开发手册(待继续完善)
|
|
99
|
+
|
|
100
|
+
> 系统类库除了app,其他都是Class类型,开发时建议继承系统类库,这样可以在类内使用$开头的属性,可以自动加载系统类,链式调用类方法时会自动实例化一个单例。例如,在控制器内使用 `this.$logger` 会返回系统Logger类,使用 `this.$logger.info()`,会自动生成一个logger单例,并调用info方法,其他系统类库及类库内可以以这种方法调用。
|
|
101
|
+
|
|
102
|
+
### Controller控制器
|
|
103
|
+
|
|
104
|
+
系统控制器类继承自系统中间件类Middleware,包含所有Middleware方法。
|
|
105
|
+
|
|
106
|
+
> 属性:**middleware**
|
|
107
|
+
|
|
108
|
+
数组,定义控制器中间件,一个元素为一个中间件,元素为字符串或对象。
|
|
109
|
+
|
|
110
|
+
案例1: `this.middleware = ['index']`,则控制器内所有方法访问之前都会调用当前应用目录(app)下中间件目录(middleware )下的控制器同名中间件的index方法。
|
|
111
|
+
|
|
112
|
+
案例2: `this.middleware = ['index', {middleware: 'auth/test', accept: 'middleTest'}]`,则控制器内所有方法访问之前都会先调用当前应用目录(app)下中间件目录(middleware )下的控制器同名中间件的index方法。仅当访问控制器middleTest方法之前,还会再调用当前应用下中间件目录下的auth中间件的test方法(需index中间件内调用`this.$next()`方法,否则后续程序不会执行)。
|
|
113
|
+
|
|
114
|
+
> 方法:**$assign(name, value)**
|
|
115
|
+
|
|
116
|
+
同步方法,赋值模版变量。
|
|
117
|
+
|
|
118
|
+
案例1:`this.$assign('title', 'Hello jj.js !')`,在模版内使用变量 `{{title}}`
|
|
119
|
+
|
|
120
|
+
如果name为一个对象,则清除之前赋值的模板变量,并将name设置为模板变量对象。
|
|
121
|
+
|
|
122
|
+
案例2:`this.$assign({'title': 'jj.js', 'content': 'Hello jj.js !'})`,在模版内可使用变量 `{{title}}`、`{{content}}`
|
|
123
|
+
|
|
124
|
+
> 方法:**$data(name)**
|
|
125
|
+
|
|
126
|
+
同步方法,获取已赋模版变量。
|
|
127
|
+
如果name为空,则获取全部变量。
|
|
128
|
+
|
|
129
|
+
> 方法:**$show(content)**
|
|
130
|
+
|
|
131
|
+
同步方法,继承自Middleware类,输出content,如果content为对象,则输出json字符串。
|
|
132
|
+
|
|
133
|
+
> 方法:**$fetch(template)**
|
|
134
|
+
|
|
135
|
+
异步方法,渲染模板文件,并输出。
|
|
136
|
+
|
|
137
|
+
其中template会自动自动定位模板文件,如果name为空,则定位到当前应用下view目录下的控制器同名目录下的方法同名htm文件。
|
|
138
|
+
|
|
139
|
+
案例1:`this.$fetch()`,在index控制器类的index方法调用,则模板定位到`/app/view/index/index.htm`
|
|
140
|
+
|
|
141
|
+
案例2:`this.$fetch('list/show')`,则模板定位到`/app/view/list/show.htm`
|
|
142
|
+
|
|
143
|
+
> 方法:**$load(template)**
|
|
144
|
+
|
|
145
|
+
异步方法,直接加载模板,并输出。模板定位规则同$fetch方法。
|
|
146
|
+
|
|
147
|
+
> 方法:**$render(data)**
|
|
148
|
+
|
|
149
|
+
异步方法,渲染字符串模板,并输出。data为字符串模版内容。
|
|
150
|
+
|
|
151
|
+
案例1:`this.$render('<div>{{title}}</div>')`,会输出`<div>jj.js</div>`
|
|
152
|
+
|
|
153
|
+
> 方法:**$redirect(name, status = 302)**
|
|
154
|
+
|
|
155
|
+
同步方法,继承自Middleware类,网页跳转,name解析同$fetch方法。
|
|
156
|
+
|
|
157
|
+
案例1:`this.$fetch('test')`,在index控制器类的index方法调用,则跳转到到`/app/index/test`地址
|
|
158
|
+
|
|
159
|
+
案例2:`this.$fetch('/show')`,name包含'/'前缀,则跳转到地址`/show`
|
|
160
|
+
|
|
161
|
+
> 方法:**$success(msg, name)**
|
|
162
|
+
|
|
163
|
+
同步方法,继承自Middleware类,返回成功提示,name解析同$redirect方法,如果是ajax请求,则返回json数据。
|
|
164
|
+
|
|
165
|
+
案例1:`this.$success('操作成功!', 'test')`,返回成功提示,并跳转到`/app/index/test`地址
|
|
166
|
+
|
|
167
|
+
案例2:`this.$success({ajax: 'data'})`,ajax返回json `{state: 1, msg: '操作成功!', data: {ajax: 'data'}}`
|
|
168
|
+
|
|
169
|
+
> 方法:**$error(msg, name)**
|
|
170
|
+
|
|
171
|
+
同步方法,继承自Middleware类,返回成功提示,name解析同$success方法,name为空,则跳转来源网址。
|
|
172
|
+
|
|
173
|
+
### Middleware中间件类
|
|
174
|
+
|
|
175
|
+
> 方法:**$show(content)** 参照控制器类
|
|
176
|
+
|
|
177
|
+
> 方法:**$redirect(url, status)** 参照控制器类
|
|
178
|
+
|
|
179
|
+
> 方法:**$success(msg, url)** 参照控制器类
|
|
180
|
+
|
|
181
|
+
> 方法:**$error(msg, url)** 参照控制器类
|
|
182
|
+
|
|
183
|
+
### Db数据库类
|
|
184
|
+
|
|
185
|
+
> 方法:**async startTrans(fun)** 开启事务
|
|
186
|
+
|
|
187
|
+
> 方法:**async commit()** 提交事务
|
|
188
|
+
|
|
189
|
+
> 方法:**async rollback()** 事务回滚
|
|
190
|
+
|
|
191
|
+
> 方法:**prefix(prefix)** 设置数据表前缀
|
|
192
|
+
|
|
193
|
+
> 方法:**table(table)** 设置数据表
|
|
194
|
+
|
|
195
|
+
> 方法:**field(field)** 设置查询字段
|
|
196
|
+
|
|
197
|
+
> 方法:**where(where, logic)** 设置查询条件
|
|
198
|
+
|
|
199
|
+
> 方法:**distinct()** 数据去重
|
|
200
|
+
|
|
201
|
+
> 方法:**group(field)** 数据分组
|
|
202
|
+
|
|
203
|
+
> 方法:**having(condition)** 数据筛选
|
|
204
|
+
|
|
205
|
+
> 方法:**order(field, order='asc')** 查询排序
|
|
206
|
+
|
|
207
|
+
> 方法:**limit(offset, rows)** 查询数据限制
|
|
208
|
+
|
|
209
|
+
> 方法:**page(page, pageSize)** 分页查询
|
|
210
|
+
|
|
211
|
+
> 方法:**cache(time)** 设置缓存时间
|
|
212
|
+
|
|
213
|
+
> 方法:**getSql(fetch = true)** 设置返回sql语句
|
|
214
|
+
|
|
215
|
+
> 方法:**join(table, on, type='left')** 设置表连接
|
|
216
|
+
|
|
217
|
+
> 方法:**async select(condition)** 查询多条数据
|
|
218
|
+
|
|
219
|
+
> 方法:**async find(condition)** 查询单条数据
|
|
220
|
+
|
|
221
|
+
> 方法:**async value(field)** 查询单个值
|
|
222
|
+
|
|
223
|
+
> 方法:**async count(field='*')** 查询记录数
|
|
224
|
+
|
|
225
|
+
> 方法:**async max(field)** 查询最大值
|
|
226
|
+
|
|
227
|
+
> 方法:**async min(field)** 查询最小值
|
|
228
|
+
|
|
229
|
+
> 方法:**async avg(field)** 查询平均值
|
|
230
|
+
|
|
231
|
+
> 方法:**async sum(field)** 对列求和
|
|
232
|
+
|
|
233
|
+
> 方法:**async column(field, key)** 获取一列数据,如果设置key则获取一列键值对
|
|
234
|
+
|
|
235
|
+
> 方法:**async pagination(page, page_size, pagination)** 分页查询并返回分页实例
|
|
236
|
+
|
|
237
|
+
> 方法:**data(data)** 设置写入数据
|
|
238
|
+
|
|
239
|
+
> 方法:**allowField(field = true)** 设置过滤非数据表字段
|
|
240
|
+
|
|
241
|
+
> 方法:**async insert(data)** 插入一条数据
|
|
242
|
+
|
|
243
|
+
> 方法:**async update(data, condition)** 更新数据
|
|
244
|
+
|
|
245
|
+
> 方法:**async inc(field, step)** 数据表字段自增
|
|
246
|
+
|
|
247
|
+
> 方法:**async dec(field, step)** 数据表字段自减
|
|
248
|
+
|
|
249
|
+
> 方法:**async exp(field, step)** 数据表字段执行自定义方法
|
|
250
|
+
|
|
251
|
+
> 方法:**async delete(condition)** 删除数据
|
|
252
|
+
|
|
253
|
+
> 方法:**async execute(sql, params, reset=true)** 解析并执行sql语句
|
|
254
|
+
|
|
255
|
+
> 方法:**async tableInfo(table)** 获取表信息
|
|
256
|
+
|
|
257
|
+
> 方法:**async tableField(table)** 获取表字段信息
|
|
258
|
+
|
|
259
|
+
> 方法:**format(sql, params)** 解析sql语句
|
|
260
|
+
|
|
261
|
+
> 方法:**deleteCache()** 清空数据库查询缓存
|
|
262
|
+
|
|
263
|
+
### Model模型类
|
|
264
|
+
|
|
265
|
+
> 属性:**db** 模型的db实例
|
|
266
|
+
|
|
267
|
+
> 方法:**async add(data)** 同Db类insert方法
|
|
268
|
+
|
|
269
|
+
> 方法:**async save(data, condition = {})** 智能调用Db类insert或update方法
|
|
270
|
+
|
|
271
|
+
> 方法:**async del(condition)** 同Db类delete方法
|
|
272
|
+
|
|
273
|
+
> 方法:**async get(condition)** 同Db类find方法
|
|
274
|
+
|
|
275
|
+
> 方法:**async all(condition)** 同Db类select方法
|
|
276
|
+
|
|
277
|
+
### Pagination分页类
|
|
278
|
+
|
|
279
|
+
### View模板引擎类
|
|
280
|
+
|
|
281
|
+
### Logger日志类
|
|
282
|
+
|
|
283
|
+
### Cookie类
|
|
284
|
+
|
|
285
|
+
### Response跳转相应类
|
|
286
|
+
|
|
287
|
+
### Upload上传类
|
|
288
|
+
|
|
289
|
+
### Url网址解析类
|
|
290
|
+
|
|
291
|
+
### Context自动加载基类
|
|
292
|
+
|
|
293
|
+
### config配置
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
## 应用案例
|
|
297
|
+
|
|
298
|
+
- [基于jj.js的轻量博客系统:Melog](https://me.i-i.me/melog/)
|
|
299
|
+
|
|
300
|
+
### Nginx代理
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
location / {
|
|
304
|
+
proxy_pass http://127.0.0.1:3000;
|
|
305
|
+
proxy_http_version 1.1;
|
|
306
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
307
|
+
proxy_set_header Connection "upgrade";
|
|
308
|
+
proxy_set_header Host $host;
|
|
309
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
310
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
311
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### License
|
|
316
|
+
|
|
317
|
+
[MIT](LICENSE)
|
package/lib/cache.js
CHANGED
|
@@ -7,7 +7,7 @@ class Cache
|
|
|
7
7
|
class ChildCache extends this.constructor {}
|
|
8
8
|
ChildCache.cache = {};
|
|
9
9
|
ChildCache.timer = null;
|
|
10
|
-
ChildCache.
|
|
10
|
+
ChildCache.setIntervalTime(cfg_cache.clear_time);
|
|
11
11
|
return ChildCache;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -20,12 +20,13 @@ class Cache
|
|
|
20
20
|
if(this.cache[key] && this.cache[key].time > now_time) {
|
|
21
21
|
return this.cache[key].data;
|
|
22
22
|
} else {
|
|
23
|
+
this.delete(key);
|
|
23
24
|
return undefined;
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
static set(key, data, cache_time) {
|
|
28
|
-
|
|
29
|
+
cache_time || (cache_time = cfg_cache.cache_time || 60 * 60 * 24 * 365 * 10);
|
|
29
30
|
const now_time = this.time();
|
|
30
31
|
this.cache[key] = {data: data, time: cache_time + now_time};
|
|
31
32
|
}
|
|
@@ -38,26 +39,18 @@ class Cache
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
static
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
static setIntervalTime(time) {
|
|
43
|
+
if(time) {
|
|
44
|
+
this.timer && clearInterval(this.timer);
|
|
45
|
+
this.timer = setInterval(() => {
|
|
44
46
|
const now_time = this.time();
|
|
45
47
|
for(let key in this.cache) {
|
|
46
|
-
this.cache[key].time < now_time &&
|
|
48
|
+
this.cache[key].time < now_time && this.delete(key);
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
break;
|
|
53
|
-
default:
|
|
54
|
-
this.timer && clearInterval(this.timer);
|
|
55
|
-
this.timer = setInterval(() => {
|
|
56
|
-
const now_time = this.time();
|
|
57
|
-
for(let key in this.cache) {
|
|
58
|
-
this.cache[key].time < now_time && (delete this.cache[key]);
|
|
59
|
-
}
|
|
60
|
-
}, time * 1000);
|
|
50
|
+
}, time * 1000);
|
|
51
|
+
} else {
|
|
52
|
+
this.timer && clearInterval(this.timer);
|
|
53
|
+
this.timer = null;
|
|
61
54
|
}
|
|
62
55
|
}
|
|
63
56
|
|
|
@@ -68,6 +61,6 @@ class Cache
|
|
|
68
61
|
|
|
69
62
|
Cache.cache = {};
|
|
70
63
|
Cache.timer = null;
|
|
71
|
-
Cache.
|
|
64
|
+
Cache.setIntervalTime(cfg_cache.clear_time);
|
|
72
65
|
|
|
73
66
|
module.exports = Cache;
|
package/lib/config.js
CHANGED
|
@@ -45,8 +45,8 @@ const log = {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const cache = {
|
|
48
|
-
cache_time: 60 * 60 * 24, // 默认缓存时间(1
|
|
49
|
-
clear_time: undefined // (undefined: 清理一次, 0: 关闭自动清理, >0:
|
|
48
|
+
cache_time: 60 * 60 * 24, // 默认缓存时间(1天),为空或false则为10年
|
|
49
|
+
clear_time: undefined // (undefined: 清理一次, 0: 关闭自动清理, >0: 为自动清理周期)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
const page = {
|
package/lib/cookie.js
CHANGED
|
@@ -8,11 +8,18 @@ class Cookie extends Context
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
get(key) {
|
|
11
|
+
if(key === undefined) {
|
|
12
|
+
return this.all();
|
|
13
|
+
}
|
|
11
14
|
return this.ctx.cookies.get(key);
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
delete(key) {
|
|
15
|
-
|
|
18
|
+
if(key === undefined) {
|
|
19
|
+
return this.clear();
|
|
20
|
+
} else {
|
|
21
|
+
this.ctx.cookies.set(key, '', {maxAge: 0});
|
|
22
|
+
}
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
all() {
|
package/lib/db.js
CHANGED
|
@@ -14,31 +14,31 @@ class Db extends Context
|
|
|
14
14
|
constructor(ctx) {
|
|
15
15
|
ctx = ctx || {};
|
|
16
16
|
super(ctx);
|
|
17
|
-
this.
|
|
17
|
+
this._config = null;
|
|
18
18
|
this._table = '';
|
|
19
19
|
this._prefix = '';
|
|
20
|
-
this.
|
|
20
|
+
this._options = {};
|
|
21
21
|
this._queryStr = '';
|
|
22
22
|
this._tableField = {};
|
|
23
23
|
this.connect();
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
connect(options='default') {
|
|
27
|
-
this.
|
|
28
|
-
this._prefix = this.
|
|
27
|
+
this._config = typeof options === 'string' ? cfg_db[options] : options;
|
|
28
|
+
this._prefix = this._config.prefix || '';
|
|
29
29
|
this.reset();
|
|
30
30
|
|
|
31
|
-
let cur_pool = pool.get(this.
|
|
31
|
+
let cur_pool = pool.get(this._config);
|
|
32
32
|
if(!cur_pool) {
|
|
33
|
-
switch(this.
|
|
33
|
+
switch(this._config.type) {
|
|
34
34
|
case 'mysql':
|
|
35
|
-
cur_pool = require('mysql').createPool(this.
|
|
35
|
+
cur_pool = require('mysql').createPool(this._config);
|
|
36
36
|
break;
|
|
37
37
|
default:
|
|
38
38
|
//other database, please provide database driver and implement the connection method
|
|
39
|
-
cur_pool = this.
|
|
39
|
+
cur_pool = this._config.connect(this._config);
|
|
40
40
|
}
|
|
41
|
-
pool.set(this.
|
|
41
|
+
pool.set(this._config, cur_pool);
|
|
42
42
|
this.$logger.sql(`连接池创建成功:{all: ${pool.size}}`);
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -46,15 +46,15 @@ class Db extends Context
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
close() {
|
|
49
|
-
if(pool.has(this.
|
|
50
|
-
pool.get(this.
|
|
49
|
+
if(pool.has(this._config)) {
|
|
50
|
+
pool.get(this._config).end(err => {
|
|
51
51
|
if(err) {
|
|
52
52
|
const message = '连接池销毁失败:' + err['message'];
|
|
53
53
|
this.$logger.sql(message);
|
|
54
54
|
this.$logger.error(message);
|
|
55
55
|
throw new Error(message);
|
|
56
56
|
} else {
|
|
57
|
-
pool.delete(this.
|
|
57
|
+
pool.delete(this._config);
|
|
58
58
|
this.$logger.sql(`连接池销毁成功:{poolTotal: ${pool.size}}`);
|
|
59
59
|
}
|
|
60
60
|
});
|
|
@@ -91,7 +91,7 @@ class Db extends Context
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
async _getConnect() {
|
|
94
|
-
return trans.get(this.ctx) || await this._creatConnect(pool.get(this.
|
|
94
|
+
return trans.get(this.ctx) || await this._creatConnect(pool.get(this._config));
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
async startTrans(fun) {
|
|
@@ -220,7 +220,7 @@ class Db extends Context
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
reset() {
|
|
223
|
-
this.
|
|
223
|
+
this._options = {
|
|
224
224
|
distinct: '',
|
|
225
225
|
field: [],
|
|
226
226
|
join: {},
|
|
@@ -252,7 +252,7 @@ class Db extends Context
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
distinct() {
|
|
255
|
-
this.
|
|
255
|
+
this._options.distinct = 'distinct';
|
|
256
256
|
return this;
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -261,42 +261,42 @@ class Db extends Context
|
|
|
261
261
|
if(typeof field === 'string') {
|
|
262
262
|
field = field.split(',').map(value=>value.trim().replace(/ +/g, ' ').replace(/ as /g, ' '));
|
|
263
263
|
}
|
|
264
|
-
this.
|
|
264
|
+
this._options.field = [...this._options.field, ...field];
|
|
265
265
|
}
|
|
266
266
|
return this;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
join(table, on, type='left') {
|
|
270
270
|
if(table) {
|
|
271
|
-
this.
|
|
271
|
+
this._options.join[table.trim().replace(/ +/g, ' ')] = {on, type};
|
|
272
272
|
}
|
|
273
273
|
return this;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
where(where, logic) {
|
|
277
277
|
if(where) {
|
|
278
|
-
this.
|
|
278
|
+
this._options.where.push([where, logic]);
|
|
279
279
|
}
|
|
280
280
|
return this;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
group(field) {
|
|
284
284
|
if(field) {
|
|
285
|
-
this.
|
|
285
|
+
this._options.group = 'group by `' + field.trim().replace(/\./g, '`.`') + '`';
|
|
286
286
|
}
|
|
287
287
|
return this;
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
having(condition) {
|
|
291
291
|
if(condition) {
|
|
292
|
-
this.
|
|
292
|
+
this._options.having = 'having ' + condition;
|
|
293
293
|
}
|
|
294
294
|
return this;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
order(field, order='asc') {
|
|
298
298
|
if(field) {
|
|
299
|
-
this.
|
|
299
|
+
this._options.order[field.trim()] = order === 'asc' ? 'asc' : 'desc';
|
|
300
300
|
}
|
|
301
301
|
return this;
|
|
302
302
|
}
|
|
@@ -305,7 +305,7 @@ class Db extends Context
|
|
|
305
305
|
if(typeof offset === 'undefined') return this;
|
|
306
306
|
offset = offset ? parseInt(offset) : 0;
|
|
307
307
|
rows = rows ? parseInt(rows) : null;
|
|
308
|
-
this.
|
|
308
|
+
this._options.limit = 'limit ' + offset + (rows ? ',' + rows : '');
|
|
309
309
|
return this;
|
|
310
310
|
}
|
|
311
311
|
|
|
@@ -314,17 +314,17 @@ class Db extends Context
|
|
|
314
314
|
page = page ? parseInt(page) : 1;
|
|
315
315
|
pageSize = pageSize ? parseInt(pageSize) : 10;
|
|
316
316
|
this.limit((page - 1) * pageSize, pageSize);
|
|
317
|
-
this.
|
|
317
|
+
this._options.page = {page, pageSize};
|
|
318
318
|
return this;
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
cache(time) {
|
|
322
|
-
this.
|
|
322
|
+
this._options.cache_time = time;
|
|
323
323
|
return this;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
getSql(fetch = true) {
|
|
327
|
-
this.
|
|
327
|
+
this._options.getSql = fetch;
|
|
328
328
|
return this;
|
|
329
329
|
}
|
|
330
330
|
|
|
@@ -334,23 +334,23 @@ class Db extends Context
|
|
|
334
334
|
} else if(typeof field == 'string') {
|
|
335
335
|
field = field.split(',').map(value => value.trim());
|
|
336
336
|
}
|
|
337
|
-
this.
|
|
337
|
+
this._options.allowField = field;
|
|
338
338
|
return this;
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
data(data) {
|
|
342
342
|
if(data) {
|
|
343
|
-
this.
|
|
343
|
+
this._options.data = {...this._options.data, ...data};
|
|
344
344
|
}
|
|
345
345
|
return this;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
async select(condition) {
|
|
349
|
-
condition && (this.
|
|
349
|
+
condition && (this._options.where = [], this._options.where.push([condition]));
|
|
350
350
|
|
|
351
351
|
let params = [];
|
|
352
352
|
const table = this._parseTable();
|
|
353
|
-
const distinct = this.
|
|
353
|
+
const distinct = this._options.distinct;
|
|
354
354
|
const field = this._parseField();
|
|
355
355
|
const join = this._parseJoin();
|
|
356
356
|
|
|
@@ -359,19 +359,19 @@ class Db extends Context
|
|
|
359
359
|
|
|
360
360
|
const order = this._parseOrder();
|
|
361
361
|
|
|
362
|
-
const group = this.
|
|
363
|
-
const having = this.
|
|
364
|
-
const limit = this.
|
|
362
|
+
const group = this._options.group;
|
|
363
|
+
const having = this._options.having;
|
|
364
|
+
const limit = this._options.limit;
|
|
365
365
|
|
|
366
366
|
this._queryStr = `select ${distinct} ${field} from ${table} ${join} ${where[0]} ${group} ${having} ${order} ${limit}`;
|
|
367
367
|
|
|
368
|
-
if(this.
|
|
369
|
-
this.
|
|
368
|
+
if(this._options.getSql) {
|
|
369
|
+
this._options.getSql = false;
|
|
370
370
|
return this.format(this._queryStr, params);
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
if(this.
|
|
374
|
-
const cache_time = this.
|
|
373
|
+
if(this._options.cache_time) {
|
|
374
|
+
const cache_time = this._options.cache_time;
|
|
375
375
|
const cache_key = md5(this.format(this._queryStr, params));
|
|
376
376
|
if(this.getCache(cache_key)) {
|
|
377
377
|
this.reset();
|
|
@@ -386,10 +386,10 @@ class Db extends Context
|
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
async find(condition) {
|
|
389
|
-
condition && (this.
|
|
389
|
+
condition && (this._options.where = [], this._options.where.push([condition]));
|
|
390
390
|
this.limit(1);
|
|
391
391
|
|
|
392
|
-
if(this.
|
|
392
|
+
if(this._options.getSql) {
|
|
393
393
|
return await this.select();
|
|
394
394
|
}
|
|
395
395
|
|
|
@@ -398,10 +398,10 @@ class Db extends Context
|
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
async value(field) {
|
|
401
|
-
this.
|
|
401
|
+
this._options.field = [];
|
|
402
402
|
this.field(field);
|
|
403
403
|
|
|
404
|
-
if(this.
|
|
404
|
+
if(this._options.getSql) {
|
|
405
405
|
return await this.find();
|
|
406
406
|
}
|
|
407
407
|
|
|
@@ -430,11 +430,11 @@ class Db extends Context
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
async column(field, key) {
|
|
433
|
-
this.
|
|
433
|
+
this._options.field = [];
|
|
434
434
|
this.field(field);
|
|
435
435
|
key && this.field(key);
|
|
436
436
|
|
|
437
|
-
if(this.
|
|
437
|
+
if(this._options.getSql) {
|
|
438
438
|
return await this.select();
|
|
439
439
|
}
|
|
440
440
|
|
|
@@ -458,7 +458,7 @@ class Db extends Context
|
|
|
458
458
|
pagination = this.$pagination.__node.isClass ? this.$pagination : this.$.pagination;
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
const options = {...this.
|
|
461
|
+
const options = {...this._options};
|
|
462
462
|
const total = await this.count();
|
|
463
463
|
pagination.total(total);
|
|
464
464
|
|
|
@@ -466,7 +466,7 @@ class Db extends Context
|
|
|
466
466
|
page_size ? pagination.pageSize(page_size) : (page_size = pagination.pageSize());
|
|
467
467
|
|
|
468
468
|
if(total) {
|
|
469
|
-
this.
|
|
469
|
+
this._options = options;
|
|
470
470
|
const result = await this.page(page, page_size).select();
|
|
471
471
|
return [result, pagination];
|
|
472
472
|
} else {
|
|
@@ -475,7 +475,7 @@ class Db extends Context
|
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
async insert(data) {
|
|
478
|
-
data && (this.
|
|
478
|
+
data && (this._options.data = data);
|
|
479
479
|
|
|
480
480
|
let params = [];
|
|
481
481
|
const table = this._parseTable();
|
|
@@ -486,16 +486,16 @@ class Db extends Context
|
|
|
486
486
|
params = params.concat(data[1]);
|
|
487
487
|
|
|
488
488
|
this._queryStr = `insert into ${table} set ${data[0]}`;
|
|
489
|
-
if(this.
|
|
490
|
-
this.
|
|
489
|
+
if(this._options.getSql) {
|
|
490
|
+
this._options.getSql = false;
|
|
491
491
|
return this.format(this._queryStr, params);
|
|
492
492
|
}
|
|
493
493
|
return await this.query(this._queryStr, params);
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
async update(data, condition) {
|
|
497
|
-
data && (this.
|
|
498
|
-
condition && (this.
|
|
497
|
+
data && (this._options.data = data);
|
|
498
|
+
condition && (this._options.where = [], this._options.where.push([condition]));
|
|
499
499
|
|
|
500
500
|
let params = [];
|
|
501
501
|
const table = this._parseTable();
|
|
@@ -514,8 +514,8 @@ class Db extends Context
|
|
|
514
514
|
params = params.concat(where[1]);
|
|
515
515
|
|
|
516
516
|
this._queryStr = `update ${table} set ${data[0]} ${where[0]}`;
|
|
517
|
-
if(this.
|
|
518
|
-
this.
|
|
517
|
+
if(this._options.getSql) {
|
|
518
|
+
this._options.getSql = false;
|
|
519
519
|
return this.format(this._queryStr, params);
|
|
520
520
|
}
|
|
521
521
|
return await this.query(this._queryStr, params);
|
|
@@ -534,7 +534,7 @@ class Db extends Context
|
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
async delete(condition) {
|
|
537
|
-
condition && (this.
|
|
537
|
+
condition && (this._options.where = [], this._options.where.push([condition]));
|
|
538
538
|
|
|
539
539
|
let params = [];
|
|
540
540
|
const table = this._parseTable();
|
|
@@ -547,8 +547,8 @@ class Db extends Context
|
|
|
547
547
|
params = params.concat(where[1]);
|
|
548
548
|
|
|
549
549
|
this._queryStr = `delete from ${table} ${where[0]}`;
|
|
550
|
-
if(this.
|
|
551
|
-
this.
|
|
550
|
+
if(this._options.getSql) {
|
|
551
|
+
this._options.getSql = false;
|
|
552
552
|
return this.format(this._queryStr, params);
|
|
553
553
|
}
|
|
554
554
|
return await this.query(this._queryStr, params);
|
|
@@ -556,18 +556,18 @@ class Db extends Context
|
|
|
556
556
|
|
|
557
557
|
async execute(sql, params, reset=true) {
|
|
558
558
|
this._queryStr = sql;
|
|
559
|
-
if(this.
|
|
560
|
-
this.
|
|
559
|
+
if(this._options.getSql) {
|
|
560
|
+
this._options.getSql = false;
|
|
561
561
|
return this.format(this._queryStr, params);
|
|
562
562
|
}
|
|
563
563
|
return await this.query(this._queryStr, params, reset);
|
|
564
564
|
}
|
|
565
565
|
|
|
566
566
|
async tableInfo(table) {
|
|
567
|
-
const get_sql = this.
|
|
568
|
-
this.
|
|
567
|
+
const get_sql = this._options.getSql;
|
|
568
|
+
this._options.getSql = false;
|
|
569
569
|
const table_info = await this.table(table).execute(`show columns from ${this._parseTable()}`, false);
|
|
570
|
-
this.
|
|
570
|
+
this._options.getSql = get_sql;
|
|
571
571
|
return table_info;
|
|
572
572
|
}
|
|
573
573
|
|
|
@@ -588,9 +588,9 @@ class Db extends Context
|
|
|
588
588
|
|
|
589
589
|
_parseJoin() {
|
|
590
590
|
let join = '';
|
|
591
|
-
Object.keys(this.
|
|
591
|
+
Object.keys(this._options.join).forEach(key => {
|
|
592
592
|
const table = '`' + this._prefix + key.replace(' ', '` `') + '`';
|
|
593
|
-
const value = this.
|
|
593
|
+
const value = this._options.join[key];
|
|
594
594
|
join += (join ? ' ' : '') + value.type + ' join ' + table + ' on ' + value.on;
|
|
595
595
|
});
|
|
596
596
|
return join;
|
|
@@ -598,7 +598,7 @@ class Db extends Context
|
|
|
598
598
|
|
|
599
599
|
_parseField() {
|
|
600
600
|
let fields = [];
|
|
601
|
-
this.
|
|
601
|
+
this._options.field.forEach(value => {
|
|
602
602
|
let field = value.split(' ');
|
|
603
603
|
let alias = '';
|
|
604
604
|
const length = field.length;
|
|
@@ -620,7 +620,7 @@ class Db extends Context
|
|
|
620
620
|
const logic = ['=', '<>', '!=', '>', '>=', '<', '<=', 'like', 'not like', 'in', 'not in', 'between', 'not between', 'is', 'is not', 'exp'];
|
|
621
621
|
const where = [];
|
|
622
622
|
const params = [];
|
|
623
|
-
this.
|
|
623
|
+
this._options.where.forEach(item => {
|
|
624
624
|
const whereList = item[0];
|
|
625
625
|
const whereLink = (item[1] && item[1].toLowerCase()) === 'or' ? 'or' : 'and';
|
|
626
626
|
let whereChild = '';
|
|
@@ -673,9 +673,9 @@ class Db extends Context
|
|
|
673
673
|
|
|
674
674
|
_parseOrder() {
|
|
675
675
|
let order = '';
|
|
676
|
-
Object.keys(this.
|
|
676
|
+
Object.keys(this._options.order).forEach(key => {
|
|
677
677
|
const field = '`' + key.replace('.', '`.`') + '`';
|
|
678
|
-
const value = this.
|
|
678
|
+
const value = this._options.order[key];
|
|
679
679
|
order += (order ? ',' : 'order by ') + field + (value ? ' ' + value : '');
|
|
680
680
|
});
|
|
681
681
|
return order;
|
|
@@ -684,9 +684,9 @@ class Db extends Context
|
|
|
684
684
|
_parseData() {
|
|
685
685
|
let data = '';
|
|
686
686
|
const params = [];
|
|
687
|
-
Object.keys(this.
|
|
687
|
+
Object.keys(this._options.data).forEach(key => {
|
|
688
688
|
const field = '`' + key.replace('.', '`.`') + '`';
|
|
689
|
-
const value = this.
|
|
689
|
+
const value = this._options.data[key];
|
|
690
690
|
data += (data ? ',' : '') + field + '=';
|
|
691
691
|
if(value instanceof Array) {
|
|
692
692
|
value[0] = value[0].toLowerCase();
|
|
@@ -712,11 +712,11 @@ class Db extends Context
|
|
|
712
712
|
}
|
|
713
713
|
|
|
714
714
|
async _filterData() {
|
|
715
|
-
if(!this.
|
|
716
|
-
return this.
|
|
715
|
+
if(!this._options.allowField) {
|
|
716
|
+
return this._options.data;
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
-
let allowField = this.
|
|
719
|
+
let allowField = this._options.allowField;
|
|
720
720
|
if(allowField === true) {
|
|
721
721
|
const table_name = this._prefix + this._table;
|
|
722
722
|
if(!this._tableField[table_name]) {
|
|
@@ -725,32 +725,28 @@ class Db extends Context
|
|
|
725
725
|
allowField = this._tableField[table_name];
|
|
726
726
|
}
|
|
727
727
|
|
|
728
|
-
Object.keys(this.
|
|
728
|
+
Object.keys(this._options.data).forEach(key => {
|
|
729
729
|
if(!~allowField.indexOf(key)) {
|
|
730
|
-
delete this.
|
|
730
|
+
delete this._options.data[key];
|
|
731
731
|
}
|
|
732
732
|
});
|
|
733
|
-
return this.
|
|
733
|
+
return this._options.data;
|
|
734
734
|
}
|
|
735
735
|
|
|
736
736
|
getCache(key) {
|
|
737
|
-
return
|
|
737
|
+
return Db.cache.get(key);
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
setCache(key, data, cache_time) {
|
|
741
|
-
|
|
741
|
+
Db.cache.set(key, data, cache_time);
|
|
742
742
|
}
|
|
743
743
|
|
|
744
|
-
deleteCache(key) {
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
clearCache(time) {
|
|
749
|
-
this.constructor.cache.clear(time);
|
|
744
|
+
deleteCache(key) {console.log('deleteCache', key);
|
|
745
|
+
Db.cache.delete(key);
|
|
750
746
|
}
|
|
751
747
|
}
|
|
752
748
|
|
|
753
749
|
Db.cache = new (require('./cache'))();
|
|
754
|
-
Db.cache.
|
|
750
|
+
Db.cache.setIntervalTime(20 * 60 * 60);
|
|
755
751
|
|
|
756
752
|
module.exports = Db;
|
package/lib/upload.js
CHANGED
|
@@ -37,7 +37,7 @@ class Upload extends Context
|
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
39
|
const filePath = pt.join(this.$config.app.base_dir, dir, savename);
|
|
40
|
-
await utils.fs.mkdirs(filePath);
|
|
40
|
+
await utils.fs.mkdirs(pt.dirname(filePath));
|
|
41
41
|
const reader = fs.createReadStream(this._file.path);
|
|
42
42
|
const writer = fs.createWriteStream(filePath);
|
|
43
43
|
reader.pipe(writer);
|
package/lib/utils/fs.js
CHANGED
|
@@ -64,23 +64,13 @@ fsFun.isDirSync = (path) => {return fs.existsSync(path) && fs.statSync(path).isD
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
//(多级目录生成)
|
|
67
|
-
fsFun.mkdirs = async function (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
pathtmp = pt.join(pathtmp, dirname);
|
|
75
|
-
} else {
|
|
76
|
-
pathtmp = dirname;
|
|
77
|
-
}
|
|
78
|
-
if(!await fsFun.isDir(pathtmp)) {
|
|
79
|
-
const result = await fsFun.mkdir(pathtmp)
|
|
80
|
-
if (!result) {
|
|
81
|
-
throw result;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
67
|
+
fsFun.mkdirs = async function (dirname) {
|
|
68
|
+
if(await fsFun.isDir(dirname)) {
|
|
69
|
+
return true;
|
|
70
|
+
} else {
|
|
71
|
+
if(await fsFun.mkdirs(pt.dirname(dirname))) {
|
|
72
|
+
await fsFun.mkdir(dirname);
|
|
73
|
+
return true;
|
|
84
74
|
}
|
|
85
75
|
}
|
|
86
76
|
}
|