jj.js 0.20.0 → 1.0.0-rc.2
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 +47 -26
- package/jj.js +1 -1
- package/lib/app.js +10 -2
- package/lib/cache.js +1 -1
- package/lib/config.js +34 -21
- package/lib/controller.js +16 -1
- package/lib/ctx.js +80 -57
- package/lib/db/sqlite.js +28 -2
- package/lib/db.js +64 -34
- package/lib/loader.js +67 -37
- package/lib/model.js +2 -2
- package/lib/mvc.js +34 -60
- package/lib/request.js +25 -13
- package/lib/response.js +1 -1
- package/lib/router.js +42 -19
- package/lib/tpl/types.js +5 -5
- package/lib/types.js +175 -263
- package/lib/url.js +28 -27
- package/lib/utils/escape-html.js +15 -0
- package/lib/utils/internal.js +146 -0
- package/lib/utils/is-class.js +12 -0
- package/lib/utils/libs.js +3 -0
- package/lib/view.js +12 -15
- package/logo.png +0 -0
- package/package.json +8 -10
- package/types.js +21 -5
- package/lib/utils/str.js +0 -21
- package/lib/utils/validate.js +0 -13
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
## 📖 项目介绍
|
|
8
8
|
|
|
9
|
-
jj.js 是一个模仿 ThinkPHP5 设计的轻量级 Node.js MVC 框架。基于 Proxy 实现了**类库自动加载**、**懒加载**和 **Class
|
|
9
|
+
jj.js 是一个模仿 ThinkPHP5 设计的轻量级 Node.js MVC 框架。基于 Proxy 实现了**类库自动加载**、**懒加载**和 **Class 自动实例化及单例化**技术,所有类库想用就能直接调用,系统会自动导入,无需手动 require/import。
|
|
10
|
+
|
|
11
|
+
框架采用**单应用无限子级**架构,在 `app/` 目录下可自由创建任意层级的子模块(如 `app/admin/`、`app/api/`),每个子级拥有独立的 controller、model、middleware 等,子级自动向上继承父级类库。
|
|
10
12
|
|
|
11
13
|
### ✨ 核心特性
|
|
12
14
|
|
|
@@ -16,7 +18,7 @@ jj.js 是一个模仿 ThinkPHP5 设计的轻量级 Node.js MVC 框架。基于 P
|
|
|
16
18
|
| 🔄 **自动加载** | 系统类库、用户类库都支持自动加载、懒加载 |
|
|
17
19
|
| 🎯 **智能实例化** | Class 自动生成单实例,节省内存开销 |
|
|
18
20
|
| 🧩 **三级中间件** | 应用级、路由级、控制器级,方便插件及二次开发 |
|
|
19
|
-
|
|
|
21
|
+
| 🌳 **单应用多级模式** | 单应用架构,支持无限子级分层,模块化更清晰 |
|
|
20
22
|
| 📝 **完整类型提示** | 基于 JSDoc,自动生成应用端 types 类型文件 |
|
|
21
23
|
|
|
22
24
|
### 📍 项目地址
|
|
@@ -84,18 +86,24 @@ node server.js
|
|
|
84
86
|
|
|
85
87
|
```
|
|
86
88
|
project/
|
|
87
|
-
├── app/ #
|
|
89
|
+
├── app/ # 应用目录(根级,不可改名)
|
|
88
90
|
│ ├── controller/ # 控制器目录(可改名)
|
|
89
91
|
│ │ └── index.js # 首页控制器
|
|
90
92
|
│ ├── view/ # 模板目录(可改名)
|
|
91
93
|
│ │ └── index/ # index 控制器模板
|
|
92
94
|
│ │ └── index.htm # 模板文件
|
|
93
|
-
│ ├── middleware/ #
|
|
95
|
+
│ ├── middleware/ # 中间件目录(可改名)
|
|
94
96
|
│ ├── model/ # 模型目录(可改名)
|
|
95
97
|
│ ├── pagination/ # 分页目录(可改名)
|
|
96
98
|
│ ├── logic/ # 逻辑目录(可改名)
|
|
97
|
-
│
|
|
98
|
-
├──
|
|
99
|
+
│ ├── admin/ # 子级模块(示例)
|
|
100
|
+
│ │ ├── controller/ # 子级控制器
|
|
101
|
+
│ │ ├── model/ # 子级模型
|
|
102
|
+
│ │ ├── middleware/ # 子级中间件
|
|
103
|
+
│ │ └── view/ # 子级模板
|
|
104
|
+
│ ├── api/
|
|
105
|
+
│ │ └── controller/ # API 子级控制器
|
|
106
|
+
│ └── ... # 其他自定义目录或子级
|
|
99
107
|
├── config/ # 配置目录(不可改名)
|
|
100
108
|
│ ├── app.js # 应用配置
|
|
101
109
|
│ ├── db.js # 数据库配置
|
|
@@ -117,13 +125,10 @@ project/
|
|
|
117
125
|
| 目录 | 必需 | 说明 |
|
|
118
126
|
|------|------|------|
|
|
119
127
|
| `config/` | ❌ | 应用配置目录,所有配置参数放在这里,可简化为 `config.js` |
|
|
120
|
-
| `app/` | ✅ |
|
|
121
|
-
| `common/` | ❌ | 公共应用目录,存放公共 model、logic 等 |
|
|
128
|
+
| `app/` | ✅ | 应用根目录,支持无限子级分层(如 `app/admin/`、`app/api/`) |
|
|
122
129
|
| `public/` | ❌ | 静态资源目录,在 `config/app.js` 中通过 `static_dir` 配置 |
|
|
123
130
|
| `server.js` | ✅ | 应用入口文件,名字可任意修改 |
|
|
124
131
|
|
|
125
|
-
> **多应用模式**:在 `./config/app.js` 中设置 `app_multi: true` 即可启用。
|
|
126
|
-
|
|
127
132
|
---
|
|
128
133
|
|
|
129
134
|
### 🏛️ 系统类库
|
|
@@ -213,25 +218,42 @@ module.exports = Index;
|
|
|
213
218
|
|
|
214
219
|
**访问**:`http://127.0.0.1:3000/index/user`
|
|
215
220
|
|
|
216
|
-
|
|
221
|
+
#### 加载流程
|
|
217
222
|
|
|
218
223
|
```
|
|
219
224
|
this.$db
|
|
220
225
|
↓
|
|
221
|
-
1.
|
|
222
|
-
↓ (
|
|
223
|
-
2.
|
|
226
|
+
1. 检查当前层级目录 ./app/[deep]/db.js 或 ./app/[deep]/db/
|
|
227
|
+
↓ (没有,向上遍历父级)
|
|
228
|
+
2. 检查父级目录 ./app/db.js 或 ./app/db/
|
|
224
229
|
↓ (没有)
|
|
225
|
-
3.
|
|
226
|
-
↓ (没有)
|
|
227
|
-
4. 检查框架 lib/db.js ✅ 找到!
|
|
230
|
+
3. 检查框架 lib/db.js ✅ 找到!
|
|
228
231
|
↓
|
|
229
232
|
自动实例化(单例)并返回 Db 实例
|
|
230
233
|
```
|
|
231
234
|
|
|
235
|
+
> **向上继承**:子级模块可以访问父级定义的同名类库,自动向上查找最近的定义。系统类库(如 `$db`、`$model` 等)在应用目录找不到时,自动回退到框架内置类库。
|
|
236
|
+
|
|
232
237
|
> **智能实例化**:调用 `this.$db.table('user')` 时,框架先检测是否有 `table` 静态方法,没有则自动 new 实例,然后调用实例方法。
|
|
233
238
|
|
|
234
|
-
#### 示例 2
|
|
239
|
+
#### 示例 2:子级模块
|
|
240
|
+
|
|
241
|
+
在 `app/` 下创建子级目录即可实现模块化分层,每个子级拥有独立的 controller、model、middleware 等:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
app/
|
|
245
|
+
├── controller/index.js # 根级控制器 → /index/index
|
|
246
|
+
├── model/user.js # 根级模型
|
|
247
|
+
├── admin/
|
|
248
|
+
│ ├── controller/index.js # 子级控制器 → /admin/index/index
|
|
249
|
+
│ └── model/admin.js # 子级模型(可覆盖根级同名模型)
|
|
250
|
+
└── api/
|
|
251
|
+
└── controller/index.js # API 控制器 → /api/index/index
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
> **URL 规则**:URL 路径自动映射到子级,如 `/admin/index/index` 对应 `app/admin/controller/index.js` 的 `index` 方法。
|
|
255
|
+
|
|
256
|
+
#### 示例 3:使用自定义模型
|
|
235
257
|
|
|
236
258
|
**模型** `./app/model/user.js`:
|
|
237
259
|
|
|
@@ -270,12 +292,11 @@ async user() {
|
|
|
270
292
|
```javascript
|
|
271
293
|
module.exports = {
|
|
272
294
|
app_debug: false, // 调试模式
|
|
273
|
-
|
|
274
|
-
default_app: 'app', // 默认应用
|
|
295
|
+
default_deep: '', // 默认应用深度(子级路径),为空表示 app 根目录
|
|
275
296
|
default_controller: 'index', // 默认控制器
|
|
276
297
|
default_action: 'index', // 默认方法
|
|
277
|
-
common_app: 'common', // 公共应用
|
|
278
298
|
controller_folder: 'controller', // 控制器目录名
|
|
299
|
+
middleware_folder: 'middleware', // 中间件目录名
|
|
279
300
|
static_dir: '', // 静态文件目录(为空关闭静态访问)
|
|
280
301
|
koa_body: null // koa-body 配置(null 关闭)
|
|
281
302
|
};
|
|
@@ -286,6 +307,11 @@ module.exports = {
|
|
|
286
307
|
```javascript
|
|
287
308
|
module.exports = {
|
|
288
309
|
default: {
|
|
310
|
+
type: 'sqlite',
|
|
311
|
+
database: ':memory:', // 数据库文件绝对路径,支持 :memory: 内存数据库
|
|
312
|
+
prefix: 'jj_'
|
|
313
|
+
},
|
|
314
|
+
mysql: {
|
|
289
315
|
type: 'mysql',
|
|
290
316
|
host: '127.0.0.1',
|
|
291
317
|
database: 'jj',
|
|
@@ -295,11 +321,6 @@ module.exports = {
|
|
|
295
321
|
charset: 'utf8mb4',
|
|
296
322
|
prefix: 'jj_'
|
|
297
323
|
},
|
|
298
|
-
sqlite: {
|
|
299
|
-
type: 'sqlite',
|
|
300
|
-
database: ':memory:',
|
|
301
|
-
prefix: 'jj_'
|
|
302
|
-
},
|
|
303
324
|
mongodb: {
|
|
304
325
|
type: 'mongodb',
|
|
305
326
|
host: '127.0.0.1',
|
package/jj.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* jj.js核心库<br/>
|
|
3
|
-
* {App, Cache, Context, Controller, Cookie, Ctx, Db, Logger, Middleware, Model, Pagination, Request, Response, Upload, Url, View, utils, config}
|
|
3
|
+
* {App, Cache, Context, Controller, Cookie, Ctx, Db, Logger, Middleware, Model, Pagination, Request, Response, Upload, Url, View, utils, config, loader}
|
|
4
4
|
* @module core
|
|
5
5
|
* @type {import('./types').Core}
|
|
6
6
|
*/
|
package/lib/app.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const Koa = require('koa');
|
|
3
|
-
const
|
|
3
|
+
const config = require('./config');
|
|
4
|
+
const {app: cfg_app, cookie: cfg_cookie} = config;
|
|
4
5
|
const loader = require('./loader');
|
|
5
6
|
const Logger = require('./logger');
|
|
6
7
|
const Response = require('./response');
|
|
@@ -46,9 +47,16 @@ class App extends Koa
|
|
|
46
47
|
this.use(async (ctx, next) => {
|
|
47
48
|
ctx.APP_TIME = Date.now();
|
|
48
49
|
ctx.APP_VERSION = pjson.version;
|
|
50
|
+
const _ = loader(cfg_app.base_dir, ctx);
|
|
51
|
+
_.config || (_.config = {});
|
|
52
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
53
|
+
_.config[key] = value;
|
|
54
|
+
});
|
|
49
55
|
await storage.run({
|
|
50
56
|
$: loader(__dirname, ctx),
|
|
51
|
-
_
|
|
57
|
+
$$: _.app,
|
|
58
|
+
$config: _.config,
|
|
59
|
+
DEEP: '', // 初始化,防止后面报错
|
|
52
60
|
}, async() => {
|
|
53
61
|
await next();
|
|
54
62
|
});
|
package/lib/cache.js
CHANGED
package/lib/config.js
CHANGED
|
@@ -4,17 +4,15 @@ const {format} = require('./utils/date');
|
|
|
4
4
|
|
|
5
5
|
const app = {
|
|
6
6
|
app_debug: false, // 调试模式
|
|
7
|
-
app_multi: false, // 是否开启多应用
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
default_deep: '', // 默认应用深度,为空表示app根目录
|
|
10
9
|
default_controller: 'index', //默认控制器
|
|
11
10
|
default_action: 'index', // 默认方法
|
|
12
11
|
|
|
13
|
-
common_app: 'common', // 公共应用,存放公共模型及逻辑
|
|
14
12
|
controller_folder: 'controller', //控制器目录名
|
|
13
|
+
middleware_folder: 'middleware', //中间件目录名
|
|
15
14
|
|
|
16
15
|
static_dir: '', // 静态文件目录,相对于应用根目录,为空时,关闭静态访问
|
|
17
|
-
|
|
18
16
|
koa_body: null // koa-body配置参数,为null或空时,关闭koa-body
|
|
19
17
|
}
|
|
20
18
|
|
|
@@ -22,12 +20,22 @@ const view = {
|
|
|
22
20
|
view_folder: 'view', // 模板目录名
|
|
23
21
|
view_depr: '/', // 模版文件名分割符,'/'代表二级目录
|
|
24
22
|
view_ext: '.htm', // 模版后缀
|
|
25
|
-
view_engine: 'art-template', // 默认模版引擎,字符串或引擎类
|
|
23
|
+
view_engine: '@yafoo/art-template', // 默认模版引擎,字符串或引擎类
|
|
26
24
|
view_filter: {}, // 模版函数
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
const db = {
|
|
30
28
|
default: {
|
|
29
|
+
type : 'sqlite', // 数据库类型
|
|
30
|
+
database : ':memory:', // 数据库文件绝对地址,支持:memory:内存数据库
|
|
31
|
+
prefix : 'jj_' // 数据库表前缀
|
|
32
|
+
},
|
|
33
|
+
sqlite: {
|
|
34
|
+
type : 'sqlite', // 数据库类型
|
|
35
|
+
database : ':memory:', // 数据库文件绝对地址,支持:memory:内存数据库
|
|
36
|
+
prefix : 'jj_' // 数据库表前缀
|
|
37
|
+
},
|
|
38
|
+
mysql: {
|
|
31
39
|
type : 'mysql', // 数据库类型
|
|
32
40
|
host : '127.0.0.1', // 服务器地址
|
|
33
41
|
database : 'jj', // 数据库名
|
|
@@ -37,11 +45,6 @@ const db = {
|
|
|
37
45
|
charset : 'utf8mb4', // 数据库编码默认采用utf8mb4
|
|
38
46
|
prefix : 'jj_' // 数据库表前缀
|
|
39
47
|
},
|
|
40
|
-
sqlite: {
|
|
41
|
-
type : 'sqlite', // 数据库类型
|
|
42
|
-
database : ':memory:', // 数据库文件绝对地址,支持:memory:内存数据库
|
|
43
|
-
prefix : 'jj_' // 数据库表前缀
|
|
44
|
-
},
|
|
45
48
|
mongodb: {
|
|
46
49
|
type : 'mongodb', // 数据库类型
|
|
47
50
|
host : '127.0.0.1', // 服务器地址
|
|
@@ -56,7 +59,7 @@ const db = {
|
|
|
56
59
|
const log = {
|
|
57
60
|
log_level: ['system', 'error'], // [system, error, warning, info, debug, http, sql]
|
|
58
61
|
// @ts-ignore
|
|
59
|
-
log_handle: function(level, ...args) {console
|
|
62
|
+
log_handle: function(level, ...args) {console[level in console ? level : 'log'](`[${format('YY-mm-dd HH:ii:ss')}] [${level}]`, ...args.map(msg => typeof msg == 'object' ? JSON.stringify(msg) : String(msg)));}
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
const cache = {
|
|
@@ -100,20 +103,30 @@ const tpl = {
|
|
|
100
103
|
}
|
|
101
104
|
// @ts-ignore
|
|
102
105
|
const base_dir = require.main.path;
|
|
103
|
-
const
|
|
106
|
+
const {
|
|
107
|
+
app: config_app,
|
|
108
|
+
view: config_view,
|
|
109
|
+
db: config_db,
|
|
110
|
+
log: config_log,
|
|
111
|
+
cache: config_cache,
|
|
112
|
+
page: config_page,
|
|
113
|
+
routes: config_routes,
|
|
114
|
+
cookie: config_cookie,
|
|
115
|
+
tpl: config_tpl
|
|
116
|
+
} = loader(path.join(base_dir, './config')) || {};
|
|
104
117
|
|
|
105
118
|
/**
|
|
106
119
|
* @module config
|
|
107
120
|
* @type {import('../types').Config}
|
|
108
121
|
*/
|
|
109
122
|
module.exports = {
|
|
110
|
-
app: {...app, ...
|
|
111
|
-
view: {...view, ...
|
|
112
|
-
db: {...db, ...
|
|
113
|
-
log: {...log, ...
|
|
114
|
-
cache: {...cache, ...
|
|
115
|
-
page: {...page, ...
|
|
116
|
-
routes:
|
|
117
|
-
cookie: {...cookie, ...
|
|
118
|
-
tpl: {...tpl, ...
|
|
123
|
+
app: {...app, ...config_app, base_dir},
|
|
124
|
+
view: {...view, ...config_view},
|
|
125
|
+
db: {...db, ...config_db},
|
|
126
|
+
log: {...log, ...config_log},
|
|
127
|
+
cache: {...cache, ...config_cache},
|
|
128
|
+
page: {...page, ...config_page},
|
|
129
|
+
routes: config_routes,
|
|
130
|
+
cookie: {...cookie, ...config_cookie},
|
|
131
|
+
tpl: {...tpl, ...config_tpl}
|
|
119
132
|
};
|
package/lib/controller.js
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
const Middleware = require('./middleware');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @typedef {import('../types').
|
|
4
|
+
* @typedef {import('../types').ControllerMiddleware} ControllerMiddleware - Controller中间件
|
|
5
|
+
* @typedef {import('../types').ViewInstance} ViewInstance - View实例
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @extends Middleware
|
|
10
|
+
* @property {ControllerMiddleware[]} [middleware] - 控制器中间件
|
|
9
11
|
*/
|
|
10
12
|
class Controller extends Middleware
|
|
11
13
|
{
|
|
14
|
+
/**
|
|
15
|
+
* 初始化方法,在控制器方法执行前自动执行
|
|
16
|
+
* @protected
|
|
17
|
+
* @returns {any} - 返回Bool值false,则不会执行控制器及后续方法
|
|
18
|
+
*/
|
|
19
|
+
_init() {}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 结束方法,在控制器方法执行后自动执行。如果控制器方法返回Bool值false,则不会执行此方法
|
|
23
|
+
* @protected
|
|
24
|
+
*/
|
|
25
|
+
_end() {}
|
|
26
|
+
|
|
12
27
|
/**
|
|
13
28
|
* 模版数据赋值
|
|
14
29
|
* @public
|
package/lib/ctx.js
CHANGED
|
@@ -1,58 +1,81 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
const storage = require('./storage');
|
|
3
|
-
|
|
4
|
-
const
|
|
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
|
-
|
|
57
|
-
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
const storage = require('./storage');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const {app: cfg_app} = require('./config');
|
|
5
|
+
const libs = require('./utils/libs').filter(lib => lib != 'config'); //排除config
|
|
6
|
+
const {pathToDeep} = require('./utils/internal');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 开发jj.js库本身时,需改为import('../types')
|
|
10
|
+
* type {typeof import('../types')}
|
|
11
|
+
* @type {typeof import('../../../types')}
|
|
12
|
+
*/
|
|
13
|
+
const Ctx = new Proxy(class Ctx {
|
|
14
|
+
_setDeep(mod) {
|
|
15
|
+
this.DEEP = pathToDeep(path.dirname(mod.path), cfg_app.base_dir);
|
|
16
|
+
}
|
|
17
|
+
}, {
|
|
18
|
+
construct() {
|
|
19
|
+
return new Proxy({__proto__: arguments[2].prototype}, {
|
|
20
|
+
get: (target, $prop, receiver) => {
|
|
21
|
+
if($prop in target || typeof $prop == 'symbol' || $prop == 'inspect' || $prop == 'ctx' || $prop == '$next' || $prop == 'DEEP') {
|
|
22
|
+
return Reflect.get(target, $prop, receiver);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const store = storage.getStore();
|
|
26
|
+
if($prop == '$' || $prop == '$$') {
|
|
27
|
+
return store[$prop];
|
|
28
|
+
}
|
|
29
|
+
if($prop.slice(0, 1) != '$') {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const {$, $$, $config, DEEP} = store;
|
|
34
|
+
const prop = $prop.slice(1);
|
|
35
|
+
|
|
36
|
+
const DEEPS = (target.DEEP !== undefined ? target.DEEP : DEEP).split('/').filter(Boolean);
|
|
37
|
+
const $nodes = [];
|
|
38
|
+
|
|
39
|
+
DEEPS.reduce((node, deep) => {
|
|
40
|
+
if(!node) return;
|
|
41
|
+
if(node[deep] && node[deep][prop]) $nodes.unshift(node[deep][prop]);
|
|
42
|
+
return node[deep];
|
|
43
|
+
}, $$);
|
|
44
|
+
|
|
45
|
+
if(prop == 'config' && $config) $nodes.push($config);
|
|
46
|
+
if($$ && $$[prop]) $nodes.push($$[prop]);
|
|
47
|
+
|
|
48
|
+
if(!libs.includes(prop) && !$nodes.length) return undefined;
|
|
49
|
+
if(libs.includes(prop) && !$nodes.length) return $[prop];
|
|
50
|
+
if(!libs.includes(prop) && $nodes.length == 1) return $nodes[0];
|
|
51
|
+
|
|
52
|
+
target[$prop] = new Proxy(function() {}, {
|
|
53
|
+
construct(_, args, newTarget) {
|
|
54
|
+
const node = $nodes.find(node => node.__ISCLASS__)
|
|
55
|
+
|| libs.includes(prop) && $[prop].__ISCLASS__ && $[prop]
|
|
56
|
+
|| undefined;
|
|
57
|
+
return node ? Reflect.construct(node, args, newTarget) : undefined;
|
|
58
|
+
},
|
|
59
|
+
get: (...args) => {
|
|
60
|
+
const node = $nodes.find(node => args[1] in node) || libs.includes(prop) && args[1] in $[prop] && $[prop] || {};
|
|
61
|
+
return Reflect.get(node, args[1], args[2]);
|
|
62
|
+
},
|
|
63
|
+
set: (...args) => {
|
|
64
|
+
const node = $nodes.find(node => args[1] in node);
|
|
65
|
+
if(node) {
|
|
66
|
+
node[args[1]] = args[2];
|
|
67
|
+
} else if(libs.includes(prop)) {
|
|
68
|
+
$[prop][args[1]] = args[2];
|
|
69
|
+
} else {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
return Reflect.get(target, $prop, receiver);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
58
81
|
module.exports = Ctx;
|
package/lib/db/sqlite.js
CHANGED
|
@@ -34,8 +34,34 @@ class Sqlite extends Sql
|
|
|
34
34
|
|
|
35
35
|
let connection = connections.get(this._config);
|
|
36
36
|
if(!connection) {
|
|
37
|
-
const sqlite3 =
|
|
37
|
+
const sqlite3 = require('sqlite3');
|
|
38
|
+
cfg_app.app_debug && sqlite3.verbose();
|
|
38
39
|
connection = new sqlite3.Database(this._config.database);
|
|
40
|
+
|
|
41
|
+
// 性能优化:启用WAL模式,提升读写并发性能
|
|
42
|
+
await new Promise((resolve, reject) => {
|
|
43
|
+
connection.run('PRAGMA journal_mode = WAL;', (err) => {
|
|
44
|
+
if(err) reject(err);
|
|
45
|
+
else resolve();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 性能优化:配合WAL模式,减少不必要的磁盘同步
|
|
50
|
+
await new Promise((resolve, reject) => {
|
|
51
|
+
connection.run('PRAGMA synchronous = NORMAL;', (err) => {
|
|
52
|
+
if(err) reject(err);
|
|
53
|
+
else resolve();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// 性能优化:设置锁等待超时时间,避免并发写入时直接报错
|
|
58
|
+
await new Promise((resolve, reject) => {
|
|
59
|
+
connection.run('PRAGMA busy_timeout = 5000;', (err) => {
|
|
60
|
+
if(err) reject(err);
|
|
61
|
+
else resolve();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
39
65
|
connections.set(this._config, connection);
|
|
40
66
|
this.logger.sql(`SQLITE数据库连接创建成功:{all: ${connections.size}}`);
|
|
41
67
|
}
|
|
@@ -289,4 +315,4 @@ class Sqlite extends Sql
|
|
|
289
315
|
}
|
|
290
316
|
}
|
|
291
317
|
|
|
292
|
-
module.exports = Sqlite;
|
|
318
|
+
module.exports = Sqlite;
|