wok-server 0.1.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/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/cache/cache.js +94 -0
- package/dist/cache/config.js +19 -0
- package/dist/cache/index.js +27 -0
- package/dist/cache/purge-task.js +56 -0
- package/dist/cache/stat.js +47 -0
- package/dist/config/convert.js +36 -0
- package/dist/config/exception.js +14 -0
- package/dist/config/index.js +67 -0
- package/dist/http-client/index.js +132 -0
- package/dist/i18n/ar.js +17 -0
- package/dist/i18n/de.js +17 -0
- package/dist/i18n/en-us.js +17 -0
- package/dist/i18n/es.js +17 -0
- package/dist/i18n/fr.js +17 -0
- package/dist/i18n/i18n.js +231 -0
- package/dist/i18n/index.js +52 -0
- package/dist/i18n/ja.js +17 -0
- package/dist/i18n/ko.js +17 -0
- package/dist/i18n/msg.js +2 -0
- package/dist/i18n/pt.js +17 -0
- package/dist/i18n/ru.js +17 -0
- package/dist/i18n/tag.js +18 -0
- package/dist/i18n/zh-HK.js +17 -0
- package/dist/i18n/zh-TW.js +17 -0
- package/dist/i18n/zh-cn.js +17 -0
- package/dist/index.js +13 -0
- package/dist/log/config.js +28 -0
- package/dist/log/date.js +21 -0
- package/dist/log/file.js +79 -0
- package/dist/log/index.js +109 -0
- package/dist/log/level.js +39 -0
- package/dist/log/store.js +16 -0
- package/dist/mongodb/collection.js +2 -0
- package/dist/mongodb/config.js +34 -0
- package/dist/mongodb/doc.js +2 -0
- package/dist/mongodb/exception.js +14 -0
- package/dist/mongodb/index.js +58 -0
- package/dist/mongodb/manager/base.js +563 -0
- package/dist/mongodb/manager/index.js +63 -0
- package/dist/mongodb/manager/tx-strict.js +84 -0
- package/dist/mongodb/manager/tx.js +30 -0
- package/dist/mongodb/migration.js +52 -0
- package/dist/mvc/access-log.js +31 -0
- package/dist/mvc/config.js +20 -0
- package/dist/mvc/exchange.js +113 -0
- package/dist/mvc/handler/index.js +6 -0
- package/dist/mvc/handler/json.js +33 -0
- package/dist/mvc/handler/restful.js +35 -0
- package/dist/mvc/handler/upload.js +33 -0
- package/dist/mvc/index.js +316 -0
- package/dist/mvc/interceptor.js +2 -0
- package/dist/mvc/query.js +43 -0
- package/dist/mvc/render/file.js +177 -0
- package/dist/mvc/render/html/html.js +90 -0
- package/dist/mvc/render/html/index.js +18 -0
- package/dist/mvc/render/html/style.js +2 -0
- package/dist/mvc/render/index.js +7 -0
- package/dist/mvc/render/json.js +26 -0
- package/dist/mvc/render/text.js +16 -0
- package/dist/mvc/router.js +2 -0
- package/dist/mysql/config.js +49 -0
- package/dist/mysql/exception.js +14 -0
- package/dist/mysql/index.js +85 -0
- package/dist/mysql/manager/base.js +233 -0
- package/dist/mysql/manager/index.js +107 -0
- package/dist/mysql/manager/ops/count.js +20 -0
- package/dist/mysql/manager/ops/criteria.js +326 -0
- package/dist/mysql/manager/ops/delete.js +65 -0
- package/dist/mysql/manager/ops/exist.js +26 -0
- package/dist/mysql/manager/ops/find.js +111 -0
- package/dist/mysql/manager/ops/index.js +14 -0
- package/dist/mysql/manager/ops/insert.js +101 -0
- package/dist/mysql/manager/ops/modify.js +10 -0
- package/dist/mysql/manager/ops/paginate.js +23 -0
- package/dist/mysql/manager/ops/query.js +9 -0
- package/dist/mysql/manager/ops/update.js +201 -0
- package/dist/mysql/manager/tx-strict.js +98 -0
- package/dist/mysql/manager/tx.js +30 -0
- package/dist/mysql/manager/utils.js +56 -0
- package/dist/mysql/migration.js +136 -0
- package/dist/mysql/table-info.js +8 -0
- package/dist/task/daily.js +58 -0
- package/dist/task/fixed-delay.js +33 -0
- package/dist/task/fixed-rate.js +37 -0
- package/dist/task/index.js +9 -0
- package/dist/task/task.js +39 -0
- package/dist/validation/exception.js +44 -0
- package/dist/validation/index.js +29 -0
- package/dist/validation/validator/array.js +38 -0
- package/dist/validation/validator/enum.js +28 -0
- package/dist/validation/validator/index.js +14 -0
- package/dist/validation/validator/length.js +40 -0
- package/dist/validation/validator/max-length.js +35 -0
- package/dist/validation/validator/max.js +29 -0
- package/dist/validation/validator/min-length.js +33 -0
- package/dist/validation/validator/min.js +29 -0
- package/dist/validation/validator/not-blank.js +33 -0
- package/dist/validation/validator/not-null.js +21 -0
- package/dist/validation/validator/plain-obj.js +32 -0
- package/dist/validation/validator/regexp.js +30 -0
- package/documentation/en/index.md +1 -0
- package/documentation/zh-cn/cache.md +59 -0
- package/documentation/zh-cn/config.md +68 -0
- package/documentation/zh-cn/http-client.md +33 -0
- package/documentation/zh-cn/i18n.md +154 -0
- package/documentation/zh-cn/index.md +25 -0
- package/documentation/zh-cn/log.md +40 -0
- package/documentation/zh-cn/mongodb.md +262 -0
- package/documentation/zh-cn/mvc.md +430 -0
- package/documentation/zh-cn/mysql.md +389 -0
- package/documentation/zh-cn/task.md +50 -0
- package/documentation/zh-cn/test.md +57 -0
- package/documentation/zh-cn/validate.md +125 -0
- package/package.json +46 -0
- package/types/cache/cache.d.ts +52 -0
- package/types/cache/config.d.ts +32 -0
- package/types/cache/index.d.ts +2 -0
- package/types/cache/purge-task.d.ts +11 -0
- package/types/cache/stat.d.ts +26 -0
- package/types/config/convert.d.ts +6 -0
- package/types/config/exception.d.ts +7 -0
- package/types/config/index.d.ts +15 -0
- package/types/http-client/index.d.ts +71 -0
- package/types/i18n/ar.d.ts +2 -0
- package/types/i18n/de.d.ts +2 -0
- package/types/i18n/en-us.d.ts +2 -0
- package/types/i18n/es.d.ts +2 -0
- package/types/i18n/fr.d.ts +2 -0
- package/types/i18n/i18n.d.ts +102 -0
- package/types/i18n/index.d.ts +9 -0
- package/types/i18n/ja.d.ts +2 -0
- package/types/i18n/ko.d.ts +2 -0
- package/types/i18n/msg.d.ts +50 -0
- package/types/i18n/pt.d.ts +2 -0
- package/types/i18n/ru.d.ts +2 -0
- package/types/i18n/tag.d.ts +11 -0
- package/types/i18n/zh-HK.d.ts +2 -0
- package/types/i18n/zh-TW.d.ts +2 -0
- package/types/i18n/zh-cn.d.ts +2 -0
- package/types/index.d.ts +10 -0
- package/types/log/config.d.ts +27 -0
- package/types/log/date.d.ts +2 -0
- package/types/log/file.d.ts +5 -0
- package/types/log/index.d.ts +34 -0
- package/types/log/level.d.ts +15 -0
- package/types/log/store.d.ts +12 -0
- package/types/mongodb/collection.d.ts +25 -0
- package/types/mongodb/config.d.ts +45 -0
- package/types/mongodb/doc.d.ts +11 -0
- package/types/mongodb/exception.d.ts +7 -0
- package/types/mongodb/index.d.ts +29 -0
- package/types/mongodb/manager/base.d.ts +188 -0
- package/types/mongodb/manager/index.d.ts +38 -0
- package/types/mongodb/manager/tx-strict.d.ts +41 -0
- package/types/mongodb/manager/tx.d.ts +21 -0
- package/types/mongodb/migration.d.ts +12 -0
- package/types/mvc/access-log.d.ts +7 -0
- package/types/mvc/config.d.ts +30 -0
- package/types/mvc/exchange.d.ts +72 -0
- package/types/mvc/handler/index.d.ts +3 -0
- package/types/mvc/handler/json.d.ts +23 -0
- package/types/mvc/handler/restful.d.ts +11 -0
- package/types/mvc/handler/upload.d.ts +40 -0
- package/types/mvc/index.d.ts +49 -0
- package/types/mvc/interceptor.d.ts +11 -0
- package/types/mvc/query.d.ts +13 -0
- package/types/mvc/render/file.d.ts +10 -0
- package/types/mvc/render/html/html.d.ts +98 -0
- package/types/mvc/render/html/index.d.ts +11 -0
- package/types/mvc/render/html/style.d.ts +1201 -0
- package/types/mvc/render/index.d.ts +4 -0
- package/types/mvc/render/json.d.ts +17 -0
- package/types/mvc/render/text.d.ts +10 -0
- package/types/mvc/router.d.ts +11 -0
- package/types/mysql/config.d.ts +86 -0
- package/types/mysql/exception.d.ts +7 -0
- package/types/mysql/index.d.ts +16 -0
- package/types/mysql/manager/base.d.ts +158 -0
- package/types/mysql/manager/index.d.ts +36 -0
- package/types/mysql/manager/ops/count.d.ts +13 -0
- package/types/mysql/manager/ops/criteria.d.ts +120 -0
- package/types/mysql/manager/ops/delete.d.ts +46 -0
- package/types/mysql/manager/ops/exist.d.ts +6 -0
- package/types/mysql/manager/ops/find.d.ts +66 -0
- package/types/mysql/manager/ops/index.d.ts +10 -0
- package/types/mysql/manager/ops/insert.d.ts +18 -0
- package/types/mysql/manager/ops/modify.d.ts +3 -0
- package/types/mysql/manager/ops/paginate.d.ts +36 -0
- package/types/mysql/manager/ops/query.d.ts +3 -0
- package/types/mysql/manager/ops/update.d.ts +70 -0
- package/types/mysql/manager/tx-strict.d.ts +34 -0
- package/types/mysql/manager/tx.d.ts +15 -0
- package/types/mysql/manager/utils.d.ts +17 -0
- package/types/mysql/migration.d.ts +8 -0
- package/types/mysql/table-info.d.ts +36 -0
- package/types/task/daily.d.ts +15 -0
- package/types/task/fixed-delay.d.ts +8 -0
- package/types/task/fixed-rate.d.ts +8 -0
- package/types/task/index.d.ts +4 -0
- package/types/task/task.d.ts +33 -0
- package/types/validation/exception.d.ts +43 -0
- package/types/validation/index.d.ts +32 -0
- package/types/validation/validator/array.d.ts +5 -0
- package/types/validation/validator/enum.d.ts +8 -0
- package/types/validation/validator/index.d.ts +11 -0
- package/types/validation/validator/length.d.ts +10 -0
- package/types/validation/validator/max-length.d.ts +8 -0
- package/types/validation/validator/max.d.ts +7 -0
- package/types/validation/validator/min-length.d.ts +6 -0
- package/types/validation/validator/min.d.ts +7 -0
- package/types/validation/validator/not-blank.d.ts +7 -0
- package/types/validation/validator/not-null.d.ts +6 -0
- package/types/validation/validator/plain-obj.d.ts +7 -0
- package/types/validation/validator/regexp.d.ts +8 -0
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseMongoManager = void 0;
|
|
4
|
+
const log_1 = require("../../log");
|
|
5
|
+
const validation_1 = require("../../validation");
|
|
6
|
+
const exception_1 = require("../exception");
|
|
7
|
+
/**
|
|
8
|
+
* mongodb 管理器基类,提供基本的操作功能.
|
|
9
|
+
*/
|
|
10
|
+
class BaseMongoManager {
|
|
11
|
+
config;
|
|
12
|
+
db;
|
|
13
|
+
session;
|
|
14
|
+
/**
|
|
15
|
+
* mongodb 管理器构建
|
|
16
|
+
* @param db 库
|
|
17
|
+
* @param session 要绑定的会话,用于事务
|
|
18
|
+
*/
|
|
19
|
+
constructor(config, db, session) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.db = db;
|
|
22
|
+
this.session = session;
|
|
23
|
+
}
|
|
24
|
+
getCollection(collInfo) {
|
|
25
|
+
return this.db.collection(collInfo.collectionName);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 查询计时
|
|
29
|
+
* @param opts
|
|
30
|
+
*/
|
|
31
|
+
async timingQuery(opts) {
|
|
32
|
+
const start = new Date().getTime();
|
|
33
|
+
try {
|
|
34
|
+
return await opts.query();
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
if (this.config.slowQueryWarn) {
|
|
38
|
+
const cost = new Date().getTime() - start;
|
|
39
|
+
if (cost > this.config.slowQueryMs) {
|
|
40
|
+
(0, log_1.getLogger)().warn(`[mongodb slow query] ${cost}ms ${JSON.stringify(opts.desc())}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async findById(coll, id) {
|
|
46
|
+
return this.timingQuery({
|
|
47
|
+
query: async () => {
|
|
48
|
+
const res = await this.getCollection(coll).findOne({ _id: id }, {
|
|
49
|
+
limit: 1,
|
|
50
|
+
session: this.session
|
|
51
|
+
});
|
|
52
|
+
return res;
|
|
53
|
+
},
|
|
54
|
+
desc: () => ({
|
|
55
|
+
op: 'findById',
|
|
56
|
+
coll: coll.collectionName,
|
|
57
|
+
id
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 根据id列表查询
|
|
63
|
+
* @param coll
|
|
64
|
+
* @param ids
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
findByIdIn(coll, ids) {
|
|
68
|
+
return this.timingQuery({
|
|
69
|
+
query: async () => {
|
|
70
|
+
const res = this.getCollection(coll).find({ _id: { $in: ids } }, { session: this.session });
|
|
71
|
+
return res.toArray();
|
|
72
|
+
},
|
|
73
|
+
desc() {
|
|
74
|
+
return {
|
|
75
|
+
op: 'findByIdIn',
|
|
76
|
+
coll: coll.collectionName,
|
|
77
|
+
ids
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 根据id判定是否存在
|
|
84
|
+
* @param coll
|
|
85
|
+
* @param id
|
|
86
|
+
*/
|
|
87
|
+
async existsById(coll, id) {
|
|
88
|
+
const res = await this.findById(coll, id);
|
|
89
|
+
return !!res;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 按指定的条件来判定是否存在记录
|
|
93
|
+
* @param coll
|
|
94
|
+
* @param filter
|
|
95
|
+
*/
|
|
96
|
+
async existsBy(coll, filter) {
|
|
97
|
+
return this.timingQuery({
|
|
98
|
+
query: async () => {
|
|
99
|
+
const res = await this.getCollection(coll).findOne(filter, {
|
|
100
|
+
limit: 1,
|
|
101
|
+
session: this.session
|
|
102
|
+
});
|
|
103
|
+
return !!res;
|
|
104
|
+
},
|
|
105
|
+
desc() {
|
|
106
|
+
return {
|
|
107
|
+
op: 'existsBy',
|
|
108
|
+
coll: coll.collectionName,
|
|
109
|
+
filter
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 按id进行删除
|
|
116
|
+
* @param coll
|
|
117
|
+
* @param id
|
|
118
|
+
* @returns
|
|
119
|
+
*/
|
|
120
|
+
async deleteById(coll, id) {
|
|
121
|
+
return this.timingQuery({
|
|
122
|
+
query: async () => {
|
|
123
|
+
const res = await this.getCollection(coll).deleteOne({ _id: id }, {
|
|
124
|
+
session: this.session
|
|
125
|
+
});
|
|
126
|
+
return res.deletedCount === 1;
|
|
127
|
+
},
|
|
128
|
+
desc() {
|
|
129
|
+
return {
|
|
130
|
+
op: 'deleteById',
|
|
131
|
+
coll: coll.collectionName,
|
|
132
|
+
id
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 仅删除一条记录
|
|
139
|
+
* @param coll
|
|
140
|
+
* @param filter
|
|
141
|
+
* @returns
|
|
142
|
+
*/
|
|
143
|
+
async deleteOne(coll, filter) {
|
|
144
|
+
if (!Object.keys(filter).length) {
|
|
145
|
+
throw new exception_1.MongoDBException('filter cannot be empty !');
|
|
146
|
+
}
|
|
147
|
+
return this.timingQuery({
|
|
148
|
+
query: async () => {
|
|
149
|
+
const res = await this.getCollection(coll).deleteOne(filter, {
|
|
150
|
+
session: this.session
|
|
151
|
+
});
|
|
152
|
+
return res.deletedCount === 1;
|
|
153
|
+
},
|
|
154
|
+
desc() {
|
|
155
|
+
return {
|
|
156
|
+
op: 'deleteMany',
|
|
157
|
+
coll: coll.collectionName,
|
|
158
|
+
filter
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 按条件删除数据,返回删除的记录行数.
|
|
165
|
+
* 务必谨慎使用,大批量删除容易带来性能问题,造成线上事故.
|
|
166
|
+
* @param coll
|
|
167
|
+
* @param filter
|
|
168
|
+
* @returns 被删除记录的数量
|
|
169
|
+
*/
|
|
170
|
+
async deleteMany(coll, filter) {
|
|
171
|
+
if (!Object.keys(filter).length) {
|
|
172
|
+
throw new exception_1.MongoDBException('filter cannot be empty !');
|
|
173
|
+
}
|
|
174
|
+
return this.timingQuery({
|
|
175
|
+
query: async () => {
|
|
176
|
+
const res = await this.getCollection(coll).deleteMany(filter, {
|
|
177
|
+
session: this.session
|
|
178
|
+
});
|
|
179
|
+
return res.deletedCount;
|
|
180
|
+
},
|
|
181
|
+
desc() {
|
|
182
|
+
return {
|
|
183
|
+
op: 'deleteMany',
|
|
184
|
+
coll: coll.collectionName,
|
|
185
|
+
filter
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 查询集合中所有记录.谨慎使用!
|
|
192
|
+
* @param coll
|
|
193
|
+
* @returns
|
|
194
|
+
*/
|
|
195
|
+
async findAll(coll) {
|
|
196
|
+
return this.timingQuery({
|
|
197
|
+
query: async () => {
|
|
198
|
+
const arr = await this.getCollection(coll).find({}, { session: this.session }).toArray();
|
|
199
|
+
return arr;
|
|
200
|
+
},
|
|
201
|
+
desc() {
|
|
202
|
+
return {
|
|
203
|
+
op: 'findAll',
|
|
204
|
+
coll: coll.collectionName
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* 根据给定的条件查找第一条符合条件的记录
|
|
211
|
+
* @param coll
|
|
212
|
+
* @param filter
|
|
213
|
+
* @returns
|
|
214
|
+
*/
|
|
215
|
+
async findFirst(coll, filter) {
|
|
216
|
+
return this.timingQuery({
|
|
217
|
+
query: async () => {
|
|
218
|
+
const res = await this.getCollection(coll).findOne(filter, {
|
|
219
|
+
limit: 1,
|
|
220
|
+
session: this.session
|
|
221
|
+
});
|
|
222
|
+
return res;
|
|
223
|
+
},
|
|
224
|
+
desc() {
|
|
225
|
+
return {
|
|
226
|
+
op: 'findFirst',
|
|
227
|
+
coll: coll.collectionName,
|
|
228
|
+
filter
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* 插入新记录
|
|
235
|
+
* @param coll
|
|
236
|
+
* @param data
|
|
237
|
+
* @returns
|
|
238
|
+
*/
|
|
239
|
+
async insert(coll, data) {
|
|
240
|
+
return this.timingQuery({
|
|
241
|
+
query: async () => {
|
|
242
|
+
// 创建时间和更新时间
|
|
243
|
+
if (coll.createdDate) {
|
|
244
|
+
const createdData = coll.createdDate.type === 'date' ? new Date() : new Date().getTime();
|
|
245
|
+
data[coll.createdDate.field] = createdData;
|
|
246
|
+
}
|
|
247
|
+
if (coll.updatedDate) {
|
|
248
|
+
const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
249
|
+
data[coll.updatedDate.field] = updatedDate;
|
|
250
|
+
}
|
|
251
|
+
const collection = this.getCollection(coll);
|
|
252
|
+
const res = await collection.insertOne(data, { session: this.session });
|
|
253
|
+
if (data._id) {
|
|
254
|
+
return data;
|
|
255
|
+
}
|
|
256
|
+
data._id = res.insertedId;
|
|
257
|
+
return data;
|
|
258
|
+
},
|
|
259
|
+
desc() {
|
|
260
|
+
return {
|
|
261
|
+
op: 'insert',
|
|
262
|
+
coll: coll.collectionName,
|
|
263
|
+
data
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 插入多条,批量插入.
|
|
270
|
+
* @param coll
|
|
271
|
+
* @param list
|
|
272
|
+
*/
|
|
273
|
+
async insertMany(coll, list) {
|
|
274
|
+
return this.timingQuery({
|
|
275
|
+
query: async () => {
|
|
276
|
+
const docList = list.map(data => {
|
|
277
|
+
// 创建时间和更新时间
|
|
278
|
+
if (coll.createdDate) {
|
|
279
|
+
const createdData = coll.createdDate.type === 'date' ? new Date() : new Date().getTime();
|
|
280
|
+
data[coll.createdDate.field] = createdData;
|
|
281
|
+
}
|
|
282
|
+
if (coll.updatedDate) {
|
|
283
|
+
const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
284
|
+
data[coll.updatedDate.field] = updatedDate;
|
|
285
|
+
}
|
|
286
|
+
return data;
|
|
287
|
+
});
|
|
288
|
+
const collection = this.getCollection(coll);
|
|
289
|
+
const res = await collection.insertMany(docList, { session: this.session });
|
|
290
|
+
docList.forEach((doc, idx) => {
|
|
291
|
+
if (doc._id) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (res.insertedIds[idx]) {
|
|
295
|
+
doc._id = res.insertedIds[idx];
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
return docList;
|
|
299
|
+
},
|
|
300
|
+
desc() {
|
|
301
|
+
return {
|
|
302
|
+
op: 'insertMany',
|
|
303
|
+
coll: coll.collectionName,
|
|
304
|
+
list
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* 更新,更新完整的文档内容。
|
|
311
|
+
* @param coll 集合信息
|
|
312
|
+
* @param data 要更新的数据,必须包含 _id 字段,支持 mongo 更新语法 $inc 等
|
|
313
|
+
* @returns 返回最新的数据
|
|
314
|
+
* @throws MongoDBException 当无法完成更新时抛出
|
|
315
|
+
*/
|
|
316
|
+
async update(coll, data) {
|
|
317
|
+
return this.timingQuery({
|
|
318
|
+
query: async () => {
|
|
319
|
+
const id = data._id;
|
|
320
|
+
if (!id) {
|
|
321
|
+
throw new exception_1.MongoDBException(`Cannot update a document without an id,collection name:${coll.collectionName}`);
|
|
322
|
+
}
|
|
323
|
+
delete data._id;
|
|
324
|
+
let createData = undefined;
|
|
325
|
+
// 保护创建时间不被更新
|
|
326
|
+
if (coll.createdDate && data[coll.createdDate.field]) {
|
|
327
|
+
createData = data[coll.createdDate.field];
|
|
328
|
+
delete data[coll.createdDate.field];
|
|
329
|
+
}
|
|
330
|
+
// 更新时间
|
|
331
|
+
if (coll.updatedDate) {
|
|
332
|
+
const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
333
|
+
data[coll.updatedDate.field] = updatedDate;
|
|
334
|
+
}
|
|
335
|
+
const res = await this.getCollection(coll).updateOne({ _id: id }, { $set: data }, {
|
|
336
|
+
session: this.session
|
|
337
|
+
});
|
|
338
|
+
if (res.modifiedCount !== 1) {
|
|
339
|
+
throw new exception_1.MongoDBException(`Failed to update record, possibly due to non-existent record,collection:${coll.collectionName},id:${id}`);
|
|
340
|
+
}
|
|
341
|
+
data._id = id;
|
|
342
|
+
if (coll.createdDate && createData) {
|
|
343
|
+
data[coll.createdDate.field] = createData;
|
|
344
|
+
}
|
|
345
|
+
return data;
|
|
346
|
+
},
|
|
347
|
+
desc() {
|
|
348
|
+
return {
|
|
349
|
+
op: 'update',
|
|
350
|
+
coll: coll.collectionName,
|
|
351
|
+
data
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* 仅更新一条记录
|
|
358
|
+
* @param coll
|
|
359
|
+
* @param filter
|
|
360
|
+
* @param updater
|
|
361
|
+
*/
|
|
362
|
+
async updateOne(coll, filter, updater) {
|
|
363
|
+
if (!Object.keys(filter).length) {
|
|
364
|
+
throw new exception_1.MongoDBException('filter cannot be empty !');
|
|
365
|
+
}
|
|
366
|
+
if (!Object.keys(updater).length) {
|
|
367
|
+
throw new exception_1.MongoDBException('updater cannot be empty !');
|
|
368
|
+
}
|
|
369
|
+
return this.timingQuery({
|
|
370
|
+
query: async () => {
|
|
371
|
+
// 更新时间处理
|
|
372
|
+
if (coll.updatedDate) {
|
|
373
|
+
const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
374
|
+
if (updater.$set) {
|
|
375
|
+
updater.$set[coll.updatedDate.field] = updatedDate;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
updater.$set = { [coll.updatedDate.field]: updatedDate };
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const res = await this.getCollection(coll).updateOne(filter, updater, {
|
|
382
|
+
session: this.session
|
|
383
|
+
});
|
|
384
|
+
return res.modifiedCount === 1;
|
|
385
|
+
},
|
|
386
|
+
desc() {
|
|
387
|
+
return {
|
|
388
|
+
op: 'updateOne',
|
|
389
|
+
coll: coll.collectionName,
|
|
390
|
+
filter,
|
|
391
|
+
updator: updater
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* 局部更新,仅更新部分字段,可对字段做递增或数组元组的处理。
|
|
398
|
+
* @param coll 集合信息
|
|
399
|
+
* @param id id
|
|
400
|
+
* @param updater 更新内容
|
|
401
|
+
* @returns 更新是否成功
|
|
402
|
+
*/
|
|
403
|
+
async partialUpdate(coll, id, updater) {
|
|
404
|
+
if (!Object.keys(updater).length) {
|
|
405
|
+
throw new exception_1.MongoDBException('updater cannot be empty !');
|
|
406
|
+
}
|
|
407
|
+
return this.timingQuery({
|
|
408
|
+
query: async () => {
|
|
409
|
+
// 更新时间处理
|
|
410
|
+
if (coll.updatedDate) {
|
|
411
|
+
const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
412
|
+
if (updater.$set) {
|
|
413
|
+
updater.$set[coll.updatedDate.field] = updatedDate;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
updater.$set = { [coll.updatedDate.field]: updatedDate };
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const res = await this.getCollection(coll).updateOne({ _id: id }, updater, {
|
|
420
|
+
session: this.session
|
|
421
|
+
});
|
|
422
|
+
return res.modifiedCount === 1;
|
|
423
|
+
},
|
|
424
|
+
desc() {
|
|
425
|
+
return {
|
|
426
|
+
op: 'partialUpdate',
|
|
427
|
+
coll: coll.collectionName,
|
|
428
|
+
id,
|
|
429
|
+
updator: updater
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* 根据条件更新多条记录,和 partialUpdate 区别是可以根据过滤条件来处理多条记录。
|
|
436
|
+
* @param coll 集合
|
|
437
|
+
* @param filter 过滤规则
|
|
438
|
+
* @param updater 更新内容
|
|
439
|
+
* @returns 此次更新的记录数
|
|
440
|
+
*/
|
|
441
|
+
async updateMany(coll, filter, updater) {
|
|
442
|
+
if (!Object.keys(filter).length) {
|
|
443
|
+
throw new exception_1.MongoDBException('filter cannot be empty !');
|
|
444
|
+
}
|
|
445
|
+
if (!Object.keys(updater).length) {
|
|
446
|
+
throw new exception_1.MongoDBException('updater cannot be empty !');
|
|
447
|
+
}
|
|
448
|
+
return this.timingQuery({
|
|
449
|
+
query: async () => {
|
|
450
|
+
// 更新时间处理
|
|
451
|
+
if (coll.updatedDate) {
|
|
452
|
+
const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime();
|
|
453
|
+
if (updater.$set) {
|
|
454
|
+
updater.$set[coll.updatedDate.field] = updatedDate;
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
updater.$set = { [coll.updatedDate.field]: updatedDate };
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
const res = await this.getCollection(coll).updateMany(filter, updater, {
|
|
461
|
+
session: this.session
|
|
462
|
+
});
|
|
463
|
+
return res.modifiedCount;
|
|
464
|
+
},
|
|
465
|
+
desc() {
|
|
466
|
+
return {
|
|
467
|
+
op: 'updateMany',
|
|
468
|
+
coll: coll.collectionName,
|
|
469
|
+
filter,
|
|
470
|
+
updator: updater
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* 条件查询
|
|
477
|
+
* @param coll 集合信息
|
|
478
|
+
* @param filter 过滤条件
|
|
479
|
+
* @param opts 额外的选项
|
|
480
|
+
* @returns
|
|
481
|
+
*/
|
|
482
|
+
async find(coll, filter, opts) {
|
|
483
|
+
return this.timingQuery({
|
|
484
|
+
query: async () => {
|
|
485
|
+
const arr = await this.getCollection(coll)
|
|
486
|
+
.find(filter, {
|
|
487
|
+
limit: opts && opts.limit && opts.limit > 0 ? opts.limit : undefined,
|
|
488
|
+
skip: opts && opts.limit && opts.limit > 0 && opts.offset && opts.offset > 0
|
|
489
|
+
? opts.offset
|
|
490
|
+
: undefined,
|
|
491
|
+
sort: opts && opts.orderBy ? opts.orderBy : undefined,
|
|
492
|
+
session: this.session
|
|
493
|
+
})
|
|
494
|
+
.toArray();
|
|
495
|
+
return arr;
|
|
496
|
+
},
|
|
497
|
+
desc() {
|
|
498
|
+
return {
|
|
499
|
+
op: 'find',
|
|
500
|
+
coll: coll.collectionName,
|
|
501
|
+
filter,
|
|
502
|
+
opts
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* 查询符合条件的文档数量。请谨慎使用,count 是不能从索引直接读取的,只能实时计数,使用不当容易造成性能问题,引发线上事故。
|
|
509
|
+
* @param coll
|
|
510
|
+
* @param filter
|
|
511
|
+
* @returns
|
|
512
|
+
*/
|
|
513
|
+
count(coll, filter) {
|
|
514
|
+
return this.timingQuery({
|
|
515
|
+
query: async () => {
|
|
516
|
+
return this.getCollection(coll).countDocuments(filter, { session: this.session });
|
|
517
|
+
},
|
|
518
|
+
desc() {
|
|
519
|
+
return {
|
|
520
|
+
op: 'count',
|
|
521
|
+
coll: coll.collectionName,
|
|
522
|
+
filter
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* 分页查询。谨慎使用,不建议对规模较大的数据查询直接使用分页。
|
|
529
|
+
* @param coll 集合信息
|
|
530
|
+
* @param filter 过滤条件
|
|
531
|
+
* @param opts 分页参数
|
|
532
|
+
*/
|
|
533
|
+
async paginate(coll, filter, opts) {
|
|
534
|
+
(0, validation_1.validate)(opts, {
|
|
535
|
+
pn: [(0, validation_1.notNull)(), (0, validation_1.min)(1)],
|
|
536
|
+
pz: [(0, validation_1.notNull)(), (0, validation_1.min)(1)]
|
|
537
|
+
});
|
|
538
|
+
const start = new Date().getTime();
|
|
539
|
+
try {
|
|
540
|
+
const offset = (opts.pn - 1) * opts.pz;
|
|
541
|
+
const res = await Promise.all([
|
|
542
|
+
this.find(coll, filter, { offset, limit: opts.pz, orderBy: opts.orderBy }),
|
|
543
|
+
this.count(coll, filter)
|
|
544
|
+
]);
|
|
545
|
+
const [list, total] = res;
|
|
546
|
+
return { list, total };
|
|
547
|
+
}
|
|
548
|
+
finally {
|
|
549
|
+
if (this.config.slowQueryWarn) {
|
|
550
|
+
const cost = new Date().getTime() - start;
|
|
551
|
+
if (cost > this.config.slowQueryMs) {
|
|
552
|
+
(0, log_1.getLogger)().warn(`[mongodb slow query] ${cost}ms ${JSON.stringify({
|
|
553
|
+
op: 'paginate',
|
|
554
|
+
coll: coll.collectionName,
|
|
555
|
+
filter,
|
|
556
|
+
opts
|
|
557
|
+
})}`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
exports.BaseMongoManager = BaseMongoManager;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongoTxSession = exports.BaseMongoManager = exports.MongoDBManager = void 0;
|
|
4
|
+
const exception_1 = require("../exception");
|
|
5
|
+
const base_1 = require("./base");
|
|
6
|
+
Object.defineProperty(exports, "BaseMongoManager", { enumerable: true, get: function () { return base_1.BaseMongoManager; } });
|
|
7
|
+
const tx_1 = require("./tx");
|
|
8
|
+
Object.defineProperty(exports, "MongoTxSession", { enumerable: true, get: function () { return tx_1.MongoTxSession; } });
|
|
9
|
+
const tx_strict_1 = require("./tx-strict");
|
|
10
|
+
/**
|
|
11
|
+
* mongodb 管理器,目前尚未实现事务的处理.
|
|
12
|
+
*/
|
|
13
|
+
class MongoDBManager extends base_1.BaseMongoManager {
|
|
14
|
+
client;
|
|
15
|
+
/**
|
|
16
|
+
* mongodb 管理器构建
|
|
17
|
+
* @param db 库
|
|
18
|
+
*/
|
|
19
|
+
constructor(config, db, client) {
|
|
20
|
+
super(config, db);
|
|
21
|
+
this.client = client;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 事务操作。mongodb 的版本必须在 4.0 以上,连接的必须是副本集节点或分片集群的mongos节点。
|
|
25
|
+
* @param ops 操作逻辑,所有事务相关的操作都必须使用函数提供的 session 对象
|
|
26
|
+
* @param opts mongo 事务选项
|
|
27
|
+
*/
|
|
28
|
+
async tx(ops, opts) {
|
|
29
|
+
const timeout = opts && typeof opts.timeout === 'number' ? opts.timeout : this.config.transactionTimeout;
|
|
30
|
+
const nativeSession = this.client.startSession();
|
|
31
|
+
nativeSession.startTransaction(opts);
|
|
32
|
+
const txSesssion = this.config.transactionStrict
|
|
33
|
+
? new tx_strict_1.MongoStrictTxSession(this.config, this.db, nativeSession)
|
|
34
|
+
: new tx_1.MongoTxSession(this.config, this.db, nativeSession);
|
|
35
|
+
try {
|
|
36
|
+
const result = timeout > 0
|
|
37
|
+
? await Promise.race([
|
|
38
|
+
ops(txSesssion),
|
|
39
|
+
new Promise((resolve, reject) => {
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
// 立即中止会话,防止再有后续操作
|
|
42
|
+
txSesssion.abort();
|
|
43
|
+
reject(new exception_1.MongoDBException('Transaction timeout !'));
|
|
44
|
+
}, timeout);
|
|
45
|
+
})
|
|
46
|
+
])
|
|
47
|
+
: await ops(txSesssion);
|
|
48
|
+
await nativeSession.commitTransaction();
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
await nativeSession.abortTransaction();
|
|
53
|
+
// 将原错误抛出,如果有需要,调用处可对异常做进一步的处理
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
// 无论如何中止会话,离开事务,会话就不能再被使用
|
|
58
|
+
txSesssion.abort();
|
|
59
|
+
await nativeSession.endSession();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.MongoDBManager = MongoDBManager;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongoStrictTxSession = void 0;
|
|
4
|
+
const exception_1 = require("../exception");
|
|
5
|
+
const tx_1 = require("./tx");
|
|
6
|
+
/**
|
|
7
|
+
* 严格事务会话
|
|
8
|
+
*/
|
|
9
|
+
class MongoStrictTxSession extends tx_1.MongoTxSession {
|
|
10
|
+
#opsCount = 0;
|
|
11
|
+
constructor(config, db, session) {
|
|
12
|
+
super(config, db, session);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 为操作计数,检查是否操作次数过多.
|
|
16
|
+
*/
|
|
17
|
+
#checkAndAddOpsCount() {
|
|
18
|
+
if (this.#opsCount >= 10) {
|
|
19
|
+
throw new exception_1.MongoDBException('Too many operations in a strict transaction.');
|
|
20
|
+
}
|
|
21
|
+
this.#opsCount++;
|
|
22
|
+
}
|
|
23
|
+
findById(coll, id) {
|
|
24
|
+
this.#checkAndAddOpsCount();
|
|
25
|
+
return super.findById(coll, id);
|
|
26
|
+
}
|
|
27
|
+
findByIdIn(coll, ids) {
|
|
28
|
+
if (ids.length > 100) {
|
|
29
|
+
throw new exception_1.MongoDBException(`The augument ids length(${ids.length}) passed to findByIdIn in a strict transaction is too large .`);
|
|
30
|
+
}
|
|
31
|
+
this.#checkAndAddOpsCount();
|
|
32
|
+
return super.findByIdIn(coll, ids);
|
|
33
|
+
}
|
|
34
|
+
existsBy(coll, filter) {
|
|
35
|
+
this.#checkAndAddOpsCount();
|
|
36
|
+
return super.existsBy(coll, filter);
|
|
37
|
+
}
|
|
38
|
+
deleteById(coll, id) {
|
|
39
|
+
this.#checkAndAddOpsCount();
|
|
40
|
+
return super.deleteById(coll, id);
|
|
41
|
+
}
|
|
42
|
+
deleteOne(coll, filter) {
|
|
43
|
+
this.#checkAndAddOpsCount();
|
|
44
|
+
return super.deleteOne(coll, filter);
|
|
45
|
+
}
|
|
46
|
+
deleteMany(coll, filter) {
|
|
47
|
+
throw new exception_1.MongoDBException('Prohibited to use deleteMany in a strict transaction.');
|
|
48
|
+
}
|
|
49
|
+
findAll(coll) {
|
|
50
|
+
throw new exception_1.MongoDBException('Prohibited to use findAll in a strict transaction.');
|
|
51
|
+
}
|
|
52
|
+
findFirst(coll, filter) {
|
|
53
|
+
this.#checkAndAddOpsCount();
|
|
54
|
+
return super.findFirst(coll, filter);
|
|
55
|
+
}
|
|
56
|
+
insert(coll, data) {
|
|
57
|
+
this.#checkAndAddOpsCount();
|
|
58
|
+
return super.insert(coll, data);
|
|
59
|
+
}
|
|
60
|
+
insertMany(coll, list) {
|
|
61
|
+
throw new exception_1.MongoDBException('Prohibited to use insertMany in a strict transaction.');
|
|
62
|
+
}
|
|
63
|
+
update(coll, data) {
|
|
64
|
+
this.#checkAndAddOpsCount();
|
|
65
|
+
return super.update(coll, data);
|
|
66
|
+
}
|
|
67
|
+
partialUpdate(coll, id, updator) {
|
|
68
|
+
this.#checkAndAddOpsCount();
|
|
69
|
+
return super.partialUpdate(coll, id, updator);
|
|
70
|
+
}
|
|
71
|
+
updateMany(coll, filter, updator) {
|
|
72
|
+
throw new exception_1.MongoDBException('Prohibited to use updateMany in a strict transaction.');
|
|
73
|
+
}
|
|
74
|
+
find(coll, filter, opts) {
|
|
75
|
+
throw new exception_1.MongoDBException('Prohibited to use find in a strict transaction.');
|
|
76
|
+
}
|
|
77
|
+
count(coll, filter) {
|
|
78
|
+
throw new exception_1.MongoDBException('Prohibited to use count in a strict transaction.');
|
|
79
|
+
}
|
|
80
|
+
paginate(coll, filter, opts) {
|
|
81
|
+
throw new exception_1.MongoDBException('Prohibited to use paginate in a strict transaction.');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.MongoStrictTxSession = MongoStrictTxSession;
|