You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
4.8 KiB

  1. /*!
  2. * Module requirements.
  3. */
  4. var SchemaType = require('../schematype')
  5. , CastError = SchemaType.CastError
  6. , utils = require('../utils')
  7. , Document
  8. /**
  9. * Number SchemaType constructor.
  10. *
  11. * @param {String} key
  12. * @param {Object} options
  13. * @inherits SchemaType
  14. * @api private
  15. */
  16. function SchemaNumber (key, options) {
  17. SchemaType.call(this, key, options, 'Number');
  18. };
  19. /*!
  20. * Inherits from SchemaType.
  21. */
  22. SchemaNumber.prototype.__proto__ = SchemaType.prototype;
  23. /**
  24. * Required validator for number
  25. *
  26. * @api private
  27. */
  28. SchemaNumber.prototype.checkRequired = function checkRequired (value, doc) {
  29. if (SchemaType._isRef(this, value, doc, true)) {
  30. return null != value;
  31. } else {
  32. return typeof value == 'number' || value instanceof Number;
  33. }
  34. };
  35. /**
  36. * Sets a minimum number validator.
  37. *
  38. * ####Example:
  39. *
  40. * var s = new Schema({ n: { type: Number, min: 10 })
  41. * var M = db.model('M', s)
  42. * var m = new M({ n: 9 })
  43. * m.save(function (err) {
  44. * console.error(err) // validator error
  45. * m.n = 10;
  46. * m.save() // success
  47. * })
  48. *
  49. * @param {Number} value minimum number
  50. * @return {SchemaType} this
  51. * @api public
  52. */
  53. SchemaNumber.prototype.min = function (value) {
  54. if (this.minValidator) {
  55. this.validators = this.validators.filter(function (v) {
  56. return 'min' != v[1];
  57. });
  58. }
  59. if (value != null) {
  60. this.validators.push([this.minValidator = function (v) {
  61. return v === null || v >= value;
  62. }, 'min']);
  63. }
  64. return this;
  65. };
  66. /**
  67. * Sets a maximum number validator.
  68. *
  69. * ####Example:
  70. *
  71. * var s = new Schema({ n: { type: Number, max: 10 })
  72. * var M = db.model('M', s)
  73. * var m = new M({ n: 11 })
  74. * m.save(function (err) {
  75. * console.error(err) // validator error
  76. * m.n = 10;
  77. * m.save() // success
  78. * })
  79. *
  80. * @param {Number} maximum number
  81. * @return {SchemaType} this
  82. * @api public
  83. */
  84. SchemaNumber.prototype.max = function (value) {
  85. if (this.maxValidator) {
  86. this.validators = this.validators.filter(function(v){
  87. return 'max' != v[1];
  88. });
  89. }
  90. if (value != null) {
  91. this.validators.push([this.maxValidator = function(v){
  92. return v === null || v <= value;
  93. }, 'max']);
  94. }
  95. return this;
  96. };
  97. /**
  98. * Casts to number
  99. *
  100. * @param {Object} value value to cast
  101. * @param {Document} doc document that triggers the casting
  102. * @param {Boolean} init
  103. * @api private
  104. */
  105. SchemaNumber.prototype.cast = function (value, doc, init) {
  106. if (SchemaType._isRef(this, value, doc, init)) {
  107. // wait! we may need to cast this to a document
  108. if (null == value) {
  109. return value;
  110. }
  111. // lazy load
  112. Document || (Document = require('./../document'));
  113. if (value instanceof Document) {
  114. value.$__.wasPopulated = true;
  115. return value;
  116. }
  117. // setting a populated path
  118. if ('number' == typeof value) {
  119. return value;
  120. } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
  121. throw new CastError('number', value, this.path);
  122. }
  123. // Handle the case where user directly sets a populated
  124. // path to a plain object; cast to the Model used in
  125. // the population query.
  126. var path = doc.$__fullPath(this.path);
  127. var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
  128. var pop = owner.populated(path, true);
  129. var ret = new pop.options.model(value);
  130. ret.$__.wasPopulated = true;
  131. return ret;
  132. }
  133. var val = value && value._id
  134. ? value._id // documents
  135. : value;
  136. if (!isNaN(val)){
  137. if (null === val) return val;
  138. if ('' === val) return null;
  139. if ('string' == typeof val) val = Number(val);
  140. if (val instanceof Number) return val
  141. if ('number' == typeof val) return val;
  142. if (val.toString && !Array.isArray(val) &&
  143. val.toString() == Number(val)) {
  144. return new Number(val)
  145. }
  146. }
  147. throw new CastError('number', value, this.path);
  148. };
  149. /*!
  150. * ignore
  151. */
  152. function handleSingle (val) {
  153. return this.cast(val)
  154. }
  155. function handleArray (val) {
  156. var self = this;
  157. return val.map(function (m) {
  158. return self.cast(m)
  159. });
  160. }
  161. SchemaNumber.prototype.$conditionalHandlers = {
  162. '$lt' : handleSingle
  163. , '$lte': handleSingle
  164. , '$gt' : handleSingle
  165. , '$gte': handleSingle
  166. , '$ne' : handleSingle
  167. , '$in' : handleArray
  168. , '$nin': handleArray
  169. , '$mod': handleArray
  170. , '$all': handleArray
  171. };
  172. /**
  173. * Casts contents for queries.
  174. *
  175. * @param {String} $conditional
  176. * @param {any} [value]
  177. * @api private
  178. */
  179. SchemaNumber.prototype.castForQuery = function ($conditional, val) {
  180. var handler;
  181. if (arguments.length === 2) {
  182. handler = this.$conditionalHandlers[$conditional];
  183. if (!handler)
  184. throw new Error("Can't use " + $conditional + " with Number.");
  185. return handler.call(this, val);
  186. } else {
  187. val = this.cast($conditional);
  188. return val == null ? val : val
  189. }
  190. };
  191. /*!
  192. * Module exports.
  193. */
  194. module.exports = SchemaNumber;