wok-server 0.1.5 → 0.1.7
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/dist/mvc/handler/json.js +1 -1
- package/dist/mvc/handler/upload.js +1 -3
- package/dist/mysql/manager/ops/criteria.js +16 -4
- package/documentation/zh-cn/engineering.md +57 -4
- package/package.json +1 -1
- package/types/mvc/handler/json.d.ts +9 -2
- package/types/mvc/handler/upload.d.ts +5 -9
- package/types/mysql/manager/ops/criteria.d.ts +6 -0
package/dist/mvc/handler/json.js
CHANGED
|
@@ -27,7 +27,7 @@ function createJsonHandler(opts) {
|
|
|
27
27
|
(0, validation_1.validate)(body, opts.validation);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
const res = await opts.handle(body, exchange);
|
|
30
|
+
const res = await opts.handle(body, { request: exchange.request });
|
|
31
31
|
if (!res) {
|
|
32
32
|
exchange.respond({ statusCode: 200 });
|
|
33
33
|
return;
|
|
@@ -17,10 +17,8 @@ function createUploadHandler(opts) {
|
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
const body = await exchange.bodyBuffer();
|
|
20
|
-
const { url, headers } = exchange.request;
|
|
21
20
|
const res = await opts.handle(body, {
|
|
22
|
-
|
|
23
|
-
headers,
|
|
21
|
+
request: exchange.request,
|
|
24
22
|
query: exchange.parseQueryString()
|
|
25
23
|
});
|
|
26
24
|
if (!res) {
|
|
@@ -102,6 +102,15 @@ class MysqlCriteria {
|
|
|
102
102
|
this.criteria.push({ type: 'in', columnName: column, value: values });
|
|
103
103
|
return this;
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* not in 条件
|
|
107
|
+
* @param column
|
|
108
|
+
* @param values
|
|
109
|
+
*/
|
|
110
|
+
notIn(column, values) {
|
|
111
|
+
this.criteria.push({ type: 'notIn', columnName: column, value: values });
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
105
114
|
/**
|
|
106
115
|
* 嵌入其它的查询条件,与现有的查询条件是或者关系.
|
|
107
116
|
* @param criteria
|
|
@@ -165,12 +174,12 @@ class MysqlCriteria {
|
|
|
165
174
|
if (criterion.type === 'isNull' || criterion.type === 'isNotNull') {
|
|
166
175
|
continue;
|
|
167
176
|
}
|
|
168
|
-
if (criterion.type === 'in') {
|
|
177
|
+
if (criterion.type === 'in' || criterion.type === 'notIn') {
|
|
169
178
|
if (!Array.isArray(criterion.value)) {
|
|
170
|
-
throw new exception_1.MysqlException(`Invalid
|
|
179
|
+
throw new exception_1.MysqlException(`Invalid ${criterion.type} condition,the condition value is not a array type,column name:${criterion.columnName.toString()}`);
|
|
171
180
|
}
|
|
172
181
|
if (!criterion.value.length) {
|
|
173
|
-
throw new exception_1.MysqlException(`Invalid
|
|
182
|
+
throw new exception_1.MysqlException(`Invalid ${criterion.type} condition,the condition value cannot be an empty array,column name:${criterion.columnName.toString()}`);
|
|
174
183
|
}
|
|
175
184
|
continue;
|
|
176
185
|
}
|
|
@@ -230,6 +239,9 @@ class MysqlCriteria {
|
|
|
230
239
|
else if (criterion.type === 'in') {
|
|
231
240
|
sign = 'in';
|
|
232
241
|
}
|
|
242
|
+
else if (criterion.type === 'notIn') {
|
|
243
|
+
sign = 'not in';
|
|
244
|
+
}
|
|
233
245
|
else if (criterion.type === 'like') {
|
|
234
246
|
sign = 'like';
|
|
235
247
|
}
|
|
@@ -237,7 +249,7 @@ class MysqlCriteria {
|
|
|
237
249
|
sign = 'not like';
|
|
238
250
|
}
|
|
239
251
|
if (sign) {
|
|
240
|
-
if (criterion.type === 'in') {
|
|
252
|
+
if (criterion.type === 'in' || criterion.type === 'notIn') {
|
|
241
253
|
sqlFragments.push(`and ?? ${sign} (?) `);
|
|
242
254
|
}
|
|
243
255
|
else {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
│ │ ├──create-tag.ts 创建标签接口(/tag/create)
|
|
34
34
|
│ │ ├──delete-tag.ts 删除标签接口(/tag/delete)
|
|
35
35
|
│ │ └──index.ts 包入口文件,导出需要导出的模块
|
|
36
|
+
│ ├──exception.ts 全局异常
|
|
36
37
|
│ └──main.ts 入口文件,启动服务,配置路由
|
|
37
38
|
├──.env 开发环境变量配置
|
|
38
39
|
├──package.json
|
|
@@ -42,12 +43,64 @@
|
|
|
42
43
|
|
|
43
44
|
## 文件说明
|
|
44
45
|
|
|
46
|
+
exception.ts 这个文件中包含了自定义的业务异常,以及异常的处理拦截器。
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
/**
|
|
50
|
+
* 自定义业务异常.
|
|
51
|
+
*/
|
|
52
|
+
export class BusinessException {
|
|
53
|
+
constructor(
|
|
54
|
+
/**
|
|
55
|
+
* 提示信息.
|
|
56
|
+
*/
|
|
57
|
+
readonly message: string,
|
|
58
|
+
/**
|
|
59
|
+
* 自定义状态码,默认 400
|
|
60
|
+
*/
|
|
61
|
+
readonly status?: number
|
|
62
|
+
) {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 全局异常拦截器,对一些特定的异常做处理,给予合适的响应信息.
|
|
67
|
+
* @param exchange
|
|
68
|
+
* @param next
|
|
69
|
+
*/
|
|
70
|
+
export async function globalErrorInterceptor(
|
|
71
|
+
exchange: ServerExchange,
|
|
72
|
+
next: () => Promise<void>
|
|
73
|
+
): Promise<void> {
|
|
74
|
+
try {
|
|
75
|
+
await next()
|
|
76
|
+
} catch (e) {
|
|
77
|
+
// 处理自定义业务异常
|
|
78
|
+
if (e instanceof BusinessException) {
|
|
79
|
+
const status = typeof e.status === 'number' ? e.status : 400
|
|
80
|
+
const message = e.message || ''
|
|
81
|
+
exchange.respondErrMsg(message, status)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
// 校验异常
|
|
85
|
+
if (e instanceof ValidationException) {
|
|
86
|
+
exchange.respondErrMsg(`${e.propertyPath}:${e.errMsg}`, 400)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
// 其它异常直接抛出,框架默认会响应 500 状态码
|
|
90
|
+
throw e
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
使用自定义业务异常,在业务无法进行的情况下抛出异常中止请求处理,事务的处理过程中遇到异常也会进行回滚,这是推荐的做法。
|
|
96
|
+
|
|
45
97
|
main.ts 示例:
|
|
46
98
|
|
|
47
99
|
```ts
|
|
48
100
|
import { createAuth, authInterceptor, ccuTask } from './auth'
|
|
49
101
|
import { createUser, updateUser, deleteUser } from './user'
|
|
50
102
|
import { createTag, deleteTag } from './tag'
|
|
103
|
+
import { globalErrorInterceptor } from './exception'
|
|
51
104
|
|
|
52
105
|
async function main() {
|
|
53
106
|
// 改写 date 原型,将日期序列化为数字
|
|
@@ -77,7 +130,7 @@ async function main() {
|
|
|
77
130
|
'/tag/delete': deleteTag
|
|
78
131
|
},
|
|
79
132
|
// 拦截器
|
|
80
|
-
interceptors: [authInterceptor]
|
|
133
|
+
interceptors: [globalErrorInterceptor, authInterceptor]
|
|
81
134
|
})
|
|
82
135
|
// 周期性任务
|
|
83
136
|
// 每60秒统计一次在线人数
|
|
@@ -194,9 +247,9 @@ export const createUser = createJsonHandler<Form, Resp>({
|
|
|
194
247
|
async handle(body, exchange) {
|
|
195
248
|
const manager = getMysqlManager()
|
|
196
249
|
if (await manager.existsBy(tableUser, { code: body.code })) {
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
250
|
+
// 抛出异常,中止处理
|
|
251
|
+
// 异常最终会由拦截器来处理并响应
|
|
252
|
+
throw new BusinessException('编号已经存在')
|
|
200
253
|
}
|
|
201
254
|
const newUser = await manager.insert(tableUser, body)
|
|
202
255
|
return { id: newUser.id }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wok-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"packageManager": "pnpm@8.9.0",
|
|
5
5
|
"description": "一个基于 NodeJs 和 TypeScript 的后端框架,轻量级、克制、简洁。A lightweight, restrained, and concise backend framework based on Node.js and TypeScript.",
|
|
6
6
|
"scripts": {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingMessage } from 'http';
|
|
1
3
|
import { ValidationOpts } from '../../validation';
|
|
2
|
-
import { ServerExchange } from '../exchange';
|
|
3
4
|
import { RouterHandler } from '../router';
|
|
5
|
+
export interface JsonHandlerExchange {
|
|
6
|
+
/**
|
|
7
|
+
* 请求信息
|
|
8
|
+
*/
|
|
9
|
+
request: IncomingMessage;
|
|
10
|
+
}
|
|
4
11
|
/**
|
|
5
12
|
* 创建 json 处理器..
|
|
6
13
|
* @param <REQ> 表示请求的 json 数据格式类型
|
|
@@ -19,5 +26,5 @@ export declare function createJsonHandler<REQ, RES = void>(opts: {
|
|
|
19
26
|
* @param exchange 请求传输对象,用于获取请求的基本信息
|
|
20
27
|
* @returns
|
|
21
28
|
*/
|
|
22
|
-
handle: (body: REQ, exchange:
|
|
29
|
+
handle: (body: REQ, exchange: JsonHandlerExchange) => Promise<RES>;
|
|
23
30
|
}): RouterHandler;
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import {
|
|
3
|
+
import { IncomingMessage } from 'http';
|
|
4
4
|
import { QueryString } from '../query';
|
|
5
5
|
import { RouterHandler } from '../router';
|
|
6
6
|
/**
|
|
7
7
|
* 上传请求传输对象.
|
|
8
8
|
*/
|
|
9
|
-
export interface
|
|
9
|
+
export interface UploadHandlerExchange {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* 请求信息
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 请求头
|
|
16
|
-
*/
|
|
17
|
-
headers: IncomingHttpHeaders;
|
|
13
|
+
request: IncomingMessage;
|
|
18
14
|
/**
|
|
19
15
|
* querystring 解析结果
|
|
20
16
|
*/
|
|
@@ -36,5 +32,5 @@ export declare function createUploadHandler<RES = void>(opts: {
|
|
|
36
32
|
* @param exchange 请求传输对象,用于获取请求的基本信息
|
|
37
33
|
* @returns
|
|
38
34
|
*/
|
|
39
|
-
handle: (body: Buffer, exchange:
|
|
35
|
+
handle: (body: Buffer, exchange: UploadHandlerExchange) => Promise<RES>;
|
|
40
36
|
}): RouterHandler;
|
|
@@ -72,6 +72,12 @@ export declare class MysqlCriteria<T> {
|
|
|
72
72
|
* @param values
|
|
73
73
|
*/
|
|
74
74
|
in(column: keyof T, values: Array<string | number>): this;
|
|
75
|
+
/**
|
|
76
|
+
* not in 条件
|
|
77
|
+
* @param column
|
|
78
|
+
* @param values
|
|
79
|
+
*/
|
|
80
|
+
notIn(column: keyof T, values: Array<string | number>): this;
|
|
75
81
|
/**
|
|
76
82
|
* 嵌入其它的查询条件,与现有的查询条件是或者关系.
|
|
77
83
|
* @param criteria
|