mongoose
Version:
Mongoose MongoDB ODM
278 lines (232 loc) • 6.06 kB
JavaScript
/*!
* Module dependencies.
*/
;
const Binary = require('bson').Binary;
const utils = require('../utils');
/**
* Mongoose Buffer constructor.
*
* Values always have to be passed to the constructor to initialize.
*
* @param {Buffer} value
* @param {String} encode
* @param {Number} offset
* @api private
* @inherits Buffer https://nodejs.org/api/buffer.html
* @see https://bit.ly/f6CnZU
*/
function MongooseBuffer(value, encode, offset) {
let val = value;
if (value == null) {
val = 0;
}
let encoding;
let path;
let doc;
if (Array.isArray(encode)) {
// internal casting
path = encode[0];
doc = encode[1];
} else {
encoding = encode;
}
let buf;
if (typeof val === 'number' || val instanceof Number) {
buf = Buffer.alloc(val);
} else { // string, array or object { type: 'Buffer', data: [...] }
buf = Buffer.from(val, encoding, offset);
}
utils.decorate(buf, MongooseBuffer.mixin);
buf.isMongooseBuffer = true;
// make sure these internal props don't show up in Object.keys()
buf[MongooseBuffer.pathSymbol] = path;
buf[parentSymbol] = doc;
buf._subtype = 0;
return buf;
}
const pathSymbol = Symbol.for('mongoose#Buffer#_path');
const parentSymbol = Symbol.for('mongoose#Buffer#_parent');
MongooseBuffer.pathSymbol = pathSymbol;
/*!
* Inherit from Buffer.
*/
MongooseBuffer.mixin = {
/**
* Default subtype for the Binary representing this Buffer
*
* @api private
* @property _subtype
* @memberOf MongooseBuffer.mixin
* @static
*/
_subtype: undefined,
/**
* Marks this buffer as modified.
*
* @api private
* @method _markModified
* @memberOf MongooseBuffer.mixin
* @static
*/
_markModified: function() {
const parent = this[parentSymbol];
if (parent) {
parent.markModified(this[MongooseBuffer.pathSymbol]);
}
return this;
},
/**
* Writes the buffer.
*
* @api public
* @method write
* @memberOf MongooseBuffer.mixin
* @static
*/
write: function() {
const written = Buffer.prototype.write.apply(this, arguments);
if (written > 0) {
this._markModified();
}
return written;
},
/**
* Copies the buffer.
*
* #### Note:
*
* `Buffer#copy` does not mark `target` as modified so you must copy from a `MongooseBuffer` for it to work as expected. This is a work around since `copy` modifies the target, not this.
*
* @return {Number} The number of bytes copied.
* @param {Buffer} target
* @method copy
* @memberOf MongooseBuffer.mixin
* @static
*/
copy: function(target) {
const ret = Buffer.prototype.copy.apply(this, arguments);
if (target && target.isMongooseBuffer) {
target._markModified();
}
return ret;
}
};
/*!
* Compile other Buffer methods marking this buffer as modified.
*/
utils.each(
[
// node < 0.5
'writeUInt8', 'writeUInt16', 'writeUInt32', 'writeInt8', 'writeInt16', 'writeInt32',
'writeFloat', 'writeDouble', 'fill',
'utf8Write', 'binaryWrite', 'asciiWrite', 'set',
// node >= 0.5
'writeUInt16LE', 'writeUInt16BE', 'writeUInt32LE', 'writeUInt32BE',
'writeInt16LE', 'writeInt16BE', 'writeInt32LE', 'writeInt32BE', 'writeFloatLE', 'writeFloatBE', 'writeDoubleLE', 'writeDoubleBE']
, function(method) {
if (!Buffer.prototype[method]) {
return;
}
MongooseBuffer.mixin[method] = function() {
const ret = Buffer.prototype[method].apply(this, arguments);
this._markModified();
return ret;
};
});
/**
* Converts this buffer to its Binary type representation.
*
* #### SubTypes:
*
* const bson = require('bson')
* bson.BSON_BINARY_SUBTYPE_DEFAULT
* bson.BSON_BINARY_SUBTYPE_FUNCTION
* bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
* bson.BSON_BINARY_SUBTYPE_UUID
* bson.BSON_BINARY_SUBTYPE_MD5
* bson.BSON_BINARY_SUBTYPE_USER_DEFINED
* doc.buffer.toObject(bson.BSON_BINARY_SUBTYPE_USER_DEFINED);
*
* @see bsonspec https://bsonspec.org/#/specification
* @param {Hex} [subtype]
* @return {Binary}
* @api public
* @method toObject
* @memberOf MongooseBuffer
*/
MongooseBuffer.mixin.toObject = function(options) {
const subtype = typeof options === 'number'
? options
: (this._subtype || 0);
return new Binary(Buffer.from(this), subtype);
};
MongooseBuffer.mixin.$toObject = MongooseBuffer.mixin.toObject;
/**
* Converts this buffer for storage in MongoDB, including subtype
*
* @return {Binary}
* @api public
* @method toBSON
* @memberOf MongooseBuffer
*/
MongooseBuffer.mixin.toBSON = function() {
return new Binary(this, this._subtype || 0);
};
/**
* Determines if this buffer is equals to `other` buffer
*
* @param {Buffer} other
* @return {Boolean}
* @method equals
* @memberOf MongooseBuffer
*/
MongooseBuffer.mixin.equals = function(other) {
if (!Buffer.isBuffer(other)) {
return false;
}
if (this.length !== other.length) {
return false;
}
for (let i = 0; i < this.length; ++i) {
if (this[i] !== other[i]) {
return false;
}
}
return true;
};
/**
* Sets the subtype option and marks the buffer modified.
*
* #### SubTypes:
*
* const bson = require('bson')
* bson.BSON_BINARY_SUBTYPE_DEFAULT
* bson.BSON_BINARY_SUBTYPE_FUNCTION
* bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
* bson.BSON_BINARY_SUBTYPE_UUID
* bson.BSON_BINARY_SUBTYPE_MD5
* bson.BSON_BINARY_SUBTYPE_USER_DEFINED
*
* doc.buffer.subtype(bson.BSON_BINARY_SUBTYPE_UUID);
*
* @see bsonspec https://bsonspec.org/#/specification
* @param {Hex} subtype
* @api public
* @method subtype
* @memberOf MongooseBuffer
*/
MongooseBuffer.mixin.subtype = function(subtype) {
if (typeof subtype !== 'number') {
throw new TypeError('Invalid subtype. Expected a number');
}
if (this._subtype !== subtype) {
this._markModified();
}
this._subtype = subtype;
};
/*!
* Module exports.
*/
MongooseBuffer.Binary = Binary;
module.exports = MongooseBuffer;