thoughts/node_modules/mongoose/lib/schema/string.js
node_modules/mongoose/lib/schema/string.jsRaw
1
2/*!
3 * Module dependencies.
4 */
5
6var SchemaType = require('../schematype')
7 , CastError = SchemaType.CastError
8 , utils = require('../utils')
9 , Document
10
11/**
12 * String SchemaType constructor.
13 *
14 * @param {String} key
15 * @param {Object} options
16 * @inherits SchemaType
17 * @api private
18 */
19
20function SchemaString (key, options) {
21 this.enumValues = [];
22 this.regExp = null;
23 SchemaType.call(this, key, options, 'String');
24};
25
26/*!
27 * Inherits from SchemaType.
28 */
29
30SchemaString.prototype.__proto__ = SchemaType.prototype;
31
32/**
33 * Adds enumeration values and a coinciding validator.
34 *
35 * ####Example:
36 *
37 * var states = 'opening open closing closed'.split(' ')
38 * var s = new Schema({ state: { type: String, enum: states })
39 * var M = db.model('M', s)
40 * var m = new M({ state: 'invalid' })
41 * m.save(function (err) {
42 * console.error(err) // validator error
43 * m.state = 'open'
44 * m.save() // success
45 * })
46 *
47 * @param {String} [args...] enumeration values
48 * @return {SchemaType} this
49 * @api public
50 */
51
52SchemaString.prototype.enum = function () {
53 var len = arguments.length;
54
55 if (!len || undefined === arguments[0] || false === arguments[0]) {
56 if (this.enumValidator){
57 this.enumValidator = false;
58 this.validators = this.validators.filter(function(v){
59 return v[1] != 'enum';
60 });
61 }
62 return this;
63 }
64
65 for (var i = 0; i < len; i++) {
66 if (undefined !== arguments[i]) {
67 this.enumValues.push(this.cast(arguments[i]));
68 }
69 }
70
71 if (!this.enumValidator) {
72 var values = this.enumValues;
73 this.enumValidator = function(v){
74 return undefined === v || ~values.indexOf(v);
75 };
76 this.validators.push([this.enumValidator, 'enum']);
77 }
78
79 return this;
80};
81
82/**
83 * Adds a lowercase setter.
84 *
85 * ####Example:
86 *
87 * var s = new Schema({ email: { type: String, lowercase: true }})
88 * var M = db.model('M', s);
89 * var m = new M({ email: 'SomeEmail@example.COM' });
90 * console.log(m.email) // someemail@example.com
91 *
92 * @api public
93 * @return {SchemaType} this
94 */
95
96SchemaString.prototype.lowercase = function () {
97 return this.set(function (v, self) {
98 if ('string' != typeof v) v = self.cast(v)
99 if (v) return v.toLowerCase();
100 return v;
101 });
102};
103
104/**
105 * Adds an uppercase setter.
106 *
107 * ####Example:
108 *
109 * var s = new Schema({ caps: { type: String, uppercase: true }})
110 * var M = db.model('M', s);
111 * var m = new M({ caps: 'an example' });
112 * console.log(m.caps) // AN EXAMPLE
113 *
114 * @api public
115 * @return {SchemaType} this
116 */
117
118SchemaString.prototype.uppercase = function () {
119 return this.set(function (v, self) {
120 if ('string' != typeof v) v = self.cast(v)
121 if (v) return v.toUpperCase();
122 return v;
123 });
124};
125
126/**
127 * Adds a trim setter.
128 *
129 * The string value will be trimmed when set.
130 *
131 * ####Example:
132 *
133 * var s = new Schema({ name: { type: String, trim: true }})
134 * var M = db.model('M', s)
135 * var string = ' some name '
136 * console.log(string.length) // 11
137 * var m = new M({ name: string })
138 * console.log(m.name.length) // 9
139 *
140 * @api public
141 * @return {SchemaType} this
142 */
143
144SchemaString.prototype.trim = function () {
145 return this.set(function (v, self) {
146 if ('string' != typeof v) v = self.cast(v)
147 if (v) return v.trim();
148 return v;
149 });
150};
151
152/**
153 * Sets a regexp validator.
154 *
155 * Any value that does not pass `regExp`.test(val) will fail validation.
156 *
157 * ####Example:
158 *
159 * var s = new Schema({ name: { type: String, match: /^a/ }})
160 * var M = db.model('M', s)
161 * var m = new M({ name: 'invalid' })
162 * m.validate(function (err) {
163 * console.error(err) // validation error
164 * m.name = 'apples'
165 * m.validate(function (err) {
166 * assert.ok(err) // success
167 * })
168 * })
169 *
170 * @param {RegExp} regExp regular expression to test against
171 * @return {SchemaType} this
172 * @api public
173 */
174
175SchemaString.prototype.match = function match (regExp) {
176 this.validators.push([function(v){
177 return null != v && '' !== v
178 ? regExp.test(v)
179 : true
180 }, 'regexp']);
181
182 return this;
183};
184
185/**
186 * Check required
187 *
188 * @param {String|null|undefined} value
189 * @api private
190 */
191
192SchemaString.prototype.checkRequired = function checkRequired (value, doc) {
193 if (SchemaType._isRef(this, value, doc, true)) {
194 return null != value;
195 } else {
196 return (value instanceof String || typeof value == 'string') && value.length;
197 }
198};
199
200/**
201 * Casts to String
202 *
203 * @api private
204 */
205
206SchemaString.prototype.cast = function (value, doc, init) {
207 if (SchemaType._isRef(this, value, doc, init)) {
208 // wait! we may need to cast this to a document
209
210 if (null == value) {
211 return value;
212 }
213
214 // lazy load
215 Document || (Document = require('./../document'));
216
217 if (value instanceof Document) {
218 value.$__.wasPopulated = true;
219 return value;
220 }
221
222 // setting a populated path
223 if ('string' == typeof value) {
224 return value;
225 } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
226 throw new CastError('string', value, this.path);
227 }
228
229 // Handle the case where user directly sets a populated
230 // path to a plain object; cast to the Model used in
231 // the population query.
232 var path = doc.$__fullPath(this.path);
233 var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
234 var pop = owner.populated(path, true);
235 var ret = new pop.options.model(value);
236 ret.$__.wasPopulated = true;
237 return ret;
238 }
239
240 if (value === null) {
241 return value;
242 }
243
244 if ('undefined' !== typeof value) {
245 // handle documents being passed
246 if (value._id && 'string' == typeof value._id) {
247 return value._id;
248 }
249 if (value.toString) {
250 return value.toString();
251 }
252 }
253
254
255 throw new CastError('string', value, this.path);
256};
257
258/*!
259 * ignore
260 */
261
262function handleSingle (val) {
263 return this.castForQuery(val);
264}
265
266function handleArray (val) {
267 var self = this;
268 return val.map(function (m) {
269 return self.castForQuery(m);
270 });
271}
272
273SchemaString.prototype.$conditionalHandlers = {
274 '$ne' : handleSingle
275 , '$in' : handleArray
276 , '$nin': handleArray
277 , '$gt' : handleSingle
278 , '$lt' : handleSingle
279 , '$gte': handleSingle
280 , '$lte': handleSingle
281 , '$all': handleArray
282 , '$regex': handleSingle
283 , '$options': handleSingle
284};
285
286/**
287 * Casts contents for queries.
288 *
289 * @param {String} $conditional
290 * @param {any} [val]
291 * @api private
292 */
293
294SchemaString.prototype.castForQuery = function ($conditional, val) {
295 var handler;
296 if (arguments.length === 2) {
297 handler = this.$conditionalHandlers[$conditional];
298 if (!handler)
299 throw new Error("Can't use " + $conditional + " with String.");
300 return handler.call(this, val);
301 } else {
302 val = $conditional;
303 if (val instanceof RegExp) return val;
304 return this.cast(val);
305 }
306};
307
308/*!
309 * Module exports.
310 */
311
312module.exports = SchemaString;