wok-server 0.4.13 → 0.6.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 (376) hide show
  1. package/README.en.md +61 -0
  2. package/README.md +44 -29
  3. package/dist/cache/cache.js +98 -98
  4. package/dist/cache/config.js +19 -19
  5. package/dist/cache/index.js +27 -27
  6. package/dist/cache/purge-task.js +46 -46
  7. package/dist/cache/stat.js +47 -47
  8. package/dist/config/convert.js +36 -36
  9. package/dist/config/exception.js +14 -14
  10. package/dist/config/index.js +81 -81
  11. package/dist/http-client/index.js +136 -136
  12. package/dist/i18n/ar.js +17 -17
  13. package/dist/i18n/de.js +17 -17
  14. package/dist/i18n/en-us.js +17 -17
  15. package/dist/i18n/es.js +17 -17
  16. package/dist/i18n/fr.js +17 -17
  17. package/dist/i18n/i18n.js +231 -231
  18. package/dist/i18n/index.js +52 -52
  19. package/dist/i18n/ja.js +17 -17
  20. package/dist/i18n/ko.js +17 -17
  21. package/dist/i18n/msg.js +2 -2
  22. package/dist/i18n/pt.js +17 -17
  23. package/dist/i18n/ru.js +17 -17
  24. package/dist/i18n/tag.js +18 -18
  25. package/dist/i18n/zh-HK.js +17 -17
  26. package/dist/i18n/zh-TW.js +17 -17
  27. package/dist/i18n/zh-cn.js +17 -17
  28. package/dist/index.js +14 -14
  29. package/dist/lock/index.js +114 -114
  30. package/dist/log/config.js +35 -29
  31. package/dist/log/date.js +21 -21
  32. package/dist/log/file.js +198 -72
  33. package/dist/log/index.js +135 -105
  34. package/dist/log/level.js +33 -33
  35. package/dist/log/log.js +56 -0
  36. package/dist/log/store.js +19 -16
  37. package/dist/mongodb/collection.js +2 -2
  38. package/dist/mongodb/config.js +34 -34
  39. package/dist/mongodb/doc.js +2 -2
  40. package/dist/mongodb/exception.js +14 -14
  41. package/dist/mongodb/index.js +58 -58
  42. package/dist/mongodb/manager/base.js +563 -563
  43. package/dist/mongodb/manager/index.js +63 -63
  44. package/dist/mongodb/manager/tx-strict.js +84 -84
  45. package/dist/mongodb/manager/tx.js +30 -30
  46. package/dist/mongodb/migration.js +52 -52
  47. package/dist/mvc/access-log.js +33 -33
  48. package/dist/mvc/config.js +27 -27
  49. package/dist/mvc/exchange.js +113 -113
  50. package/dist/mvc/handler/index.js +7 -6
  51. package/dist/mvc/handler/json.js +65 -65
  52. package/dist/mvc/handler/restful.js +35 -35
  53. package/dist/mvc/handler/sse.js +65 -0
  54. package/dist/mvc/handler/upload.js +31 -31
  55. package/dist/mvc/index.js +50 -50
  56. package/dist/mvc/interceptor.js +2 -2
  57. package/dist/mvc/query.js +43 -43
  58. package/dist/mvc/render/file.js +132 -132
  59. package/dist/mvc/render/html/html.js +90 -90
  60. package/dist/mvc/render/html/index.js +18 -18
  61. package/dist/mvc/render/html/style.js +2 -2
  62. package/dist/mvc/render/index.js +7 -7
  63. package/dist/mvc/render/json.js +26 -26
  64. package/dist/mvc/render/text.js +16 -16
  65. package/dist/mvc/router.js +2 -2
  66. package/dist/mvc/server.js +272 -272
  67. package/dist/mvc/static/header.js +67 -67
  68. package/dist/mvc/static/index.js +6 -6
  69. package/dist/mvc/static/mime-type.js +84 -84
  70. package/dist/mvc/static/server-cache-config.js +66 -66
  71. package/dist/mvc/static/server-cache.js +133 -133
  72. package/dist/mvc/static/static-handler.js +372 -372
  73. package/dist/mysql/config.js +51 -51
  74. package/dist/mysql/exception.js +14 -14
  75. package/dist/mysql/index.js +87 -87
  76. package/dist/mysql/manager/base.js +239 -231
  77. package/dist/mysql/manager/index.js +107 -107
  78. package/dist/mysql/manager/ops/count.js +20 -20
  79. package/dist/mysql/manager/ops/criteria.js +356 -356
  80. package/dist/mysql/manager/ops/delete.js +65 -65
  81. package/dist/mysql/manager/ops/exist.js +26 -26
  82. package/dist/mysql/manager/ops/find.js +169 -130
  83. package/dist/mysql/manager/ops/index.js +14 -14
  84. package/dist/mysql/manager/ops/insert.js +106 -106
  85. package/dist/mysql/manager/ops/modify.js +10 -10
  86. package/dist/mysql/manager/ops/paginate.js +23 -23
  87. package/dist/mysql/manager/ops/query.js +9 -9
  88. package/dist/mysql/manager/ops/update.js +216 -216
  89. package/dist/mysql/manager/ops/utils.js +24 -24
  90. package/dist/mysql/manager/tx-strict.js +103 -100
  91. package/dist/mysql/manager/tx.js +30 -30
  92. package/dist/mysql/manager/utils.js +56 -56
  93. package/dist/mysql/migration.js +136 -136
  94. package/dist/mysql/table-info.js +8 -8
  95. package/dist/task/daily.js +59 -59
  96. package/dist/task/fixed-delay.js +38 -38
  97. package/dist/task/fixed-rate.js +42 -42
  98. package/dist/task/index.js +9 -9
  99. package/dist/task/task.js +56 -56
  100. package/dist/validation/exception.js +36 -36
  101. package/dist/validation/index.js +40 -40
  102. package/dist/validation/validator/array.js +34 -34
  103. package/dist/validation/validator/enum.js +28 -28
  104. package/dist/validation/validator/index.js +14 -14
  105. package/dist/validation/validator/length.js +40 -40
  106. package/dist/validation/validator/max-length.js +35 -35
  107. package/dist/validation/validator/max.js +29 -29
  108. package/dist/validation/validator/min-length.js +33 -33
  109. package/dist/validation/validator/min.js +29 -29
  110. package/dist/validation/validator/not-blank.js +33 -33
  111. package/dist/validation/validator/not-null.js +21 -21
  112. package/dist/validation/validator/plain-obj.js +32 -32
  113. package/dist/validation/validator/regexp.js +34 -34
  114. package/documentation/en/cache.md +56 -0
  115. package/documentation/en/config.md +96 -0
  116. package/documentation/en/engineering.md +256 -0
  117. package/documentation/en/http-client.md +32 -0
  118. package/documentation/en/i18n.md +143 -0
  119. package/documentation/en/index.md +24 -0
  120. package/documentation/en/lock.md +51 -0
  121. package/documentation/en/log.md +109 -0
  122. package/documentation/en/mongodb.md +256 -0
  123. package/documentation/en/mvc.md +688 -0
  124. package/documentation/en/mysql.md +552 -0
  125. package/documentation/en/task.md +45 -0
  126. package/documentation/en/test.md +56 -0
  127. package/documentation/en/validate.md +130 -0
  128. package/documentation/zh-cn/engineering.md +1 -1
  129. package/documentation/zh-cn/log.md +81 -8
  130. package/documentation/zh-cn/mvc.md +66 -24
  131. package/documentation/zh-cn/mysql.md +24 -23
  132. package/documentation/zh-cn/validate.md +2 -2
  133. package/package.json +3 -1
  134. package/skills/wok-server-api-rules/SKILL.md +350 -0
  135. package/skills/wok-server-cache/SKILL.md +216 -0
  136. package/skills/wok-server-config/SKILL.md +200 -0
  137. package/skills/wok-server-getting-started/SKILL.md +123 -0
  138. package/skills/wok-server-getting-started/references/engineering.md +169 -0
  139. package/skills/wok-server-http-client/SKILL.md +164 -0
  140. package/skills/wok-server-i18n/SKILL.md +214 -0
  141. package/skills/wok-server-lock/SKILL.md +144 -0
  142. package/skills/wok-server-log/SKILL.md +218 -0
  143. package/skills/wok-server-mongodb/SKILL.md +235 -0
  144. package/skills/wok-server-mvc/SKILL.md +251 -0
  145. package/skills/wok-server-mvc/references/respond-html.md +157 -0
  146. package/skills/wok-server-mvc/references/sse.md +121 -0
  147. package/skills/wok-server-mvc/references/static-files.md +47 -0
  148. package/skills/wok-server-mvc/references/upload.md +62 -0
  149. package/skills/wok-server-mvc/references/websocket.md +30 -0
  150. package/skills/wok-server-mysql/SKILL.md +315 -0
  151. package/skills/wok-server-mysql/references/multi-datasource.md +76 -0
  152. package/skills/wok-server-mysql/references/version-control.md +22 -0
  153. package/skills/wok-server-task/SKILL.md +158 -0
  154. package/skills/wok-server-validate/SKILL.md +167 -0
  155. package/src/cache/cache.ts +118 -0
  156. package/src/cache/config.ts +53 -0
  157. package/src/cache/index.ts +27 -0
  158. package/src/cache/purge-task.ts +53 -0
  159. package/src/cache/stat.ts +47 -0
  160. package/src/config/convert.ts +27 -0
  161. package/src/config/exception.ts +8 -0
  162. package/src/config/index.ts +92 -0
  163. package/src/http-client/index.ts +202 -0
  164. package/src/i18n/ar.ts +16 -0
  165. package/src/i18n/de.ts +16 -0
  166. package/src/i18n/en-us.ts +16 -0
  167. package/src/i18n/es.ts +16 -0
  168. package/src/i18n/fr.ts +16 -0
  169. package/src/i18n/i18n.ts +230 -0
  170. package/src/i18n/index.ts +50 -0
  171. package/src/i18n/ja.ts +16 -0
  172. package/src/i18n/ko.ts +16 -0
  173. package/src/i18n/msg.ts +50 -0
  174. package/src/i18n/pt.ts +16 -0
  175. package/src/i18n/ru.ts +16 -0
  176. package/src/i18n/tag.ts +18 -0
  177. package/src/i18n/zh-HK.ts +16 -0
  178. package/src/i18n/zh-TW.ts +16 -0
  179. package/src/i18n/zh-cn.ts +16 -0
  180. package/src/index.ts +11 -0
  181. package/src/lock/index.ts +164 -0
  182. package/src/log/config.ts +71 -0
  183. package/src/log/date.ts +19 -0
  184. package/src/log/file.ts +215 -0
  185. package/src/log/index.ts +136 -0
  186. package/src/log/level.ts +29 -0
  187. package/src/log/log.ts +77 -0
  188. package/src/log/store.ts +31 -0
  189. package/src/mongodb/collection.ts +25 -0
  190. package/src/mongodb/config.ts +69 -0
  191. package/src/mongodb/doc.ts +12 -0
  192. package/src/mongodb/exception.ts +8 -0
  193. package/src/mongodb/index.ts +71 -0
  194. package/src/mongodb/manager/base.ts +674 -0
  195. package/src/mongodb/manager/index.ts +80 -0
  196. package/src/mongodb/manager/tx-strict.ts +153 -0
  197. package/src/mongodb/manager/tx.ts +34 -0
  198. package/src/mongodb/migration.ts +66 -0
  199. package/src/mvc/access-log.ts +33 -0
  200. package/src/mvc/config.ts +70 -0
  201. package/src/mvc/exchange.ts +126 -0
  202. package/src/mvc/handler/index.ts +4 -0
  203. package/src/mvc/handler/json.ts +96 -0
  204. package/src/mvc/handler/restful.ts +39 -0
  205. package/src/mvc/handler/sse.ts +90 -0
  206. package/src/mvc/handler/upload.ts +54 -0
  207. package/src/mvc/index.ts +48 -0
  208. package/src/mvc/interceptor.ts +12 -0
  209. package/src/mvc/query.ts +36 -0
  210. package/src/mvc/render/file.ts +148 -0
  211. package/src/mvc/render/html/html.ts +187 -0
  212. package/src/mvc/render/html/index.ts +16 -0
  213. package/src/mvc/render/html/style.ts +1201 -0
  214. package/src/mvc/render/index.ts +4 -0
  215. package/src/mvc/render/json.ts +24 -0
  216. package/src/mvc/render/text.ts +14 -0
  217. package/src/mvc/router.ts +13 -0
  218. package/src/mvc/server.ts +315 -0
  219. package/src/mvc/static/header.ts +86 -0
  220. package/src/mvc/static/index.ts +3 -0
  221. package/src/mvc/static/mime-type.ts +81 -0
  222. package/src/mvc/static/server-cache-config.ts +92 -0
  223. package/src/mvc/static/server-cache.ts +171 -0
  224. package/src/mvc/static/static-handler.ts +445 -0
  225. package/src/mysql/config.ts +130 -0
  226. package/src/mysql/exception.ts +8 -0
  227. package/src/mysql/index.ts +88 -0
  228. package/src/mysql/manager/base.ts +285 -0
  229. package/src/mysql/manager/index.ts +112 -0
  230. package/src/mysql/manager/ops/count.ts +30 -0
  231. package/src/mysql/manager/ops/criteria.ts +412 -0
  232. package/src/mysql/manager/ops/delete.ts +96 -0
  233. package/src/mysql/manager/ops/exist.ts +41 -0
  234. package/src/mysql/manager/ops/find.ts +226 -0
  235. package/src/mysql/manager/ops/index.ts +11 -0
  236. package/src/mysql/manager/ops/insert.ts +120 -0
  237. package/src/mysql/manager/ops/modify.ts +14 -0
  238. package/src/mysql/manager/ops/paginate.ts +60 -0
  239. package/src/mysql/manager/ops/query.ts +13 -0
  240. package/src/mysql/manager/ops/update.ts +294 -0
  241. package/src/mysql/manager/ops/utils.ts +20 -0
  242. package/src/mysql/manager/tx-strict.ts +138 -0
  243. package/src/mysql/manager/tx.ts +31 -0
  244. package/src/mysql/manager/utils.ts +75 -0
  245. package/src/mysql/migration.ts +149 -0
  246. package/src/mysql/table-info.ts +41 -0
  247. package/src/task/daily.ts +70 -0
  248. package/src/task/fixed-delay.ts +45 -0
  249. package/src/task/fixed-rate.ts +49 -0
  250. package/src/task/index.ts +4 -0
  251. package/src/task/task.ts +70 -0
  252. package/src/validation/exception.ts +27 -0
  253. package/src/validation/index.ts +61 -0
  254. package/src/validation/validator/array.ts +32 -0
  255. package/src/validation/validator/enum.ts +25 -0
  256. package/src/validation/validator/index.ts +11 -0
  257. package/src/validation/validator/length.ts +42 -0
  258. package/src/validation/validator/max-length.ts +33 -0
  259. package/src/validation/validator/max.ts +26 -0
  260. package/src/validation/validator/min-length.ts +31 -0
  261. package/src/validation/validator/min.ts +26 -0
  262. package/src/validation/validator/not-blank.ts +31 -0
  263. package/src/validation/validator/not-null.ts +19 -0
  264. package/src/validation/validator/plain-obj.ts +30 -0
  265. package/src/validation/validator/regexp.ts +32 -0
  266. package/types/cache/cache.d.ts +52 -52
  267. package/types/cache/config.d.ts +32 -32
  268. package/types/cache/index.d.ts +2 -2
  269. package/types/cache/purge-task.d.ts +11 -11
  270. package/types/cache/stat.d.ts +26 -26
  271. package/types/config/convert.d.ts +6 -6
  272. package/types/config/exception.d.ts +7 -7
  273. package/types/config/index.d.ts +25 -25
  274. package/types/http-client/index.d.ts +71 -71
  275. package/types/i18n/ar.d.ts +2 -2
  276. package/types/i18n/de.d.ts +2 -2
  277. package/types/i18n/en-us.d.ts +2 -2
  278. package/types/i18n/es.d.ts +2 -2
  279. package/types/i18n/fr.d.ts +2 -2
  280. package/types/i18n/i18n.d.ts +102 -102
  281. package/types/i18n/index.d.ts +9 -9
  282. package/types/i18n/ja.d.ts +2 -2
  283. package/types/i18n/ko.d.ts +2 -2
  284. package/types/i18n/msg.d.ts +50 -50
  285. package/types/i18n/pt.d.ts +2 -2
  286. package/types/i18n/ru.d.ts +2 -2
  287. package/types/i18n/tag.d.ts +11 -11
  288. package/types/i18n/zh-HK.d.ts +2 -2
  289. package/types/i18n/zh-TW.d.ts +2 -2
  290. package/types/i18n/zh-cn.d.ts +2 -2
  291. package/types/index.d.ts +11 -11
  292. package/types/lock/index.d.ts +64 -64
  293. package/types/log/config.d.ts +35 -27
  294. package/types/log/date.d.ts +2 -2
  295. package/types/log/file.d.ts +13 -5
  296. package/types/log/index.d.ts +53 -34
  297. package/types/log/level.d.ts +14 -14
  298. package/types/log/log.d.ts +40 -0
  299. package/types/log/store.d.ts +19 -12
  300. package/types/mongodb/collection.d.ts +25 -25
  301. package/types/mongodb/config.d.ts +45 -45
  302. package/types/mongodb/doc.d.ts +11 -11
  303. package/types/mongodb/exception.d.ts +7 -7
  304. package/types/mongodb/index.d.ts +29 -29
  305. package/types/mongodb/manager/base.d.ts +188 -188
  306. package/types/mongodb/manager/index.d.ts +38 -38
  307. package/types/mongodb/manager/tx-strict.d.ts +41 -41
  308. package/types/mongodb/manager/tx.d.ts +21 -21
  309. package/types/mongodb/migration.d.ts +12 -12
  310. package/types/mvc/access-log.d.ts +7 -7
  311. package/types/mvc/config.d.ts +42 -42
  312. package/types/mvc/exchange.d.ts +72 -72
  313. package/types/mvc/handler/index.d.ts +4 -3
  314. package/types/mvc/handler/json.d.ts +44 -44
  315. package/types/mvc/handler/restful.d.ts +11 -11
  316. package/types/mvc/handler/sse.d.ts +34 -0
  317. package/types/mvc/handler/upload.d.ts +36 -36
  318. package/types/mvc/index.d.ts +22 -22
  319. package/types/mvc/interceptor.d.ts +11 -11
  320. package/types/mvc/query.d.ts +13 -13
  321. package/types/mvc/render/file.d.ts +10 -10
  322. package/types/mvc/render/html/html.d.ts +98 -98
  323. package/types/mvc/render/html/index.d.ts +11 -11
  324. package/types/mvc/render/html/style.d.ts +1201 -1201
  325. package/types/mvc/render/index.d.ts +4 -4
  326. package/types/mvc/render/json.d.ts +17 -17
  327. package/types/mvc/render/text.d.ts +10 -10
  328. package/types/mvc/router.d.ts +11 -11
  329. package/types/mvc/server.d.ts +90 -90
  330. package/types/mvc/static/header.d.ts +27 -27
  331. package/types/mvc/static/index.d.ts +3 -3
  332. package/types/mvc/static/mime-type.d.ts +2 -2
  333. package/types/mvc/static/server-cache-config.d.ts +30 -30
  334. package/types/mvc/static/server-cache.d.ts +76 -76
  335. package/types/mvc/static/static-handler.d.ts +77 -77
  336. package/types/mysql/config.d.ts +90 -90
  337. package/types/mysql/exception.d.ts +7 -7
  338. package/types/mysql/index.d.ts +16 -16
  339. package/types/mysql/manager/base.d.ts +165 -159
  340. package/types/mysql/manager/index.d.ts +36 -36
  341. package/types/mysql/manager/ops/count.d.ts +13 -13
  342. package/types/mysql/manager/ops/criteria.d.ts +134 -134
  343. package/types/mysql/manager/ops/delete.d.ts +46 -46
  344. package/types/mysql/manager/ops/exist.d.ts +6 -6
  345. package/types/mysql/manager/ops/find.d.ts +86 -70
  346. package/types/mysql/manager/ops/index.d.ts +10 -10
  347. package/types/mysql/manager/ops/insert.d.ts +18 -18
  348. package/types/mysql/manager/ops/modify.d.ts +3 -3
  349. package/types/mysql/manager/ops/paginate.d.ts +36 -36
  350. package/types/mysql/manager/ops/query.d.ts +3 -3
  351. package/types/mysql/manager/ops/update.d.ts +76 -76
  352. package/types/mysql/manager/ops/utils.d.ts +5 -5
  353. package/types/mysql/manager/tx-strict.d.ts +36 -35
  354. package/types/mysql/manager/tx.d.ts +15 -15
  355. package/types/mysql/manager/utils.d.ts +17 -17
  356. package/types/mysql/migration.d.ts +8 -8
  357. package/types/mysql/table-info.d.ts +36 -36
  358. package/types/task/daily.d.ts +16 -16
  359. package/types/task/fixed-delay.d.ts +9 -9
  360. package/types/task/fixed-rate.d.ts +9 -9
  361. package/types/task/index.d.ts +4 -4
  362. package/types/task/task.d.ts +34 -34
  363. package/types/validation/exception.d.ts +38 -38
  364. package/types/validation/index.d.ts +32 -32
  365. package/types/validation/validator/array.d.ts +5 -5
  366. package/types/validation/validator/enum.d.ts +8 -8
  367. package/types/validation/validator/index.d.ts +11 -11
  368. package/types/validation/validator/length.d.ts +10 -10
  369. package/types/validation/validator/max-length.d.ts +8 -8
  370. package/types/validation/validator/max.d.ts +7 -7
  371. package/types/validation/validator/min-length.d.ts +6 -6
  372. package/types/validation/validator/min.d.ts +7 -7
  373. package/types/validation/validator/not-blank.d.ts +7 -7
  374. package/types/validation/validator/not-null.d.ts +6 -6
  375. package/types/validation/validator/plain-obj.d.ts +7 -7
  376. package/types/validation/validator/regexp.d.ts +8 -8
