Skip to content

Commit 4492a3e

Browse files
requested changes 2
1 parent 538629c commit 4492a3e

File tree

6 files changed

+354
-67
lines changed

6 files changed

+354
-67
lines changed

docs/schematypes.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,29 @@ const student = new Student({ id: 1339 });
664664
typeof student.id; // 'number'
665665
```
666666

667+
There are several types of values that will be successfully cast to a Number.
668+
669+
```javascript
670+
new Student({ id: '15' }).id; // 15 as a Int32
671+
new Student({ id: true }).id; // 1 as a Int32
672+
new Student({ id: false }).id; // 0 as a Int32
673+
new Student({ id: { valueOf: () => 83 } }).id; // 83 as a Int32
674+
new Student({ id: '' }).id; // null as a Int32
675+
```
676+
677+
If you pass an object with a `valueOf()` function that returns a Number, Mongoose will
678+
call it and assign the returned value to the path.
679+
680+
The values `null` and `undefined` are not cast.
681+
682+
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:
683+
- NaN
684+
- strings that cast to NaN
685+
- objects that don't have a `valueOf()` function
686+
- a decimal that must be rounded to be an integer
687+
- an input that represents a value beyond the bounds of an 32-bit integer
688+
689+
667690
## Getters {#getters}
668691

669692
Getters are like virtuals for paths defined in your schema. For example,

lib/cast/int32.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const assert = require('assert');
4+
const BSON = require('bson');
45

56
/**
67
* Given a value, cast it to a Int32, or throw an `Error` if the value
@@ -20,16 +21,23 @@ module.exports = function castInt32(val) {
2021
return null;
2122
}
2223

23-
if (typeof val === 'string' || typeof val === 'number') {
24-
25-
const INT32_MAX = 0x7FFFFFFF;
26-
const INT32_MIN = -0x80000000;
24+
let coercedVal;
25+
if (val instanceof BSON.Int32 || val instanceof BSON.Double) {
26+
coercedVal = val.value;
27+
} else if (val instanceof BSON.Long) {
28+
coercedVal = val.toNumber();
29+
} else {
30+
coercedVal = Number(val);
31+
}
2732

28-
const _val = Number(val);
33+
const INT32_MAX = 0x7FFFFFFF;
34+
const INT32_MIN = -0x80000000;
2935

30-
if (_val === (_val | 0) && _val > INT32_MIN && _val < INT32_MAX) {
31-
return _val;
32-
}
33-
assert.ok(false);
36+
if (coercedVal === (coercedVal | 0) &&
37+
coercedVal >= INT32_MIN &&
38+
coercedVal <= INT32_MAX
39+
) {
40+
return coercedVal;
3441
}
42+
assert.ok(false);
3543
};

lib/schema/bigint.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ SchemaBigInt.get = SchemaType.get;
8686
* #### Example:
8787
*
8888
* // Make Mongoose cast empty string '' to false.
89-
* const original = mongoose.Schema.BigInt.cast();
89+
* const original = mongoose.Schema.Types.BigInt.cast();
9090
* mongoose.Schema.BigInt.cast(v => {
9191
* if (v === '') {
9292
* return false;

lib/schema/int32.js

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
const CastError = require('../error/cast');
88
const SchemaType = require('../schemaType');
99
const castInt32 = require('../cast/int32');
10-
const isBsonType = require('../helpers/isBsonType');
1110

1211
/**
1312
* Int32 SchemaType constructor.
@@ -81,23 +80,44 @@ SchemaInt32.setters = [];
8180

8281
SchemaInt32.get = SchemaType.get;
8382

83+
/*!
84+
* ignore
85+
*/
86+
87+
SchemaInt32._defaultCaster = v => {
88+
const INT32_MAX = 0x7FFFFFFF;
89+
const INT32_MIN = -0x80000000;
90+
91+
if (v != null) {
92+
if (typeof v !== 'number') {
93+
throw new Error();
94+
}
95+
if (v < INT32_MIN || v > INT32_MAX) {
96+
throw new Error();
97+
}
98+
}
99+
100+
return v;
101+
};
102+
84103
/**
85104
* Get/set the function used to cast arbitrary values to 32-bit integers
86105
*
87106
* #### Example:
88107
*
89108
* // Make Mongoose cast NaN to 0
90-
* const defaultCast = mongoose.Schema.Int32.cast();
91-
* mongoose.Schema.Int32.cast(v => {
109+
* const defaultCast = mongoose.Schema.Types.Int32.cast();
110+
* mongoose.Schema.Types.Int32.cast(v => {
92111
* if (isNaN(v)) {
93112
* return 0;
94113
* }
95114
* return defaultCast(v);
96115
* });
97116
*
98-
* // Or disable casting for Int32s entirely
117+
* // Or disable casting for Int32s entirely (only JS numbers within 32-bit integer bounds and null-ish values are permitted)
99118
* mongoose.Schema.Int32.cast(false);
100119
*
120+
*
101121
* @param {Function} caster
102122
* @return {Function}
103123
* @function get
@@ -112,16 +132,18 @@ SchemaInt32.cast = function cast(caster) {
112132
if (caster === false) {
113133
caster = this._defaultCaster;
114134
}
135+
115136
this._cast = caster;
116137

117138
return this._cast;
118139
};
119140

141+
120142
/*!
121143
* ignore
122144
*/
123145

124-
SchemaInt32._checkRequired = v => v != null && isBsonType(v, 'Int32');
146+
SchemaInt32._checkRequired = v => v != null;
125147
/**
126148
* Override the function the required validator uses to check whether a value
127149
* passes the `required` check.
@@ -157,9 +179,6 @@ SchemaInt32.prototype.checkRequired = function(value) {
157179

158180
SchemaInt32.prototype.cast = function(value) {
159181
let castInt32;
160-
if (isBsonType(value, 'Int32')) {
161-
return value;
162-
}
163182
if (typeof this._castFunction === 'function') {
164183
castInt32 = this._castFunction;
165184
} else if (typeof this.constructor.cast === 'function') {
@@ -225,24 +244,6 @@ SchemaInt32.prototype.castForQuery = function($conditional, val, context) {
225244
}
226245
};
227246

228-
/**
229-
*
230-
* @api private
231-
*/
232-
233-
SchemaInt32.prototype._castNullish = function _castNullish(v) {
234-
if (typeof v === 'undefined') {
235-
return v;
236-
}
237-
const castInt32 = typeof this.constructor.cast === 'function' ?
238-
this.constructor.cast() :
239-
SchemaInt32.cast();
240-
if (castInt32 == null) {
241-
return v;
242-
}
243-
return v;
244-
};
245-
246247
/*!
247248
* Module exports.
248249
*/

lib/utils.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,6 @@ exports.deepEqual = function deepEqual(a, b) {
9393
return a.toString() === b.toString();
9494
}
9595

96-
if (isBsonType(a, 'Int32') && isBsonType(b, 'In32')) {
97-
return a.value === b.value();
98-
}
99-
10096
if (a instanceof RegExp && b instanceof RegExp) {
10197
return a.source === b.source &&
10298
a.ignoreCase === b.ignoreCase &&

0 commit comments

Comments
 (0)