chanjs 1.2.3 → 1.2.5
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/core/config.js +1 -1
- package/core/helper.js +6 -1
- package/core/lib/controller.js +29 -0
- package/core/lib/service.js +160 -100
- package/index.js +1 -1
- package/package.json +3 -2
package/core/config.js
CHANGED
package/core/helper.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import knex from 'knex';
|
2
|
+
import merge from 'deepmerge';
|
2
3
|
|
3
4
|
/**
|
4
5
|
* @description 实例化一个类,并将该类的所有方法绑定到一个新的对象上。
|
@@ -97,4 +98,8 @@ export const zodValidator = (schemas) => (req, res, next) => {
|
|
97
98
|
req[key] = result.data;
|
98
99
|
}
|
99
100
|
next();
|
100
|
-
};
|
101
|
+
};
|
102
|
+
|
103
|
+
|
104
|
+
// 重新导出 deepmerge 的命名导出
|
105
|
+
export { default as merge } from 'deepmerge';
|
package/core/lib/controller.js
CHANGED
@@ -23,5 +23,34 @@ export default class Controller {
|
|
23
23
|
return result;
|
24
24
|
}
|
25
25
|
|
26
|
+
success(data) {
|
27
|
+
return {
|
28
|
+
success: true,
|
29
|
+
msg: '操作成功',
|
30
|
+
code: 200,
|
31
|
+
data
|
32
|
+
};
|
33
|
+
}
|
34
|
+
|
35
|
+
fail(data, code = 201) {
|
36
|
+
return {
|
37
|
+
success: false,
|
38
|
+
msg: '操作失败',
|
39
|
+
code,
|
40
|
+
data
|
41
|
+
};
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
err(data={}, code = 500){
|
46
|
+
return {
|
47
|
+
success: false,
|
48
|
+
msg: '系统异常',
|
49
|
+
code,
|
50
|
+
data
|
51
|
+
};
|
52
|
+
}
|
53
|
+
|
54
|
+
|
26
55
|
|
27
56
|
}
|
package/core/lib/service.js
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
const errCode = {
|
2
|
+
"ECONNREFUSED": "数据库连接被拒绝,请检查数据库服务是否正常运行。",
|
3
|
+
"ER_ACCESS_DENIED_ERROR": "无权限访问,账号或密码错误。",
|
4
|
+
"ER_ROW_IS_REFERENCED_2": "无法删除或更新记录,存在关联数据。",
|
5
|
+
"ER_BAD_FIELD_ERROR": "SQL语句中包含无效字段,请检查查询条件或列名。",
|
6
|
+
"ER_DUP_ENTRY": "插入失败:数据重复,违反唯一性约束。",
|
7
|
+
"ER_NO_SUCH_TABLE": "操作失败:目标表不存在。",
|
8
|
+
"ETIMEOUT": "数据库操作超时,请稍后再试。"
|
9
|
+
}
|
10
|
+
const getDefaultErrorMessage = (error) => {
|
11
|
+
if (error.message.includes('syntax') ||
|
12
|
+
error.message.includes('SQL')) {
|
13
|
+
return '数据库语法错误,请检查您的查询语句。';
|
14
|
+
} else if (error.message.includes('Connection closed')) {
|
15
|
+
return '数据库连接已关闭,请重试。';
|
16
|
+
} else if (error.message.includes('permission')) {
|
17
|
+
return '数据库权限不足,请检查配置。';
|
18
|
+
}
|
19
|
+
return '数据库发生未知错误,请稍后重试。';
|
20
|
+
}
|
21
|
+
|
1
22
|
class BaseService {
|
2
23
|
/**
|
3
24
|
* @description 构造函数
|
@@ -10,15 +31,21 @@ class BaseService {
|
|
10
31
|
}
|
11
32
|
|
12
33
|
/**
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
all(query = {}) {
|
18
|
-
|
19
|
-
|
34
|
+
* @description 查询表所有记录,慎用
|
35
|
+
* @param {Object} query - 包含查询参数的对象
|
36
|
+
* @returns {Promise} 返回所有记录
|
37
|
+
*/
|
38
|
+
async all(query = {}) {
|
39
|
+
try {
|
40
|
+
let dbQuery = this.DB(this.model);
|
41
|
+
if (Object.keys(query).length > 0) {
|
42
|
+
dbQuery = dbQuery.where(query);
|
43
|
+
}
|
44
|
+
let res = await dbQuery.select();
|
45
|
+
return this.success(res);
|
46
|
+
} catch (err) {
|
47
|
+
return this.error(err);
|
20
48
|
}
|
21
|
-
return this.DB(this.model).where(query).select();
|
22
49
|
}
|
23
50
|
|
24
51
|
/**
|
@@ -31,22 +58,22 @@ class BaseService {
|
|
31
58
|
* @returns {Promise} 返回匹配条件的记录或记录列表
|
32
59
|
*/
|
33
60
|
async findById({ query, field = [], len = 1 }) {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
61
|
+
try {
|
62
|
+
let dataQuery = this.DB(this.model).where(query);
|
63
|
+
if (field.length > 0) {
|
64
|
+
dataQuery = dataQuery.select(field);
|
65
|
+
}
|
66
|
+
if (len === 1) {
|
67
|
+
dataQuery = dataQuery.first();
|
68
|
+
} else if (len > 1) {
|
69
|
+
dataQuery = dataQuery.limit(len);
|
70
|
+
}
|
71
|
+
let res = await dataQuery;
|
72
|
+
console.log('111',res);
|
73
|
+
return this.success(res || (len === 1 ? {} : []));
|
74
|
+
} catch (err) {
|
75
|
+
return this.error(err);
|
46
76
|
}
|
47
|
-
let res = await dataQuery;
|
48
|
-
//返回结果 undefined 则返回空数组或空对象
|
49
|
-
return res || (len === 1 ? {} : []);
|
50
77
|
}
|
51
78
|
|
52
79
|
|
@@ -56,11 +83,15 @@ class BaseService {
|
|
56
83
|
* @returns {Promise<boolean>} 返回操作是否成功
|
57
84
|
*/
|
58
85
|
async insert(data = {}) {
|
59
|
-
|
60
|
-
|
86
|
+
try {
|
87
|
+
if (Object.keys(data).length === 0) {
|
88
|
+
return this.fail('插入数据不能为空');
|
89
|
+
}
|
90
|
+
const result = await this.DB(this.model).insert(data);
|
91
|
+
return this.success(result?.length > 0 || !!result)
|
92
|
+
} catch (err) {
|
93
|
+
return this.error(err); // 假设你有 this.error() 的封装
|
61
94
|
}
|
62
|
-
const result = await this.DB(this.model).insert(data);
|
63
|
-
return result?.length > 0 || !!result;
|
64
95
|
}
|
65
96
|
|
66
97
|
/**
|
@@ -69,17 +100,15 @@ class BaseService {
|
|
69
100
|
* @returns {Promise<Array|Number>} 返回插入后的记录或受影响行数,具体取决于数据库驱动
|
70
101
|
*/
|
71
102
|
async insertMany(records = []) {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
103
|
+
try {
|
104
|
+
if (records.length === 0) {
|
105
|
+
return this.fail('插入数据不能为空');
|
106
|
+
}
|
107
|
+
const result = await this.DB(this.model).insert(records);
|
108
|
+
return this.success(result)
|
109
|
+
} catch (err) {
|
110
|
+
return this.error(err); // 假设你有 this.error() 的封装
|
76
111
|
}
|
77
|
-
|
78
|
-
// 执行插入操作并获取结果
|
79
|
-
const result = await this.DB(this.model).insert(records);
|
80
|
-
|
81
|
-
// 返回插入的结果
|
82
|
-
return result;
|
83
112
|
}
|
84
113
|
|
85
114
|
/**
|
@@ -88,63 +117,63 @@ class BaseService {
|
|
88
117
|
* @returns {Promise<boolean>} 返回操作是否成功(即是否有任何记录被删除)
|
89
118
|
*/
|
90
119
|
async delete(query = {}) {
|
91
|
-
|
92
|
-
|
120
|
+
try {
|
121
|
+
if (Object.keys(query).length === 0) {
|
122
|
+
return this.error("请指定删除条件");
|
123
|
+
}
|
124
|
+
const affectedRows = await this.DB(this.model).where(query).del();
|
125
|
+
return this.success(affectedRows > 0);
|
126
|
+
} catch (err) {
|
127
|
+
return this.error(err); // 假设你有 this.error() 的封装
|
93
128
|
}
|
94
|
-
const affectedRows = await this.DB(this.model).where(query).del();
|
95
|
-
return affectedRows > 0;
|
96
129
|
}
|
97
130
|
/**
|
98
131
|
* @description 根据指定条件更新记录
|
99
132
|
* @param {Object} query - 查询条件
|
100
|
-
* @param {
|
101
|
-
* @returns {Promise<boolean>}
|
133
|
+
* @param {Object} params - 要更新的数据
|
134
|
+
* @returns {Promise<boolean>} 返回操作是否成功(是否有行被更新)
|
102
135
|
*/
|
103
136
|
async update({ query, params } = {}) {
|
104
|
-
|
105
|
-
|
137
|
+
try {
|
138
|
+
console.log('update--->',query, params)
|
139
|
+
if (!query || !params || Object.keys(query).length === 0) {
|
140
|
+
return this.fail("参数错误");
|
141
|
+
}
|
142
|
+
const result = await this.DB(this.model).where(query).update(params);
|
143
|
+
return this.success(!!result);
|
144
|
+
} catch (err) {
|
145
|
+
return this.error(err); // 假设你有 this.error() 的封装
|
146
|
+
}
|
106
147
|
}
|
107
148
|
|
108
|
-
|
109
149
|
/**
|
110
150
|
* @description 批量更新多条记录(基于事务保证原子性)
|
111
|
-
* @param {Array<{query: Object, params: Object}>} updates -
|
112
|
-
* @returns {Promise<
|
151
|
+
* @param {Array<{query: Object, params: Object}>} updates - 更新操作数组
|
152
|
+
* @returns {Promise<boolean>} 返回是否所有记录都更新成功
|
113
153
|
*/
|
114
154
|
async updateMany(updates = []) {
|
115
|
-
// 参数合法性校验
|
116
155
|
if (!Array.isArray(updates)) {
|
117
|
-
|
156
|
+
return this.fail('参数必须为数组格式');
|
118
157
|
}
|
119
|
-
|
120
158
|
// 获取事务对象
|
121
159
|
const trx = await this.DB.transaction();
|
122
|
-
|
123
160
|
try {
|
124
|
-
const affectedRows = [];
|
125
|
-
// 循环处理每个更新操作
|
126
161
|
for (const { query, params } of updates) {
|
127
|
-
|
128
|
-
|
129
|
-
.
|
130
|
-
.
|
131
|
-
|
162
|
+
const result = await trx(this.model).where(query).update(params);
|
163
|
+
if (result === 0) {
|
164
|
+
await trx.rollback(); // 有一条失败就回滚
|
165
|
+
return this.fail('更新失败');
|
166
|
+
}
|
132
167
|
}
|
133
|
-
|
168
|
+
|
134
169
|
await trx.commit();
|
135
|
-
|
136
|
-
return { affectedRows };
|
170
|
+
return this.success(true);
|
137
171
|
} catch (err) {
|
138
|
-
// 回滚事务
|
139
172
|
await trx.rollback();
|
140
|
-
|
141
|
-
throw err;
|
173
|
+
return this.error(error);
|
142
174
|
}
|
143
175
|
}
|
144
176
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
177
|
/**
|
149
178
|
* 查找所有符合条件的记录,并提供分页信息。
|
150
179
|
* @param {Object} options - 包含查询参数的对象
|
@@ -155,28 +184,29 @@ class BaseService {
|
|
155
184
|
* @returns {Promise<Object>} 返回包含数据列表、总记录数、当前页、每页大小的对象
|
156
185
|
*/
|
157
186
|
async query({ current = 1, pageSize = 10, query = {}, field = [] }) {
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
Object.
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
//字段筛选
|
170
|
-
if (field.length > 0) {
|
171
|
-
dataQuery = dataQuery.select(field);
|
172
|
-
}
|
173
|
-
|
174
|
-
//并行执行获取总记录数和分页数据的查询
|
175
|
-
const [totalResult, list] = await Promise.all([countQuery.first(), dataQuery.offset(offset).limit(pageSize)]);
|
176
|
-
// 提取总记录数
|
177
|
-
const total = totalResult?.total || 0;
|
187
|
+
try {
|
188
|
+
const offset = (current - 1) * pageSize;
|
189
|
+
let countQuery = this.DB(this.model).count("* as total");
|
190
|
+
let dataQuery = this.DB(this.model);
|
191
|
+
// 应用查询条件
|
192
|
+
if (Object.keys(query).length > 0) {
|
193
|
+
Object.entries(query).forEach(([key, value]) => {
|
194
|
+
dataQuery = dataQuery.where(key, value);
|
195
|
+
countQuery = countQuery.where(key, value);
|
196
|
+
})
|
197
|
+
}
|
178
198
|
|
179
|
-
|
199
|
+
//字段筛选
|
200
|
+
if (field.length > 0) {
|
201
|
+
dataQuery = dataQuery.select(field);
|
202
|
+
}
|
203
|
+
//并行执行获取总记录数和分页数据的查询
|
204
|
+
const [totalResult, list] = await Promise.all([countQuery.first(), dataQuery.offset(offset).limit(pageSize)]);
|
205
|
+
// 提取总记录数
|
206
|
+
const total = totalResult?.total || 0;
|
207
|
+
return this.success({ list, total, current, pageSize });
|
208
|
+
} catch (err) { }
|
209
|
+
return this.error(err);
|
180
210
|
}
|
181
211
|
|
182
212
|
|
@@ -186,24 +216,54 @@ class BaseService {
|
|
186
216
|
* @returns {Promise<number>} 返回符合条件的记录数量
|
187
217
|
*/
|
188
218
|
async count(query = []) {
|
189
|
-
|
190
|
-
|
191
|
-
query.
|
192
|
-
|
193
|
-
|
219
|
+
try {
|
220
|
+
let dataQuery = this.DB(this.model);
|
221
|
+
if (query.length > 0) {
|
222
|
+
query.forEach((condition) => {
|
223
|
+
dataQuery = dataQuery.where(condition);
|
224
|
+
});
|
225
|
+
}
|
226
|
+
const result = await dataQuery.count("* as total").first();
|
227
|
+
return this.success(result?.total || 0);
|
228
|
+
} catch (error) {
|
229
|
+
return this.error(error);
|
194
230
|
}
|
195
|
-
const result = await dataQuery.count("* as total").first();
|
196
|
-
return result.total || 0;
|
197
231
|
}
|
198
232
|
|
233
|
+
|
199
234
|
error(err) {
|
200
|
-
console.error(err);
|
235
|
+
console.error('-->',err);
|
236
|
+
// 从映射表中查找对应的错误信息
|
237
|
+
const message = errCode[err.code] || getDefaultErrorMessage(err);
|
201
238
|
return {
|
202
|
-
|
203
|
-
msg:
|
204
|
-
|
239
|
+
success: false,
|
240
|
+
msg: message,
|
241
|
+
code: 500, // 或者根据错误类型区分
|
242
|
+
data: {
|
243
|
+
sql: err.sql,
|
244
|
+
sqlMessage: err.sqlMessage
|
245
|
+
}
|
205
246
|
};
|
206
247
|
}
|
207
248
|
|
249
|
+
fail(msg = "操作失败", data = {}) {
|
250
|
+
console.error(msg);
|
251
|
+
return {
|
252
|
+
success: false,
|
253
|
+
msg,
|
254
|
+
code: 201, // 或者根据错误类型区分
|
255
|
+
data: data
|
256
|
+
}
|
257
|
+
}
|
258
|
+
|
259
|
+
success(data = {}, msg = "操作成功") {
|
260
|
+
return {
|
261
|
+
success: true,
|
262
|
+
msg,
|
263
|
+
code: 200,
|
264
|
+
data
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
208
268
|
}
|
209
269
|
export default BaseService;
|
package/index.js
CHANGED
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"type": "module",
|
3
3
|
"name": "chanjs",
|
4
|
-
"version": "1.2.
|
4
|
+
"version": "1.2.5",
|
5
5
|
"description": "chanjs基于express5 纯js研发的轻量级mvc框架。",
|
6
6
|
"main": "index.js",
|
7
7
|
"module": "index.js",
|
@@ -29,6 +29,7 @@
|
|
29
29
|
"knex": "^3.1.0",
|
30
30
|
"morgan": "^1.10.0",
|
31
31
|
"mysql2": "^3.14.1",
|
32
|
-
"schedule": "^0.5.0"
|
32
|
+
"schedule": "^0.5.0",
|
33
|
+
"deepmerge": "^4.3.1"
|
33
34
|
}
|
34
35
|
}
|