@resolveio/server-lib 12.5.52 → 12.5.54

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 (400) hide show
  1. package/.nodemon.json +5 -0
  2. package/.vscode/settings.json +3 -0
  3. package/README.md +22 -0
  4. package/compileDTS.pl +64 -0
  5. package/gulpfile.js +127 -0
  6. package/mongodbensurers.js +2 -0
  7. package/mongostop.js +3 -0
  8. package/package.json +1 -1
  9. package/settings.development.json +13 -0
  10. package/src/client-server-app.ts +7 -0
  11. package/src/collections/app-status.collection.ts +51 -0
  12. package/src/collections/counter.collection.ts +54 -0
  13. package/src/collections/cron-job-history.collection.ts +82 -0
  14. package/src/collections/cron-job.collection.ts +85 -0
  15. package/src/collections/email-history.collection.ts +66 -0
  16. package/src/collections/email-verified.collection.ts +61 -0
  17. package/src/collections/file.collection.ts +73 -0
  18. package/src/collections/flag.collection.ts +56 -0
  19. package/src/collections/log-method-latency.collection.ts +64 -0
  20. package/src/collections/log-subscription.collection.ts +68 -0
  21. package/src/collections/log-ts.collection.ts +78 -0
  22. package/src/collections/log.collection.ts +77 -0
  23. package/src/collections/logged-in-users.collection.ts +65 -0
  24. package/src/collections/method-response.collection.ts +66 -0
  25. package/src/collections/monitor-cpu.collection.ts +63 -0
  26. package/src/collections/monitor-memory.collection.ts +75 -0
  27. package/src/collections/monitor-mongo.collection.ts +69 -0
  28. package/src/collections/notification.collection.ts +51 -0
  29. package/src/collections/report-builder-dashboard-builder.collection.ts +109 -0
  30. package/src/collections/report-builder-library.collection.ts +89 -0
  31. package/src/collections/report-builder-report.collection.ts +149 -0
  32. package/src/collections/user-group.collection.ts +90 -0
  33. package/src/collections/user-guide.collection.ts +57 -0
  34. package/src/collections/user.collection.ts +259 -0
  35. package/src/cron/cron.ts +188 -0
  36. package/src/fixtures/cron-jobs.ts +25 -0
  37. package/src/fixtures/init.ts +10 -0
  38. package/src/http/auth.ts +732 -0
  39. package/src/http/health.ts +7 -0
  40. package/src/http/home.ts +71 -0
  41. package/src/index.ts +71 -0
  42. package/src/managers/cron.manager.ts +208 -0
  43. package/src/managers/method.manager.ts +607 -0
  44. package/src/managers/mongo.manager.ts +2282 -0
  45. package/src/managers/monitor.manager.ts +323 -0
  46. package/src/managers/subscription.manager.ts +1196 -0
  47. package/{managers/subscription.performance.js → src/managers/subscription.performance.ts} +68 -33
  48. package/src/methods/accounts.ts +202 -0
  49. package/src/methods/aws.ts +507 -0
  50. package/src/methods/collections.ts +512 -0
  51. package/src/methods/counters.ts +75 -0
  52. package/src/methods/cron-jobs.ts +1454 -0
  53. package/src/methods/flags.ts +7 -0
  54. package/src/methods/logs.ts +327 -0
  55. package/src/methods/monitor.ts +548 -0
  56. package/src/methods/pdf.ts +615 -0
  57. package/src/methods/report-builder.ts +876 -0
  58. package/src/methods/support.ts +146 -0
  59. package/{models/app-status.model.d.ts → src/models/app-status.model.ts} +3 -2
  60. package/{models/billing-logged-in-users.model.d.ts → src/models/billing-logged-in-users.model.ts} +5 -4
  61. package/src/models/collection-document.model.ts +22 -0
  62. package/{models/counter.model.d.ts → src/models/counter.model.ts} +4 -3
  63. package/src/models/cron-job-history.model.ts +13 -0
  64. package/src/models/cron-job.model.ts +14 -0
  65. package/src/models/dialog.model.ts +25 -0
  66. package/{models/email-history.model.d.ts → src/models/email-history.model.ts} +8 -7
  67. package/{models/email-verified.model.d.ts → src/models/email-verified.model.ts} +6 -5
  68. package/{models/file.model.d.ts → src/models/file.model.ts} +8 -7
  69. package/{models/flag.model.d.ts → src/models/flag.model.ts} +4 -3
  70. package/{models/log-method-latency.model.d.ts → src/models/log-method-latency.model.ts} +5 -4
  71. package/{models/log-subscription.model.d.ts → src/models/log-subscription.model.ts} +8 -6
  72. package/{models/log.model.d.ts → src/models/log.model.ts} +12 -10
  73. package/{models/logged-in-users.model.d.ts → src/models/logged-in-users.model.ts} +6 -5
  74. package/{models/method-response.model.d.ts → src/models/method-response.model.ts} +7 -6
  75. package/src/models/method.model.ts +11 -0
  76. package/{models/monitor-cpu.model.d.ts → src/models/monitor-cpu.model.ts} +9 -7
  77. package/src/models/monitor-memory.model.ts +17 -0
  78. package/src/models/monitor-mongo.model.ts +15 -0
  79. package/{models/notification.model.d.ts → src/models/notification.model.ts} +3 -2
  80. package/src/models/pagination.model.ts +30 -0
  81. package/src/models/permission.model.ts +14 -0
  82. package/src/models/report-builder-dashboard-builder.model.ts +29 -0
  83. package/src/models/report-builder-library.model.ts +20 -0
  84. package/src/models/report-builder-report.model.ts +110 -0
  85. package/src/models/report-builder.model.ts +68 -0
  86. package/src/models/select-data-label.model.ts +9 -0
  87. package/src/models/server-response.model.ts +5 -0
  88. package/src/models/subscription.model.ts +64 -0
  89. package/src/models/support-ticket.model.ts +81 -0
  90. package/src/models/user-group.model.ts +23 -0
  91. package/{models/user-guide.model.d.ts → src/models/user-guide.model.ts} +5 -4
  92. package/src/models/user.model.ts +79 -0
  93. package/{public_api.d.ts → src/public_api.ts} +1 -1
  94. package/src/publications/app-status.ts +13 -0
  95. package/src/publications/cron-jobs.ts +30 -0
  96. package/src/publications/files.ts +34 -0
  97. package/src/publications/flags.ts +20 -0
  98. package/src/publications/logs.ts +164 -0
  99. package/src/publications/method-responses.ts +13 -0
  100. package/src/publications/notifications.ts +13 -0
  101. package/src/publications/report-builder-dashboard-builders.ts +39 -0
  102. package/src/publications/report-builder-libraries.ts +41 -0
  103. package/src/publications/report-builder-reports.ts +48 -0
  104. package/src/publications/super-admin.ts +13 -0
  105. package/src/publications/user-groups.ts +12 -0
  106. package/src/publications/user-guides.ts +12 -0
  107. package/src/server-app.ts +769 -0
  108. package/src/util/common.ts +519 -0
  109. package/src/util/schema-report-builder.ts +413 -0
  110. package/tsconfig.json +30 -0
  111. package/tslint.json +143 -0
  112. package/client-server-app.d.ts +0 -1
  113. package/client-server-app.js +0 -48
  114. package/client-server-app.js.map +0 -1
  115. package/collections/app-status.collection.d.ts +0 -3
  116. package/collections/app-status.collection.js +0 -51
  117. package/collections/app-status.collection.js.map +0 -1
  118. package/collections/counter.collection.d.ts +0 -3
  119. package/collections/counter.collection.js +0 -54
  120. package/collections/counter.collection.js.map +0 -1
  121. package/collections/cron-job-history.collection.d.ts +0 -3
  122. package/collections/cron-job-history.collection.js +0 -82
  123. package/collections/cron-job-history.collection.js.map +0 -1
  124. package/collections/cron-job.collection.d.ts +0 -3
  125. package/collections/cron-job.collection.js +0 -85
  126. package/collections/cron-job.collection.js.map +0 -1
  127. package/collections/email-history.collection.d.ts +0 -3
  128. package/collections/email-history.collection.js +0 -66
  129. package/collections/email-history.collection.js.map +0 -1
  130. package/collections/email-verified.collection.d.ts +0 -3
  131. package/collections/email-verified.collection.js +0 -61
  132. package/collections/email-verified.collection.js.map +0 -1
  133. package/collections/file.collection.d.ts +0 -3
  134. package/collections/file.collection.js +0 -73
  135. package/collections/file.collection.js.map +0 -1
  136. package/collections/flag.collection.d.ts +0 -3
  137. package/collections/flag.collection.js +0 -56
  138. package/collections/flag.collection.js.map +0 -1
  139. package/collections/log-method-latency.collection.d.ts +0 -3
  140. package/collections/log-method-latency.collection.js +0 -64
  141. package/collections/log-method-latency.collection.js.map +0 -1
  142. package/collections/log-subscription.collection.d.ts +0 -3
  143. package/collections/log-subscription.collection.js +0 -68
  144. package/collections/log-subscription.collection.js.map +0 -1
  145. package/collections/log-ts.collection.d.ts +0 -3
  146. package/collections/log-ts.collection.js +0 -78
  147. package/collections/log-ts.collection.js.map +0 -1
  148. package/collections/log.collection.d.ts +0 -3
  149. package/collections/log.collection.js +0 -77
  150. package/collections/log.collection.js.map +0 -1
  151. package/collections/logged-in-users.collection.d.ts +0 -3
  152. package/collections/logged-in-users.collection.js +0 -65
  153. package/collections/logged-in-users.collection.js.map +0 -1
  154. package/collections/method-response.collection.d.ts +0 -3
  155. package/collections/method-response.collection.js +0 -66
  156. package/collections/method-response.collection.js.map +0 -1
  157. package/collections/monitor-cpu.collection.d.ts +0 -3
  158. package/collections/monitor-cpu.collection.js +0 -63
  159. package/collections/monitor-cpu.collection.js.map +0 -1
  160. package/collections/monitor-memory.collection.d.ts +0 -3
  161. package/collections/monitor-memory.collection.js +0 -75
  162. package/collections/monitor-memory.collection.js.map +0 -1
  163. package/collections/monitor-mongo.collection.d.ts +0 -3
  164. package/collections/monitor-mongo.collection.js +0 -69
  165. package/collections/monitor-mongo.collection.js.map +0 -1
  166. package/collections/notification.collection.d.ts +0 -3
  167. package/collections/notification.collection.js +0 -51
  168. package/collections/notification.collection.js.map +0 -1
  169. package/collections/report-builder-dashboard-builder.collection.d.ts +0 -3
  170. package/collections/report-builder-dashboard-builder.collection.js +0 -109
  171. package/collections/report-builder-dashboard-builder.collection.js.map +0 -1
  172. package/collections/report-builder-library.collection.d.ts +0 -3
  173. package/collections/report-builder-library.collection.js +0 -87
  174. package/collections/report-builder-library.collection.js.map +0 -1
  175. package/collections/report-builder-report.collection.d.ts +0 -4
  176. package/collections/report-builder-report.collection.js +0 -149
  177. package/collections/report-builder-report.collection.js.map +0 -1
  178. package/collections/user-group.collection.d.ts +0 -4
  179. package/collections/user-group.collection.js +0 -90
  180. package/collections/user-group.collection.js.map +0 -1
  181. package/collections/user-guide.collection.d.ts +0 -3
  182. package/collections/user-guide.collection.js +0 -57
  183. package/collections/user-guide.collection.js.map +0 -1
  184. package/collections/user.collection.d.ts +0 -4
  185. package/collections/user.collection.js +0 -259
  186. package/collections/user.collection.js.map +0 -1
  187. package/cron/cron.d.ts +0 -5
  188. package/cron/cron.js +0 -162
  189. package/cron/cron.js.map +0 -1
  190. package/fixtures/cron-jobs.d.ts +0 -1
  191. package/fixtures/cron-jobs.js +0 -73
  192. package/fixtures/cron-jobs.js.map +0 -1
  193. package/fixtures/init.d.ts +0 -1
  194. package/fixtures/init.js +0 -59
  195. package/fixtures/init.js.map +0 -1
  196. package/http/auth.d.ts +0 -2
  197. package/http/auth.js +0 -763
  198. package/http/auth.js.map +0 -1
  199. package/http/health.d.ts +0 -1
  200. package/http/health.js +0 -12
  201. package/http/health.js.map +0 -1
  202. package/http/home.d.ts +0 -2
  203. package/http/home.js +0 -66
  204. package/http/home.js.map +0 -1
  205. package/index.d.ts +0 -23
  206. package/index.js +0 -127
  207. package/index.js.map +0 -1
  208. package/managers/cron.manager.d.ts +0 -17
  209. package/managers/cron.manager.js +0 -242
  210. package/managers/cron.manager.js.map +0 -1
  211. package/managers/method.manager.d.ts +0 -38
  212. package/managers/method.manager.js +0 -595
  213. package/managers/method.manager.js.map +0 -1
  214. package/managers/mongo.manager.d.ts +0 -178
  215. package/managers/mongo.manager.js +0 -2221
  216. package/managers/mongo.manager.js.map +0 -1
  217. package/managers/monitor.manager.d.ts +0 -59
  218. package/managers/monitor.manager.js +0 -351
  219. package/managers/monitor.manager.js.map +0 -1
  220. package/managers/subscription.manager.d.ts +0 -50
  221. package/managers/subscription.manager.js +0 -1091
  222. package/managers/subscription.manager.js.map +0 -1
  223. package/managers/subscription.performance.d.ts +0 -1
  224. package/managers/subscription.performance.js.map +0 -1
  225. package/methods/accounts.d.ts +0 -2
  226. package/methods/accounts.js +0 -274
  227. package/methods/accounts.js.map +0 -1
  228. package/methods/aws.d.ts +0 -2
  229. package/methods/aws.js +0 -617
  230. package/methods/aws.js.map +0 -1
  231. package/methods/collections.d.ts +0 -2
  232. package/methods/collections.js +0 -499
  233. package/methods/collections.js.map +0 -1
  234. package/methods/counters.d.ts +0 -2
  235. package/methods/counters.js +0 -122
  236. package/methods/counters.js.map +0 -1
  237. package/methods/cron-jobs.d.ts +0 -2
  238. package/methods/cron-jobs.js +0 -1315
  239. package/methods/cron-jobs.js.map +0 -1
  240. package/methods/flags.d.ts +0 -2
  241. package/methods/flags.js +0 -9
  242. package/methods/flags.js.map +0 -1
  243. package/methods/logs.d.ts +0 -2
  244. package/methods/logs.js +0 -371
  245. package/methods/logs.js.map +0 -1
  246. package/methods/monitor.d.ts +0 -2
  247. package/methods/monitor.js +0 -565
  248. package/methods/monitor.js.map +0 -1
  249. package/methods/pdf.d.ts +0 -2
  250. package/methods/pdf.js +0 -324
  251. package/methods/pdf.js.map +0 -1
  252. package/methods/report-builder.d.ts +0 -2
  253. package/methods/report-builder.js +0 -858
  254. package/methods/report-builder.js.map +0 -1
  255. package/methods/support.d.ts +0 -2
  256. package/methods/support.js +0 -246
  257. package/methods/support.js.map +0 -1
  258. package/models/app-status.model.js +0 -4
  259. package/models/app-status.model.js.map +0 -1
  260. package/models/billing-logged-in-users.model.js +0 -4
  261. package/models/billing-logged-in-users.model.js.map +0 -1
  262. package/models/collection-document.model.d.ts +0 -19
  263. package/models/collection-document.model.js +0 -4
  264. package/models/collection-document.model.js.map +0 -1
  265. package/models/counter.model.js +0 -4
  266. package/models/counter.model.js.map +0 -1
  267. package/models/cron-job-history.model.d.ts +0 -12
  268. package/models/cron-job-history.model.js +0 -4
  269. package/models/cron-job-history.model.js.map +0 -1
  270. package/models/cron-job.model.d.ts +0 -13
  271. package/models/cron-job.model.js +0 -4
  272. package/models/cron-job.model.js.map +0 -1
  273. package/models/dialog.model.d.ts +0 -23
  274. package/models/dialog.model.js +0 -4
  275. package/models/dialog.model.js.map +0 -1
  276. package/models/email-history.model.js +0 -4
  277. package/models/email-history.model.js.map +0 -1
  278. package/models/email-verified.model.js +0 -4
  279. package/models/email-verified.model.js.map +0 -1
  280. package/models/file.model.js +0 -4
  281. package/models/file.model.js.map +0 -1
  282. package/models/flag.model.js +0 -4
  283. package/models/flag.model.js.map +0 -1
  284. package/models/log-method-latency.model.js +0 -4
  285. package/models/log-method-latency.model.js.map +0 -1
  286. package/models/log-subscription.model.js +0 -4
  287. package/models/log-subscription.model.js.map +0 -1
  288. package/models/log.model.js +0 -4
  289. package/models/log.model.js.map +0 -1
  290. package/models/logged-in-users.model.js +0 -4
  291. package/models/logged-in-users.model.js.map +0 -1
  292. package/models/method-response.model.js +0 -4
  293. package/models/method-response.model.js.map +0 -1
  294. package/models/method.model.d.ts +0 -9
  295. package/models/method.model.js +0 -4
  296. package/models/method.model.js.map +0 -1
  297. package/models/monitor-cpu.model.js +0 -4
  298. package/models/monitor-cpu.model.js.map +0 -1
  299. package/models/monitor-memory.model.d.ts +0 -15
  300. package/models/monitor-memory.model.js +0 -4
  301. package/models/monitor-memory.model.js.map +0 -1
  302. package/models/monitor-mongo.model.d.ts +0 -13
  303. package/models/monitor-mongo.model.js +0 -4
  304. package/models/monitor-mongo.model.js.map +0 -1
  305. package/models/notification.model.js +0 -4
  306. package/models/notification.model.js.map +0 -1
  307. package/models/pagination.model.d.ts +0 -10
  308. package/models/pagination.model.js +0 -24
  309. package/models/pagination.model.js.map +0 -1
  310. package/models/permission.model.d.ts +0 -12
  311. package/models/permission.model.js +0 -4
  312. package/models/permission.model.js.map +0 -1
  313. package/models/report-builder-dashboard-builder.model.d.ts +0 -25
  314. package/models/report-builder-dashboard-builder.model.js +0 -4
  315. package/models/report-builder-dashboard-builder.model.js.map +0 -1
  316. package/models/report-builder-library.model.d.ts +0 -17
  317. package/models/report-builder-library.model.js +0 -4
  318. package/models/report-builder-library.model.js.map +0 -1
  319. package/models/report-builder-report.model.d.ts +0 -98
  320. package/models/report-builder-report.model.js +0 -4
  321. package/models/report-builder-report.model.js.map +0 -1
  322. package/models/report-builder.model.d.ts +0 -61
  323. package/models/report-builder.model.js +0 -4
  324. package/models/report-builder.model.js.map +0 -1
  325. package/models/select-data-label.model.d.ts +0 -9
  326. package/models/select-data-label.model.js +0 -4
  327. package/models/select-data-label.model.js.map +0 -1
  328. package/models/server-response.model.d.ts +0 -5
  329. package/models/server-response.model.js +0 -4
  330. package/models/server-response.model.js.map +0 -1
  331. package/models/subscription.model.d.ts +0 -23
  332. package/models/subscription.model.js +0 -4
  333. package/models/subscription.model.js.map +0 -1
  334. package/models/support-ticket.model.d.ts +0 -72
  335. package/models/support-ticket.model.js +0 -4
  336. package/models/support-ticket.model.js.map +0 -1
  337. package/models/user-group.model.d.ts +0 -19
  338. package/models/user-group.model.js +0 -4
  339. package/models/user-group.model.js.map +0 -1
  340. package/models/user-guide.model.js +0 -4
  341. package/models/user-guide.model.js.map +0 -1
  342. package/models/user.model.d.ts +0 -70
  343. package/models/user.model.js +0 -4
  344. package/models/user.model.js.map +0 -1
  345. package/public_api.js +0 -75
  346. package/public_api.js.map +0 -1
  347. package/publications/app-status.d.ts +0 -2
  348. package/publications/app-status.js +0 -17
  349. package/publications/app-status.js.map +0 -1
  350. package/publications/cron-jobs.d.ts +0 -2
  351. package/publications/cron-jobs.js +0 -33
  352. package/publications/cron-jobs.js.map +0 -1
  353. package/publications/files.d.ts +0 -2
  354. package/publications/files.js +0 -37
  355. package/publications/files.js.map +0 -1
  356. package/publications/flags.d.ts +0 -2
  357. package/publications/flags.js +0 -23
  358. package/publications/flags.js.map +0 -1
  359. package/publications/logs.d.ts +0 -2
  360. package/publications/logs.js +0 -165
  361. package/publications/logs.js.map +0 -1
  362. package/publications/method-responses.d.ts +0 -2
  363. package/publications/method-responses.js +0 -17
  364. package/publications/method-responses.js.map +0 -1
  365. package/publications/notifications.d.ts +0 -2
  366. package/publications/notifications.js +0 -17
  367. package/publications/notifications.js.map +0 -1
  368. package/publications/report-builder-dashboard-builders.d.ts +0 -2
  369. package/publications/report-builder-dashboard-builders.js +0 -43
  370. package/publications/report-builder-dashboard-builders.js.map +0 -1
  371. package/publications/report-builder-libraries.d.ts +0 -2
  372. package/publications/report-builder-libraries.js +0 -90
  373. package/publications/report-builder-libraries.js.map +0 -1
  374. package/publications/report-builder-reports.d.ts +0 -2
  375. package/publications/report-builder-reports.js +0 -51
  376. package/publications/report-builder-reports.js.map +0 -1
  377. package/publications/super-admin.d.ts +0 -2
  378. package/publications/super-admin.js +0 -17
  379. package/publications/super-admin.js.map +0 -1
  380. package/publications/user-groups.d.ts +0 -1
  381. package/publications/user-groups.js +0 -17
  382. package/publications/user-groups.js.map +0 -1
  383. package/publications/user-guides.d.ts +0 -1
  384. package/publications/user-guides.js +0 -17
  385. package/publications/user-guides.js.map +0 -1
  386. package/server-app.d.ts +0 -52
  387. package/server-app.js +0 -739
  388. package/server-app.js.map +0 -1
  389. package/util/common.d.ts +0 -25
  390. package/util/common.js +0 -524
  391. package/util/common.js.map +0 -1
  392. package/util/schema-report-builder.d.ts +0 -6
  393. package/util/schema-report-builder.js +0 -453
  394. package/util/schema-report-builder.js.map +0 -1
  395. /package/{private → src/private}/email-templates/enrollment.html +0 -0
  396. /package/{private → src/private}/email-templates/forgot-password.html +0 -0
  397. /package/{private → src/private}/email-templates/support-ticket-deleted.html +0 -0
  398. /package/{private → src/private}/email-templates/support-ticket-modified.html +0 -0
  399. /package/{private → src/private}/email-templates/support-ticket.html +0 -0
  400. /package/{private → src/private}/images/ResolveIO.png +0 -0
