buffer.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*!
  2. * Module dependencies.
  3. */
  4. 'use strict';
  5. const MongooseBuffer = require('../types/buffer');
  6. const SchemaBufferOptions = require('../options/SchemaBufferOptions');
  7. const SchemaType = require('../schematype');
  8. const handleBitwiseOperator = require('./operators/bitwise');
  9. const utils = require('../utils');
  10. const Binary = MongooseBuffer.Binary;
  11. const CastError = SchemaType.CastError;
  12. /**
  13. * Buffer SchemaType constructor
  14. *
  15. * @param {String} key
  16. * @param {Object} options
  17. * @inherits SchemaType
  18. * @api public
  19. */
  20. function SchemaBuffer(key, options) {
  21. SchemaType.call(this, key, options, 'Buffer');
  22. }
  23. /**
  24. * This schema type's name, to defend against minifiers that mangle
  25. * function names.
  26. *
  27. * @api public
  28. */
  29. SchemaBuffer.schemaName = 'Buffer';
  30. SchemaBuffer.defaultOptions = {};
  31. /*!
  32. * Inherits from SchemaType.
  33. */
  34. SchemaBuffer.prototype = Object.create(SchemaType.prototype);
  35. SchemaBuffer.prototype.constructor = SchemaBuffer;
  36. SchemaBuffer.prototype.OptionsConstructor = SchemaBufferOptions;
  37. /*!
  38. * ignore
  39. */
  40. SchemaBuffer._checkRequired = v => !!(v && v.length);
  41. /**
  42. * Sets a default option for all Buffer instances.
  43. *
  44. * #### Example:
  45. *
  46. * // Make all buffers have `required` of true by default.
  47. * mongoose.Schema.Buffer.set('required', true);
  48. *
  49. * const User = mongoose.model('User', new Schema({ test: Buffer }));
  50. * new User({ }).validateSync().errors.test.message; // Path `test` is required.
  51. *
  52. * @param {String} option - The option you'd like to set the value for
  53. * @param {*} value - value for option
  54. * @return {undefined}
  55. * @function set
  56. * @static
  57. * @api public
  58. */
  59. SchemaBuffer.set = SchemaType.set;
  60. /**
  61. * Override the function the required validator uses to check whether a string
  62. * passes the `required` check.
  63. *
  64. * #### Example:
  65. *
  66. * // Allow empty strings to pass `required` check
  67. * mongoose.Schema.Types.String.checkRequired(v => v != null);
  68. *
  69. * const M = mongoose.model({ buf: { type: Buffer, required: true } });
  70. * new M({ buf: Buffer.from('') }).validateSync(); // validation passes!
  71. *
  72. * @param {Function} fn
  73. * @return {Function}
  74. * @function checkRequired
  75. * @static
  76. * @api public
  77. */
  78. SchemaBuffer.checkRequired = SchemaType.checkRequired;
  79. /**
  80. * Check if the given value satisfies a required validator. To satisfy a
  81. * required validator, a buffer must not be null or undefined and have
  82. * non-zero length.
  83. *
  84. * @param {Any} value
  85. * @param {Document} doc
  86. * @return {Boolean}
  87. * @api public
  88. */
  89. SchemaBuffer.prototype.checkRequired = function(value, doc) {
  90. if (SchemaType._isRef(this, value, doc, true)) {
  91. return !!value;
  92. }
  93. return this.constructor._checkRequired(value);
  94. };
  95. /**
  96. * Casts contents
  97. *
  98. * @param {Object} value
  99. * @param {Document} doc document that triggers the casting
  100. * @param {Boolean} init
  101. * @api private
  102. */
  103. SchemaBuffer.prototype.cast = function(value, doc, init) {
  104. let ret;
  105. if (SchemaType._isRef(this, value, doc, init)) {
  106. if (value && value.isMongooseBuffer) {
  107. return value;
  108. }
  109. if (Buffer.isBuffer(value)) {
  110. if (!value || !value.isMongooseBuffer) {
  111. value = new MongooseBuffer(value, [this.path, doc]);
  112. if (this.options.subtype != null) {
  113. value._subtype = this.options.subtype;
  114. }
  115. }
  116. return value;
  117. }
  118. if (value instanceof Binary) {
  119. ret = new MongooseBuffer(value.value(true), [this.path, doc]);
  120. if (typeof value.sub_type !== 'number') {
  121. throw new CastError('Buffer', value, this.path, null, this);
  122. }
  123. ret._subtype = value.sub_type;
  124. return ret;
  125. }
  126. if (value == null || utils.isNonBuiltinObject(value)) {
  127. return this._castRef(value, doc, init);
  128. }
  129. }
  130. // documents
  131. if (value && value._id) {
  132. value = value._id;
  133. }
  134. if (value && value.isMongooseBuffer) {
  135. return value;
  136. }
  137. if (Buffer.isBuffer(value)) {
  138. if (!value || !value.isMongooseBuffer) {
  139. value = new MongooseBuffer(value, [this.path, doc]);
  140. if (this.options.subtype != null) {
  141. value._subtype = this.options.subtype;
  142. }
  143. }
  144. return value;
  145. }
  146. if (value instanceof Binary) {
  147. ret = new MongooseBuffer(value.value(true), [this.path, doc]);
  148. if (typeof value.sub_type !== 'number') {
  149. throw new CastError('Buffer', value, this.path, null, this);
  150. }
  151. ret._subtype = value.sub_type;
  152. return ret;
  153. }
  154. if (value === null) {
  155. return value;
  156. }
  157. const type = typeof value;
  158. if (
  159. type === 'string' || type === 'number' || Array.isArray(value) ||
  160. (type === 'object' && value.type === 'Buffer' && Array.isArray(value.data)) // gh-6863
  161. ) {
  162. if (type === 'number') {
  163. value = [value];
  164. }
  165. ret = new MongooseBuffer(value, [this.path, doc]);
  166. if (this.options.subtype != null) {
  167. ret._subtype = this.options.subtype;
  168. }
  169. return ret;
  170. }
  171. throw new CastError('Buffer', value, this.path, null, this);
  172. };
  173. /**
  174. * Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/)
  175. * for this buffer. You can find a [list of allowed subtypes here](https://api.mongodb.com/python/current/api/bson/binary.html).
  176. *
  177. * #### Example:
  178. *
  179. * const s = new Schema({ uuid: { type: Buffer, subtype: 4 });
  180. * const M = db.model('M', s);
  181. * const m = new M({ uuid: 'test string' });
  182. * m.uuid._subtype; // 4
  183. *
  184. * @param {Number} subtype the default subtype
  185. * @return {SchemaType} this
  186. * @api public
  187. */
  188. SchemaBuffer.prototype.subtype = function(subtype) {
  189. this.options.subtype = subtype;
  190. return this;
  191. };
  192. /*!
  193. * ignore
  194. */
  195. function handleSingle(val) {
  196. return this.castForQuery(val);
  197. }
  198. SchemaBuffer.prototype.$conditionalHandlers =
  199. utils.options(SchemaType.prototype.$conditionalHandlers, {
  200. $bitsAllClear: handleBitwiseOperator,
  201. $bitsAnyClear: handleBitwiseOperator,
  202. $bitsAllSet: handleBitwiseOperator,
  203. $bitsAnySet: handleBitwiseOperator,
  204. $gt: handleSingle,
  205. $gte: handleSingle,
  206. $lt: handleSingle,
  207. $lte: handleSingle
  208. });
  209. /**
  210. * Casts contents for queries.
  211. *
  212. * @param {String} $conditional
  213. * @param {any} [value]
  214. * @api private
  215. */
  216. SchemaBuffer.prototype.castForQuery = function($conditional, val) {
  217. let handler;
  218. if (arguments.length === 2) {
  219. handler = this.$conditionalHandlers[$conditional];
  220. if (!handler) {
  221. throw new Error('Can\'t use ' + $conditional + ' with Buffer.');
  222. }
  223. return handler.call(this, val);
  224. }
  225. val = $conditional;
  226. const casted = this._castForQuery(val);
  227. return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
  228. };
  229. /*!
  230. * Module exports.
  231. */
  232. module.exports = SchemaBuffer;