diff --git a/lib/cast/decimal128.js b/lib/cast/decimal128.js new file mode 100644 index 00000000000..bfb1578c406 --- /dev/null +++ b/lib/cast/decimal128.js @@ -0,0 +1,36 @@ +'use strict'; + +const Decimal128Type = require('../types/decimal128'); +const assert = require('assert'); + +module.exports = function castDecimal128(value) { + if (value == null) { + return value; + } + + if (typeof value === 'object' && typeof value.$numberDecimal === 'string') { + return Decimal128Type.fromString(value.$numberDecimal); + } + + if (value instanceof Decimal128Type) { + return value; + } + + if (typeof value === 'string') { + return Decimal128Type.fromString(value); + } + + if (Buffer.isBuffer(value)) { + return new Decimal128Type(value); + } + + if (typeof value === 'number') { + return Decimal128Type.fromString(String(value)); + } + + if (typeof value.valueOf === 'function' && typeof value.valueOf() === 'string') { + return Decimal128Type.fromString(value.valueOf()); + } + + assert.ok(false); +}; \ No newline at end of file diff --git a/lib/schema/decimal128.js b/lib/schema/decimal128.js index 38acf6ec144..0338905ffe8 100644 --- a/lib/schema/decimal128.js +++ b/lib/schema/decimal128.js @@ -7,7 +7,9 @@ const SchemaType = require('../schematype'); const CastError = SchemaType.CastError; const Decimal128Type = require('../types/decimal128'); +const castDecimal128 = require('../cast/decimal128'); const utils = require('../utils'); + let Document; /** @@ -37,6 +39,51 @@ Decimal128.schemaName = 'Decimal128'; Decimal128.prototype = Object.create(SchemaType.prototype); Decimal128.prototype.constructor = Decimal128; +/*! + * ignore + */ + +Decimal128._cast = castDecimal128; + +/** + * Get/set the function used to cast arbitrary values to decimals. + * + * ####Example: + * + * // Make Mongoose only refuse to cast numbers as decimal128 + * const original = mongoose.Schema.Types.Decimal128.cast(); + * mongoose.Decimal128.cast(v => { + * assert.ok(typeof v !== 'number'); + * return original(v); + * }); + * + * // Or disable casting entirely + * mongoose.Decimal128.cast(false); + * + * @param {Function} [caster] + * @return {Function} + * @function get + * @static + * @api public + */ + +Decimal128.cast = function cast(caster) { + if (arguments.length === 0) { + return this._cast; + } + if (caster === false) { + caster = v => { + if (v != null && !(v instanceof Decimal128Type)) { + throw new Error(); + } + return v; + }; + } + this._cast = caster; + + return this._cast; +}; + /*! * ignore */ @@ -123,35 +170,12 @@ Decimal128.prototype.cast = function(value, doc, init) { return ret; } - if (value == null) { - return value; + const _castDecimal128 = this.constructor.cast(); + try { + return _castDecimal128(value); + } catch (error) { + throw new CastError('Decimal128', value, this.path); } - - if (typeof value === 'object' && typeof value.$numberDecimal === 'string') { - return Decimal128Type.fromString(value.$numberDecimal); - } - - if (value instanceof Decimal128Type) { - return value; - } - - if (typeof value === 'string') { - return Decimal128Type.fromString(value); - } - - if (Buffer.isBuffer(value)) { - return new Decimal128Type(value); - } - - if (typeof value === 'number') { - return Decimal128Type.fromString(String(value)); - } - - if (typeof value.valueOf === 'function' && typeof value.valueOf() === 'string') { - return Decimal128Type.fromString(value.valueOf()); - } - - throw new CastError('Decimal128', value, this.path); }; /*! diff --git a/test/schematype.cast.test.js b/test/schematype.cast.test.js index 743348590de..2007b52739a 100644 --- a/test/schematype.cast.test.js +++ b/test/schematype.cast.test.js @@ -12,6 +12,7 @@ describe('SchemaType.cast() (gh-7045)', function() { original.boolean = Schema.Types.Boolean.cast(); original.string = Schema.Types.String.cast(); original.date = Schema.Types.Date.cast(); + original.decimal128 = Schema.Types.Decimal128.cast(); }); afterEach(function() { @@ -19,6 +20,7 @@ describe('SchemaType.cast() (gh-7045)', function() { Schema.Types.Boolean.cast(original.boolean); Schema.Types.String.cast(original.string); Schema.Types.Date.cast(original.date); + Schema.Types.Decimal128.cast(original.decimal128); }); it('with inheritance', function() { @@ -165,4 +167,28 @@ describe('SchemaType.cast() (gh-7045)', function() { assert.throws(() => d.cast('2018-06-01'), /CastError/); }); }); + + describe('decimal128', function() { + it('supports custom cast functions', function() { + Schema.Types.Decimal128.cast(v => { + assert.ok(typeof v !== 'number'); + return original.date(v); + }); + + const d = new Schema.Types.Decimal128(); + d.cast('1000'); // Should not throw + + assert.throws(() => d.cast(1000), /CastError/); + }); + + it('supports disabling casting', function() { + Schema.Types.Decimal128.cast(false); + + const d = new Schema.Types.Decimal128(); + assert.throws(() => d.cast('1000'), /CastError/); + assert.throws(() => d.cast(1000), /CastError/); + + d.cast(original.decimal128('1000')); // Should not throw + }); + }); }); \ No newline at end of file