diff --git a/docs/guide.md b/docs/guide.md index fa653acc4dd..0164db46b9a 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -80,6 +80,7 @@ The permitted SchemaTypes are: * [Decimal128](api/mongoose.html#mongoose_Mongoose-Decimal128) * [Map](schematypes.html#maps) * [UUID](schematypes.html#uuid) +* [Double](schematypes.html#double) Read more about [SchemaTypes here](schematypes.html). diff --git a/docs/schematypes.md b/docs/schematypes.md index 904bb6a8726..f3d0a72261e 100644 --- a/docs/schematypes.md +++ b/docs/schematypes.md @@ -55,6 +55,7 @@ Check out [Mongoose's plugins search](http://plugins.mongoosejs.io) to find plug * [Schema](#schemas) * [UUID](#uuid) * [BigInt](#bigint) +* [Double](#double) ### Example @@ -68,6 +69,7 @@ const schema = new Schema({ mixed: Schema.Types.Mixed, _someId: Schema.Types.ObjectId, decimal: Schema.Types.Decimal128, + double: Schema.Types.Double, array: [], ofString: [String], ofNumber: [Number], @@ -647,6 +649,42 @@ const question = new Question({ answer: 42n }); typeof question.answer; // 'bigint' ``` +### Double {#double} + +Mongoose supports [64-bit IEEE 754-2008 floating point numbers](https://en.wikipedia.org/wiki/IEEE_754-2008_revision) as a SchemaType. +Int32s are stored as [BSON type "double" in MongoDB](https://www.mongodb.com/docs/manual/reference/bson-types/). + +```javascript +const studentsSchema = new Schema({ + id: Int32 +}); +const Student = mongoose.model('Student', schema); + +const student = new Temperature({ celsius: 1339 }); +typeof student.id; // 'number' +``` + +There are several types of values that will be successfully cast to a Double. + +```javascript +new Temperature({ celsius: '1.2e12' }).celsius; // 15 as a Double +new Temperature({ celsius: true }).celsius; // 1 as a Double +new Temperature({ celsius: false }).celsius; // 0 as a Double +new Temperature({ celsius: { valueOf: () => 83.0033 } }).celsius; // 83 as a Double +new Temperature({ celsius: '' }).celsius; // null as a Double +``` + +If you pass an object with a `valueOf()` function that returns a Number, Mongoose will +call it and assign the returned value to the path. + +The values `null` and `undefined` are not cast. + +The following inputs will result will all result in a [CastError](validation.html#cast-errors) once validated, meaning that it will not throw on initialization, only when validated: + +* strings that do not represent a numeric string, a NaN or a null-ish value +* objects that don't have a `valueOf()` function +* an input that represents a value outside the bounds of a IEEE 754-2008 floating point + ## Getters {#getters} Getters are like virtuals for paths defined in your schema. For example, diff --git a/index.js b/index.js index 6ebbd5fd5d3..f44ddb21f3a 100644 --- a/index.js +++ b/index.js @@ -46,6 +46,7 @@ module.exports.Decimal128 = mongoose.Decimal128; module.exports.Mixed = mongoose.Mixed; module.exports.Date = mongoose.Date; module.exports.Number = mongoose.Number; +module.exports.Double = mongoose.Double; module.exports.Error = mongoose.Error; module.exports.MongooseError = mongoose.MongooseError; module.exports.now = mongoose.now; diff --git a/lib/cast/double.js b/lib/cast/double.js new file mode 100644 index 00000000000..5dfc6c1a797 --- /dev/null +++ b/lib/cast/double.js @@ -0,0 +1,50 @@ +'use strict'; + +const assert = require('assert'); +const BSON = require('bson'); +const isBsonType = require('../helpers/isBsonType'); + +/** + * Given a value, cast it to a IEEE 754-2008 floating point, or throw an `Error` if the value + * cannot be casted. `null`, `undefined`, and `NaN` are considered valid inputs. + * + * @param {Any} value + * @return {Number} + * @throws {Error} if `value` does not represent a IEEE 754-2008 floating point. If casting from a string, see [BSON Double.fromString API documentation](https://mongodb.github.io/node-mongodb-native/Next/classes/BSON.Double.html#fromString) + * @api private + */ + +module.exports = function castDouble(val) { + if (val == null || val === '') { + return null; + } + + let coercedVal; + if (isBsonType(val, 'Long')) { + coercedVal = val.toNumber(); + } else if (typeof val === 'string') { + try { + coercedVal = BSON.Double.fromString(val); + return coercedVal; + } catch { + assert.ok(false); + } + } else if (typeof val === 'object') { + const tempVal = val.valueOf() ?? val.toString(); + // ex: { a: 'im an object, valueOf: () => 'helloworld' } // throw an error + if (typeof tempVal === 'string') { + try { + coercedVal = BSON.Double.fromString(val); + return coercedVal; + } catch { + assert.ok(false); + } + } else { + coercedVal = Number(tempVal); + } + } else { + coercedVal = Number(val); + } + + return new BSON.Double(coercedVal); +}; diff --git a/lib/helpers/clone.js b/lib/helpers/clone.js index 09204b8c8a4..a8dd587dbf9 100644 --- a/lib/helpers/clone.js +++ b/lib/helpers/clone.js @@ -11,6 +11,7 @@ const isObject = require('./isObject'); const isPOJO = require('./isPOJO'); const symbols = require('./symbols'); const trustedSymbol = require('./query/trusted').trustedSymbol; +const BSON = require('bson'); /** * Object clone with Mongoose natives support. @@ -30,6 +31,10 @@ function clone(obj, options, isArrayChild) { if (obj == null) { return obj; } + + if (isBsonType(obj, 'Double')) { + return new BSON.Double(obj.value); + } if (typeof obj === 'number' || typeof obj === 'string' || typeof obj === 'boolean' || typeof obj === 'bigint') { return obj; } diff --git a/lib/schema.js b/lib/schema.js index a9d23fd6199..deb0190061a 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -2848,6 +2848,7 @@ module.exports = exports = Schema; * - [Mixed](https://mongoosejs.com/docs/schematypes.html#mixed) * - [UUID](https://mongoosejs.com/docs/schematypes.html#uuid) * - [BigInt](https://mongoosejs.com/docs/schematypes.html#bigint) + * - [Double] (https://mongoosejs.com/docs/schematypes.html#double) * * Using this exposed access to the `Mixed` SchemaType, we can use them in our schema. * diff --git a/lib/schema/double.js b/lib/schema/double.js new file mode 100644 index 00000000000..79c94752184 --- /dev/null +++ b/lib/schema/double.js @@ -0,0 +1,212 @@ +'use strict'; + +/*! + * Module dependencies. + */ + +const CastError = require('../error/cast'); +const SchemaType = require('../schemaType'); +const castDouble = require('../cast/double'); + +/** + * Double SchemaType constructor. + * + * @param {String} path + * @param {Object} options + * @inherits SchemaType + * @api public + */ + +function SchemaDouble(path, options) { + SchemaType.call(this, path, options, 'Double'); +} + +/** + * This schema type's name, to defend against minifiers that mangle + * function names. + * + * @api public + */ +SchemaDouble.schemaName = 'Double'; + +SchemaDouble.defaultOptions = {}; + +/*! + * Inherits from SchemaType. + */ +SchemaDouble.prototype = Object.create(SchemaType.prototype); +SchemaDouble.prototype.constructor = SchemaDouble; + +/*! + * ignore + */ + +SchemaDouble._cast = castDouble; + +/** + * Sets a default option for all Double instances. + * + * #### Example: + * + * // Make all Double fields required by default + * mongoose.Schema.Double.set('required', true); + * + * @param {String} option The option you'd like to set the value for + * @param {Any} value value for option + * @return {undefined} + * @function set + * @static + * @api public + */ + +SchemaDouble.set = SchemaType.set; + +SchemaDouble.setters = []; + +/** + * Attaches a getter for all Double instances + * + * #### Example: + * + * // Converts Double to be a represent milliseconds upon access + * mongoose.Schema.Double.get(v => v == null ? '0.000 ms' : v.toString() + ' ms'); + * + * @param {Function} getter + * @return {this} + * @function get + * @static + * @api public + */ + +SchemaDouble.get = SchemaType.get; + +/*! + * ignore + */ + +SchemaDouble._defaultCaster = v => { + if (v != null) { + if (v._bsontype !== 'Double') { + throw new Error(); + } + } + + return v; +}; + +/** + * Get/set the function used to cast arbitrary values to IEEE 754-2008 floating points + * + * #### Example: + * + * // Make Mongoose cast any NaNs to 0 + * const defaultCast = mongoose.Schema.Types.Double.cast(); + * mongoose.Schema.Types.Double.cast(v => { + * if (isNaN(v)) { + * return 0; + * } + * return defaultCast(v); + * }); + * + * // Or disable casting for Doubles entirely (only JS numbers are permitted) + * mongoose.Schema.Double.cast(false); + * + * + * @param {Function} caster + * @return {Function} + * @function get + * @static + * @api public + */ + +SchemaDouble.cast = function cast(caster) { + if (arguments.length === 0) { + return this._cast; + } + if (caster === false) { + caster = this._defaultCaster; + } + + this._cast = caster; + + return this._cast; +}; + + +/*! + * ignore + */ + +SchemaDouble._checkRequired = v => v != null; +/** + * Override the function the required validator uses to check whether a value + * passes the `required` check. + * + * @param {Function} fn + * @return {Function} + * @function checkRequired + * @static + * @api public + */ + +SchemaDouble.checkRequired = SchemaType.checkRequired; + +/** + * Check if the given value satisfies a required validator. + * + * @param {Any} value + * @return {Boolean} + * @api public + */ + +SchemaDouble.prototype.checkRequired = function(value) { + return this.constructor._checkRequired(value); +}; + +/** + * Casts to Double + * + * @param {Object} value + * @param {Object} model this value is optional + * @api private + */ + +SchemaDouble.prototype.cast = function(value) { + let castDouble; + if (typeof this._castFunction === 'function') { + castDouble = this._castFunction; + } else if (typeof this.constructor.cast === 'function') { + castDouble = this.constructor.cast(); + } else { + castDouble = SchemaDouble.cast(); + } + + try { + return castDouble(value); + } catch (error) { + throw new CastError('Double', value, this.path, error, this); + } +}; + +/*! + * ignore + */ + +function handleSingle(val) { + return this.cast(val); +} + +SchemaDouble.prototype.$conditionalHandlers = { + ...SchemaType.prototype.$conditionalHandlers, + $gt: handleSingle, + $gte: handleSingle, + $lt: handleSingle, + $lte: handleSingle +}; + + +/*! + * Module exports. + */ + +module.exports = SchemaDouble; diff --git a/lib/schema/index.js b/lib/schema/index.js index 0caf091adf2..c31bcf6e046 100644 --- a/lib/schema/index.js +++ b/lib/schema/index.js @@ -19,6 +19,7 @@ exports.ObjectId = require('./objectId'); exports.String = require('./string'); exports.Subdocument = require('./subdocument'); exports.UUID = require('./uuid'); +exports.Double = require('./double'); // alias diff --git a/test/double.test.js b/test/double.test.js new file mode 100644 index 00000000000..6bf7e6c59e7 --- /dev/null +++ b/test/double.test.js @@ -0,0 +1,432 @@ +'use strict'; + +const assert = require('assert'); +const start = require('./common'); +const BSON = require('bson'); + +const mongoose = start.mongoose; +const Schema = mongoose.Schema; + + +describe('Double', function() { + beforeEach(() => mongoose.deleteModel(/Test/)); + + it('is a valid schema type', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: 13 + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(13)); + assert.equal(typeof doc.myDouble, 'object'); + }); + + describe('supports the required property', function() { + it('when value is null', async function() { + const schema = new Schema({ + Double: { + type: Schema.Types.Double, + required: true + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + double: null + }); + + const err = await doc.validate().then(() => null, err => err); + assert.ok(err); + assert.ok(err.errors['Double']); + assert.equal(err.errors['Double'].name, 'ValidatorError'); + assert.equal( + err.errors['Double'].message, + 'Path `Double` is required.' + ); + }); + it('when value is non-null', async function() { + const schema = new Schema({ + Double: { + type: Schema.Types.Double, + required: true + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + double: 3 + }); + + const err = await doc.validate().then(() => null, err => err); + assert.ok(err); + assert.ok(err.errors['Double']); + assert.equal(err.errors['Double'].name, 'ValidatorError'); + assert.equal( + err.errors['Double'].message, + 'Path `Double` is required.' + ); + }); + }); + + describe('special inputs', function() { + it('supports undefined as input', function() { + const schema = new Schema({ + myDouble: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: undefined + }); + assert.deepStrictEqual(doc.myDouble, undefined); + }); + + it('supports null as input', function() { + const schema = new Schema({ + myDouble: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: null + }); + assert.deepStrictEqual(doc.myDouble, null); + }); + }); + + describe('valid casts', function() { + it('casts from decimal string', function() { + const schema = new Schema({ + myDouble: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: '-42.008' + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(-42.008)); + }); + + it('casts from exponential string', function() { + const schema = new Schema({ + myDouble: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: '1.22008e45' + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(1.22008e45)); + }); + + it('casts from infinite string', function() { + const schema = new Schema({ + myDouble1: { + type: Schema.Types.Double + }, + myDouble2: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble1: 'Infinity', + myDouble2: '-Infinity' + }); + assert.deepStrictEqual(doc.myDouble1, new BSON.Double(Infinity)); + assert.deepStrictEqual(doc.myDouble2, new BSON.Double(-Infinity)); + }); + + it('casts from NaN string', function() { + const schema = new Schema({ + myDouble: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: 'NaN' + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double('NaN')); + }); + + it('casts from number', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: 988 + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(988)); + }); + + it('casts from bigint', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: -997n + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(-997)); + }); + + it('casts from BSON.Long', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: BSON.Long.fromNumber(-997987) + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(-997987)); + }); + + it('casts from BSON.Double', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: new BSON.Double(-997983.33) + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(-997983.33)); + }); + + it('casts boolean true to 1', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: true + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(1)); + }); + + it('casts boolean false to 0', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: false + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(0)); + }); + + it('casts empty string to null', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: '' + }); + assert.deepStrictEqual(doc.myDouble, null); + }); + + it('supports valueOf() function ', function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + const Test = mongoose.model('Test', schema); + + const doc = new Test({ + myDouble: { a: 'random', b: { c: 'whatever' }, valueOf: () => 83.008 } + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(83.008)); + }); + }); + + describe('cast errors', () => { + let Test; + + beforeEach(function() { + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + Test = mongoose.model('Test', schema); + }); + + describe('when a non-numeric string is provided to an Double field', () => { + it('throws a CastError upon validation', async() => { + const doc = new Test({ + myDouble: 'helloworld' + }); + + assert.deepStrictEqual(doc.myDouble, undefined); + const err = await doc.validate().catch(e => e); + assert.ok(err); + assert.ok(err.errors['myDouble']); + assert.equal(err.errors['myDouble'].name, 'CastError'); + assert.equal( + err.errors['myDouble'].message, + 'Cast to Double failed for value "helloworld" (type string) at path "myDouble"' + ); + }); + }); + }); + + describe('custom casters', () => { + const defaultCast = mongoose.Schema.Types.Double.cast(); + + afterEach(() => { + mongoose.Schema.Types.Double.cast(defaultCast); + }); + + it('supports cast disabled', async() => { + mongoose.Schema.Types.Double.cast(false); + const schema = new Schema({ + myDouble1: { + type: Schema.Types.Double + }, + myDouble2: { + type: Schema.Types.Double + } + }); + const Test = mongoose.model('Test', schema); + const doc = new Test({ + myDouble1: '52', + myDouble2: new BSON.Double(52) + }); + assert.deepStrictEqual(doc.myDouble1, undefined); + assert.deepStrictEqual(doc.myDouble2, new BSON.Double(52)); + + const err = await doc.validate().catch(e => e); + assert.ok(err); + assert.ok(err.errors['myDouble1']); + }); + + it('supports custom cast', () => { + mongoose.Schema.Types.Double.cast(v => { + if (isNaN(v)) { + return new BSON.Double(2); + } + return defaultCast(v); + }); + const schema = new Schema({ + myDouble: { + type: Schema.Types.Double + } + }); + + const Test = mongoose.model('Test', schema); + const doc = new Test({ + myDouble: NaN + }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(2)); + }); + }); + + describe('mongoDB integration', function() { + let db; + let Test; + + before(async function() { + db = await start(); + + const schema = new Schema({ + myDouble: Schema.Types.Double + }); + db.deleteModel(/Test/); + Test = db.model('Test', schema); + }); + + after(async function() { + await db.close(); + }); + + beforeEach(async() => { + await Test.deleteMany({}); + }); + + describe('$type compatibility', function() { + it('is queryable as a JS number in MongoDB', async function() { + await Test.create({ myDouble: '42.04' }); + const doc = await Test.findOne({ myDouble: { $type: 'number' } }); + assert.ok(doc); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(42.04)); + }); + + it('is NOT queryable as a BSON Integer in MongoDB if the value is NOT integer', async function() { + await Test.create({ myDouble: '42.04' }); + const doc = await Test.findOne({ myDouble: { $type: 'int' } }); + assert.deepStrictEqual(doc, null); + }); + + it('is queryable as a BSON Double in MongoDB when a non-integer is provided', async function() { + await Test.create({ myDouble: '42.04' }); + const doc = await Test.findOne({ myDouble: { $type: 'double' } }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(42.04)); + }); + + it('is queryable as a BSON Double in MongoDB when an integer is provided', async function() { + await Test.create({ myDouble: '42' }); + const doc = await Test.findOne({ myDouble: { $type: 'double' } }); + assert.deepStrictEqual(doc.myDouble, new BSON.Double(42)); + }); + }); + + it('can query with comparison operators', async function() { + await Test.create([ + { myDouble: 1.2 }, + { myDouble: 1.709 }, + { myDouble: 1.710 }, + { myDouble: 1.8 } + ]); + + let docs = await Test.find({ myDouble: { $gte: 1.710 } }).sort({ myDouble: 1 }); + assert.equal(docs.length, 2); + assert.deepStrictEqual(docs.map(doc => doc.myDouble), [new BSON.Double(1.710), new BSON.Double(1.8)]); + + docs = await Test.find({ myDouble: { $lt: 1.710 } }).sort({ myDouble: -1 }); + assert.equal(docs.length, 2); + assert.deepStrictEqual(docs.map(doc => doc.myDouble), [new BSON.Double(1.709), new BSON.Double(1.2)]); + }); + + it('supports populate()', async function() { + const parentSchema = new Schema({ + child: { + type: Schema.Types.Double, + ref: 'Child' + } + }); + const childSchema = new Schema({ + _id: Schema.Types.Double, + name: String + }); + const Parent = db.model('Parent', parentSchema); + const Child = db.model('Child', childSchema); + + const { _id } = await Parent.create({ child: 42 }); + await Child.create({ _id: 42, name: 'test-Double-populate' }); + + const doc = await Parent.findById(_id).populate('child'); + assert.ok(doc); + assert.equal(doc.child.name, 'test-Double-populate'); + assert.equal(doc.child._id, 42); + }); + }); +}); diff --git a/test/helpers/isBsonType.test.js b/test/helpers/isBsonType.test.js index 448aaf72db4..c43d6edc4e3 100644 --- a/test/helpers/isBsonType.test.js +++ b/test/helpers/isBsonType.test.js @@ -5,6 +5,7 @@ const isBsonType = require('../../lib/helpers/isBsonType'); const Decimal128 = require('mongodb').Decimal128; const ObjectId = require('mongodb').ObjectId; +const Double = require('mongodb').Double; describe('isBsonType', () => { it('true for any object with _bsontype property equal typename', () => { @@ -30,4 +31,8 @@ describe('isBsonType', () => { it('true for ObjectId', () => { assert.ok(isBsonType(new ObjectId(), 'ObjectId')); }); + + it('true for Double', () => { + assert.ok(isBsonType(new Double(), 'Double')); + }); }); diff --git a/test/types/schemaTypeOptions.test.ts b/test/types/schemaTypeOptions.test.ts index 5fc0e23a21d..2c865565386 100644 --- a/test/types/schemaTypeOptions.test.ts +++ b/test/types/schemaTypeOptions.test.ts @@ -69,6 +69,7 @@ function defaultOptions() { expectType>(new Schema.Types.Mixed('none').defaultOptions); expectType>(new Schema.Types.Number('none').defaultOptions); expectType>(new Schema.Types.ObjectId('none').defaultOptions); + expectType>(new Schema.Types.Double('none').defaultOptions); expectType>(new Schema.Types.Subdocument('none').defaultOptions); expectType>(new Schema.Types.UUID('none').defaultOptions); } diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index d73ad4cb81c..00df47b7bf8 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -229,17 +229,19 @@ type IsSchemaTypeFromBuiltinClass = T extends (typeof String) ? true : T extends (typeof Schema.Types.Buffer) ? true - : T extends Types.ObjectId + : T extends (typeof Schema.Types.Double) ? true - : T extends Types.Decimal128 + : T extends Types.ObjectId ? true - : T extends Buffer + : T extends Types.Decimal128 ? true - : T extends NativeDate + : T extends Buffer ? true - : T extends (typeof Schema.Types.Mixed) + : T extends NativeDate ? true - : IfEquals; + : T extends (typeof Schema.Types.Mixed) + ? true + : IfEquals; /** * @summary Resolve path type by returning the corresponding type. diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index aff686e1ec9..df82f6f6677 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -25,6 +25,13 @@ declare module 'mongoose' { */ type Number = Schema.Types.Number; + + /** + * The Mongoose Double [SchemaType](/docs/schematypes.html). Used for + * declaring paths in your schema that Mongoose should cast to doubles (IEEE 754-2008)/ + */ + type Double = Schema.Types.Double; + /** * The Mongoose ObjectId [SchemaType](/docs/schematypes.html). Used for * declaring paths in your schema that should be @@ -439,6 +446,14 @@ declare module 'mongoose' { defaultOptions: Record; } + class Double extends SchemaType { + /** This schema type's name, to defend against minifiers that mangle function names. */ + static schemaName: 'Double'; + + /** Default options for this SchemaType */ + defaultOptions: Record; + } + class ObjectId extends SchemaType { /** This schema type's name, to defend against minifiers that mangle function names. */ static schemaName: 'ObjectId';