@@ -0,0 +1,2282 @@
1
+ import SimpleSchema from 'simpl-schema';
2
+ import { AggregateOptions, AggregationCursor, BulkWriteOptions, ChangeStream, ChangeStreamOptions, CollStats, CollStatsOptions, CommandOperationOptions, CountDocumentsOptions, CreateCollectionOptions, CreateIndexesOptions, CursorStreamOptions, DeleteOptions, Filter, FindCursor, FindOneAndDeleteOptions, FindOneAndReplaceOptions, FindOneAndUpdateOptions, FindOptions, IndexDescription, IndexInformationOptions, InsertOneOptions, ListIndexesCursor, ListIndexesOptions, ObjectId, RenameOptions, ReplaceOptions, UpdateOptions, OptionalId, Collection, CollectionInfo, OptionalUnlessRequiredId, AnyBulkWriteOperation, BulkWriteResult } from 'mongodb';
3
+ import { LookupTables } from '../models/report-builder.model';
4
+ import { ResolveIOServer } from '../index';
5
+ import { Users } from '../collections/user.collection';
6
+ import { buildRbLookups, buildRbSchema, dateReviver, deepCopy, getBinarySize, getMongoMergeUpdatedDoc } from '../util/common';
7
+ import { UserModel } from '../models/user.model';
8
+ import { Logs } from '../collections/log.collection';
9
+ import * as NodeCache from 'node-cache';
10
+ const crypto = require('crypto');
11
+ const scmp = require('scmp');
12
+ import { MonitorMongo } from './monitor.manager';
13
+ import { CollectionDocument, Document } from '../models/collection-document.model';
14
+ import { cpus } from 'os';
15
+ const numCPUs = cpus().length;
16
+ const v8 = require('v8');
17
+
18
+ interface MongoQueueModel {
19
+ _id: number,
20
+ name_collection: string;
21
+ lookup_collections: string[];
22
+ name_function: string;
23
+ data_function: any[];
24
+ name_function_addt: string;
25
+ data_function_addt: any[];
26
+ cbs: Function[];
27
+ cbs_next: Function[];
28
+ running: boolean;
29
+ cacheId: number;
30
+ invalidateFlag: boolean;
31
+ invalidateCount: number;
32
+ }
33
+
34
+ // export declare interface MongoManagerFilterOperators<T> extends Document {
35
+ export declare interface MongoManagerFilterParamaterOperators<P> {
36
+ $eq?: P;
37
+ $gt?: P;
38
+ $gte?: P;
39
+ $in?: P extends Array<any> ? P : P[];
40
+ $lt?: P;
41
+ $lte?: P;
42
+ $ne?: P;
43
+ $nin?: P extends Array<any> ? P : P[];
44
+ $not?: P extends string ? MongoManagerFilterParamaterOperators<P> | RegExpConstructor : MongoManagerFilterParamaterOperators<P>;
45
+ $exists?: boolean;
46
+ $expr?: any[]
47
+ $regex?: P extends string ? RegExpConstructor | string : never;
48
+ $options?: P extends string ? string : never;
49
+ $geoIntersects?: {
50
+ $geometry: Document;
51
+ };
52
+ $geoWithin?: Document;
53
+ $near?: Document;
54
+ $nearSphere?: Document;
55
+ $maxDistance?: number;
56
+ $all?: any[];
57
+ $elemMatch?: Document;
58
+ $size?: P extends any[] ? number : never;
59
+ }
60
+
61
+ export declare interface MongoManagerFilterOperators<T> extends Document { //TODO: Remove extends document when I get answer on S.O.
62
+ $and?: MongoManagerFilter<T>[] | MongoManagerFilterOperators<T>;
63
+ $nor?: MongoManagerFilter<T>[] | MongoManagerFilterOperators<T>;
64
+ $or?: MongoManagerFilter<T>[] | MongoManagerFilterOperators<T>;
65
+ $text?: {
66
+ $search: string;
67
+ $language?: string;
68
+ $caseSensitive?: boolean;
69
+ $diacriticSensitive?: boolean;
70
+ };
71
+ $where?: string | ((this: T) => boolean);
72
+ $comment?: string | Document;
73
+ }
74
+
75
+ // function isDotStringRegExp(obj: Object, dotKey: string): boolean {
76
+ // let keyData = dotKey.split('.');
77
+ // let objData = obj;
78
+
79
+ // for (let i = 0; i < keyData.length; i++) {
80
+ // let key = keyData[i];
81
+ // if (objData.hasOwnProperty(key)) {
82
+ // objData = objData[key];
83
+
84
+ // if (i === keyData.length - 1) {
85
+ // return true;
86
+ // }
87
+ // }
88
+ // else {
89
+ // return false;
90
+ // }
91
+ // }
92
+ // }
93
+
94
+ // export declare type MongoManagerDotStringFilter<T> = {
95
+ // [key: string]: (isDotStringRegExp(T, key) ? any : never);
96
+ // };
97
+
98
+ export declare type MongoManagerFilter<T> = {
99
+ [P in keyof T]?: T[P] | MongoManagerFilterParamaterOperators<T[P]>;
100
+ };
101
+
102
+ export declare type MongoManagerUnsetFilter<T> = {
103
+ [P in keyof T]?: number | boolean;
104
+ };
105
+
106
+ export declare type MongoManagerIncFilter<T> = {
107
+ [P in keyof T]?: number;
108
+ };
109
+
110
+ export declare type MongoManagerUpdateFilter<T> = {
111
+ $inc?: MongoManagerIncFilter<T> | Document;
112
+ $set?: MongoManagerFilter<T> | Document;
113
+ $setOnInsert?: MongoManagerFilter<T> | Document;
114
+ $unset?: MongoManagerUnsetFilter<T> | Document;
115
+ };
116
+
117
+ export class MongoManager {
118
+ private _collections: MongoManagerCollection<CollectionDocument>[] = [];
119
+ private _mongoQueue: MongoQueueModel[] = [];
120
+ private _mongoQueueId = 0;
121
+ private _mongoQueueRunning = false;
122
+
123
+ private _nodeCache;
124
+ private _mongoQueueCacheId = 1;
125
+
126
+ private _heapStats = v8.getHeapStatistics();
127
+ private _heapLimit = this._heapStats.heap_size_limit / numCPUs / 8;
128
+
129
+ private _serverCollections: (CollectionInfo | Pick<CollectionInfo, "name" | "type">)[] = [];
130
+
131
+ private _debugMongoQueueHits = 0;
132
+ private _debugRemoveCacheHits = 0;
133
+ private _debugMongoQueueCollections = [];
134
+
135
+ constructor() {
136
+ this._nodeCache = new NodeCache( { stdTTL: 0, checkperiod: 0 } );
137
+
138
+ setInterval(() => {
139
+ if (ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
140
+ console.log(new Date(), 'Mongo Manager', 'Collections', this._collections.length);
141
+ console.log(new Date(), 'Mongo Manager', 'Mongo Queue', this._mongoQueue.length, JSON.stringify(this._mongoQueue.sort((a, b) => a.name_collection.localeCompare(b.name_collection)), null, 2));
142
+ console.log(new Date(), 'Mongo Manager', 'Server Collections', this._serverCollections.length);
143
+ console.log(new Date(), 'Mongo Manager', 'Mongo Queue Hits', this._debugMongoQueueHits);
144
+ console.log(new Date(), 'Mongo Manager', 'Mongo Queue Collections', this._debugMongoQueueCollections.sort((a, b) => a.collection.localeCompare(b.collection) || a.function.localeCompare(b.function)));
145
+ console.log(new Date(), 'Mongo Manager', 'Cache Cleanup Hits', JSON.stringify(this._debugRemoveCacheHits, null, 2));
146
+ }
147
+
148
+ this._debugMongoQueueHits = 0;
149
+ this._debugRemoveCacheHits = 0;
150
+ this._debugMongoQueueCollections = [];
151
+ }, 60000);
152
+
153
+ this.initServerCollections();
154
+
155
+ this.runQueue();
156
+ }
157
+
158
+ async initServerCollections() {
159
+ let collections = await ResolveIOServer.getMainDB().listCollections().toArray();
160
+ this._serverCollections = collections;
161
+ }
162
+
163
+ getServerCollections() {
164
+ return this._serverCollections;
165
+ }
166
+
167
+ registerCollection(collection: MongoManagerCollection<CollectionDocument>) {
168
+ if (collection.collectionOptions && collection.collectionOptions.timeseries && collection.collectionOptions.timeseries.timeField && this._serverCollections.some(a => a.name === collection.collectionName && a.type === 'collection')) {
169
+ ResolveIOServer.getMainDB().dropCollection(collection.collectionName).then(() => {
170
+ this.createCollection(collection);
171
+ });
172
+ }
173
+
174
+ this._collections.push(collection);
175
+ }
176
+
177
+ createCollection(collection: MongoManagerCollection<CollectionDocument>) {
178
+ ResolveIOServer.getMainDB().createCollection<CollectionDocument>(collection.collectionName, collection.collectionOptions);
179
+ }
180
+
181
+ collections() {
182
+ return this._collections;
183
+ }
184
+
185
+ collection(collectionName: string): MongoManagerCollection<CollectionDocument> | MongoManagerUserCollection<CollectionDocument> {
186
+ return this._collections.filter(a => a.collectionName === collectionName)[0];
187
+ }
188
+
189
+ addToQueue(mongoQueue: MongoQueueModel) {
190
+ let _mongoQueue = this._mongoQueue.filter(a => a.name_collection === mongoQueue.name_collection && a.name_function === mongoQueue.name_function && a.name_function_addt === mongoQueue.name_function_addt && JSON.stringify(a.data_function) === JSON.stringify(mongoQueue.data_function) && JSON.stringify(a.data_function_addt) === JSON.stringify(mongoQueue.data_function_addt))[0];
191
+
192
+ if (_mongoQueue) {
193
+ if (!_mongoQueue.running) {
194
+ _mongoQueue.cbs.push(mongoQueue.cbs[0]);
195
+ }
196
+ else {
197
+ _mongoQueue.cbs_next.push(mongoQueue.cbs[0]);
198
+ }
199
+ }
200
+ else {
201
+ mongoQueue._id = this._mongoQueueId;
202
+ this._mongoQueueId += 1;
203
+
204
+ this._mongoQueue.splice(0, 0, mongoQueue);
205
+ }
206
+ }
207
+
208
+ private async runQueue() {
209
+ setInterval(() => {
210
+ if (!this._mongoQueueRunning) {
211
+ const queueArr = this._mongoQueue.filter(a => !a.running && a.cbs.length);
212
+ if (queueArr.length) {
213
+ this._mongoQueueRunning = true;
214
+
215
+ for (let i = queueArr.length - 1; i >= 0; i--) {
216
+ this._debugMongoQueueHits += 1;
217
+
218
+ let mongoQueue = queueArr[i];
219
+
220
+ if (!this._debugMongoQueueCollections.some(a => a.collection === mongoQueue.name_collection && a.function === mongoQueue.name_function)) {
221
+ this._debugMongoQueueCollections.push({
222
+ collection: mongoQueue.name_collection,
223
+ function: mongoQueue.name_function,
224
+ hits: 1
225
+ });
226
+ }
227
+ else {
228
+ this._debugMongoQueueCollections.filter(a => a.collection === mongoQueue.name_collection && a.function === mongoQueue.name_function)[0].hits += 1;
229
+ }
230
+
231
+ mongoQueue.running = true;
232
+ mongoQueue.invalidateFlag = false;
233
+
234
+ if (mongoQueue.cacheId) {
235
+ try {
236
+ let res = JSON.parse(this._nodeCache.get(mongoQueue.cacheId), dateReviver);
237
+
238
+ mongoQueue.cbs.forEach(cb => {
239
+ cb(null, res, true);
240
+ });
241
+
242
+ mongoQueue.cbs = [];
243
+ mongoQueue.running = false;
244
+ }
245
+ catch {
246
+ mongoQueue.cacheId = 0;
247
+ }
248
+ }
249
+
250
+ if (!mongoQueue.cacheId) {
251
+ if (!mongoQueue.name_function_addt) {
252
+ let monitor = new MonitorMongo(mongoQueue.name_function, mongoQueue.name_collection, JSON.stringify(mongoQueue.data_function));
253
+ ResolveIOServer.getMainDB().collection(mongoQueue.name_collection)[mongoQueue.name_function](...mongoQueue.data_function).then(res => {
254
+ monitor.finish();
255
+ if (!mongoQueue.invalidateFlag) {
256
+ mongoQueue.invalidateCount = 0;
257
+
258
+ let stringifyLength = 0;
259
+ let stringifyFail = false;
260
+
261
+ try {
262
+ let stringify = JSON.stringify(res).replace(/[\[\]\,\"]/g,'');
263
+ stringifyLength = stringify.length;
264
+ }
265
+ catch(e) {
266
+ stringifyFail = true;
267
+ }
268
+
269
+ if (!stringifyFail && res !== null && res !== undefined && (!Array.isArray(res) || res.length) && stringifyLength < 10000000) {
270
+ mongoQueue.cacheId = this._mongoQueueCacheId;
271
+ this._mongoQueueCacheId += 1;
272
+
273
+ this.addToCache(mongoQueue.cacheId, res);
274
+ }
275
+ else {
276
+ mongoQueue.cacheId = 0;
277
+ }
278
+
279
+ mongoQueue.cbs.forEach(cb => {
280
+ cb(null, res, false);
281
+ });
282
+
283
+ if (mongoQueue.cbs_next.length) {
284
+ mongoQueue.cbs = mongoQueue.cbs_next;
285
+ mongoQueue.cbs_next = [];
286
+ }
287
+ else {
288
+ mongoQueue.cbs = [];
289
+ }
290
+ }
291
+ else {
292
+ if (mongoQueue.invalidateCount >= 5) {
293
+ mongoQueue.invalidateCount = 0;
294
+
295
+ mongoQueue.cbs.forEach(cb => {
296
+ cb(null, res, false);
297
+ });
298
+ }
299
+
300
+ mongoQueue.cbs = mongoQueue.cbs.concat(mongoQueue.cbs_next);
301
+ mongoQueue.cbs_next = [];
302
+ }
303
+
304
+ mongoQueue.running = false;
305
+ }, err => {
306
+ monitor.finish();
307
+
308
+ console.log(new Date(), 'Error ' + mongoQueue.name_function, mongoQueue.name_collection, ...mongoQueue.data_function, err);
309
+
310
+ mongoQueue.cbs.forEach(cb => {
311
+ cb(err, null, false);
312
+ });
313
+
314
+ mongoQueue.cbs_next.forEach(cb => {
315
+ cb(err, null, false);
316
+ });
317
+
318
+ if (this._mongoQueue.map(a => a._id).indexOf(mongoQueue._id) >= 0) {
319
+ this._mongoQueue.splice(this._mongoQueue.map(a => a._id).indexOf(mongoQueue._id), 1);
320
+ }
321
+ });
322
+ }
323
+ else {
324
+ let monitor = new MonitorMongo(mongoQueue.name_function, mongoQueue.name_collection, JSON.stringify([...mongoQueue.data_function, mongoQueue.name_function_addt, ...mongoQueue.data_function_addt]));
325
+ ResolveIOServer.getMainDB().collection(mongoQueue.name_collection)[mongoQueue.name_function](...mongoQueue.data_function)[mongoQueue.name_function_addt](...mongoQueue.data_function_addt).then(res => {
326
+ monitor.finish();
327
+ if (!mongoQueue.invalidateFlag) {
328
+ mongoQueue.invalidateCount = 0;
329
+
330
+ let stringifyLength = 0;
331
+ let stringifyFail = false;
332
+
333
+ try {
334
+ let stringify = JSON.stringify(res).replace(/[\[\]\,\"]/g,'');
335
+ stringifyLength = stringify.length;
336
+ }
337
+ catch(e) {
338
+ stringifyFail = true;
339
+ }
340
+
341
+ if (!stringifyFail && res !== null && res !== undefined && (!Array.isArray(res) || res.length) && stringifyLength < 10000000) {
342
+ mongoQueue.cacheId = this._mongoQueueCacheId;
343
+ this._mongoQueueCacheId += 1;
344
+ this.addToCache(mongoQueue.cacheId, res);
345
+ }
346
+ else {
347
+ mongoQueue.cacheId = 0;
348
+ }
349
+
350
+ mongoQueue.cbs.forEach(cb => {
351
+ cb(null, res, false);
352
+ });
353
+
354
+ if (mongoQueue.cbs_next.length) {
355
+ mongoQueue.cbs = mongoQueue.cbs_next;
356
+ mongoQueue.cbs_next = [];
357
+ }
358
+ else {
359
+ mongoQueue.cbs = [];
360
+ }
361
+ }
362
+ else {
363
+ if (mongoQueue.invalidateCount >= 5) {
364
+ mongoQueue.invalidateCount = 0;
365
+
366
+ mongoQueue.cbs.forEach(cb => {
367
+ cb(null, res, false);
368
+ });
369
+ }
370
+
371
+ mongoQueue.cbs = mongoQueue.cbs.concat(mongoQueue.cbs_next);
372
+ mongoQueue.cbs_next = [];
373
+ }
374
+
375
+ mongoQueue.running = false;
376
+ }, err => {
377
+ monitor.finish();
378
+
379
+ mongoQueue.cbs.forEach(cb => {
380
+ cb(err, null, false);
381
+ });
382
+
383
+ mongoQueue.cbs_next.forEach(cb => {
384
+ cb(err, null, false);
385
+ });
386
+
387
+ if (this._mongoQueue.map(a => a._id).indexOf(mongoQueue._id) >= 0) {
388
+ this._mongoQueue.splice(this._mongoQueue.map(a => a._id).indexOf(mongoQueue._id), 1);
389
+ }
390
+ });
391
+ }
392
+ }
393
+ }
394
+
395
+ this._mongoQueueRunning = false;
396
+ }
397
+ }
398
+ }, 25);
399
+ }
400
+
401
+ private addToCache(id, data) {
402
+ let nodeCacheSize = this._nodeCache.getStats().vsize;
403
+
404
+ if (nodeCacheSize > this._heapLimit) {
405
+ let deleteCount = 0;
406
+
407
+ const queueArr = this._mongoQueue.filter(a => a.cacheId && !a.running && !a.cbs.length);
408
+
409
+ for (let zz = queueArr.length - 1; zz >= 0; zz--) {
410
+ this._debugRemoveCacheHits += 1;
411
+
412
+ let queue = queueArr[zz];
413
+
414
+ this._nodeCache.del(queue.cacheId);
415
+ queue.cacheId = 0;
416
+
417
+ if (this._mongoQueue.map(a => a._id).indexOf(queue._id) >= 0) {
418
+ this._mongoQueue.splice(this._mongoQueue.map(a => a._id).indexOf(queue._id), 1);
419
+ }
420
+
421
+ deleteCount += 1;
422
+
423
+ nodeCacheSize = this._nodeCache.getStats().vsize;
424
+
425
+ if (nodeCacheSize < this._heapLimit * 0.75) {
426
+ break;
427
+ }
428
+ }
429
+
430
+ console.log('Query Cache: ' + 'Too Big, - Deleted: ' + deleteCount + ' - ' + nodeCacheSize);
431
+ }
432
+
433
+ this._nodeCache.set(id, JSON.stringify(data));
434
+ }
435
+
436
+ public invalidateQueryCache(collection: string) {
437
+ let queueArr = this._mongoQueue.filter(a => (a.name_collection === collection || a.lookup_collections.includes(collection)));
438
+ for (let i = queueArr.length - 1; i >= 0; i--) {
439
+ let queue = queueArr[i];
440
+ if (queue.cacheId) {
441
+ this._nodeCache.del(queue.cacheId);
442
+ queue.cacheId = 0;
443
+ }
444
+
445
+ if (queue.running) {
446
+ queue.invalidateFlag = true;
447
+ queue.invalidateCount += 1;
448
+ }
449
+ else if (!queue.cbs.length) {
450
+ if (this._mongoQueue.map(a => a._id).indexOf(queue._id) >= 0) {
451
+ this._mongoQueue.splice(this._mongoQueue.map(a => a._id).indexOf(queue._id), 1);
452
+ }
453
+ }
454
+ }
455
+ }
456
+ }
457
+
458
+ export class MongoManagerModel<T extends CollectionDocument> {
459
+ collection_main: MongoManagerCollection<T> | MongoManagerUserCollection<T> = null;
460
+ collection_version: MongoManagerCollection<T> | MongoManagerUserCollection<T> = null;
461
+
462
+ constructor(options: MongoManagerCollectionOptions) {
463
+ if (options.collectionName === 'users') {
464
+ this.collection_main = new MongoManagerUserCollection<T>(options);
465
+ }
466
+ else {
467
+ this.collection_main = new MongoManagerCollection<T>(options);
468
+ }
469
+
470
+ if (options.useVersionCollection) {
471
+ this.collection_main.useVersions = true;
472
+
473
+ let versionSchema = deepCopy(options.schema);
474
+ versionSchema._id.type = 'Object';
475
+ versionSchema._id.blackbox = true;
476
+
477
+ let versionOptions: MongoManagerCollectionOptions = {
478
+ collectionName: options.collectionName + '.versions',
479
+ schema: versionSchema,
480
+ useVersionCollection: false,
481
+ useReportBuilder: false,
482
+ reportBuilderLookupTables: [],
483
+ timestamps: true,
484
+ createLogs: false,
485
+ checkSchema: false,
486
+ collectionOptions: null
487
+ };
488
+
489
+ if (options.collectionName === 'users') {
490
+ this.collection_version = new MongoManagerUserCollection<T>(versionOptions);
491
+ }
492
+ else {
493
+ this.collection_version = new MongoManagerCollection<T>(versionOptions);
494
+ }
495
+
496
+ this.collection_version.createIndex({'_id._id': 1, '_id.__v': 1});
497
+ this.collection_main.versionCollection = options.collectionName + '.versions';
498
+ }
499
+ }
500
+ }
501
+
502
+ export interface MongoManagerCollectionOptions {
503
+ collectionName: string;
504
+ schema: object;
505
+ useVersionCollection: boolean;
506
+ useReportBuilder: boolean;
507
+ reportBuilderLookupTables: LookupTables[]
508
+ timestamps: boolean;
509
+ createLogs: boolean;
510
+ checkSchema: boolean;
511
+ collectionOptions: CreateCollectionOptions;
512
+ }
513
+
514
+ export class MongoManagerCollection<T extends CollectionDocument> {
515
+ collectionName = '';
516
+ checkSchema = false;
517
+ simplschema = null;
518
+ rbSchema = null;
519
+ timestamps = false;
520
+ useVersions = false;
521
+ versionCollection = '';
522
+ createLogs = true;
523
+ useRB = false;
524
+ collectionOptions: CreateCollectionOptions;
525
+
526
+ constructor(options: MongoManagerCollectionOptions) {
527
+ this.collectionName = options.collectionName;
528
+ this.simplschema = new SimpleSchema(options.schema);
529
+ this.timestamps = options.timestamps;
530
+ this.createLogs = options.createLogs;
531
+ this.checkSchema = options.checkSchema;
532
+ this.collectionOptions = options.collectionOptions;
533
+
534
+ if (options.useReportBuilder) {
535
+ this.useRB = true;
536
+ let schemaCopy = deepCopy(options.schema);
537
+ let rbSchema = buildRbLookups(options.reportBuilderLookupTables, schemaCopy, []);
538
+ this.rbSchema = buildRbSchema(rbSchema);
539
+ }
540
+
541
+ let interval = setInterval(() => {
542
+ if (ResolveIOServer && ResolveIOServer.getMainServer() && ResolveIOServer.getMongoManager() && ResolveIOServer.getMongoManager().getServerCollections().length) {
543
+ ResolveIOServer.getMongoManager().registerCollection(this);
544
+ clearInterval(interval);
545
+ }
546
+ }, 1);
547
+ }
548
+
549
+ aggregate(pipeline: object[], options?: AggregateOptions, skipCache = false) : Promise<any[]> {
550
+ return new Promise((resolve, reject) => {
551
+ // if (!skipCache) {
552
+ // ResolveIOServer.getMongoManager().addToQueue({
553
+ // _id: 0,
554
+ // name_collection: this.collectionName,
555
+ // name_function: 'aggregate',
556
+ // name_function_addt: 'toArray',
557
+ // data_function: [pipeline, options],
558
+ // data_function_addt: [],
559
+ // cbs: [(err, res, cached) => {
560
+ // if (err) {
561
+ // reject(err);
562
+ // }
563
+ // else {
564
+ // resolve(res);
565
+ // }
566
+ // }],
567
+ // cbs_next: [],
568
+ // running: false,
569
+ // cacheId: 0,
570
+ // lookup_collections: pipeline.filter(a => a['$lookup'] && a['$lookup'].from).map(a => a['$lookup'].from).filter((elem, index, self) => {
571
+ // return index === self.indexOf(elem);
572
+ // }),
573
+ // invalidateFlag: false,
574
+ // invalidateCount: 0
575
+ // });
576
+ // }
577
+ // else {
578
+ // let monitor = new MonitorMongo('aggregate', this.collectionName, JSON.stringify([pipeline, options]));
579
+ // ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options).toArray().then(res => {
580
+ // monitor.finish();
581
+ // resolve(res);
582
+ // }, err => {
583
+ // monitor.finish();
584
+ // console.log(new Date(), 'Error Aggregate', this.collectionName, pipeline, options, err);
585
+ // reject(err);
586
+ // });
587
+ // }
588
+
589
+ let monitor = new MonitorMongo('aggregate', this.collectionName, JSON.stringify([pipeline, options]));
590
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options).toArray().then(res => {
591
+ monitor.finish();
592
+ resolve(res);
593
+ }, err => {
594
+ monitor.finish();
595
+ console.log(new Date(), 'Error Aggregate', this.collectionName, pipeline, options, err);
596
+ reject(err);
597
+ });
598
+ });
599
+ }
600
+
601
+ aggregateCount(pipeline: object[], options?: AggregateOptions) : Promise<number> {
602
+ return new Promise((resolve, reject) => {
603
+ ResolveIOServer.getMongoManager().addToQueue({
604
+ _id: 0,
605
+ name_collection: this.collectionName,
606
+ name_function: 'aggregate',
607
+ name_function_addt: 'count',
608
+ data_function: [pipeline, options],
609
+ data_function_addt: [],
610
+ cbs: [(err, res, cached) => {
611
+ if (err) {
612
+ reject(err);
613
+ }
614
+ else {
615
+ resolve(res);
616
+ }
617
+ }],
618
+ cbs_next: [],
619
+ running: false,
620
+ cacheId: 0,
621
+ lookup_collections: pipeline.filter(a => a['$lookup'] && a['$lookup'].from).map(a => a['$lookup'].from).filter((elem, index, self) => {
622
+ return index === self.indexOf(elem);
623
+ }),
624
+ invalidateFlag: false,
625
+ invalidateCount: 0
626
+ });
627
+ });
628
+ }
629
+
630
+ aggregateCursor(pipeline: object[], options?: AggregateOptions): AggregationCursor {
631
+ let monitor = new MonitorMongo('aggregateCursor', this.collectionName, JSON.stringify([pipeline, options]));
632
+ let cursor = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options);
633
+ cursor.on('close', ev => {
634
+ monitor.finish();
635
+ return ev;
636
+ });
637
+
638
+ return cursor;
639
+ }
640
+
641
+ aggregateStream(pipeline: object[], options?: AggregateOptions, streamOptions?: CursorStreamOptions) {
642
+ let monitor = new MonitorMongo('aggregateStream', this.collectionName, JSON.stringify([pipeline, options, streamOptions]));
643
+ let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options).stream(streamOptions);
644
+ stream.on('end', ev => {
645
+ monitor.finish();
646
+ return ev;
647
+ });
648
+
649
+ return stream;
650
+ }
651
+
652
+ // bulkWrite(operations: AnyBulkWriteOperation<T>[], options: BulkWriteOptions): Promise<BulkWriteResult> {
653
+ bulkWrite(operations: any[], options?: BulkWriteOptions): Promise<BulkWriteResult> {
654
+ return new Promise((resolve, reject) => {
655
+ let monitor = new MonitorMongo('bulkWrite', this.collectionName, JSON.stringify([operations.slice(-100), options]));
656
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).bulkWrite(operations, options).then(res => {
657
+ monitor.finish();
658
+ resolve(res);
659
+ }, err => {
660
+ monitor.finish();
661
+ console.log(new Date(), 'Error Bulk Write', this.collectionName, operations.slice(-100), options, err);
662
+ reject(err);
663
+ });
664
+ });
665
+ }
666
+
667
+ countDocuments(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: CountDocumentsOptions): Promise<number> {
668
+ return new Promise((resolve, reject) => {
669
+ let monitor = new MonitorMongo('countDocuments', this.collectionName, JSON.stringify([filter, options]));
670
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).countDocuments(<any>filter, options).then(res => {
671
+ monitor.finish();
672
+ resolve(res);
673
+ }, err => {
674
+ monitor.finish();
675
+ console.log(new Date(), 'Error Count Documents', this.collectionName, filter, options, err);
676
+ reject(err);
677
+ });
678
+ });
679
+ }
680
+
681
+ //Helper Function (1 or Many) - Not Real Mongo Function
682
+ create(f_docs: T | T[], options?: InsertOneOptions | BulkWriteOptions): Promise<T | T[]> {
683
+ if (!Array.isArray(f_docs)) {
684
+ return this.insertOne(f_docs, <InsertOneOptions>options);
685
+ }
686
+ else if (f_docs.length === 1) {
687
+ return this.insertOne(f_docs[0], <InsertOneOptions>options);
688
+ }
689
+
690
+ return this.insertMany(f_docs, <BulkWriteOptions>options);
691
+ }
692
+
693
+ createIndex(fieldOrSpec: any, options?: CreateIndexesOptions): Promise<string> {
694
+ return new Promise((resolve, reject) => {
695
+ if (ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions)) {
696
+ let monitor = new MonitorMongo('createIndex', this.collectionName, JSON.stringify([fieldOrSpec, options]));
697
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).createIndex(fieldOrSpec, options).then(res => {
698
+ monitor.finish();
699
+ resolve(res);
700
+ }, err => {
701
+ monitor.finish();
702
+ console.log(new Date(), 'Error Setting Up Index for Collection', this.collectionName, fieldOrSpec, options, err);
703
+ reject(err);
704
+ });
705
+ }
706
+ });
707
+ }
708
+
709
+ createIndexes(indexSpecs: IndexDescription[], options?: CreateIndexesOptions): Promise<string[]> {
710
+ return new Promise((resolve, reject) => {
711
+ if (ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions)) {
712
+ let monitor = new MonitorMongo('createIndexes', this.collectionName, JSON.stringify([indexSpecs, options]));
713
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).createIndexes(indexSpecs, options).then(res => {
714
+ monitor.finish();
715
+ resolve(res);
716
+ }, err => {
717
+ monitor.finish();
718
+ console.log(new Date(), 'Error Setting Up Indexes for Collection', this.collectionName, indexSpecs, options, err);
719
+ reject(err);
720
+ });
721
+ }
722
+ });
723
+ }
724
+
725
+ deleteMany(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: DeleteOptions, bypassLogs = false): Promise<number> {
726
+ return new Promise(async (resolve, reject) => {
727
+ if (this.createLogs && !bypassLogs) {
728
+ let docs = await this.find(filter);
729
+
730
+ for (let i = 0; i < docs.length; i++) {
731
+ let doc = docs[i];
732
+
733
+ Logs.insertOne({
734
+ _id: objectIdHexString(),
735
+ type: 'document',
736
+ collection: this.collectionName,
737
+ id_document: doc._id,
738
+ payload: getBinarySize(JSON.stringify([doc, filter, options])) < 200000 ? JSON.stringify([doc, filter, options], null, 2) : 'Too Big',
739
+ method: 'deleteMany',
740
+ id_user: '',
741
+ user: '',
742
+ messageId: 0,
743
+ route: ''
744
+ });
745
+
746
+ if (this.useVersions) {
747
+ let versionDoc = deepCopy(doc);
748
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
749
+
750
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
751
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 1}}]});
752
+ }
753
+ }
754
+ }
755
+
756
+ let monitor = new MonitorMongo('deleteMany', this.collectionName, JSON.stringify([filter, options]));
757
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).deleteMany(<any>filter, options).then(res => {
758
+ monitor.finish();
759
+ if (res.acknowledged) {
760
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
761
+ resolve(res.deletedCount);
762
+ }
763
+ else {
764
+ reject(res.acknowledged);
765
+ }
766
+ }, err => {
767
+ monitor.finish();
768
+ console.log(new Date(), 'Error Delete Many', this.collectionName, filter, options, err);
769
+ reject(err)
770
+ });
771
+ });
772
+ }
773
+
774
+ deleteOne(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOneAndDeleteOptions, bypassLogs = false): Promise<number> {
775
+ return new Promise(async (resolve, reject) => {
776
+ if (this.createLogs && !bypassLogs) {
777
+ let monitor = new MonitorMongo('findOneAndDelete', this.collectionName, JSON.stringify([filter, options]));
778
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndDelete(<any>filter, options).then(async returnVal => {
779
+ monitor.finish();
780
+ let doc = returnVal.value;
781
+
782
+ if (doc) {
783
+ if (this.createLogs && !bypassLogs) {
784
+ Logs.insertOne({
785
+ _id: objectIdHexString(),
786
+ type: 'document',
787
+ collection: this.collectionName,
788
+ id_document: doc._id,
789
+ payload: getBinarySize(JSON.stringify([doc, filter, options])) < 200000 ? JSON.stringify([doc, filter, options], null, 2) : 'Too Big',
790
+ method: 'deleteOne',
791
+ id_user: '',
792
+ user: '',
793
+ messageId: 0,
794
+ route: ''
795
+ });
796
+ }
797
+
798
+ if (this.useVersions) {
799
+ let versionDoc = deepCopy(doc);
800
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
801
+
802
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
803
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 1}}]});
804
+ }
805
+
806
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
807
+
808
+ resolve(1);
809
+ }
810
+ else {
811
+ resolve(0);
812
+ }
813
+ }, err => {
814
+ monitor.finish();
815
+ console.log(new Date(), 'Error Find One And Delete', this.collectionName, filter, options, err);
816
+ reject(err);
817
+ });
818
+ }
819
+ else {
820
+ let monitor = new MonitorMongo('deleteOne', this.collectionName, JSON.stringify([filter, options]));
821
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).deleteOne(<any>filter, options).then(res => {
822
+ monitor.finish();
823
+ if (res.acknowledged) {
824
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
825
+ resolve(res.deletedCount);
826
+ }
827
+ else {
828
+ reject(res.acknowledged);
829
+ }
830
+ }, err => {
831
+ monitor.finish();
832
+ console.log(new Date(), 'Error Delete One', this.collectionName, filter, options, err);
833
+ reject(err);
834
+ });
835
+ }
836
+ });
837
+ }
838
+
839
+ distinct(key: string, filter?: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, options?: CommandOperationOptions): Promise<T[]> {
840
+ return new Promise((resolve, reject) => {
841
+ let monitor = new MonitorMongo('distinct', this.collectionName, JSON.stringify([key, filter, options]));
842
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).distinct(key, <any>filter, options).then(res => {
843
+ monitor.finish();
844
+ resolve(res);
845
+ }, err => {
846
+ monitor.finish();
847
+ console.log(new Date(), 'Error Distinct', this.collectionName, filter, options, err);
848
+ reject(err);
849
+ });
850
+ });
851
+ }
852
+
853
+ drop(options?: CommandOperationOptions): Promise<boolean> {
854
+ return new Promise((resolve, reject) => {
855
+ let monitor = new MonitorMongo('drop', this.collectionName, JSON.stringify([options]));
856
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).drop(options).then(res => {
857
+ monitor.finish();
858
+ resolve(res);
859
+ }, err => {
860
+ monitor.finish();
861
+ console.log(new Date(), 'Error Count Documents', this.collectionName, options, err);
862
+ reject(err);
863
+ });
864
+ });
865
+ }
866
+
867
+ dropIndex(indexName: string, options?: CommandOperationOptions): Promise<Document> {
868
+ return new Promise((resolve, reject) => {
869
+ let monitor = new MonitorMongo('dropIndex', this.collectionName, JSON.stringify([indexName, options]));
870
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).dropIndex(indexName, options).then(res => {
871
+ monitor.finish();
872
+ resolve(<Document>res);
873
+ }, err => {
874
+ monitor.finish();
875
+ console.log(new Date(), 'Error Drop Index', this.collectionName, indexName, options, err);
876
+ reject(err);
877
+ });
878
+ });
879
+ }
880
+
881
+ dropIndexes(options?: CommandOperationOptions): Promise<Document> {
882
+ return new Promise((resolve, reject) => {
883
+ let monitor = new MonitorMongo('dropIndexes', this.collectionName, JSON.stringify([options]));
884
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).dropIndexes(options).then(res => {
885
+ monitor.finish();
886
+ resolve(<Document>res);
887
+ }, err => {
888
+ monitor.finish();
889
+ console.log(new Date(), 'Error Drop Indexes', this.collectionName, options, err);
890
+ reject(err);
891
+ });
892
+ });
893
+ }
894
+
895
+ find(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOptions<T>, skipCache = false): Promise<T[]> {
896
+ return new Promise(async (resolve, reject) => {
897
+ if (!skipCache) {
898
+ ResolveIOServer.getMongoManager().addToQueue({
899
+ _id: 0,
900
+ name_collection: this.collectionName,
901
+ name_function: 'find',
902
+ name_function_addt: 'toArray',
903
+ data_function: [filter, options],
904
+ data_function_addt: [],
905
+ cbs: [(err, res, cached) => {
906
+ if (err) {
907
+ reject(err);
908
+ }
909
+ else {
910
+ resolve(res);
911
+ }
912
+ }],
913
+ cbs_next: [],
914
+ running: false,
915
+ cacheId: 0,
916
+ lookup_collections: [],
917
+ invalidateFlag: false,
918
+ invalidateCount: 0
919
+ });
920
+ }
921
+ else {
922
+ let monitor = new MonitorMongo('find', this.collectionName, JSON.stringify([filter, options]));
923
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find<T>(<any>filter, options).toArray().then(res => {
924
+ monitor.finish();
925
+ resolve(res);
926
+ }, err => {
927
+ monitor.finish();
928
+ console.log(new Date(), 'Error Find', this.collectionName, filter, options, err);
929
+ reject(err);
930
+ });
931
+ }
932
+ });
933
+ }
934
+
935
+ findById(id: string, options?: FindOptions<T>): Promise<T> {
936
+ return new Promise((resolve, reject) => {
937
+ let monitor = new MonitorMongo('findById', this.collectionName, JSON.stringify([{_id: id}, options]));
938
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOne<T>(<any>{_id: id}, options).then(res => {
939
+ monitor.finish();
940
+ resolve(res);
941
+ }, err => {
942
+ monitor.finish();
943
+ console.log(new Date(), 'Error Find By Id', this.collectionName, {_id: id}, options, err);
944
+ reject(err);
945
+ });
946
+ });
947
+ }
948
+
949
+ findCount(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOptions<T>): Promise<Number> {
950
+ return new Promise((resolve, reject) => {
951
+ let monitor = new MonitorMongo('findCount', this.collectionName, JSON.stringify([filter, options]));
952
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find(<any>filter, options).count().then(res => {
953
+ monitor.finish();
954
+ resolve(res);
955
+ }, err => {
956
+ monitor.finish();
957
+ console.log(new Date(), 'Error Find Count', this.collectionName, filter, options, err);
958
+ reject(err);
959
+ });
960
+ });
961
+ }
962
+
963
+ findCursor(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOptions<T>): FindCursor {
964
+ let monitor = new MonitorMongo('findCursor', this.collectionName, JSON.stringify([filter, options]));
965
+ let cursor = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find(<any>filter, options);
966
+ cursor.on('close', ev => {
967
+ monitor.finish();
968
+ return ev;
969
+ });
970
+ return cursor;
971
+ }
972
+
973
+ findStream(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOptions<T>, streamOptions?: CursorStreamOptions) {
974
+ let monitor = new MonitorMongo('findStream', this.collectionName, JSON.stringify([filter, options, streamOptions]));
975
+ let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find(<any>filter, options).stream(streamOptions);
976
+ stream.on('end', ev => {
977
+ monitor.finish();
978
+ return ev;
979
+ });
980
+ return stream;
981
+ }
982
+
983
+ findOne(filter: MongoManagerFilter<T> | MongoManagerFilterOperators<T> = {}, options?: FindOptions<T>, skipCache = false): Promise<T> {
984
+ return new Promise((resolve, reject) => {
985
+ if (!skipCache) {
986
+ ResolveIOServer.getMongoManager().addToQueue({
987
+ _id: 0,
988
+ name_collection: this.collectionName,
989
+ name_function: 'findOne',
990
+ name_function_addt: '',
991
+ data_function: [filter, options],
992
+ data_function_addt: [],
993
+ cbs: [(err, res, cached) => {
994
+ if (err) {
995
+ reject(err);
996
+ }
997
+ else {
998
+ resolve(res);
999
+ }
1000
+ }],
1001
+ cbs_next: [],
1002
+ running: false,
1003
+ cacheId: 0,
1004
+ lookup_collections: [],
1005
+ invalidateFlag: false,
1006
+ invalidateCount: 0
1007
+ });
1008
+ }
1009
+ else {
1010
+ let monitor = new MonitorMongo('findOne', this.collectionName, JSON.stringify([filter, options]));
1011
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOne<T>(<any>filter, options).then(res => {
1012
+ monitor.finish();
1013
+ resolve(res);
1014
+ }, err => {
1015
+ monitor.finish();
1016
+ console.log(new Date(), 'Error Find One', this.collectionName, filter, options, err);
1017
+ reject(err)
1018
+ });
1019
+ }
1020
+ });
1021
+ }
1022
+
1023
+ findOneAndDelete(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOneAndDeleteOptions, bypassLogs = false): Promise<T> {
1024
+ return new Promise(async (resolve, reject) => {
1025
+ let monitor = new MonitorMongo('findOneAndDelete', this.collectionName, JSON.stringify([filter, options]));
1026
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndDelete(<any>filter, options).then(res => {
1027
+ monitor.finish();
1028
+ let doc = res.value;
1029
+
1030
+ if (doc) {
1031
+ if (this.createLogs && !bypassLogs) {
1032
+ Logs.insertOne({
1033
+ _id: objectIdHexString(),
1034
+ type: 'document',
1035
+ collection: this.collectionName,
1036
+ id_document: doc._id,
1037
+ payload: getBinarySize(JSON.stringify([doc, filter, options])) < 200000 ? JSON.stringify([doc, filter, options], null, 2) : 'Too Big',
1038
+ method: 'findOneAndDelete',
1039
+ id_user: '',
1040
+ user: '',
1041
+ messageId: 0,
1042
+ route: ''
1043
+ });
1044
+ }
1045
+
1046
+ if (this.useVersions) {
1047
+ let versionDoc = deepCopy(doc);
1048
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
1049
+
1050
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
1051
+ }
1052
+
1053
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1054
+
1055
+ resolve(<T>doc);
1056
+ }
1057
+ else {
1058
+ resolve(null);
1059
+ }
1060
+ }, err => {
1061
+ monitor.finish();
1062
+ console.log(new Date(), 'Error Find One And Delete', this.collectionName, filter, options, err);
1063
+ reject(err)
1064
+ });
1065
+ });
1066
+ }
1067
+
1068
+ findOneAndReplace(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, replacement: T, options?: FindOneAndReplaceOptions, bypassLogs = false, bypassCheckSchema = false): Promise<T> {
1069
+ return new Promise(async (resolve, reject) => {
1070
+ if (this.checkSchema && !bypassCheckSchema) {
1071
+ const validation = this.simplschema.newContext();
1072
+ const isValid = validation.validate(replacement);
1073
+
1074
+ if (!isValid) {
1075
+ console.log(new Date(), this.collectionName, 'Schema Errors - findOneAndReplace', validation.validationErrors());
1076
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on findOneAndReplace - ' + this.collectionName, [validation.validationErrors(), replacement]);
1077
+
1078
+ reject(validation.validationErrors());
1079
+ return;
1080
+ }
1081
+ }
1082
+
1083
+ let date = new Date();
1084
+
1085
+ if (this.timestamps) {
1086
+ replacement.updatedAt = date;
1087
+ }
1088
+
1089
+ if (options && options.upsert) {
1090
+ if (!replacement._id) {
1091
+ replacement._id = objectIdHexString();
1092
+ }
1093
+
1094
+ if (this.useVersions) {
1095
+ replacement.__v = 0;
1096
+ }
1097
+
1098
+ if (this.timestamps && !replacement.createdAt) {
1099
+ replacement.createdAt = date;
1100
+ }
1101
+ }
1102
+
1103
+ let monitor = new MonitorMongo('findOneAndReplace', this.collectionName, JSON.stringify([filter, replacement, options]));
1104
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndReplace(<any>filter, replacement, options).then(res => {
1105
+ monitor.finish();
1106
+ let doc = res.value
1107
+
1108
+ if (doc) {
1109
+ if (this.createLogs && !bypassLogs) {
1110
+ Logs.insertOne({
1111
+ _id: objectIdHexString(),
1112
+ type: 'document',
1113
+ collection: this.collectionName,
1114
+ id_document: doc._id,
1115
+ payload: getBinarySize(JSON.stringify([doc, filter, replacement, options])) < 200000 ? JSON.stringify([doc, filter, replacement, options], null, 2) : 'Too Big',
1116
+ method: 'findOneAndReplace',
1117
+ id_user: '',
1118
+ user: '',
1119
+ messageId: 0,
1120
+ route: ''
1121
+ });
1122
+ }
1123
+
1124
+ if (this.useVersions) {
1125
+ let versionDoc = deepCopy(doc);
1126
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
1127
+
1128
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
1129
+ }
1130
+
1131
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1132
+
1133
+ resolve(<T>doc);
1134
+ }
1135
+ else {
1136
+ resolve(null);
1137
+ }
1138
+ }, err => {
1139
+ monitor.finish();
1140
+ console.log(new Date(), 'Error Find One And Replace', this.collectionName, filter, options, err);
1141
+ reject(err)
1142
+ });
1143
+ });
1144
+ }
1145
+
1146
+ findOneAndUpdate(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, update: MongoManagerUpdateFilter<T>, options?: FindOneAndUpdateOptions, bypassLogs = false, bypassCheckSchema = false): Promise<T> {
1147
+ return new Promise(async (resolve, reject) => {
1148
+ if (this.checkSchema && !bypassCheckSchema) {
1149
+ const validation = this.simplschema.newContext();
1150
+ const isValid = validation.validate(update, {modifier: true});
1151
+
1152
+ if (!isValid) {
1153
+ console.log(new Date(), this.collectionName, 'Schema Errors - findOneAndUpdate', validation.validationErrors());
1154
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on findOneAndUpdate - ' + this.collectionName, [validation.validationErrors(), update]);
1155
+ reject(validation.validationErrors());
1156
+ return;
1157
+ }
1158
+ }
1159
+
1160
+ if (this.timestamps) {
1161
+ let date = new Date();
1162
+
1163
+ if (!update.$set) {
1164
+ update.$set = <any>{updatedAt: date};
1165
+ }
1166
+ else {
1167
+ update.$set.updatedAt = date;
1168
+ }
1169
+ }
1170
+
1171
+ if (options && options.upsert) {
1172
+ if (!update.$setOnInsert) {
1173
+ if (this.timestamps) {
1174
+ update.$setOnInsert = <any>{
1175
+ _id: objectIdHexString(),
1176
+ createdAt: new Date()
1177
+ };
1178
+ }
1179
+ else {
1180
+ update.$setOnInsert = <any>{
1181
+ _id: objectIdHexString()
1182
+ };
1183
+ }
1184
+ }
1185
+ else {
1186
+ if (!update.$setOnInsert._id) {
1187
+ update.$setOnInsert._id = objectIdHexString();
1188
+ }
1189
+
1190
+ if (this.timestamps) {
1191
+ update.$setOnInsert.createdAt = new Date();
1192
+ }
1193
+ }
1194
+ }
1195
+
1196
+ let monitor = new MonitorMongo('findOneAndUpdate', this.collectionName, JSON.stringify([filter, update, options]));
1197
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndUpdate(<any>filter, <any>update, options).then(res => {
1198
+ monitor.finish();
1199
+ let doc = res.value;
1200
+
1201
+ if (doc) {
1202
+ if (this.createLogs && !bypassLogs) {
1203
+ Logs.insertOne({
1204
+ _id: objectIdHexString(),
1205
+ type: 'document',
1206
+ collection: this.collectionName,
1207
+ id_document: doc._id,
1208
+ payload: getBinarySize(JSON.stringify([doc, filter, update, options])) < 200000 ? JSON.stringify([doc, filter, update, options], null, 2) : 'Too Big',
1209
+ method: 'findOneAndUpdate',
1210
+ id_user: '',
1211
+ user: '',
1212
+ messageId: 0,
1213
+ route: ''
1214
+ });
1215
+ }
1216
+
1217
+ if (this.useVersions) {
1218
+ let versionDoc = deepCopy(doc);
1219
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
1220
+
1221
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
1222
+ }
1223
+
1224
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1225
+
1226
+ resolve(<T>doc);
1227
+ }
1228
+ else {
1229
+ resolve(null);
1230
+ }
1231
+ }, err => {
1232
+ monitor.finish();
1233
+ console.log(new Date(), 'Error Find One And Update', this.collectionName, filter, options, err);
1234
+ reject(err);
1235
+ });
1236
+ });
1237
+ }
1238
+
1239
+ indexes(options: IndexInformationOptions): Promise<any[]> {
1240
+ return new Promise((resolve, reject) => {
1241
+ let monitor = new MonitorMongo('indexes', this.collectionName, JSON.stringify([options]));
1242
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).indexes(options).then(res => {
1243
+ monitor.finish();
1244
+ resolve(res);
1245
+ }, err => {
1246
+ monitor.finish();
1247
+ console.log(new Date(), 'Error Indexes', this.collectionName, options, err);
1248
+ reject(err);
1249
+ });
1250
+ });
1251
+ }
1252
+
1253
+ indexExists(indexes: string | string[], options?: IndexInformationOptions): Promise<boolean> {
1254
+ return new Promise((resolve, reject) => {
1255
+ let monitor = new MonitorMongo('indexExists', this.collectionName, JSON.stringify([indexes, options]));
1256
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).indexExists(indexes, options).then(res => {
1257
+ monitor.finish();
1258
+ resolve(res);
1259
+ }, err => {
1260
+ monitor.finish();
1261
+ console.log(new Date(), 'Error Index Exists', this.collectionName, indexes, options, err);
1262
+ reject(err);
1263
+ });
1264
+ });
1265
+ }
1266
+
1267
+ insertMany(docs: T[], options?: BulkWriteOptions, bypassLogs = false, bypassCheckSchema = false, bypassMonitor = false): Promise<T[]> {
1268
+ return new Promise(async (resolve, reject) => {
1269
+ if (!docs.length) {
1270
+ resolve([]);
1271
+ return;
1272
+ }
1273
+
1274
+ let validationResults = [];
1275
+
1276
+ if (this.checkSchema && !bypassCheckSchema) {
1277
+ docs.forEach(doc => {
1278
+ const validation = this.simplschema.newContext();
1279
+ const isValid = validation.validate(doc);
1280
+
1281
+ if (!isValid) {
1282
+ console.log(new Date(), this.collectionName, 'Schema Errors - insertMany', validation.validationErrors());
1283
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on insertMany - ' + this.collectionName, [validation.validationErrors(), doc]);
1284
+ validationResults.push(false);
1285
+ }
1286
+ else {
1287
+ validationResults.push(true);
1288
+ }
1289
+ });
1290
+ }
1291
+
1292
+ let validDocs = this.checkSchema ? docs.filter((a, idx) => validationResults[idx]) : docs;
1293
+
1294
+ for (let i = 0; i < validDocs.length; i++) {
1295
+ let doc = validDocs[i];
1296
+
1297
+ if (!doc._id) {
1298
+ doc._id = objectIdHexString();
1299
+ }
1300
+
1301
+ if (this.timestamps) {
1302
+ let date = new Date();
1303
+ doc.createdAt = date;
1304
+ doc.updatedAt = date;
1305
+ }
1306
+
1307
+ if (this.createLogs && !bypassLogs) {
1308
+ Logs.insertOne({
1309
+ _id: objectIdHexString(),
1310
+ type: 'document',
1311
+ collection: this.collectionName,
1312
+ id_document: doc._id,
1313
+ payload: getBinarySize(JSON.stringify([doc, options])) < 200000 ? JSON.stringify([doc, options], null, 2) : 'Too Big',
1314
+ method: 'insertMany',
1315
+ id_user: '',
1316
+ user: '',
1317
+ messageId: 0,
1318
+ route: ''
1319
+ });
1320
+ }
1321
+ }
1322
+
1323
+ if (validDocs.length) {
1324
+ let monitor = null;
1325
+
1326
+ if (!bypassMonitor) {
1327
+ monitor = new MonitorMongo('insertMany', this.collectionName, JSON.stringify([validDocs, options]));
1328
+ }
1329
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).insertMany(<OptionalUnlessRequiredId<T>[]>validDocs, options).then(res => {
1330
+ if (monitor) {
1331
+ monitor.finish();
1332
+ }
1333
+ if (res.acknowledged) {
1334
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1335
+ resolve(validDocs);
1336
+ }
1337
+ else {
1338
+ reject(res.acknowledged);
1339
+ }
1340
+ }, err => {
1341
+ if (monitor) {
1342
+ monitor.finish();
1343
+ }
1344
+ console.log(new Date(), 'Error Insert Many', this.collectionName, validDocs, options, err);
1345
+ reject(err);
1346
+ });
1347
+ }
1348
+ });
1349
+ }
1350
+
1351
+ insertOne(doc: T, options?: InsertOneOptions, bypassLogs = false, bypassCheckSchema = false): Promise<T> {
1352
+ return new Promise(async (resolve, reject) => {
1353
+ if (!doc._id) {
1354
+ doc._id = objectIdHexString();
1355
+ }
1356
+
1357
+ if (this.checkSchema && !bypassCheckSchema) {
1358
+ const validation = this.simplschema.newContext();
1359
+ const isValid = validation.validate(doc);
1360
+
1361
+ if (!isValid) {
1362
+ console.log(new Date(), this.collectionName, 'Schema Errors - insertOne', validation.validationErrors());
1363
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on insertOne - ' + this.collectionName, [validation.validationErrors(), doc]);
1364
+ reject(validation.validationErrors());
1365
+ return;
1366
+ }
1367
+ }
1368
+
1369
+ if (this.timestamps) {
1370
+ let date = new Date();
1371
+ doc.createdAt = date;
1372
+ doc.updatedAt = date;
1373
+ }
1374
+
1375
+ if (this.createLogs && !bypassLogs) {
1376
+ Logs.insertOne({
1377
+ _id: objectIdHexString(),
1378
+ type: 'document',
1379
+ collection: this.collectionName,
1380
+ id_document: doc._id,
1381
+ payload: getBinarySize(JSON.stringify([doc, options])) < 200000 ? JSON.stringify([doc, options], null, 2) : 'Too Big',
1382
+ method: 'insertOne',
1383
+ id_user: '',
1384
+ user: '',
1385
+ messageId: 0,
1386
+ route: ''
1387
+ });
1388
+ }
1389
+
1390
+ if (this.useVersions && !doc.hasOwnProperty('__v')) {
1391
+ doc.__v = 0;
1392
+ }
1393
+
1394
+ let monitor = new MonitorMongo('insertOne', this.collectionName, JSON.stringify([doc, options]));
1395
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).insertOne(<OptionalUnlessRequiredId<T>>doc, options).then(res => {
1396
+ monitor.finish();
1397
+ if (res.acknowledged) {
1398
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1399
+ resolve(doc);
1400
+ }
1401
+ else {
1402
+ reject(res.acknowledged);
1403
+ }
1404
+ }, err => {
1405
+ monitor.finish();
1406
+ console.log(new Date(), 'Error Insert One', this.collectionName, doc, options, err);
1407
+ reject(err);
1408
+ });
1409
+ });
1410
+ }
1411
+
1412
+ listIndexes(options?: ListIndexesOptions): ListIndexesCursor {
1413
+ let monitor = new MonitorMongo('listIndexes', this.collectionName, JSON.stringify([options]));
1414
+ let cursor = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).listIndexes(options);
1415
+ cursor.on('close', ev => {
1416
+ monitor.finish();
1417
+ return ev;
1418
+ });
1419
+ return cursor;
1420
+ }
1421
+
1422
+ rename(newName: string, options?: RenameOptions): Promise<Collection<Document>> {
1423
+ return new Promise((resolve, reject) => {
1424
+ let monitor = new MonitorMongo('rename', this.collectionName, JSON.stringify([newName, options]));
1425
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).rename(newName, options).then(res => {
1426
+ monitor.finish();
1427
+ resolve(res);
1428
+ }, err => {
1429
+ monitor.finish();
1430
+ console.log(new Date(), 'Error Rename', this.collectionName, newName, options, err);
1431
+ reject(err);
1432
+ });
1433
+ });
1434
+ }
1435
+
1436
+ replaceOne(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, replacement: T, options?: ReplaceOptions, bypassLogs = false, bypassCheckSchema = false, doc: T = null) : Promise<number> {
1437
+ return new Promise(async (resolve, reject) => {
1438
+ if (this.checkSchema && !bypassCheckSchema) {
1439
+ const validation = this.simplschema.newContext();
1440
+ const isValid = validation.validate(replacement);
1441
+
1442
+ if (!isValid) {
1443
+ console.log(new Date(), this.collectionName, 'Schema Errors - replaceOne', validation.validationErrors());
1444
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on replaceOne - ' + this.collectionName, [validation.validationErrors(), replacement]);
1445
+ reject(validation.validationErrors());
1446
+ return;
1447
+ }
1448
+ }
1449
+
1450
+ let date = new Date();
1451
+
1452
+ if (this.timestamps) {
1453
+ replacement.updatedAt = date;
1454
+ }
1455
+
1456
+ if (this.useVersions) {
1457
+ if (!doc) {
1458
+ doc = await this.findOne(<any>filter, null, true);
1459
+ }
1460
+
1461
+ if (doc) {
1462
+ if (this.timestamps && !replacement.createdAt && doc.createdAt) {
1463
+ replacement.createdAt = doc.createdAt;
1464
+ }
1465
+
1466
+ if (doc.__v === replacement.__v) {
1467
+ replacement.__v += 1;
1468
+
1469
+ let versionDoc = deepCopy(doc);
1470
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
1471
+
1472
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
1473
+
1474
+ if (doc.__v >= 4) {
1475
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 4}}]});
1476
+ }
1477
+
1478
+ if (this.createLogs && !bypassLogs) {
1479
+ Logs.insertOne({
1480
+ _id: objectIdHexString(),
1481
+ type: 'document',
1482
+ collection: this.collectionName,
1483
+ id_document: doc._id,
1484
+ payload: getBinarySize(JSON.stringify([doc, filter, replacement, options])) < 200000 ? JSON.stringify([doc, filter, replacement, options], null, 2) : 'Too Big',
1485
+ method: 'replaceOne',
1486
+ id_user: '',
1487
+ user: '',
1488
+ messageId: 0,
1489
+ route: ''
1490
+ });
1491
+ }
1492
+
1493
+ let monitor = new MonitorMongo('replaceOne', this.collectionName, JSON.stringify([filter, replacement, options]));
1494
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options).then(res => {
1495
+ monitor.finish();
1496
+ if (res.acknowledged) {
1497
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1498
+ resolve(res.modifiedCount);
1499
+ }
1500
+ else {
1501
+ reject(res.acknowledged);
1502
+ }
1503
+ }, err => {
1504
+ monitor.finish();
1505
+ console.log(new Date(), 'Error Replace One', this.collectionName, filter, replacement, options, err);
1506
+ reject(err);
1507
+ });
1508
+ }
1509
+ else {
1510
+ console.log('invalid version - ' + this.collectionName, doc.__v, replacement.__v);
1511
+
1512
+ let prevDoc = await ResolveIOServer.getMongoManager().collection(this.versionCollection).findOne({
1513
+ _id: <any>{
1514
+ _id: doc._id,
1515
+ __v: replacement.__v
1516
+ }
1517
+ }, null, true);
1518
+
1519
+ if (prevDoc) {
1520
+ let docId = doc._id;
1521
+ let docVersion = doc.__v;
1522
+ let updatedDoc: T = getMongoMergeUpdatedDoc(replacement, doc, prevDoc);
1523
+ updatedDoc._id = docId;
1524
+ updatedDoc.__v = docVersion + 1;
1525
+
1526
+ if (this.createLogs && !bypassLogs) {
1527
+ Logs.insertOne({
1528
+ _id: objectIdHexString(),
1529
+ type: 'document',
1530
+ collection: this.collectionName,
1531
+ id_document: docId,
1532
+ payload: getBinarySize(JSON.stringify(['invalidVersion - merge', doc, filter, updatedDoc, options])) < 200000 ? JSON.stringify(['invalidVersion - merge', doc, filter, updatedDoc, options], null, 2) : 'Too Big',
1533
+ method: 'replaceOne',
1534
+ id_user: '',
1535
+ user: '',
1536
+ messageId: 0,
1537
+ route: ''
1538
+ });
1539
+ }
1540
+
1541
+ let monitor = new MonitorMongo('replaceOne', this.collectionName, JSON.stringify([filter, updatedDoc, options]));
1542
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, updatedDoc, options).then(res => {
1543
+ monitor.finish();
1544
+ if (res.acknowledged) {
1545
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1546
+ resolve(res.modifiedCount);
1547
+ }
1548
+ else {
1549
+ reject(res.acknowledged);
1550
+ }
1551
+ }, err => {
1552
+ monitor.finish();
1553
+ console.log(new Date(), 'Error Replace One', this.collectionName, filter, updatedDoc, options, err);
1554
+ reject(err);
1555
+ });
1556
+ }
1557
+ else {
1558
+ reject('Invalid Version And Could Not Find History - DB: ' + doc.__v + ', Trying to update with :' + replacement.__v);
1559
+ }
1560
+ }
1561
+ }
1562
+ else if (options && options.upsert) {
1563
+ if (this.timestamps) {
1564
+ replacement.createdAt = date;
1565
+ }
1566
+
1567
+ if (!replacement._id) {
1568
+ replacement._id = objectIdHexString();
1569
+ }
1570
+
1571
+ replacement.__v = 0;
1572
+
1573
+ if (this.createLogs && !bypassLogs) {
1574
+ Logs.insertOne({
1575
+ _id: objectIdHexString(),
1576
+ type: 'document',
1577
+ collection: this.collectionName,
1578
+ id_document: replacement._id,
1579
+ payload: getBinarySize(JSON.stringify(['upsert', filter, replacement, options])) < 200000 ? JSON.stringify(['upsert', filter, replacement, options], null, 2) : 'Too Big',
1580
+ method: 'replaceOne',
1581
+ id_user: '',
1582
+ user: '',
1583
+ messageId: 0,
1584
+ route: ''
1585
+ });
1586
+ }
1587
+
1588
+ let monitor = new MonitorMongo('replaceOne', this.collectionName, JSON.stringify([filter, replacement, options]));
1589
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options).then(res => {
1590
+ monitor.finish();
1591
+ if (res.acknowledged) {
1592
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1593
+ resolve(res.modifiedCount);
1594
+ }
1595
+ else {
1596
+ reject(res.acknowledged);
1597
+ }
1598
+ }, err => {
1599
+ monitor.finish();
1600
+ console.log(new Date(), 'Error Replace One', this.collectionName, filter, replacement, options, err);
1601
+ reject(err);
1602
+ });
1603
+ }
1604
+ else {
1605
+ reject('No Document');
1606
+ }
1607
+ }
1608
+ else {
1609
+ if (options && options.upsert) {
1610
+ if (this.timestamps && !replacement.createdAt) {
1611
+ replacement.createdAt = date;
1612
+ }
1613
+
1614
+ if (!replacement._id) {
1615
+ replacement._id = objectIdHexString();
1616
+ }
1617
+
1618
+ replacement.__v = 0;
1619
+ }
1620
+
1621
+ if (this.createLogs && !bypassLogs) {
1622
+ if (!options) {
1623
+ options = <FindOneAndReplaceOptions>{returnDocument: 'before'};
1624
+ }
1625
+ else {
1626
+ (<FindOneAndReplaceOptions>options).returnDocument = 'before';
1627
+ }
1628
+
1629
+ let monitor = new MonitorMongo('findOneAndReplace', this.collectionName, JSON.stringify([filter, replacement, options]));
1630
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndReplace(<any>filter, replacement, <FindOneAndReplaceOptions>options).then(res => {
1631
+ monitor.finish();
1632
+ let doc = res.value;
1633
+
1634
+ if (doc) {
1635
+ Logs.insertOne({
1636
+ _id: objectIdHexString(),
1637
+ type: 'document',
1638
+ collection: this.collectionName,
1639
+ id_document: doc._id,
1640
+ payload: getBinarySize(JSON.stringify([doc, filter, replacement, options])) < 200000 ? JSON.stringify([doc, filter, replacement, options], null, 2) : 'Too Big',
1641
+ method: 'replaceOne',
1642
+ id_user: '',
1643
+ user: '',
1644
+ messageId: 0,
1645
+ route: ''
1646
+ });
1647
+ }
1648
+ else {
1649
+ Logs.insertOne({
1650
+ _id: objectIdHexString(),
1651
+ type: 'document',
1652
+ collection: this.collectionName,
1653
+ id_document: replacement._id,
1654
+ payload: getBinarySize(JSON.stringify(['upsert', filter, replacement, options])) < 200000 ? JSON.stringify(['upsert', filter, replacement, options], null, 2) : 'Too Big',
1655
+ method: 'replaceOne',
1656
+ id_user: '',
1657
+ user: '',
1658
+ messageId: 0,
1659
+ route: ''
1660
+ });
1661
+ }
1662
+
1663
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1664
+ resolve(res.ok);
1665
+ }, err => {
1666
+ monitor.finish();
1667
+ console.log(new Date(), 'Error Find One And Replace', this.collectionName, filter, replacement, options, err);
1668
+ reject(err);
1669
+ });
1670
+ }
1671
+ else {
1672
+ let monitor = new MonitorMongo('replaceOne', this.collectionName, JSON.stringify([filter, replacement, options]));
1673
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options).then(res => {
1674
+ monitor.finish();
1675
+ if (res.acknowledged) {
1676
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1677
+ resolve(res.modifiedCount);
1678
+ }
1679
+ else {
1680
+ reject(res.acknowledged);
1681
+ }
1682
+ }, err => {
1683
+ monitor.finish();
1684
+ console.log(new Date(), 'Error Replace One', this.collectionName, filter, replacement, options, err);
1685
+ reject(err);
1686
+ });
1687
+ }
1688
+ }
1689
+ });
1690
+ }
1691
+
1692
+ stats(options?: CollStatsOptions): Promise<CollStats> {
1693
+ return new Promise((resolve, reject) => {
1694
+ let monitor = new MonitorMongo('stats', this.collectionName, JSON.stringify([options]));
1695
+ ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).stats(options).then(res => {
1696
+ monitor.finish();
1697
+ resolve(res);
1698
+ }, err => {
1699
+ monitor.finish();
1700
+ console.log(new Date(), 'Error Stats', this.collectionName, options, err);
1701
+ reject(err);
1702
+ });
1703
+ });
1704
+ }
1705
+
1706
+ updateMany(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, update: MongoManagerUpdateFilter<T>, options?: UpdateOptions, bypassLogs = false, bypassCheckSchema = false, bypassVersions = false) : Promise<number> {
1707
+ return new Promise(async (resolve, reject) => {
1708
+ if ((!update.$inc || JSON.stringify(update.$inc) === '{}') && (!update.$set || JSON.stringify(update.$set) === '{}') && (!update.$setOnInsert || JSON.stringify(update.$setOnInsert) === '{}') && (!update.$unset || JSON.stringify(update.$unset) === '{}')) {
1709
+ resolve(1);
1710
+ return;
1711
+ }
1712
+
1713
+ if (this.timestamps) {
1714
+ let date = new Date();
1715
+
1716
+ if (!update.$set) {
1717
+ update.$set = <any>{updatedAt: date};
1718
+ }
1719
+ else {
1720
+ update.$set.updatedAt = date;
1721
+ }
1722
+ }
1723
+
1724
+ if (this.checkSchema && !bypassCheckSchema) {
1725
+ const validation = this.simplschema.newContext();
1726
+ const isValid = validation.validate(update, {modifier: true});
1727
+
1728
+ if (!isValid) {
1729
+ console.log(new Date(), this.collectionName, 'Schema Errors - updateMany', validation.validationErrors());
1730
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on updateMany - ' + this.collectionName, [validation.validationErrors(), update]);
1731
+ reject(validation.validationErrors());
1732
+ return;
1733
+ }
1734
+ }
1735
+
1736
+ if ((this.useVersions && !bypassVersions) || (this.createLogs && !bypassLogs)) {
1737
+ let docs = await this.find(filter);
1738
+
1739
+ for (let i = 0; i < docs.length; i++) {
1740
+ let doc = docs[i];
1741
+
1742
+ if (this.createLogs && !bypassLogs) {
1743
+ Logs.insertOne({
1744
+ _id: objectIdHexString(),
1745
+ type: 'document',
1746
+ collection: this.collectionName,
1747
+ id_document: doc._id,
1748
+ payload: getBinarySize(JSON.stringify([doc, filter, update, options])) < 200000 ? JSON.stringify([doc, filter, update, options], null, 2) : 'Too Big',
1749
+ method: 'updateMany',
1750
+ id_user: '',
1751
+ user: '',
1752
+ messageId: 0,
1753
+ route: ''
1754
+ });
1755
+ }
1756
+
1757
+ if (this.useVersions) {
1758
+ let versionDoc = deepCopy(doc);
1759
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
1760
+
1761
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
1762
+
1763
+ if (doc.__v >= 4) {
1764
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 4}}]});
1765
+ }
1766
+
1767
+ if (!objectContainsPropertyDeep(update, '__v')) {
1768
+ if (!update.$inc) {
1769
+ update.$inc = {__v: 1};
1770
+ }
1771
+ else if (!update.$inc.__v) {
1772
+ update.$inc.__v = 1;
1773
+ }
1774
+ }
1775
+ }
1776
+ }
1777
+ }
1778
+
1779
+ let monitor = new MonitorMongo('updateMany', this.collectionName, JSON.stringify([filter, update, options]));
1780
+ ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateMany(<any>filter, update, options).then(res => {
1781
+ monitor.finish();
1782
+ if (res.acknowledged) {
1783
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1784
+ resolve(res.modifiedCount);
1785
+ }
1786
+ else {
1787
+ reject(res.acknowledged);
1788
+ }
1789
+ }, err => {
1790
+ monitor.finish();
1791
+ console.log(new Date(), 'Error Update Many', this.collectionName, filter, update, options, err);
1792
+ reject(err)
1793
+ });
1794
+ });
1795
+ }
1796
+
1797
+ updateOne(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, update: MongoManagerUpdateFilter<T>, options?: UpdateOptions, bypassLogs = false, bypassCheckSchema = false) : Promise<number> {
1798
+ return new Promise(async (resolve, reject) => {
1799
+ if (this.checkSchema && !bypassCheckSchema) {
1800
+ const validation = this.simplschema.newContext();
1801
+ const isValid = validation.validate(update, {modifier: true});
1802
+
1803
+ if (!isValid) {
1804
+ console.log(new Date(), this.collectionName, 'Schema Errors - updateOne', validation.validationErrors());
1805
+ ResolveIOServer.getMainServer().getMethodManager().callMethodInternal.call(ResolveIOServer.getMainServer().getMethodManager(), 'insertErrorLog', 'Schema Failed on updateOne - ' + this.collectionName, [validation.validationErrors(), update]);
1806
+ reject(validation.validationErrors());
1807
+ return;
1808
+ }
1809
+ }
1810
+
1811
+ if ((!update.$inc || JSON.stringify(update.$inc) === '{}') && (!update.$set || JSON.stringify(update.$set) === '{}') && (!update.$setOnInsert || JSON.stringify(update.$setOnInsert) === '{}') && (!update.$unset || JSON.stringify(update.$unset) === '{}')) {
1812
+ resolve(1);
1813
+ return;
1814
+ }
1815
+
1816
+ let date = new Date();
1817
+
1818
+ if (this.timestamps) {
1819
+ if (!update.$set) {
1820
+ update.$set = <any>{updatedAt: date};
1821
+ }
1822
+ else {
1823
+ update.$set.updatedAt = date;
1824
+ }
1825
+ }
1826
+
1827
+ if (this.useVersions) {
1828
+ let doc = await this.findOne(filter, null, true);
1829
+
1830
+ if (doc) {
1831
+ if (this.createLogs && !bypassLogs) {
1832
+ Logs.insertOne({
1833
+ _id: objectIdHexString(),
1834
+ type: 'document',
1835
+ collection: this.collectionName,
1836
+ id_document: doc._id,
1837
+ payload: getBinarySize(JSON.stringify([doc, filter, update, options])) < 200000 ? JSON.stringify([doc, filter, update, options], null, 2) : 'Too Big',
1838
+ method: 'updateOne',
1839
+ id_user: '',
1840
+ user: '',
1841
+ messageId: 0,
1842
+ route: ''
1843
+ });
1844
+ }
1845
+
1846
+ let versionDoc = deepCopy(doc);
1847
+ versionDoc._id = {_id: doc._id, __v: doc.__v};
1848
+
1849
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
1850
+
1851
+ if (doc.__v >= 4) {
1852
+ ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 4}}]});
1853
+ }
1854
+
1855
+ if (!objectContainsPropertyDeep(update, '__v')) {
1856
+ if (!update.$inc) {
1857
+ update.$inc = {__v: 1};
1858
+ }
1859
+ else if (!update.$inc.__v) {
1860
+ update.$inc.__v = 1;
1861
+ }
1862
+ }
1863
+
1864
+ let monitor = new MonitorMongo('updateOne', this.collectionName, JSON.stringify([filter, update, options]));
1865
+ ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, update, options).then(res => {
1866
+ monitor.finish();
1867
+ if (res.acknowledged) {
1868
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1869
+ resolve(res.modifiedCount);
1870
+ }
1871
+ else {
1872
+ reject(res.acknowledged);
1873
+ }
1874
+ }, err => {
1875
+ monitor.finish();
1876
+ console.log(new Date(), 'Error Update One', this.collectionName, filter, update, options, err);
1877
+ reject(err);
1878
+ });
1879
+ }
1880
+ else if (options && options.upsert) {
1881
+ if (!update.$setOnInsert) {
1882
+ if (this.timestamps) {
1883
+ update.$setOnInsert = <any>{
1884
+ _id: objectIdHexString(),
1885
+ __v: 0,
1886
+ createdAt: new Date()
1887
+ };
1888
+ }
1889
+ else {
1890
+ update.$setOnInsert = <any>{
1891
+ _id: objectIdHexString(),
1892
+ __v: 0
1893
+ };
1894
+ }
1895
+ }
1896
+ else {
1897
+ if (!update.$setOnInsert._id) {
1898
+ update.$setOnInsert._id = objectIdHexString();
1899
+ }
1900
+
1901
+ if (this.timestamps) {
1902
+ update.$setOnInsert.createdAt = new Date();
1903
+ }
1904
+ }
1905
+
1906
+ if (this.createLogs && !bypassLogs) {
1907
+ Logs.insertOne({
1908
+ _id: objectIdHexString(),
1909
+ type: 'document',
1910
+ collection: this.collectionName,
1911
+ id_document: update.$setOnInsert._id,
1912
+ payload: getBinarySize(JSON.stringify(['upsert', filter, update, options])) < 200000 ? JSON.stringify(['upsert', filter, update, options], null, 2) : 'Too Big',
1913
+ method: 'updateOne',
1914
+ id_user: '',
1915
+ user: '',
1916
+ messageId: 0,
1917
+ route: ''
1918
+ });
1919
+ }
1920
+
1921
+ let monitor = new MonitorMongo('updateOne', this.collectionName, JSON.stringify([filter, update, options]));
1922
+ ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, update, options).then(res => {
1923
+ monitor.finish();
1924
+ if (res.acknowledged) {
1925
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1926
+ resolve(res.modifiedCount);
1927
+ }
1928
+ else {
1929
+ reject(res.acknowledged);
1930
+ }
1931
+ }, err => {
1932
+ monitor.finish();
1933
+ console.log(new Date(), 'Error Update One', this.collectionName, filter, update, options, err);
1934
+ reject(err);
1935
+ });
1936
+ }
1937
+ else {
1938
+ reject('No Document');
1939
+ }
1940
+ }
1941
+ else {
1942
+ if (options && options.upsert) {
1943
+ if (!update.$setOnInsert) {
1944
+ if (this.timestamps) {
1945
+ update.$setOnInsert = <any>{
1946
+ _id: objectIdHexString(),
1947
+ createdAt: new Date()
1948
+ };
1949
+ }
1950
+ else {
1951
+ update.$setOnInsert = <any>{
1952
+ _id: objectIdHexString()
1953
+ };
1954
+ }
1955
+ }
1956
+ else {
1957
+ if (!update.$setOnInsert._id) {
1958
+ update.$setOnInsert._id = objectIdHexString();
1959
+ }
1960
+
1961
+ if (this.timestamps) {
1962
+ update.$setOnInsert.createdAt = new Date();
1963
+ }
1964
+ }
1965
+ }
1966
+
1967
+ if (this.createLogs && !bypassLogs) {
1968
+ if (!options) {
1969
+ options = <FindOneAndUpdateOptions>{returnDocument: 'before'};
1970
+ }
1971
+ else {
1972
+ (<FindOneAndUpdateOptions>options).returnDocument = 'before';
1973
+ }
1974
+
1975
+ let monitor = new MonitorMongo('findOneAndUpdate', this.collectionName, JSON.stringify([filter, update, options]));
1976
+ ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).findOneAndUpdate(<any>filter, update, <FindOneAndUpdateOptions>options).then(res => {
1977
+ monitor.finish();
1978
+ let doc = res.value;
1979
+
1980
+ if (doc) {
1981
+ Logs.insertOne({
1982
+ _id: objectIdHexString(),
1983
+ type: 'document',
1984
+ collection: this.collectionName,
1985
+ id_document: <any>doc._id,
1986
+ payload: getBinarySize(JSON.stringify([doc, filter, update, options])) < 200000 ? JSON.stringify([doc, filter, update, options], null, 2) : 'Too Big',
1987
+ method: 'updateOne',
1988
+ id_user: '',
1989
+ user: '',
1990
+ messageId: 0,
1991
+ route: ''
1992
+ });
1993
+
1994
+ resolve(res.ok);
1995
+ }
1996
+ else if (update.$setOnInsert) {
1997
+ Logs.insertOne({
1998
+ _id: objectIdHexString(),
1999
+ type: 'document',
2000
+ collection: this.collectionName,
2001
+ id_document: update.$setOnInsert._id,
2002
+ payload: getBinarySize(JSON.stringify(['upsert', filter, update, options])) < 200000 ? JSON.stringify(['upsert', filter, update, options], null, 2) : 'Too Big',
2003
+ method: 'updateOne',
2004
+ id_user: '',
2005
+ user: '',
2006
+ messageId: 0,
2007
+ route: ''
2008
+ });
2009
+
2010
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2011
+
2012
+ resolve(res.ok);
2013
+ }
2014
+ else {
2015
+ resolve(0);
2016
+ }
2017
+ }, err => {
2018
+ monitor.finish();
2019
+ console.log(new Date(), 'Error Find One And Update', this.collectionName, filter, update, options, err);
2020
+ reject(err)
2021
+ });
2022
+ }
2023
+ else {
2024
+ let monitor = new MonitorMongo('updateOne', this.collectionName, JSON.stringify([filter, update, options]));
2025
+ ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, update, options).then(res => {
2026
+ monitor.finish();
2027
+ if (res.acknowledged) {
2028
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2029
+ resolve(res.modifiedCount);
2030
+ }
2031
+ else {
2032
+ reject(res.acknowledged);
2033
+ }
2034
+ }, err => {
2035
+ monitor.finish();
2036
+ console.log(new Date(), 'Error Update One', this.collectionName, filter, update, options, err);
2037
+ reject(err);
2038
+ });
2039
+ }
2040
+ }
2041
+ });
2042
+ }
2043
+
2044
+ watchCollection(pipeline = [], options?: ChangeStreamOptions): ChangeStream<T> {
2045
+ let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).watch(pipeline, options);
2046
+ stream.on('change', evData => {
2047
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2048
+ return evData;
2049
+ });
2050
+ return <ChangeStream<T>>stream;
2051
+ }
2052
+
2053
+ watchCollectionWithAggregate(pipeline = [], options?: ChangeStreamOptions): ChangeStream<T> {
2054
+ let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).watch(pipeline, options);
2055
+ stream.on('change', evData => {
2056
+ ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2057
+ return evData;
2058
+ });
2059
+ return <ChangeStream<T>>stream;
2060
+ }
2061
+ }
2062
+
2063
+ export class MongoManagerUserCollection<T extends CollectionDocument> extends MongoManagerCollection<T> {
2064
+ authenticateStrategy() {
2065
+ return async (username, password, cb) => {
2066
+ let user = await Users.findOne({username: username});
2067
+ this.authenticate(user, password).then(authUser => {
2068
+ if (authUser.data) {
2069
+ cb(null, user, null);
2070
+ }
2071
+ else {
2072
+ cb(null, null, authUser.error);
2073
+ }
2074
+ }, err => {
2075
+ cb(err, null, null);
2076
+ })
2077
+ };
2078
+ }
2079
+
2080
+ authenticate(user: UserModel, password: string): Promise<{data: UserModel, error: string}> {
2081
+ return new Promise(async (resolve, reject) => {
2082
+ const attemptsInterval = Math.pow(100, Math.log(user.attempts + 1));
2083
+ const calculatedInterval = attemptsInterval < 300000 ? attemptsInterval : 300000;
2084
+
2085
+ if (user.last) {
2086
+ if (Date.now() - user.last.getTime() < calculatedInterval) {
2087
+ user.last = new Date();
2088
+ await Users.updateOne({_id: user._id}, {$set: {last: user.last}});
2089
+ resolve({
2090
+ data: null,
2091
+ error: 'Attempt Too Soon'
2092
+ });
2093
+
2094
+ return;
2095
+ }
2096
+ }
2097
+ else {
2098
+ user.last = new Date();
2099
+ }
2100
+
2101
+ if (user.attempts >= 5) {
2102
+ resolve({
2103
+ data: null,
2104
+ error: 'Too Many Attempts'
2105
+ });
2106
+
2107
+ return;
2108
+ }
2109
+
2110
+ if (!user.salt) {
2111
+ resolve({
2112
+ data: null,
2113
+ error: 'No Salt Value Stored'
2114
+ });
2115
+
2116
+ return;
2117
+ }
2118
+
2119
+ pbkdf2(password, user.salt, {
2120
+ iterations: 25000,
2121
+ keylen: 512,
2122
+ digestAlgorithm: 'sha256'
2123
+ }, async (err, hashBuffer) => {
2124
+ if (err) {
2125
+ return reject(err);
2126
+ }
2127
+
2128
+ if (scmp(hashBuffer, Buffer.from(user.hash, 'hex'))) {
2129
+ user.last = new Date();
2130
+ user.attempts = 0;
2131
+ await Users.updateOne({_id: user._id}, {$set: {last: user.last, attempts: user.attempts}});
2132
+
2133
+ resolve({
2134
+ data: user,
2135
+ error: ''
2136
+ });
2137
+ }
2138
+ else {
2139
+ user.last = new Date();
2140
+ user.attempts = user.attempts + 1;
2141
+ await Users.updateOne({_id: user._id}, {$set: {last: user.last, attempts: user.attempts}});
2142
+
2143
+ if (user.attempts >= 5) {
2144
+ resolve({
2145
+ data: null,
2146
+ error: 'Too Many Attempts'
2147
+ });
2148
+ }
2149
+ else {
2150
+ resolve({
2151
+ data: null,
2152
+ error: 'Invalid Username And Password'
2153
+ });
2154
+ }
2155
+ }
2156
+ });
2157
+ });
2158
+ }
2159
+
2160
+ serializeUser() {
2161
+ return (user, cb) => {
2162
+ cb(null, user.username);
2163
+ };
2164
+ }
2165
+
2166
+ deserializeUser() {
2167
+ return (username, cb) => {
2168
+ Users.findOne({username: username}).then(res => {
2169
+ cb(null, res);
2170
+ }, err => {
2171
+ cb(err, null);
2172
+ });
2173
+ };
2174
+ }
2175
+
2176
+ setPassword(user: UserModel, password: string) {
2177
+ return new Promise(async (resolve, reject) => {
2178
+ if (!user) {
2179
+ reject('No User');
2180
+ }
2181
+ else if (!password) {
2182
+ reject('No Password');
2183
+ }
2184
+ else {
2185
+ let saltBuffer = await randomBytes(32);
2186
+ let salt = saltBuffer.toString('hex');
2187
+ let hashRaw = await pbkdf2Promisified(password, salt, {
2188
+ iterations: 25000,
2189
+ keylen: 512,
2190
+ digestAlgorithm: 'sha256'
2191
+ });
2192
+ let hash = Buffer.from(hashRaw, 'binary').toString('hex');
2193
+ Users.updateOne({_id: user._id}, {$set: {hash: hash, salt: salt, services: {}, attempts: 0}}).then(res => resolve(res), rej => reject(rej));
2194
+ }
2195
+ });
2196
+ };
2197
+
2198
+ changePassword(user, oldPassword, newPassword) {
2199
+ return new Promise(async (resolve, reject) => {
2200
+ if (!user) {
2201
+ reject('Missing User');
2202
+ }
2203
+ else if (!oldPassword || !newPassword) {
2204
+ reject('Missing Password');
2205
+ }
2206
+ else {
2207
+ let authUser = await this.authenticate(user, oldPassword);
2208
+
2209
+ if (!authUser['data']) {
2210
+ reject(authUser['error']);
2211
+ }
2212
+ else {
2213
+ this.setPassword(user, newPassword).then(res => resolve(res), rej => reject(rej));
2214
+ }
2215
+ }
2216
+ });
2217
+ }
2218
+
2219
+ register(user, password) {
2220
+ return new Promise(async (resolve, reject) => {
2221
+ if (!user.username) {
2222
+ reject('Missing Username');
2223
+ }
2224
+ else {
2225
+ let dbUser = await Users.findOne({username: user.username});
2226
+
2227
+ if (dbUser) {
2228
+ reject('Username Exists');
2229
+ }
2230
+ else {
2231
+ dbUser = await Users.findOne({email: user.email});
2232
+
2233
+ if (dbUser) {
2234
+ reject('Email Exists');
2235
+ }
2236
+ else {
2237
+ user.setPassword(password);
2238
+ resolve(user);
2239
+ }
2240
+ }
2241
+ }
2242
+ });
2243
+ }
2244
+
2245
+ resetAttempts(user: UserModel) {
2246
+ return Users.updateOne({_id: user._id}, {$set: {attempts: 0}});
2247
+ }
2248
+ }
2249
+
2250
+ export function objectIdHexString() {
2251
+ let objectId = new ObjectId();
2252
+ return objectId.toHexString();
2253
+ }
2254
+
2255
+ function pbkdf2(password, salt, options, callback) {
2256
+ crypto.pbkdf2(password, salt, options.iterations, options.keylen, options.digestAlgorithm, callback);
2257
+ };
2258
+
2259
+ function pbkdf2Promisified(password, salt, options): Promise<any> {
2260
+ return new Promise((resolve, reject) => pbkdf2(password, salt, options, (err, hashRaw) => (err ? reject(err) : resolve(hashRaw))));
2261
+ }
2262
+
2263
+ function randomBytes(saltlen): Promise<Buffer> {
2264
+ return new Promise((resolve, reject) => crypto.randomBytes(saltlen, (err, saltBuffer) => (err ? reject(err) : resolve(saltBuffer))));
2265
+ }
2266
+
2267
+ function objectContainsPropertyDeep(obj: Object, prop: string) {
2268
+ let keys = Object.keys(obj);
2269
+
2270
+ if (keys.some(a => a === prop)) {
2271
+ return true;
2272
+ }
2273
+
2274
+ for (let i = 0; i < keys.length; i++) {
2275
+ let key = keys[i];
2276
+ if (obj[key] && typeof obj[key] === 'object' && objectContainsPropertyDeep(obj[key], prop)) {
2277
+ return true;
2278
+ }
2279
+ }
2280
+
2281
+ return false;
2282
+ }