MongoManager.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS102: Remove unnecessary code created because of implicit returns
  10. * DS207: Consider shorter variations of null checks
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. let MongoManager
  14. const { db, ObjectId } = require('./mongodb')
  15. const logger = require('logger-sharelatex')
  16. const metrics = require('@overleaf/metrics')
  17. const Settings = require('@overleaf/settings')
  18. const Errors = require('./Errors')
  19. const { promisify } = require('util')
  20. module.exports = MongoManager = {
  21. findDoc(project_id, doc_id, filter, callback) {
  22. if (callback == null) {
  23. callback = function (error, doc) {}
  24. }
  25. db.docs.findOne(
  26. {
  27. _id: ObjectId(doc_id.toString()),
  28. project_id: ObjectId(project_id.toString()),
  29. },
  30. {
  31. projection: filter,
  32. },
  33. callback
  34. )
  35. },
  36. getProjectsDeletedDocs(project_id, filter, callback) {
  37. db.docs
  38. .find(
  39. {
  40. project_id: ObjectId(project_id.toString()),
  41. deleted: true,
  42. },
  43. {
  44. projection: filter,
  45. sort: { deletedAt: -1 },
  46. limit: Settings.max_deleted_docs,
  47. }
  48. )
  49. .toArray(callback)
  50. },
  51. getProjectsDocs(project_id, options, filter, callback) {
  52. const query = { project_id: ObjectId(project_id.toString()) }
  53. if (!options.include_deleted) {
  54. query.deleted = { $ne: true }
  55. }
  56. const queryOptions = {
  57. projection: filter,
  58. }
  59. if (options.limit) {
  60. queryOptions.limit = options.limit
  61. }
  62. db.docs.find(query, queryOptions).toArray(callback)
  63. },
  64. getArchivedProjectDocs(project_id, maxResults, callback) {
  65. const query = {
  66. project_id: ObjectId(project_id.toString()),
  67. inS3: true,
  68. }
  69. db.docs
  70. .find(query, { projection: { _id: 1 }, limit: maxResults })
  71. .toArray(callback)
  72. },
  73. getNonArchivedProjectDocs(project_id, maxResults, callback) {
  74. const query = {
  75. project_id: ObjectId(project_id.toString()),
  76. inS3: { $ne: true },
  77. }
  78. db.docs.find(query, { limit: maxResults }).toArray(callback)
  79. },
  80. getNonDeletedArchivedProjectDocs(project_id, maxResults, callback) {
  81. const query = {
  82. project_id: ObjectId(project_id.toString()),
  83. deleted: { $ne: true },
  84. inS3: true,
  85. }
  86. db.docs
  87. .find(query, { projection: { _id: 1 }, limit: maxResults })
  88. .toArray(callback)
  89. },
  90. upsertIntoDocCollection(project_id, doc_id, updates, callback) {
  91. const update = {
  92. $set: updates,
  93. $inc: {
  94. rev: 1,
  95. },
  96. $unset: {
  97. inS3: true,
  98. },
  99. }
  100. update.$set.project_id = ObjectId(project_id)
  101. db.docs.updateOne(
  102. { _id: ObjectId(doc_id) },
  103. update,
  104. { upsert: true },
  105. callback
  106. )
  107. },
  108. patchDoc(project_id, doc_id, meta, callback) {
  109. db.docs.updateOne(
  110. {
  111. _id: ObjectId(doc_id),
  112. project_id: ObjectId(project_id),
  113. },
  114. { $set: meta },
  115. callback
  116. )
  117. },
  118. markDocAsArchived(doc_id, rev, callback) {
  119. const update = {
  120. $set: {},
  121. $unset: {},
  122. }
  123. update.$set.inS3 = true
  124. update.$unset.lines = true
  125. update.$unset.ranges = true
  126. const query = {
  127. _id: doc_id,
  128. rev,
  129. }
  130. db.docs.updateOne(query, update, callback)
  131. },
  132. getDocVersion(doc_id, callback) {
  133. if (callback == null) {
  134. callback = function (error, version) {}
  135. }
  136. db.docOps.findOne(
  137. {
  138. doc_id: ObjectId(doc_id),
  139. },
  140. {
  141. projection: {
  142. version: 1,
  143. },
  144. },
  145. function (error, doc) {
  146. if (error != null) {
  147. return callback(error)
  148. }
  149. callback(null, (doc && doc.version) || 0)
  150. }
  151. )
  152. },
  153. setDocVersion(doc_id, version, callback) {
  154. if (callback == null) {
  155. callback = function (error) {}
  156. }
  157. db.docOps.updateOne(
  158. {
  159. doc_id: ObjectId(doc_id),
  160. },
  161. {
  162. $set: { version },
  163. },
  164. {
  165. upsert: true,
  166. },
  167. callback
  168. )
  169. },
  170. getDocRev(doc_id, callback) {
  171. db.docs.findOne(
  172. {
  173. _id: ObjectId(doc_id.toString()),
  174. },
  175. {
  176. projection: { rev: 1 },
  177. },
  178. function (err, doc) {
  179. if (err != null) {
  180. return callback(err)
  181. }
  182. callback(null, doc && doc.rev)
  183. }
  184. )
  185. },
  186. // Helper method to support optimistic locking. Call the provided method for
  187. // an existing doc and return the result if the rev in mongo is unchanged when
  188. // checked afterwards. If the rev has changed, return a DocModifiedError.
  189. withRevCheck(doc, method, callback) {
  190. method(doc._id, function (err, result) {
  191. if (err) return callback(err)
  192. MongoManager.getDocRev(doc._id, function (err, currentRev) {
  193. if (err) return callback(err)
  194. if (doc.rev !== currentRev) {
  195. return callback(
  196. new Errors.DocModifiedError('doc rev has changed', {
  197. doc_id: doc._id,
  198. rev: doc.rev,
  199. currentRev,
  200. })
  201. )
  202. }
  203. return callback(null, result)
  204. })
  205. })
  206. },
  207. destroyDoc(doc_id, callback) {
  208. db.docs.deleteOne(
  209. {
  210. _id: ObjectId(doc_id),
  211. },
  212. function (err) {
  213. if (err != null) {
  214. return callback(err)
  215. }
  216. db.docOps.deleteOne(
  217. {
  218. doc_id: ObjectId(doc_id),
  219. },
  220. callback
  221. )
  222. }
  223. )
  224. },
  225. }
  226. const methods = Object.getOwnPropertyNames(MongoManager)
  227. module.exports.promises = {}
  228. for (const method of methods) {
  229. metrics.timeAsyncMethod(MongoManager, method, 'mongo.MongoManager', logger)
  230. module.exports.promises[method] = promisify(module.exports[method])
  231. }