buffer.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. return this._castRef(value, doc, init);
  127. }
  128. // documents
  129. if (value && value._id) {
  130. value = value._id;
  131. }
  132. if (value && value.isMongooseBuffer) {
  133. return value;
  134. }
  135. if (Buffer.isBuffer(value)) {
  136. if (!value || !value.isMongooseBuffer) {
  137. value = new MongooseBuffer(value, [this.path, doc]);
  138. if (this.options.subtype != null) {
  139. value._subtype = this.options.subtype;
  140. }
  141. }
  142. return value;
  143. }
  144. if (value instanceof Binary) {
  145. ret = new MongooseBuffer(value.value(true), [this.path, doc]);
  146. if (typeof value.sub_type !== 'number') {
  147. throw new CastError('Buffer', value, this.path, null, this);
  148. }
  149. ret._subtype = value.sub_type;
  150. return ret;
  151. }
  152. if (value === null) {
  153. return value;
  154. }
  155. const type = typeof value;
  156. if (
  157. type === 'string' || type === 'number' || Array.isArray(value) ||
  158. (type === 'object' && value.type === 'Buffer' && Array.isArray(value.data)) // gh-6863
  159. ) {
  160. if (type === 'number') {
  161. value = [value];
  162. }
  163. ret = new MongooseBuffer(value, [this.path, doc]);
  164. if (this.options.subtype != null) {
  165. ret._subtype = this.options.subtype;
  166. }
  167. return ret;
  168. }
  169. throw new CastError('Buffer', value, this.path, null, this);
  170. };
  171. /**
  172. * Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/)
  173. * for this buffer. You can find a [list of allowed subtypes here](http://api.mongodb.com/python/current/api/bson/binary.html).
  174. *
  175. * ####Example:
  176. *
  177. * const s = new Schema({ uuid: { type: Buffer, subtype: 4 });
  178. * const M = db.model('M', s);
  179. * const m = new M({ uuid: 'test string' });
  180. * m.uuid._subtype; // 4
  181. *
  182. * @param {Number} subtype the default subtype
  183. * @return {SchemaType} this
  184. * @api public
  185. */
  186. SchemaBuffer.prototype.subtype = function(subtype) {
  187. this.options.subtype = subtype;
  188. return this;
  189. };
  190. /*!
  191. * ignore
  192. */
  193. function handleSingle(val) {
  194. return this.castForQuery(val);
  195. }
  196. SchemaBuffer.prototype.$conditionalHandlers =
  197. utils.options(SchemaType.prototype.$conditionalHandlers, {
  198. $bitsAllClear: handleBitwiseOperator,
  199. $bitsAnyClear: handleBitwiseOperator,
  200. $bitsAllSet: handleBitwiseOperator,
  201. $bitsAnySet: handleBitwiseOperator,
  202. $gt: handleSingle,
  203. $gte: handleSingle,
  204. $lt: handleSingle,
  205. $lte: handleSingle
  206. });
  207. /**
  208. * Casts contents for queries.
  209. *
  210. * @param {String} $conditional
  211. * @param {any} [value]
  212. * @api private
  213. */
  214. SchemaBuffer.prototype.castForQuery = function($conditional, val) {
  215. let handler;
  216. if (arguments.length === 2) {
  217. handler = this.$conditionalHandlers[$conditional];
  218. if (!handler) {
  219. throw new Error('Can\'t use ' + $conditional + ' with Buffer.');
  220. }
  221. return handler.call(this, val);
  222. }
  223. val = $conditional;
  224. const casted = this._castForQuery(val);
  225. return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
  226. };
  227. /*!
  228. * Module exports.
  229. */
  230. module.exports = SchemaBuffer;