thoughts/node_modules/mongoose/lib/schema/number.js
node_modules/mongoose/lib/schema/number.jsRaw
1/*!
2 * Module requirements.
3 */
4
5var SchemaType = require('../schematype');
6var CastError = SchemaType.CastError;
7var handleBitwiseOperator = require('./operators/bitwise');
8var MongooseError = require('../error');
9var utils = require('../utils');
10var Document;
11
12/**
13 * Number SchemaType constructor.
14 *
15 * @param {String} key
16 * @param {Object} options
17 * @inherits SchemaType
18 * @api public
19 */
20
21function SchemaNumber(key, options) {
22 SchemaType.call(this, key, options, 'Number');
23}
24
25/**
26 * This schema type's name, to defend against minifiers that mangle
27 * function names.
28 *
29 * @api public
30 */
31SchemaNumber.schemaName = 'Number';
32
33/*!
34 * Inherits from SchemaType.
35 */
36SchemaNumber.prototype = Object.create(SchemaType.prototype);
37SchemaNumber.prototype.constructor = SchemaNumber;
38
39/**
40 * Check if the given value satisfies a required validator.
41 *
42 * @param {Any} value
43 * @param {Document} doc
44 * @return {Boolean}
45 * @api public
46 */
47
48SchemaNumber.prototype.checkRequired = function checkRequired(value, doc) {
49 if (SchemaType._isRef(this, value, doc, true)) {
50 return !!value;
51 }
52 return typeof value === 'number' || value instanceof Number;
53};
54
55/**
56 * Sets a minimum number validator.
57 *
58 * ####Example:
59 *
60 * var s = new Schema({ n: { type: Number, min: 10 })
61 * var M = db.model('M', s)
62 * var m = new M({ n: 9 })
63 * m.save(function (err) {
64 * console.error(err) // validator error
65 * m.n = 10;
66 * m.save() // success
67 * })
68 *
69 * // custom error messages
70 * // We can also use the special {MIN} token which will be replaced with the invalid value
71 * var min = [10, 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).'];
72 * var schema = new Schema({ n: { type: Number, min: min })
73 * var M = mongoose.model('Measurement', schema);
74 * var s= new M({ n: 4 });
75 * s.validate(function (err) {
76 * console.log(String(err)) // ValidationError: The value of path `n` (4) is beneath the limit (10).
77 * })
78 *
79 * @param {Number} value minimum number
80 * @param {String} [message] optional custom error message
81 * @return {SchemaType} this
82 * @see Customized Error Messages #error_messages_MongooseError-messages
83 * @api public
84 */
85
86SchemaNumber.prototype.min = function(value, message) {
87 if (this.minValidator) {
88 this.validators = this.validators.filter(function(v) {
89 return v.validator !== this.minValidator;
90 }, this);
91 }
92
93 if (value !== null && value !== undefined) {
94 var msg = message || MongooseError.messages.Number.min;
95 msg = msg.replace(/{MIN}/, value);
96 this.validators.push({
97 validator: this.minValidator = function(v) {
98 return v == null || v >= value;
99 },
100 message: msg,
101 type: 'min',
102 min: value
103 });
104 }
105
106 return this;
107};
108
109/**
110 * Sets a maximum number validator.
111 *
112 * ####Example:
113 *
114 * var s = new Schema({ n: { type: Number, max: 10 })
115 * var M = db.model('M', s)
116 * var m = new M({ n: 11 })
117 * m.save(function (err) {
118 * console.error(err) // validator error
119 * m.n = 10;
120 * m.save() // success
121 * })
122 *
123 * // custom error messages
124 * // We can also use the special {MAX} token which will be replaced with the invalid value
125 * var max = [10, 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).'];
126 * var schema = new Schema({ n: { type: Number, max: max })
127 * var M = mongoose.model('Measurement', schema);
128 * var s= new M({ n: 4 });
129 * s.validate(function (err) {
130 * console.log(String(err)) // ValidationError: The value of path `n` (4) exceeds the limit (10).
131 * })
132 *
133 * @param {Number} maximum number
134 * @param {String} [message] optional custom error message
135 * @return {SchemaType} this
136 * @see Customized Error Messages #error_messages_MongooseError-messages
137 * @api public
138 */
139
140SchemaNumber.prototype.max = function(value, message) {
141 if (this.maxValidator) {
142 this.validators = this.validators.filter(function(v) {
143 return v.validator !== this.maxValidator;
144 }, this);
145 }
146
147 if (value !== null && value !== undefined) {
148 var msg = message || MongooseError.messages.Number.max;
149 msg = msg.replace(/{MAX}/, value);
150 this.validators.push({
151 validator: this.maxValidator = function(v) {
152 return v == null || v <= value;
153 },
154 message: msg,
155 type: 'max',
156 max: value
157 });
158 }
159
160 return this;
161};
162
163/**
164 * Casts to number
165 *
166 * @param {Object} value value to cast
167 * @param {Document} doc document that triggers the casting
168 * @param {Boolean} init
169 * @api private
170 */
171
172SchemaNumber.prototype.cast = function(value, doc, init) {
173 if (SchemaType._isRef(this, value, doc, init)) {
174 // wait! we may need to cast this to a document
175
176 if (value === null || value === undefined) {
177 return value;
178 }
179
180 // lazy load
181 Document || (Document = require('./../document'));
182
183 if (value instanceof Document) {
184 value.$__.wasPopulated = true;
185 return value;
186 }
187
188 // setting a populated path
189 if (typeof value === 'number') {
190 return value;
191 } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
192 throw new CastError('number', value, this.path);
193 }
194
195 // Handle the case where user directly sets a populated
196 // path to a plain object; cast to the Model used in
197 // the population query.
198 var path = doc.$__fullPath(this.path);
199 var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
200 var pop = owner.populated(path, true);
201 var ret = new pop.options.model(value);
202 ret.$__.wasPopulated = true;
203 return ret;
204 }
205
206 var val = value && value._id
207 ? value._id // documents
208 : value;
209
210 if (!isNaN(val)) {
211 if (val === null) {
212 return val;
213 }
214 if (val === '') {
215 return null;
216 }
217 if (typeof val === 'string' || typeof val === 'boolean') {
218 val = Number(val);
219 }
220 if (val instanceof Number) {
221 return val;
222 }
223 if (typeof val === 'number') {
224 return val;
225 }
226 if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) {
227 return new Number(val);
228 }
229 }
230
231 throw new CastError('number', value, this.path);
232};
233
234/*!
235 * ignore
236 */
237
238function handleSingle(val) {
239 return this.cast(val);
240}
241
242function handleArray(val) {
243 var _this = this;
244 if (!Array.isArray(val)) {
245 return [this.cast(val)];
246 }
247 return val.map(function(m) {
248 return _this.cast(m);
249 });
250}
251
252SchemaNumber.prototype.$conditionalHandlers =
253 utils.options(SchemaType.prototype.$conditionalHandlers, {
254 $bitsAllClear: handleBitwiseOperator,
255 $bitsAnyClear: handleBitwiseOperator,
256 $bitsAllSet: handleBitwiseOperator,
257 $bitsAnySet: handleBitwiseOperator,
258 $gt: handleSingle,
259 $gte: handleSingle,
260 $lt: handleSingle,
261 $lte: handleSingle,
262 $mod: handleArray
263 });
264
265/**
266 * Casts contents for queries.
267 *
268 * @param {String} $conditional
269 * @param {any} [value]
270 * @api private
271 */
272
273SchemaNumber.prototype.castForQuery = function($conditional, val) {
274 var handler;
275 if (arguments.length === 2) {
276 handler = this.$conditionalHandlers[$conditional];
277 if (!handler) {
278 throw new Error('Can\'t use ' + $conditional + ' with Number.');
279 }
280 return handler.call(this, val);
281 }
282 val = this.cast($conditional);
283 return val;
284};
285
286/*!
287 * Module exports.
288 */
289
290module.exports = SchemaNumber;