buffer.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*!
  2. * Module dependencies.
  3. */
  4. 'use strict';
  5. const handleBitwiseOperator = require('./operators/bitwise');
  6. const utils = require('../utils');
  7. const MongooseBuffer = require('../types/buffer');
  8. const SchemaType = require('../schematype');
  9. const Binary = MongooseBuffer.Binary;
  10. const CastError = SchemaType.CastError;
  11. let Document;
  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. /*!
  31. * Inherits from SchemaType.
  32. */
  33. SchemaBuffer.prototype = Object.create(SchemaType.prototype);
  34. SchemaBuffer.prototype.constructor = SchemaBuffer;
  35. /*!
  36. * ignore
  37. */
  38. SchemaBuffer._checkRequired = v => !!(v && v.length);
  39. /**
  40. * Override the function the required validator uses to check whether a string
  41. * passes the `required` check.
  42. *
  43. * ####Example:
  44. *
  45. * // Allow empty strings to pass `required` check
  46. * mongoose.Schema.Types.String.checkRequired(v => v != null);
  47. *
  48. * const M = mongoose.model({ buf: { type: Buffer, required: true } });
  49. * new M({ buf: Buffer.from('') }).validateSync(); // validation passes!
  50. *
  51. * @param {Function} fn
  52. * @return {Function}
  53. * @function checkRequired
  54. * @static
  55. * @api public
  56. */
  57. SchemaBuffer.checkRequired = SchemaType.checkRequired;
  58. /**
  59. * Check if the given value satisfies a required validator. To satisfy a
  60. * required validator, a buffer must not be null or undefined and have
  61. * non-zero length.
  62. *
  63. * @param {Any} value
  64. * @param {Document} doc
  65. * @return {Boolean}
  66. * @api public
  67. */
  68. SchemaBuffer.prototype.checkRequired = function(value, doc) {
  69. if (SchemaType._isRef(this, value, doc, true)) {
  70. return !!value;
  71. }
  72. return this.constructor._checkRequired(value);
  73. };
  74. /**
  75. * Casts contents
  76. *
  77. * @param {Object} value
  78. * @param {Document} doc document that triggers the casting
  79. * @param {Boolean} init
  80. * @api private
  81. */
  82. SchemaBuffer.prototype.cast = function(value, doc, init) {
  83. let ret;
  84. if (SchemaType._isRef(this, value, doc, init)) {
  85. // wait! we may need to cast this to a document
  86. if (value === null || value === undefined) {
  87. return value;
  88. }
  89. // lazy load
  90. Document || (Document = require('./../document'));
  91. if (value instanceof Document) {
  92. value.$__.wasPopulated = true;
  93. return value;
  94. }
  95. // setting a populated path
  96. if (Buffer.isBuffer(value)) {
  97. return value;
  98. } else if (!utils.isObject(value)) {
  99. throw new CastError('buffer', value, this.path);
  100. }
  101. // Handle the case where user directly sets a populated
  102. // path to a plain object; cast to the Model used in
  103. // the population query.
  104. const path = doc.$__fullPath(this.path);
  105. const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
  106. const pop = owner.populated(path, true);
  107. ret = new pop.options.model(value);
  108. ret.$__.wasPopulated = true;
  109. return ret;
  110. }
  111. // documents
  112. if (value && value._id) {
  113. value = value._id;
  114. }
  115. if (value && value.isMongooseBuffer) {
  116. return value;
  117. }
  118. if (Buffer.isBuffer(value)) {
  119. if (!value || !value.isMongooseBuffer) {
  120. value = new MongooseBuffer(value, [this.path, doc]);
  121. if (this.options.subtype != null) {
  122. value._subtype = this.options.subtype;
  123. }
  124. }
  125. return value;
  126. }
  127. if (value instanceof Binary) {
  128. ret = new MongooseBuffer(value.value(true), [this.path, doc]);
  129. if (typeof value.sub_type !== 'number') {
  130. throw new CastError('buffer', value, this.path);
  131. }
  132. ret._subtype = value.sub_type;
  133. return ret;
  134. }
  135. if (value === null) {
  136. return value;
  137. }
  138. const type = typeof value;
  139. if (
  140. type === 'string' || type === 'number' || Array.isArray(value) ||
  141. (type === 'object' && value.type === 'Buffer' && Array.isArray(value.data)) // gh-6863
  142. ) {
  143. if (type === 'number') {
  144. value = [value];
  145. }
  146. ret = new MongooseBuffer(value, [this.path, doc]);
  147. if (this.options.subtype != null) {
  148. ret._subtype = this.options.subtype;
  149. }
  150. return ret;
  151. }
  152. throw new CastError('buffer', value, this.path);
  153. };
  154. /**
  155. * Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/)
  156. * for this buffer. You can find a [list of allowed subtypes here](http://api.mongodb.com/python/current/api/bson/binary.html).
  157. *
  158. * ####Example:
  159. *
  160. * var s = new Schema({ uuid: { type: Buffer, subtype: 4 });
  161. * var M = db.model('M', s);
  162. * var m = new M({ uuid: 'test string' });
  163. * m.uuid._subtype; // 4
  164. *
  165. * @param {Number} subtype the default subtype
  166. * @return {SchemaType} this
  167. * @api public
  168. */
  169. SchemaBuffer.prototype.subtype = function(subtype) {
  170. this.options.subtype = subtype;
  171. return this;
  172. };
  173. /*!
  174. * ignore
  175. */
  176. function handleSingle(val) {
  177. return this.castForQuery(val);
  178. }
  179. SchemaBuffer.prototype.$conditionalHandlers =
  180. utils.options(SchemaType.prototype.$conditionalHandlers, {
  181. $bitsAllClear: handleBitwiseOperator,
  182. $bitsAnyClear: handleBitwiseOperator,
  183. $bitsAllSet: handleBitwiseOperator,
  184. $bitsAnySet: handleBitwiseOperator,
  185. $gt: handleSingle,
  186. $gte: handleSingle,
  187. $lt: handleSingle,
  188. $lte: handleSingle
  189. });
  190. /**
  191. * Casts contents for queries.
  192. *
  193. * @param {String} $conditional
  194. * @param {any} [value]
  195. * @api private
  196. */
  197. SchemaBuffer.prototype.castForQuery = function($conditional, val) {
  198. let handler;
  199. if (arguments.length === 2) {
  200. handler = this.$conditionalHandlers[$conditional];
  201. if (!handler) {
  202. throw new Error('Can\'t use ' + $conditional + ' with Buffer.');
  203. }
  204. return handler.call(this, val);
  205. }
  206. val = $conditional;
  207. const casted = this._castForQuery(val);
  208. return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
  209. };
  210. /*!
  211. * Module exports.
  212. */
  213. module.exports = SchemaBuffer;