date.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*!
  2. * Module requirements.
  3. */
  4. var errorMessages = require('../error').messages
  5. var utils = require('../utils');
  6. var SchemaType = require('../schematype');
  7. var CastError = SchemaType.CastError;
  8. /**
  9. * Date SchemaType constructor.
  10. *
  11. * @param {String} key
  12. * @param {Object} options
  13. * @inherits SchemaType
  14. * @api private
  15. */
  16. function SchemaDate (key, options) {
  17. SchemaType.call(this, key, options, 'Date');
  18. }
  19. /**
  20. * This schema type's name, to defend against minifiers that mangle
  21. * function names.
  22. *
  23. * @api private
  24. */
  25. SchemaDate.schemaName = 'Date';
  26. /*!
  27. * Inherits from SchemaType.
  28. */
  29. SchemaDate.prototype = Object.create( SchemaType.prototype );
  30. SchemaDate.prototype.constructor = SchemaDate;
  31. /**
  32. * Declares a TTL index (rounded to the nearest second) for _Date_ types only.
  33. *
  34. * This sets the `expiresAfterSeconds` index option available in MongoDB >= 2.1.2.
  35. * This index type is only compatible with Date types.
  36. *
  37. * ####Example:
  38. *
  39. * // expire in 24 hours
  40. * new Schema({ createdAt: { type: Date, expires: 60*60*24 }});
  41. *
  42. * `expires` utilizes the `ms` module from [guille](https://github.com/guille/) allowing us to use a friendlier syntax:
  43. *
  44. * ####Example:
  45. *
  46. * // expire in 24 hours
  47. * new Schema({ createdAt: { type: Date, expires: '24h' }});
  48. *
  49. * // expire in 1.5 hours
  50. * new Schema({ createdAt: { type: Date, expires: '1.5h' }});
  51. *
  52. * // expire in 7 days
  53. * var schema = new Schema({ createdAt: Date });
  54. * schema.path('createdAt').expires('7d');
  55. *
  56. * @param {Number|String} when
  57. * @added 3.0.0
  58. * @return {SchemaType} this
  59. * @api public
  60. */
  61. SchemaDate.prototype.expires = function (when) {
  62. if (!this._index || 'Object' !== this._index.constructor.name) {
  63. this._index = {};
  64. }
  65. this._index.expires = when;
  66. utils.expires(this._index);
  67. return this;
  68. };
  69. /**
  70. * Required validator for date
  71. *
  72. * @api private
  73. */
  74. SchemaDate.prototype.checkRequired = function (value) {
  75. return value instanceof Date;
  76. };
  77. /**
  78. * Sets a minimum date validator.
  79. *
  80. * ####Example:
  81. *
  82. * var s = new Schema({ d: { type: Date, min: Date('1970-01-01') })
  83. * var M = db.model('M', s)
  84. * var m = new M({ d: Date('1969-12-31') })
  85. * m.save(function (err) {
  86. * console.error(err) // validator error
  87. * m.d = Date('2014-12-08');
  88. * m.save() // success
  89. * })
  90. *
  91. * // custom error messages
  92. * // We can also use the special {MIN} token which will be replaced with the invalid value
  93. * var min = [Date('1970-01-01'), 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).'];
  94. * var schema = new Schema({ d: { type: Date, min: min })
  95. * var M = mongoose.model('M', schema);
  96. * var s= new M({ d: Date('1969-12-31') });
  97. * s.validate(function (err) {
  98. * console.log(String(err)) // ValidationError: The value of path `d` (1969-12-31) is before the limit (1970-01-01).
  99. * })
  100. *
  101. * @param {Date} value minimum date
  102. * @param {String} [message] optional custom error message
  103. * @return {SchemaType} this
  104. * @see Customized Error Messages #error_messages_MongooseError-messages
  105. * @api public
  106. */
  107. SchemaDate.prototype.min = function (value, message) {
  108. if (this.minValidator) {
  109. this.validators = this.validators.filter(function (v) {
  110. return v.validator != this.minValidator;
  111. }, this);
  112. }
  113. if (value) {
  114. var msg = message || errorMessages.Date.min;
  115. msg = msg.replace(/{MIN}/, (value === Date.now ? 'Date.now()' : this.cast(value).toString()));
  116. var self = this;
  117. this.validators.push({
  118. validator: this.minValidator = function (val) {
  119. var min = (value === Date.now ? value() : self.cast(value));
  120. return val === null || val.valueOf() >= min.valueOf();
  121. },
  122. message: msg,
  123. type: 'min'
  124. });
  125. }
  126. return this;
  127. };
  128. /**
  129. * Sets a maximum date validator.
  130. *
  131. * ####Example:
  132. *
  133. * var s = new Schema({ d: { type: Date, max: Date('2014-01-01') })
  134. * var M = db.model('M', s)
  135. * var m = new M({ d: Date('2014-12-08') })
  136. * m.save(function (err) {
  137. * console.error(err) // validator error
  138. * m.d = Date('2013-12-31');
  139. * m.save() // success
  140. * })
  141. *
  142. * // custom error messages
  143. * // We can also use the special {MAX} token which will be replaced with the invalid value
  144. * var max = [Date('2014-01-01'), 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).'];
  145. * var schema = new Schema({ d: { type: Date, max: max })
  146. * var M = mongoose.model('M', schema);
  147. * var s= new M({ d: Date('2014-12-08') });
  148. * s.validate(function (err) {
  149. * console.log(String(err)) // ValidationError: The value of path `d` (2014-12-08) exceeds the limit (2014-01-01).
  150. * })
  151. *
  152. * @param {Date} maximum date
  153. * @param {String} [message] optional custom error message
  154. * @return {SchemaType} this
  155. * @see Customized Error Messages #error_messages_MongooseError-messages
  156. * @api public
  157. */
  158. SchemaDate.prototype.max = function (value, message) {
  159. if (this.maxValidator) {
  160. this.validators = this.validators.filter(function(v){
  161. return v.validator != this.maxValidator;
  162. }, this);
  163. }
  164. if (value) {
  165. var msg = message || errorMessages.Date.max;
  166. msg = msg.replace(/{MAX}/, (value === Date.now ? 'Date.now()' : this.cast(value).toString()));
  167. var self = this;
  168. this.validators.push({
  169. validator: this.maxValidator = function(val) {
  170. var max = (value === Date.now ? value() : self.cast(value));
  171. return val === null || val.valueOf() <= max.valueOf();
  172. },
  173. message: msg,
  174. type: 'max'
  175. });
  176. }
  177. return this;
  178. };
  179. /**
  180. * Casts to date
  181. *
  182. * @param {Object} value to cast
  183. * @api private
  184. */
  185. SchemaDate.prototype.cast = function (value) {
  186. // If null or undefined
  187. if (value == null || value === '')
  188. return value;
  189. if (value instanceof Date)
  190. return value;
  191. var date;
  192. // support for timestamps
  193. if (typeof value !== 'undefined') {
  194. if (value instanceof Number || 'number' == typeof value
  195. || String(value) == Number(value)) {
  196. date = new Date(Number(value));
  197. } else if (value.toString) {
  198. // support for date strings
  199. date = new Date(value.toString());
  200. }
  201. if (date.toString() != 'Invalid Date') {
  202. return date;
  203. }
  204. }
  205. throw new CastError('date', value, this.path);
  206. };
  207. /*!
  208. * Date Query casting.
  209. *
  210. * @api private
  211. */
  212. function handleSingle (val) {
  213. return this.cast(val);
  214. }
  215. function handleArray (val) {
  216. var self = this;
  217. return val.map( function (m) {
  218. return self.cast(m);
  219. });
  220. }
  221. SchemaDate.prototype.$conditionalHandlers =
  222. utils.options(SchemaType.prototype.$conditionalHandlers, {
  223. '$all': handleArray,
  224. '$gt': handleSingle,
  225. '$gte': handleSingle,
  226. '$in': handleArray,
  227. '$lt': handleSingle,
  228. '$lte': handleSingle,
  229. '$ne': handleSingle,
  230. '$nin': handleArray
  231. });
  232. /**
  233. * Casts contents for queries.
  234. *
  235. * @param {String} $conditional
  236. * @param {any} [value]
  237. * @api private
  238. */
  239. SchemaDate.prototype.castForQuery = function ($conditional, val) {
  240. var handler;
  241. if (2 !== arguments.length) {
  242. return this.cast($conditional);
  243. }
  244. handler = this.$conditionalHandlers[$conditional];
  245. if (!handler) {
  246. throw new Error("Can't use " + $conditional + " with Date.");
  247. }
  248. return handler.call(this, val);
  249. };
  250. /*!
  251. * Module exports.
  252. */
  253. module.exports = SchemaDate;