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.
Files changed (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/cache/cache.js +94 -0
  4. package/dist/cache/config.js +19 -0
  5. package/dist/cache/index.js +27 -0
  6. package/dist/cache/purge-task.js +56 -0
  7. package/dist/cache/stat.js +47 -0
  8. package/dist/config/convert.js +36 -0
  9. package/dist/config/exception.js +14 -0
  10. package/dist/config/index.js +67 -0
  11. package/dist/http-client/index.js +132 -0
  12. package/dist/i18n/ar.js +17 -0
  13. package/dist/i18n/de.js +17 -0
  14. package/dist/i18n/en-us.js +17 -0
  15. package/dist/i18n/es.js +17 -0
  16. package/dist/i18n/fr.js +17 -0
  17. package/dist/i18n/i18n.js +231 -0
  18. package/dist/i18n/index.js +52 -0
  19. package/dist/i18n/ja.js +17 -0
  20. package/dist/i18n/ko.js +17 -0
  21. package/dist/i18n/msg.js +2 -0
  22. package/dist/i18n/pt.js +17 -0
  23. package/dist/i18n/ru.js +17 -0
  24. package/dist/i18n/tag.js +18 -0
  25. package/dist/i18n/zh-HK.js +17 -0
  26. package/dist/i18n/zh-TW.js +17 -0
  27. package/dist/i18n/zh-cn.js +17 -0
  28. package/dist/index.js +13 -0
  29. package/dist/log/config.js +28 -0
  30. package/dist/log/date.js +21 -0
  31. package/dist/log/file.js +79 -0
  32. package/dist/log/index.js +109 -0
  33. package/dist/log/level.js +39 -0
  34. package/dist/log/store.js +16 -0
  35. package/dist/mongodb/collection.js +2 -0
  36. package/dist/mongodb/config.js +34 -0
  37. package/dist/mongodb/doc.js +2 -0
  38. package/dist/mongodb/exception.js +14 -0
  39. package/dist/mongodb/index.js +58 -0
  40. package/dist/mongodb/manager/base.js +563 -0
  41. package/dist/mongodb/manager/index.js +63 -0
  42. package/dist/mongodb/manager/tx-strict.js +84 -0
  43. package/dist/mongodb/manager/tx.js +30 -0
  44. package/dist/mongodb/migration.js +52 -0
  45. package/dist/mvc/access-log.js +31 -0
  46. package/dist/mvc/config.js +20 -0
  47. package/dist/mvc/exchange.js +113 -0
  48. package/dist/mvc/handler/index.js +6 -0
  49. package/dist/mvc/handler/json.js +33 -0
  50. package/dist/mvc/handler/restful.js +35 -0
  51. package/dist/mvc/handler/upload.js +33 -0
  52. package/dist/mvc/index.js +316 -0
  53. package/dist/mvc/interceptor.js +2 -0
  54. package/dist/mvc/query.js +43 -0
  55. package/dist/mvc/render/file.js +177 -0
  56. package/dist/mvc/render/html/html.js +90 -0
  57. package/dist/mvc/render/html/index.js +18 -0
  58. package/dist/mvc/render/html/style.js +2 -0
  59. package/dist/mvc/render/index.js +7 -0
  60. package/dist/mvc/render/json.js +26 -0
  61. package/dist/mvc/render/text.js +16 -0
  62. package/dist/mvc/router.js +2 -0
  63. package/dist/mysql/config.js +49 -0
  64. package/dist/mysql/exception.js +14 -0
  65. package/dist/mysql/index.js +85 -0
  66. package/dist/mysql/manager/base.js +233 -0
  67. package/dist/mysql/manager/index.js +107 -0
  68. package/dist/mysql/manager/ops/count.js +20 -0
  69. package/dist/mysql/manager/ops/criteria.js +326 -0
  70. package/dist/mysql/manager/ops/delete.js +65 -0
  71. package/dist/mysql/manager/ops/exist.js +26 -0
  72. package/dist/mysql/manager/ops/find.js +111 -0
  73. package/dist/mysql/manager/ops/index.js +14 -0
  74. package/dist/mysql/manager/ops/insert.js +101 -0
  75. package/dist/mysql/manager/ops/modify.js +10 -0
  76. package/dist/mysql/manager/ops/paginate.js +23 -0
  77. package/dist/mysql/manager/ops/query.js +9 -0
  78. package/dist/mysql/manager/ops/update.js +201 -0
  79. package/dist/mysql/manager/tx-strict.js +98 -0
  80. package/dist/mysql/manager/tx.js +30 -0
  81. package/dist/mysql/manager/utils.js +56 -0
  82. package/dist/mysql/migration.js +136 -0
  83. package/dist/mysql/table-info.js +8 -0
  84. package/dist/task/daily.js +58 -0
  85. package/dist/task/fixed-delay.js +33 -0
  86. package/dist/task/fixed-rate.js +37 -0
  87. package/dist/task/index.js +9 -0
  88. package/dist/task/task.js +39 -0
  89. package/dist/validation/exception.js +44 -0
  90. package/dist/validation/index.js +29 -0
  91. package/dist/validation/validator/array.js +38 -0
  92. package/dist/validation/validator/enum.js +28 -0
  93. package/dist/validation/validator/index.js +14 -0
  94. package/dist/validation/validator/length.js +40 -0
  95. package/dist/validation/validator/max-length.js +35 -0
  96. package/dist/validation/validator/max.js +29 -0
  97. package/dist/validation/validator/min-length.js +33 -0
  98. package/dist/validation/validator/min.js +29 -0
  99. package/dist/validation/validator/not-blank.js +33 -0
  100. package/dist/validation/validator/not-null.js +21 -0
  101. package/dist/validation/validator/plain-obj.js +32 -0
  102. package/dist/validation/validator/regexp.js +30 -0
  103. package/documentation/en/index.md +1 -0
  104. package/documentation/zh-cn/cache.md +59 -0
  105. package/documentation/zh-cn/config.md +68 -0
  106. package/documentation/zh-cn/http-client.md +33 -0
  107. package/documentation/zh-cn/i18n.md +154 -0
  108. package/documentation/zh-cn/index.md +25 -0
  109. package/documentation/zh-cn/log.md +40 -0
  110. package/documentation/zh-cn/mongodb.md +262 -0
  111. package/documentation/zh-cn/mvc.md +430 -0
  112. package/documentation/zh-cn/mysql.md +389 -0
  113. package/documentation/zh-cn/task.md +50 -0
  114. package/documentation/zh-cn/test.md +57 -0
  115. package/documentation/zh-cn/validate.md +125 -0
  116. package/package.json +46 -0
  117. package/types/cache/cache.d.ts +52 -0
  118. package/types/cache/config.d.ts +32 -0
  119. package/types/cache/index.d.ts +2 -0
  120. package/types/cache/purge-task.d.ts +11 -0
  121. package/types/cache/stat.d.ts +26 -0
  122. package/types/config/convert.d.ts +6 -0
  123. package/types/config/exception.d.ts +7 -0
  124. package/types/config/index.d.ts +15 -0
  125. package/types/http-client/index.d.ts +71 -0
  126. package/types/i18n/ar.d.ts +2 -0
  127. package/types/i18n/de.d.ts +2 -0
  128. package/types/i18n/en-us.d.ts +2 -0
  129. package/types/i18n/es.d.ts +2 -0
  130. package/types/i18n/fr.d.ts +2 -0
  131. package/types/i18n/i18n.d.ts +102 -0
  132. package/types/i18n/index.d.ts +9 -0
  133. package/types/i18n/ja.d.ts +2 -0
  134. package/types/i18n/ko.d.ts +2 -0
  135. package/types/i18n/msg.d.ts +50 -0
  136. package/types/i18n/pt.d.ts +2 -0
  137. package/types/i18n/ru.d.ts +2 -0
  138. package/types/i18n/tag.d.ts +11 -0
  139. package/types/i18n/zh-HK.d.ts +2 -0
  140. package/types/i18n/zh-TW.d.ts +2 -0
  141. package/types/i18n/zh-cn.d.ts +2 -0
  142. package/types/index.d.ts +10 -0
  143. package/types/log/config.d.ts +27 -0
  144. package/types/log/date.d.ts +2 -0
  145. package/types/log/file.d.ts +5 -0
  146. package/types/log/index.d.ts +34 -0
  147. package/types/log/level.d.ts +15 -0
  148. package/types/log/store.d.ts +12 -0
  149. package/types/mongodb/collection.d.ts +25 -0
  150. package/types/mongodb/config.d.ts +45 -0
  151. package/types/mongodb/doc.d.ts +11 -0
  152. package/types/mongodb/exception.d.ts +7 -0
  153. package/types/mongodb/index.d.ts +29 -0
  154. package/types/mongodb/manager/base.d.ts +188 -0
  155. package/types/mongodb/manager/index.d.ts +38 -0
  156. package/types/mongodb/manager/tx-strict.d.ts +41 -0
  157. package/types/mongodb/manager/tx.d.ts +21 -0
  158. package/types/mongodb/migration.d.ts +12 -0
  159. package/types/mvc/access-log.d.ts +7 -0
  160. package/types/mvc/config.d.ts +30 -0
  161. package/types/mvc/exchange.d.ts +72 -0
  162. package/types/mvc/handler/index.d.ts +3 -0
  163. package/types/mvc/handler/json.d.ts +23 -0
  164. package/types/mvc/handler/restful.d.ts +11 -0
  165. package/types/mvc/handler/upload.d.ts +40 -0
  166. package/types/mvc/index.d.ts +49 -0
  167. package/types/mvc/interceptor.d.ts +11 -0
  168. package/types/mvc/query.d.ts +13 -0
  169. package/types/mvc/render/file.d.ts +10 -0
  170. package/types/mvc/render/html/html.d.ts +98 -0
  171. package/types/mvc/render/html/index.d.ts +11 -0
  172. package/types/mvc/render/html/style.d.ts +1201 -0
  173. package/types/mvc/render/index.d.ts +4 -0
  174. package/types/mvc/render/json.d.ts +17 -0
  175. package/types/mvc/render/text.d.ts +10 -0
  176. package/types/mvc/router.d.ts +11 -0
  177. package/types/mysql/config.d.ts +86 -0
  178. package/types/mysql/exception.d.ts +7 -0
  179. package/types/mysql/index.d.ts +16 -0
  180. package/types/mysql/manager/base.d.ts +158 -0
  181. package/types/mysql/manager/index.d.ts +36 -0
  182. package/types/mysql/manager/ops/count.d.ts +13 -0
  183. package/types/mysql/manager/ops/criteria.d.ts +120 -0
  184. package/types/mysql/manager/ops/delete.d.ts +46 -0
  185. package/types/mysql/manager/ops/exist.d.ts +6 -0
  186. package/types/mysql/manager/ops/find.d.ts +66 -0
  187. package/types/mysql/manager/ops/index.d.ts +10 -0
  188. package/types/mysql/manager/ops/insert.d.ts +18 -0
  189. package/types/mysql/manager/ops/modify.d.ts +3 -0
  190. package/types/mysql/manager/ops/paginate.d.ts +36 -0
  191. package/types/mysql/manager/ops/query.d.ts +3 -0
  192. package/types/mysql/manager/ops/update.d.ts +70 -0
  193. package/types/mysql/manager/tx-strict.d.ts +34 -0
  194. package/types/mysql/manager/tx.d.ts +15 -0
  195. package/types/mysql/manager/utils.d.ts +17 -0
  196. package/types/mysql/migration.d.ts +8 -0
  197. package/types/mysql/table-info.d.ts +36 -0
  198. package/types/task/daily.d.ts +15 -0
  199. package/types/task/fixed-delay.d.ts +8 -0
  200. package/types/task/fixed-rate.d.ts +8 -0
  201. package/types/task/index.d.ts +4 -0
  202. package/types/task/task.d.ts +33 -0
  203. package/types/validation/exception.d.ts +43 -0
  204. package/types/validation/index.d.ts +32 -0
  205. package/types/validation/validator/array.d.ts +5 -0
  206. package/types/validation/validator/enum.d.ts +8 -0
  207. package/types/validation/validator/index.d.ts +11 -0
  208. package/types/validation/validator/length.d.ts +10 -0
  209. package/types/validation/validator/max-length.d.ts +8 -0
  210. package/types/validation/validator/max.d.ts +7 -0
  211. package/types/validation/validator/min-length.d.ts +6 -0
  212. package/types/validation/validator/min.d.ts +7 -0
  213. package/types/validation/validator/not-blank.d.ts +7 -0
  214. package/types/validation/validator/not-null.d.ts +6 -0
  215. package/types/validation/validator/plain-obj.d.ts +7 -0
  216. 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;