index.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.GridFSBucket = void 0;
  4. const error_1 = require("../error");
  5. const mongo_types_1 = require("../mongo_types");
  6. const timeout_1 = require("../timeout");
  7. const utils_1 = require("../utils");
  8. const write_concern_1 = require("../write_concern");
  9. const download_1 = require("./download");
  10. const upload_1 = require("./upload");
  11. const DEFAULT_GRIDFS_BUCKET_OPTIONS = {
  12. bucketName: 'fs',
  13. chunkSizeBytes: 255 * 1024
  14. };
  15. /**
  16. * Constructor for a streaming GridFS interface
  17. * @public
  18. */
  19. class GridFSBucket extends mongo_types_1.TypedEventEmitter {
  20. /**
  21. * When the first call to openUploadStream is made, the upload stream will
  22. * check to see if it needs to create the proper indexes on the chunks and
  23. * files collections. This event is fired either when 1) it determines that
  24. * no index creation is necessary, 2) when it successfully creates the
  25. * necessary indexes.
  26. * @event
  27. */
  28. static { this.INDEX = 'index'; }
  29. constructor(db, options) {
  30. super();
  31. this.on('error', utils_1.noop);
  32. this.setMaxListeners(0);
  33. const privateOptions = (0, utils_1.resolveOptions)(db, {
  34. ...DEFAULT_GRIDFS_BUCKET_OPTIONS,
  35. ...options,
  36. writeConcern: write_concern_1.WriteConcern.fromOptions(options)
  37. });
  38. this.s = {
  39. db,
  40. options: privateOptions,
  41. _chunksCollection: db.collection(privateOptions.bucketName + '.chunks'),
  42. _filesCollection: db.collection(privateOptions.bucketName + '.files'),
  43. checkedIndexes: false,
  44. calledOpenUploadStream: false
  45. };
  46. }
  47. /**
  48. * Returns a writable stream (GridFSBucketWriteStream) for writing
  49. * buffers to GridFS. The stream's 'id' property contains the resulting
  50. * file's id.
  51. *
  52. * @param filename - The value of the 'filename' key in the files doc
  53. * @param options - Optional settings.
  54. */
  55. openUploadStream(filename, options) {
  56. return new upload_1.GridFSBucketWriteStream(this, filename, {
  57. timeoutMS: this.s.options.timeoutMS,
  58. ...options
  59. });
  60. }
  61. /**
  62. * Returns a writable stream (GridFSBucketWriteStream) for writing
  63. * buffers to GridFS for a custom file id. The stream's 'id' property contains the resulting
  64. * file's id.
  65. */
  66. openUploadStreamWithId(id, filename, options) {
  67. return new upload_1.GridFSBucketWriteStream(this, filename, {
  68. timeoutMS: this.s.options.timeoutMS,
  69. ...options,
  70. id
  71. });
  72. }
  73. /** Returns a readable stream (GridFSBucketReadStream) for streaming file data from GridFS. */
  74. openDownloadStream(id, options) {
  75. return new download_1.GridFSBucketReadStream(this.s._chunksCollection, this.s._filesCollection, this.s.options.readPreference, { _id: id }, { timeoutMS: this.s.options.timeoutMS, ...options });
  76. }
  77. /**
  78. * Deletes a file with the given id
  79. *
  80. * @param id - The id of the file doc
  81. */
  82. async delete(id, options) {
  83. const { timeoutMS } = (0, utils_1.resolveOptions)(this.s.db, options);
  84. let timeoutContext = undefined;
  85. if (timeoutMS) {
  86. timeoutContext = new timeout_1.CSOTTimeoutContext({
  87. timeoutMS,
  88. serverSelectionTimeoutMS: this.s.db.client.s.options.serverSelectionTimeoutMS
  89. });
  90. }
  91. const { deletedCount } = await this.s._filesCollection.deleteOne({ _id: id }, { timeoutMS: timeoutContext?.remainingTimeMS });
  92. const remainingTimeMS = timeoutContext?.remainingTimeMS;
  93. if (remainingTimeMS != null && remainingTimeMS <= 0)
  94. throw new error_1.MongoOperationTimeoutError(`Timed out after ${timeoutMS}ms`);
  95. // Delete orphaned chunks before returning FileNotFound
  96. await this.s._chunksCollection.deleteMany({ files_id: id }, { timeoutMS: remainingTimeMS });
  97. if (deletedCount === 0) {
  98. // TODO(NODE-3483): Replace with more appropriate error
  99. // Consider creating new error MongoGridFSFileNotFoundError
  100. throw new error_1.MongoRuntimeError(`File not found for id ${id}`);
  101. }
  102. }
  103. /** Convenience wrapper around find on the files collection */
  104. find(filter = {}, options = {}) {
  105. return this.s._filesCollection.find(filter, options);
  106. }
  107. /**
  108. * Returns a readable stream (GridFSBucketReadStream) for streaming the
  109. * file with the given name from GridFS. If there are multiple files with
  110. * the same name, this will stream the most recent file with the given name
  111. * (as determined by the `uploadDate` field). You can set the `revision`
  112. * option to change this behavior.
  113. */
  114. openDownloadStreamByName(filename, options) {
  115. let sort = { uploadDate: -1 };
  116. let skip = undefined;
  117. if (options && options.revision != null) {
  118. if (options.revision >= 0) {
  119. sort = { uploadDate: 1 };
  120. skip = options.revision;
  121. }
  122. else {
  123. skip = -options.revision - 1;
  124. }
  125. }
  126. return new download_1.GridFSBucketReadStream(this.s._chunksCollection, this.s._filesCollection, this.s.options.readPreference, { filename }, { timeoutMS: this.s.options.timeoutMS, ...options, sort, skip });
  127. }
  128. /**
  129. * Renames the file with the given _id to the given string
  130. *
  131. * @param id - the id of the file to rename
  132. * @param filename - new name for the file
  133. */
  134. async rename(id, filename, options) {
  135. const filter = { _id: id };
  136. const update = { $set: { filename } };
  137. const { matchedCount } = await this.s._filesCollection.updateOne(filter, update, options);
  138. if (matchedCount === 0) {
  139. throw new error_1.MongoRuntimeError(`File with id ${id} not found`);
  140. }
  141. }
  142. /** Removes this bucket's files collection, followed by its chunks collection. */
  143. async drop(options) {
  144. const { timeoutMS } = (0, utils_1.resolveOptions)(this.s.db, options);
  145. let timeoutContext = undefined;
  146. if (timeoutMS) {
  147. timeoutContext = new timeout_1.CSOTTimeoutContext({
  148. timeoutMS,
  149. serverSelectionTimeoutMS: this.s.db.client.s.options.serverSelectionTimeoutMS
  150. });
  151. }
  152. if (timeoutContext) {
  153. await this.s._filesCollection.drop({ timeoutMS: timeoutContext.remainingTimeMS });
  154. const remainingTimeMS = timeoutContext.getRemainingTimeMSOrThrow(`Timed out after ${timeoutMS}ms`);
  155. await this.s._chunksCollection.drop({ timeoutMS: remainingTimeMS });
  156. }
  157. else {
  158. await this.s._filesCollection.drop();
  159. await this.s._chunksCollection.drop();
  160. }
  161. }
  162. }
  163. exports.GridFSBucket = GridFSBucket;
  164. //# sourceMappingURL=index.js.map