@@ -0,0 +1,674 @@
1
+ import { ClientSession, Db, Document, Filter, SortDirection, UpdateFilter } from 'mongodb'
2
+ import { getLogger } from '../../log'
3
+ import { min, notNull, validate } from '../../validation'
4
+ import { MongoCollection } from '../collection'
5
+ import { MongoDBConfig } from '../config'
6
+ import { MongoDocId, MongoDocWithId } from '../doc'
7
+ import { MongoDBException } from '../exception'
8
+
9
+ /**
10
+ * mysql 分页查询结果
11
+ */
12
+ export interface MongoPage<T> {
13
+ total: number
14
+ list: T[]
15
+ }
16
+
17
+ /**
18
+ * mongodb 管理器基类,提供基本的操作功能.
19
+ */
20
+ export abstract class BaseMongoManager {
21
+ /**
22
+ * mongodb 管理器构建
23
+ * @param db 库
24
+ * @param session 要绑定的会话,用于事务
25
+ */
26
+ constructor(
27
+ protected config: MongoDBConfig,
28
+ protected readonly db: Db,
29
+ private session?: ClientSession
30
+ ) {}
31
+
32
+ getCollection<T extends Document>(collInfo: MongoCollection<T>) {
33
+ return this.db.collection<T>(collInfo.collectionName)
34
+ }
35
+ /**
36
+ * 查询计时
37
+ * @param opts
38
+ */
39
+ protected async timingQuery<T, D extends { op: string; coll: string }>(opts: {
40
+ // 查询处理逻辑
41
+ query: () => Promise<T>
42
+ // 信息描述,当查询较慢时打印到日志中
43
+ desc: () => D
44
+ }): Promise<T> {
45
+ const start = new Date().getTime()
46
+ try {
47
+ return await opts.query()
48
+ } finally {
49
+ if (this.config.slowQueryWarn) {
50
+ const cost = new Date().getTime() - start
51
+ if (cost > this.config.slowQueryMs) {
52
+ getLogger().warn(`[mongodb slow query] ${cost}ms ${JSON.stringify(opts.desc())}`)
53
+ }
54
+ }
55
+ }
56
+ }
57
+
58
+ async findById<T extends Document>(
59
+ coll: MongoCollection<T>,
60
+ id: MongoDocId
61
+ ): Promise<MongoDocWithId<T> | null> {
62
+ return this.timingQuery({
63
+ query: async () => {
64
+ const res = await this.getCollection(coll).findOne({ _id: id } as Filter<T>, {
65
+ limit: 1,
66
+ session: this.session
67
+ })
68
+ return res as MongoDocWithId<T> | null
69
+ },
70
+ desc: () => ({
71
+ op: 'findById',
72
+ coll: coll.collectionName,
73
+ id
74
+ })
75
+ })
76
+ }
77
+
78
+ /**
79
+ * 根据id列表查询
80
+ * @param coll
81
+ * @param ids
82
+ * @returns
83
+ */
84
+ findByIdIn<T extends Document>(
85
+ coll: MongoCollection<T>,
86
+ ids: MongoDocId[]
87
+ ): Promise<MongoDocWithId<T>[]> {
88
+ return this.timingQuery({
89
+ query: async () => {
90
+ const res = this.getCollection(coll).find<MongoDocWithId<T>>(
91
+ { _id: { $in: ids } } as Filter<T>,
92
+ { session: this.session }
93
+ )
94
+ return res.toArray()
95
+ },
96
+ desc() {
97
+ return {
98
+ op: 'findByIdIn',
99
+ coll: coll.collectionName,
100
+ ids
101
+ }
102
+ }
103
+ })
104
+ }
105
+
106
+ /**
107
+ * 根据id判定是否存在
108
+ * @param coll
109
+ * @param id
110
+ */
111
+ async existsById<T extends Document>(coll: MongoCollection<T>, id: MongoDocId): Promise<boolean> {
112
+ const res = await this.findById(coll, id)
113
+ return !!res
114
+ }
115
+ /**
116
+ * 按指定的条件来判定是否存在记录
117
+ * @param coll
118
+ * @param filter
119
+ */
120
+ async existsBy<T extends Document>(
121
+ coll: MongoCollection<T>,
122
+ filter: Filter<MongoDocWithId<T>>
123
+ ): Promise<boolean> {
124
+ return this.timingQuery({
125
+ query: async () => {
126
+ const res = await this.getCollection(coll).findOne(filter as Filter<T>, {
127
+ limit: 1,
128
+ session: this.session
129
+ })
130
+ return !!res
131
+ },
132
+ desc() {
133
+ return {
134
+ op: 'existsBy',
135
+ coll: coll.collectionName,
136
+ filter
137
+ }
138
+ }
139
+ })
140
+ }
141
+ /**
142
+ * 按id进行删除
143
+ * @param coll
144
+ * @param id
145
+ * @returns
146
+ */
147
+ async deleteById<T extends Document>(coll: MongoCollection<T>, id: MongoDocId): Promise<boolean> {
148
+ return this.timingQuery({
149
+ query: async () => {
150
+ const res = await this.getCollection(coll).deleteOne({ _id: id } as Filter<T>, {
151
+ session: this.session
152
+ })
153
+ return res.deletedCount === 1
154
+ },
155
+ desc() {
156
+ return {
157
+ op: 'deleteById',
158
+ coll: coll.collectionName,
159
+ id
160
+ }
161
+ }
162
+ })
163
+ }
164
+
165
+ /**
166
+ * 仅删除一条记录
167
+ * @param coll
168
+ * @param filter
169
+ * @returns
170
+ */
171
+ async deleteOne<T extends Document>(
172
+ coll: MongoCollection<T>,
173
+ filter: Partial<T>
174
+ ): Promise<boolean> {
175
+ if (!Object.keys(filter).length) {
176
+ throw new MongoDBException('filter cannot be empty !')
177
+ }
178
+ return this.timingQuery({
179
+ query: async () => {
180
+ const res = await this.getCollection(coll).deleteOne(filter as Filter<T>, {
181
+ session: this.session
182
+ })
183
+ return res.deletedCount === 1
184
+ },
185
+ desc() {
186
+ return {
187
+ op: 'deleteMany',
188
+ coll: coll.collectionName,
189
+ filter
190
+ }
191
+ }
192
+ })
193
+ }
194
+
195
+ /**
196
+ * 按条件删除数据,返回删除的记录行数.
197
+ * 务必谨慎使用,大批量删除容易带来性能问题,造成线上事故.
198
+ * @param coll
199
+ * @param filter
200
+ * @returns 被删除记录的数量
201
+ */
202
+ async deleteMany<T extends Document>(
203
+ coll: MongoCollection<T>,
204
+ filter: Filter<MongoDocWithId<T>>
205
+ ): Promise<number> {
206
+ if (!Object.keys(filter).length) {
207
+ throw new MongoDBException('filter cannot be empty !')
208
+ }
209
+ return this.timingQuery({
210
+ query: async () => {
211
+ const res = await this.getCollection(coll).deleteMany(filter as Filter<T>, {
212
+ session: this.session
213
+ })
214
+ return res.deletedCount
215
+ },
216
+ desc() {
217
+ return {
218
+ op: 'deleteMany',
219
+ coll: coll.collectionName,
220
+ filter
221
+ }
222
+ }
223
+ })
224
+ }
225
+
226
+ /**
227
+ * 查询集合中所有记录.谨慎使用!
228
+ * @param coll
229
+ * @returns
230
+ */
231
+ async findAll<T extends Document>(coll: MongoCollection<T>): Promise<MongoDocWithId<T>[]> {
232
+ return this.timingQuery({
233
+ query: async () => {
234
+ const arr = await this.getCollection(coll).find({}, { session: this.session }).toArray()
235
+ return arr as MongoDocWithId<T>[]
236
+ },
237
+ desc() {
238
+ return {
239
+ op: 'findAll',
240
+ coll: coll.collectionName
241
+ }
242
+ }
243
+ })
244
+ }
245
+ /**
246
+ * 根据给定的条件查找第一条符合条件的记录
247
+ * @param coll
248
+ * @param filter
249
+ * @returns
250
+ */
251
+ async findFirst<T extends Document>(
252
+ coll: MongoCollection<T>,
253
+ filter: Filter<MongoDocWithId<T>>
254
+ ): Promise<MongoDocWithId<T> | null> {
255
+ return this.timingQuery({
256
+ query: async () => {
257
+ const res = await this.getCollection(coll).findOne(filter as Filter<T>, {
258
+ limit: 1,
259
+ session: this.session
260
+ })
261
+ return res as MongoDocWithId<T> | null
262
+ },
263
+ desc() {
264
+ return {
265
+ op: 'findFirst',
266
+ coll: coll.collectionName,
267
+ filter
268
+ }
269
+ }
270
+ })
271
+ }
272
+ /**
273
+ * 插入新记录
274
+ * @param coll
275
+ * @param data
276
+ * @returns
277
+ */
278
+ async insert<T extends Document>(
279
+ coll: MongoCollection<T>,
280
+ data: T & { _id?: MongoDocId }
281
+ ): Promise<MongoDocWithId<T>> {
282
+ return this.timingQuery({
283
+ query: async () => {
284
+ // 创建时间和更新时间
285
+ if (coll.createdDate) {
286
+ const createdData = coll.createdDate.type === 'date' ? new Date() : new Date().getTime()
287
+ data[coll.createdDate.field] = createdData as any
288
+ }
289
+ if (coll.updatedDate) {
290
+ const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime()
291
+ data[coll.updatedDate.field] = updatedDate as any
292
+ }
293
+ const collection = this.getCollection(coll)
294
+ const res = await collection.insertOne(data as any, { session: this.session })
295
+ if (data._id) {
296
+ return data as any
297
+ }
298
+ data._id = res.insertedId
299
+ return data as any
300
+ },
301
+ desc() {
302
+ return {
303
+ op: 'insert',
304
+ coll: coll.collectionName,
305
+ data
306
+ }
307
+ }
308
+ })
309
+ }
310
+ /**
311
+ * 插入多条,批量插入.
312
+ * @param coll
313
+ * @param list
314
+ */
315
+ async insertMany<T extends Document>(
316
+ coll: MongoCollection<T>,
317
+ list: Array<T & { _id?: MongoDocId }>
318
+ ): Promise<MongoDocWithId<T>[]> {
319
+ return this.timingQuery({
320
+ query: async () => {
321
+ const docList = list.map(data => {
322
+ // 创建时间和更新时间
323
+ if (coll.createdDate) {
324
+ const createdData = coll.createdDate.type === 'date' ? new Date() : new Date().getTime()
325
+ data[coll.createdDate.field] = createdData as any
326
+ }
327
+ if (coll.updatedDate) {
328
+ const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime()
329
+ data[coll.updatedDate.field] = updatedDate as any
330
+ }
331
+ return data
332
+ })
333
+
334
+ const collection = this.getCollection(coll)
335
+ const res = await collection.insertMany(docList as any, { session: this.session })
336
+ docList.forEach((doc, idx) => {
337
+ if (doc._id) {
338
+ return
339
+ }
340
+ if (res.insertedIds[idx]) {
341
+ doc._id = res.insertedIds[idx]
342
+ }
343
+ })
344
+ return docList as any
345
+ },
346
+ desc() {
347
+ return {
348
+ op: 'insertMany',
349
+ coll: coll.collectionName,
350
+ list
351
+ }
352
+ }
353
+ })
354
+ }
355
+ /**
356
+ * 更新,更新完整的文档内容。
357
+ * @param coll 集合信息
358
+ * @param data 要更新的数据,必须包含 _id 字段,支持 mongo 更新语法 $inc 等
359
+ * @returns 返回最新的数据
360
+ * @throws MongoDBException 当无法完成更新时抛出
361
+ */
362
+ async update<T extends Document>(
363
+ coll: MongoCollection<T>,
364
+ data: MongoDocWithId<T>
365
+ ): Promise<MongoDocWithId<T>> {
366
+ return this.timingQuery({
367
+ query: async () => {
368
+ const id = data._id
369
+ if (!id) {
370
+ throw new MongoDBException(
371
+ `Cannot update a document without an id,collection name:${coll.collectionName}`
372
+ )
373
+ }
374
+ delete (data as any)._id
375
+ let createData: any = undefined
376
+ // 保护创建时间不被更新
377
+ if (coll.createdDate && data[coll.createdDate.field]) {
378
+ createData = data[coll.createdDate.field]
379
+ delete data[coll.createdDate.field]
380
+ }
381
+ // 更新时间
382
+ if (coll.updatedDate) {
383
+ const updatedDate = coll.updatedDate.type === 'date' ? new Date() : new Date().getTime()
384
+ data[coll.updatedDate.field] = updatedDate as any
385
+ }
386
+
387
+ const res = await this.getCollection(coll).updateOne(
388
+ { _id: id } as Filter<T>,
389
+ { $set: data },
390
+ {
391
+ session: this.session
392
+ }
393
+ )
394
+ if (res.modifiedCount !== 1) {
395
+ throw new MongoDBException(
396
+ `Failed to update record, possibly due to non-existent record,collection:${coll.collectionName},id:${id}`
397
+ )
398
+ }
399
+ data._id = id
400
+ if (coll.createdDate && createData) {
401
+ data[coll.createdDate.field] = createData
402
+ }
403
+ return data
404
+ },
405
+ desc() {
406
+ return {
407
+ op: 'update',
408
+ coll: coll.collectionName,
409
+ data
410
+ }
411
+ }
412
+ })
413
+ }
414
+ /**
415
+ * 仅更新一条记录
416
+ * @param coll
417
+ * @param filter
418
+ * @param updater
419
+ */
420
+ async updateOne<T extends Document>(
421
+ coll: MongoCollection<T>,
422
+ filter: Partial<T>,
423
+ updater: UpdateFilter<T>
424
+ ) {
425
+ if (!Object.keys(filter).length) {
426
+ throw new MongoDBException('filter cannot be empty !')
427
+ }
428
+ if (!Object.keys(updater).length) {
429
+ throw new MongoDBException('updater cannot be empty !')
430
+ }
431
+ return this.timingQuery({
432
+ query: async () => {
433
+ // 更新时间处理
434
+ if (coll.updatedDate) {
435
+ const updatedDate: any =
436
+ coll.updatedDate.type === 'date' ? new Date() : new Date().getTime()
437
+ if (updater.$set) {
438
+ updater.$set[coll.updatedDate.field] = updatedDate
439
+ } else {
440
+ updater.$set = { [coll.updatedDate.field]: updatedDate } as any
441
+ }
442
+ }
443
+ const res = await this.getCollection(coll).updateOne(filter as Filter<T>, updater, {
444
+ session: this.session
445
+ })
446
+ return res.modifiedCount === 1
447
+ },
448
+ desc() {
449
+ return {
450
+ op: 'updateOne',
451
+ coll: coll.collectionName,
452
+ filter,
453
+ updator: updater
454
+ }
455
+ }
456
+ })
457
+ }
458
+ /**
459
+ * 局部更新,仅更新部分字段,可对字段做递增或数组元组的处理。
460
+ * @param coll 集合信息
461
+ * @param id id
462
+ * @param updater 更新内容
463
+ * @returns 更新是否成功
464
+ */
465
+ async partialUpdate<T extends Document>(
466
+ coll: MongoCollection<T>,
467
+ id: MongoDocId,
468
+ updater: UpdateFilter<T>
469
+ ): Promise<boolean> {
470
+ if (!Object.keys(updater).length) {
471
+ throw new MongoDBException('updater cannot be empty !')
472
+ }
473
+ return this.timingQuery({
474
+ query: async () => {
475
+ // 更新时间处理
476
+ if (coll.updatedDate) {
477
+ const updatedDate: any =
478
+ coll.updatedDate.type === 'date' ? new Date() : new Date().getTime()
479
+ if (updater.$set) {
480
+ updater.$set[coll.updatedDate.field] = updatedDate
481
+ } else {
482
+ updater.$set = { [coll.updatedDate.field]: updatedDate } as any
483
+ }
484
+ }
485
+ const res = await this.getCollection(coll).updateOne({ _id: id as any }, updater, {
486
+ session: this.session
487
+ })
488
+ return res.modifiedCount === 1
489
+ },
490
+ desc() {
491
+ return {
492
+ op: 'partialUpdate',
493
+ coll: coll.collectionName,
494
+ id,
495
+ updator: updater
496
+ }
497
+ }
498
+ })
499
+ }
500
+
501
+ /**
502
+ * 根据条件更新多条记录,和 partialUpdate 区别是可以根据过滤条件来处理多条记录。
503
+ * @param coll 集合
504
+ * @param filter 过滤规则
505
+ * @param updater 更新内容
506
+ * @returns 此次更新的记录数
507
+ */
508
+ async updateMany<T extends Document>(
509
+ coll: MongoCollection<T>,
510
+ filter: Filter<MongoDocWithId<T>>,
511
+ updater: UpdateFilter<T>
512
+ ): Promise<number> {
513
+ if (!Object.keys(filter).length) {
514
+ throw new MongoDBException('filter cannot be empty !')
515
+ }
516
+ if (!Object.keys(updater).length) {
517
+ throw new MongoDBException('updater cannot be empty !')
518
+ }
519
+ return this.timingQuery({
520
+ query: async () => {
521
+ // 更新时间处理
522
+ if (coll.updatedDate) {
523
+ const updatedDate: any =
524
+ coll.updatedDate.type === 'date' ? new Date() : new Date().getTime()
525
+ if (updater.$set) {
526
+ updater.$set[coll.updatedDate.field] = updatedDate
527
+ } else {
528
+ updater.$set = { [coll.updatedDate.field]: updatedDate } as any
529
+ }
530
+ }
531
+ const res = await this.getCollection(coll).updateMany(filter as Filter<T>, updater, {
532
+ session: this.session
533
+ })
534
+ return res.modifiedCount
535
+ },
536
+ desc() {
537
+ return {
538
+ op: 'updateMany',
539
+ coll: coll.collectionName,
540
+ filter,
541
+ updator: updater
542
+ }
543
+ }
544
+ })
545
+ }
546
+
547
+ /**
548
+ * 条件查询
549
+ * @param coll 集合信息
550
+ * @param filter 过滤条件
551
+ * @param opts 额外的选项
552
+ * @returns
553
+ */
554
+ async find<T extends Document>(
555
+ coll: MongoCollection<T>,
556
+ filter: Filter<MongoDocWithId<T>>,
557
+ opts?: {
558
+ /**
559
+ * 偏移,需要 limit 有值才可以
560
+ */
561
+ offset?: number
562
+ /**
563
+ * 限制返回的数量
564
+ */
565
+ limit?: number
566
+ /**
567
+ * 排序规则,按先后顺序放入,每个规则是一个元组,第一个元素是字段名称,第二个元素是顺序
568
+ */
569
+ orderBy?: Array<[keyof MongoDocWithId<T>, 'asc' | 'desc']>
570
+ }
571
+ ): Promise<MongoDocWithId<T>[]> {
572
+ return this.timingQuery({
573
+ query: async () => {
574
+ const arr = await this.getCollection(coll)
575
+ .find(filter as Filter<T>, {
576
+ limit: opts && opts.limit && opts.limit > 0 ? opts.limit : undefined,
577
+ skip:
578
+ opts && opts.limit && opts.limit > 0 && opts.offset && opts.offset > 0
579
+ ? opts.offset
580
+ : undefined,
581
+ sort: opts && opts.orderBy ? (opts.orderBy as [string, SortDirection][]) : undefined,
582
+ session: this.session
583
+ })
584
+ .toArray()
585
+ return arr as MongoDocWithId<T>[]
586
+ },
587
+ desc() {
588
+ return {
589
+ op: 'find',
590
+ coll: coll.collectionName,
591
+ filter,
592
+ opts
593
+ }
594
+ }
595
+ })
596
+ }
597
+ /**
598
+ * 查询符合条件的文档数量。请谨慎使用,count 是不能从索引直接读取的,只能实时计数,使用不当容易造成性能问题,引发线上事故。
599
+ * @param coll
600
+ * @param filter
601
+ * @returns
602
+ */
603
+ count<T extends Document>(
604
+ coll: MongoCollection<T>,
605
+ filter: Filter<MongoDocWithId<T>>
606
+ ): Promise<number> {
607
+ return this.timingQuery({
608
+ query: async () => {
609
+ return this.getCollection(coll).countDocuments(filter, { session: this.session })
610
+ },
611
+ desc() {
612
+ return {
613
+ op: 'count',
614
+ coll: coll.collectionName,
615
+ filter
616
+ }
617
+ }
618
+ })
619
+ }
620
+
621
+ /**
622
+ * 分页查询。谨慎使用,不建议对规模较大的数据查询直接使用分页。
623
+ * @param coll 集合信息
624
+ * @param filter 过滤条件
625
+ * @param opts 分页参数
626
+ */
627
+ async paginate<T extends Document>(
628
+ coll: MongoCollection<T>,
629
+ filter: Filter<MongoDocWithId<T>>,
630
+ opts: {
631
+ /**
632
+ * 页码,从1开始,第一页是 1
633
+ */
634
+ pn: number
635
+ /**
636
+ * 每页的数据量大小
637
+ */
638
+ pz: number
639
+ /**
640
+ * 排序规则,按先后顺序放入,每个规则是一个元组,第一个元素是字段名称,第二个元素是顺序
641
+ */
642
+ orderBy?: Array<[keyof MongoDocWithId<T>, 'asc' | 'desc']>
643
+ }
644
+ ): Promise<MongoPage<MongoDocWithId<T>>> {
645
+ validate(opts, {
646
+ pn: [notNull(), min(1)],
647
+ pz: [notNull(), min(1)]
648
+ })
649
+ const start = new Date().getTime()
650
+ try {
651
+ const offset = (opts.pn - 1) * opts.pz
652
+ const res = await Promise.all([
653
+ this.find(coll, filter, { offset, limit: opts.pz, orderBy: opts.orderBy }),
654
+ this.count(coll, filter)
655
+ ])
656
+ const [list, total] = res
657
+ return { list, total }
658
+ } finally {
659
+ if (this.config.slowQueryWarn) {
660
+ const cost = new Date().getTime() - start
661
+ if (cost > this.config.slowQueryMs) {
662
+ getLogger().warn(
663
+ `[mongodb slow query] ${cost}ms ${JSON.stringify({
664
+ op: 'paginate',
665
+ coll: coll.collectionName,
666
+ filter,
667
+ opts
668
+ })}`
669
+ )
670
+ }
671
+ }
672
+ }
673
+ }
674
+ }