1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | 'use strict';
|
8 |
|
9 |
|
10 | const async = require('async');
|
11 | const bdd = require('./helpers/bdd-if');
|
12 | const should = require('./init.js');
|
13 | const uid = require('./helpers/uid-generator');
|
14 | const createTestSetupForParentRef = require('./helpers/setup-parent-ref');
|
15 |
|
16 | let db, User;
|
17 |
|
18 | describe('basic-querying', function() {
|
19 | before(function(done) {
|
20 | const userModelDef = {
|
21 | seq: {type: Number, index: true},
|
22 | name: {type: String, index: true, sort: true},
|
23 | email: {type: String, index: true},
|
24 | birthday: {type: Date, index: true},
|
25 | role: {type: String, index: true},
|
26 | order: {type: Number, index: true, sort: true},
|
27 | tag: {type: String, index: true},
|
28 | vip: {type: Boolean},
|
29 | address: {
|
30 | street: String,
|
31 | city: String,
|
32 | state: String,
|
33 | zipCode: String,
|
34 | tags: [
|
35 | {
|
36 | tag: String,
|
37 | },
|
38 | ],
|
39 | },
|
40 | friends: [
|
41 | {
|
42 | name: String,
|
43 | },
|
44 | ],
|
45 | addressLoc: {
|
46 | lat: Number,
|
47 | lng: Number,
|
48 | },
|
49 | };
|
50 |
|
51 | db = getSchema();
|
52 |
|
53 | connectorCapabilities.geoPoint = (db.adapter.name != 'dashdb') && (db.adapter.name != 'db2') &&
|
54 | (db.adapter.name != 'informix') && (db.adapter.name != 'cassandra');
|
55 | if (connectorCapabilities.geoPoint) userModelDef.addressLoc = {type: 'GeoPoint'};
|
56 | User = db.define('User', userModelDef);
|
57 | db.automigrate(done);
|
58 | });
|
59 |
|
60 | describe('ping', function() {
|
61 | it('should be able to test connections', function(done) {
|
62 | db.ping(function(err) {
|
63 | should.not.exist(err);
|
64 | done();
|
65 | });
|
66 | });
|
67 | });
|
68 |
|
69 | describe('findById', function() {
|
70 | before(function(done) {
|
71 | db = getSchema();
|
72 | User.destroyAll(done);
|
73 | });
|
74 |
|
75 | it('should query by id: not found', function(done) {
|
76 | const unknownId = uid.fromConnector(db) || 1;
|
77 | User.findById(unknownId, function(err, u) {
|
78 | should.not.exist(u);
|
79 | should.not.exist(err);
|
80 | done();
|
81 | });
|
82 | });
|
83 |
|
84 | it('should query by id: found', function(done) {
|
85 | User.create(function(err, u) {
|
86 | should.not.exist(err);
|
87 | should.exist(u.id);
|
88 | User.findById(u.id, function(err, u) {
|
89 | should.exist(u);
|
90 | should.not.exist(err);
|
91 | u.should.be.an.instanceOf(User);
|
92 | done();
|
93 | });
|
94 | });
|
95 | });
|
96 | });
|
97 |
|
98 | describe('findByIds', function() {
|
99 | let createdUsers;
|
100 | before(function(done) {
|
101 | db = getSchema();
|
102 | const people = [
|
103 | {name: 'a', vip: true},
|
104 | {name: 'b', vip: null},
|
105 | {name: 'c'},
|
106 | {name: 'd', vip: true},
|
107 | {name: 'e'},
|
108 | {name: 'f'},
|
109 | ];
|
110 | db.automigrate(['User'], function(err) {
|
111 | User.create(people, function(err, users) {
|
112 | should.not.exist(err);
|
113 |
|
114 |
|
115 | createdUsers = users;
|
116 | done();
|
117 | });
|
118 | });
|
119 | });
|
120 |
|
121 | it('should query by ids', function(done) {
|
122 | User.findByIds(
|
123 | [createdUsers[2].id, createdUsers[1].id, createdUsers[0].id],
|
124 | function(err, users) {
|
125 | should.exist(users);
|
126 | should.not.exist(err);
|
127 | const names = users.map(function(u) {
|
128 | return u.name;
|
129 | });
|
130 | names.should.eql(
|
131 | [createdUsers[2].name, createdUsers[1].name, createdUsers[0].name],
|
132 | );
|
133 | done();
|
134 | },
|
135 | );
|
136 | });
|
137 |
|
138 | it('should query by ids and condition', function(done) {
|
139 | User.findByIds([
|
140 | createdUsers[0].id,
|
141 | createdUsers[1].id,
|
142 | createdUsers[2].id,
|
143 | createdUsers[3].id],
|
144 | {where: {vip: true}}, function(err, users) {
|
145 | should.exist(users);
|
146 | should.not.exist(err);
|
147 | const names = users.map(function(u) {
|
148 | return u.name;
|
149 | });
|
150 | names.should.eql(createdUsers.slice(0, 4).
|
151 | filter(function(u) {
|
152 | return u.vip;
|
153 | }).map(function(u) {
|
154 | return u.name;
|
155 | }));
|
156 | done();
|
157 | });
|
158 | });
|
159 |
|
160 | bdd.itIf(connectorCapabilities.nullDataValueExists !== false,
|
161 | 'should query by ids to check null property', function(done) {
|
162 | User.findByIds([
|
163 | createdUsers[0].id,
|
164 | createdUsers[1].id],
|
165 | {where: {vip: null}}, function(err, users) {
|
166 | should.not.exist(err);
|
167 | should.exist(users);
|
168 | users.length.should.eql(1);
|
169 | users[0].name.should.eql(createdUsers[1].name);
|
170 | done();
|
171 | });
|
172 | });
|
173 | });
|
174 |
|
175 | describe('find', function() {
|
176 | before(seed);
|
177 |
|
178 | before(function setupDelayingLoadedHook() {
|
179 | User.observe('loaded', nextAfterDelay);
|
180 | });
|
181 |
|
182 | after(function removeDelayingLoadHook() {
|
183 | User.removeObserver('loaded', nextAfterDelay);
|
184 | });
|
185 |
|
186 | it('should query collection', function(done) {
|
187 | User.find(function(err, users) {
|
188 | should.exists(users);
|
189 | should.not.exists(err);
|
190 | users.should.have.lengthOf(6);
|
191 | done();
|
192 | });
|
193 | });
|
194 |
|
195 | it('should query limited collection', function(done) {
|
196 | User.find({limit: 3}, function(err, users) {
|
197 | should.exists(users);
|
198 | should.not.exists(err);
|
199 | users.should.have.lengthOf(3);
|
200 | done();
|
201 | });
|
202 | });
|
203 |
|
204 | bdd.itIf(connectorCapabilities.supportPagination !== false, 'should query collection with skip & ' +
|
205 | 'limit', function(done) {
|
206 | User.find({skip: 1, limit: 4, order: 'seq'}, function(err, users) {
|
207 | should.exists(users);
|
208 | should.not.exists(err);
|
209 | users[0].seq.should.be.eql(1);
|
210 | users.should.have.lengthOf(4);
|
211 | done();
|
212 | });
|
213 | });
|
214 |
|
215 | bdd.itIf(connectorCapabilities.supportPagination !== false, 'should query collection with offset & ' +
|
216 | 'limit', function(done) {
|
217 | User.find({offset: 2, limit: 3, order: 'seq'}, function(err, users) {
|
218 | should.exists(users);
|
219 | should.not.exists(err);
|
220 | users[0].seq.should.be.eql(2);
|
221 | users.should.have.lengthOf(3);
|
222 | done();
|
223 | });
|
224 | });
|
225 |
|
226 | it('should query filtered collection', function(done) {
|
227 | User.find({where: {role: 'lead'}}, function(err, users) {
|
228 | should.exists(users);
|
229 | should.not.exists(err);
|
230 | users.should.have.lengthOf(2);
|
231 | done();
|
232 | });
|
233 | });
|
234 |
|
235 | bdd.itIf(connectorCapabilities.adhocSort !== false, 'should query collection sorted by numeric ' +
|
236 | 'field', function(done) {
|
237 | User.find({order: 'order'}, function(err, users) {
|
238 | should.exists(users);
|
239 | should.not.exists(err);
|
240 | users.forEach(function(u, i) {
|
241 | u.order.should.eql(i + 1);
|
242 | });
|
243 | done();
|
244 | });
|
245 | });
|
246 |
|
247 | bdd.itIf(connectorCapabilities.adhocSort !== false, 'should query collection desc sorted by ' +
|
248 | 'numeric field', function(done) {
|
249 | User.find({order: 'order DESC'}, function(err, users) {
|
250 | should.exists(users);
|
251 | should.not.exists(err);
|
252 | users.forEach(function(u, i) {
|
253 | u.order.should.eql(users.length - i);
|
254 | });
|
255 | done();
|
256 | });
|
257 | });
|
258 |
|
259 | bdd.itIf(connectorCapabilities.adhocSort !== false, 'should query collection sorted by string ' +
|
260 | 'field', function(done) {
|
261 | User.find({order: 'name'}, function(err, users) {
|
262 | should.exists(users);
|
263 | should.not.exists(err);
|
264 | users.shift().name.should.equal('George Harrison');
|
265 | users.shift().name.should.equal('John Lennon');
|
266 | users.pop().name.should.equal('Stuart Sutcliffe');
|
267 | done();
|
268 | });
|
269 | });
|
270 |
|
271 | bdd.itIf(connectorCapabilities.adhocSort !== false, 'should query collection desc sorted by ' +
|
272 | 'string field', function(done) {
|
273 | User.find({order: 'name DESC'}, function(err, users) {
|
274 | should.exists(users);
|
275 | should.not.exists(err);
|
276 | users.pop().name.should.equal('George Harrison');
|
277 | users.pop().name.should.equal('John Lennon');
|
278 | users.shift().name.should.equal('Stuart Sutcliffe');
|
279 | done();
|
280 | });
|
281 | });
|
282 |
|
283 | bdd.itIf(connectorCapabilities.adhocSort !== false, 'should query sorted desc by order integer field' +
|
284 | ' even though there is an async model loaded hook', function(done) {
|
285 | User.find({order: 'order DESC'}, function(err, users) {
|
286 | if (err) return done(err);
|
287 | should.exists(users);
|
288 | const order = users.map(function(u) { return u.order; });
|
289 | order.should.eql([6, 5, 4, 3, 2, 1]);
|
290 | done();
|
291 | });
|
292 | });
|
293 |
|
294 | it('should support "and" operator that is satisfied', function(done) {
|
295 | User.find({where: {and: [
|
296 | {name: 'John Lennon'},
|
297 | {role: 'lead'},
|
298 | ]}}, function(err, users) {
|
299 | should.not.exist(err);
|
300 | users.should.have.property('length', 1);
|
301 | done();
|
302 | });
|
303 | });
|
304 |
|
305 | it('should support "and" operator that is not satisfied', function(done) {
|
306 | User.find({where: {and: [
|
307 | {name: 'John Lennon'},
|
308 | {role: 'member'},
|
309 | ]}}, function(err, users) {
|
310 | should.not.exist(err);
|
311 | users.should.have.property('length', 0);
|
312 | done();
|
313 | });
|
314 | });
|
315 |
|
316 | bdd.itIf(connectorCapabilities.supportOrOperator !== false, 'should support "or" that is ' +
|
317 | 'satisfied', function(done) {
|
318 | User.find({where: {or: [
|
319 | {name: 'John Lennon'},
|
320 | {role: 'lead'},
|
321 | ]}}, function(err, users) {
|
322 | should.not.exist(err);
|
323 | users.should.have.property('length', 2);
|
324 | done();
|
325 | });
|
326 | });
|
327 |
|
328 | bdd.itIf(connectorCapabilities.supportOrOperator !== false, 'should support "or" operator that is ' +
|
329 | 'not satisfied', function(done) {
|
330 | User.find({where: {or: [
|
331 | {name: 'XYZ'},
|
332 | {role: 'Hello1'},
|
333 | ]}}, function(err, users) {
|
334 | should.not.exist(err);
|
335 | users.should.have.property('length', 0);
|
336 | done();
|
337 | });
|
338 | });
|
339 |
|
340 | bdd.itIf(connectorCapabilities.nullDataValueExists !== false,
|
341 | 'should support where date "neq" null', function(done) {
|
342 | User.find({where: {birthday: {'neq': null},
|
343 | }}, function(err, users) {
|
344 | should.not.exist(err);
|
345 | should.exist(users);
|
346 | users.should.have.property('length', 2);
|
347 | should(users[0].name).be.oneOf('John Lennon', 'Paul McCartney');
|
348 | should(users[1].name).be.oneOf('John Lennon', 'Paul McCartney');
|
349 | done();
|
350 | });
|
351 | });
|
352 |
|
353 | bdd.itIf(connectorCapabilities.nullDataValueExists !== false,
|
354 | 'should support where date is null', function(done) {
|
355 | User.find({where: {birthday: null,
|
356 | }}, function(err, users) {
|
357 | should.not.exist(err);
|
358 | should.exist(users);
|
359 | users.should.have.property('length', 4);
|
360 | done();
|
361 | });
|
362 | });
|
363 |
|
364 | it('should support date "gte" that is satisfied', function(done) {
|
365 | User.find({where: {birthday: {'gte': new Date('1980-12-08')},
|
366 | }}, function(err, users) {
|
367 | should.not.exist(err);
|
368 | users.should.have.property('length', 1);
|
369 | users[0].name.should.equal('John Lennon');
|
370 | done();
|
371 | });
|
372 | });
|
373 |
|
374 | it('should support date "gt" that is not satisfied', function(done) {
|
375 | User.find({where: {birthday: {'gt': new Date('1980-12-08')},
|
376 | }}, function(err, users) {
|
377 | should.not.exist(err);
|
378 | users.should.have.property('length', 0);
|
379 | done();
|
380 | });
|
381 | });
|
382 |
|
383 | it('should support date "gt" that is satisfied', function(done) {
|
384 | User.find({where: {birthday: {'gt': new Date('1980-12-07')},
|
385 | }}, function(err, users) {
|
386 | should.not.exist(err);
|
387 | users.should.have.property('length', 1);
|
388 | users[0].name.should.equal('John Lennon');
|
389 | done();
|
390 | });
|
391 | });
|
392 |
|
393 | bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
394 | 'should support date "lt" that is satisfied', function(done) {
|
395 | User.find({where: {birthday: {'lt': new Date('1980-12-07')},
|
396 | }}, function(err, users) {
|
397 | should.not.exist(err);
|
398 | users.should.have.property('length', 1);
|
399 | users[0].name.should.equal('Paul McCartney');
|
400 | done();
|
401 | });
|
402 | });
|
403 |
|
404 | it('should support number "gte" that is satisfied', function(done) {
|
405 | User.find({where: {order: {'gte': 3}}}, function(err, users) {
|
406 | should.not.exist(err);
|
407 | users.should.have.property('length', 4);
|
408 | users.map(u => u.name).should.containDeep([
|
409 | 'George Harrison', 'Ringo Starr', 'Pete Best', 'Stuart Sutcliffe',
|
410 | ]);
|
411 | done();
|
412 | });
|
413 | });
|
414 |
|
415 | it('should support number "gt" that is not satisfied', function(done) {
|
416 | User.find({where: {order: {'gt': 6},
|
417 | }}, function(err, users) {
|
418 | should.not.exist(err);
|
419 | users.should.have.property('length', 0);
|
420 | done();
|
421 | });
|
422 | });
|
423 |
|
424 | it('should support number "gt" that is satisfied', function(done) {
|
425 | User.find({where: {order: {'gt': 5},
|
426 | }}, function(err, users) {
|
427 | should.not.exist(err);
|
428 | users.should.have.property('length', 1);
|
429 | users[0].name.should.equal('Ringo Starr');
|
430 | done();
|
431 | });
|
432 | });
|
433 |
|
434 | it('should support number "lt" that is satisfied', function(done) {
|
435 | User.find({where: {order: {'lt': 2},
|
436 | }}, function(err, users) {
|
437 | should.not.exist(err);
|
438 | users.should.have.property('length', 1);
|
439 | users[0].name.should.equal('Paul McCartney');
|
440 | done();
|
441 | });
|
442 | });
|
443 |
|
444 | bdd.itIf(connectorCapabilities.ignoreUndefinedConditionValue !== false, 'should support number "gt" ' +
|
445 | 'that is satisfied by null value', function(done) {
|
446 | User.find({order: 'seq', where: {order: {'gt': null}}}, function(err, users) {
|
447 | should.not.exist(err);
|
448 | users.should.have.property('length', 0);
|
449 | done();
|
450 | });
|
451 | });
|
452 |
|
453 | bdd.itIf(connectorCapabilities.ignoreUndefinedConditionValue !== false, 'should support number "lt" ' +
|
454 | 'that is not satisfied by null value', function(done) {
|
455 | User.find({where: {order: {'lt': null}}}, function(err, users) {
|
456 | should.not.exist(err);
|
457 | users.should.have.property('length', 0);
|
458 | done();
|
459 | });
|
460 | });
|
461 |
|
462 | bdd.itIf(connectorCapabilities.ignoreUndefinedConditionValue !== false, 'should support string "gte" ' +
|
463 | 'that is satisfied by null value', function(done) {
|
464 | User.find({order: 'seq', where: {name: {'gte': null}}}, function(err, users) {
|
465 | should.not.exist(err);
|
466 | users.should.have.property('length', 0);
|
467 | done();
|
468 | });
|
469 | });
|
470 |
|
471 | bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
472 | 'should support string "gte" that is satisfied', function(done) {
|
473 | User.find({where: {name: {'gte': 'Paul McCartney'}}}, function(err, users) {
|
474 | should.not.exist(err);
|
475 | users.should.have.property('length', 4);
|
476 | for (let ix = 0; ix < users.length; ix++) {
|
477 | users[ix].name.should.be.greaterThanOrEqual('Paul McCartney');
|
478 | }
|
479 | done();
|
480 | });
|
481 | });
|
482 |
|
483 | it('should support string "gt" that is not satisfied', function(done) {
|
484 | User.find({where: {name: {'gt': 'xyz'},
|
485 | }}, function(err, users) {
|
486 | should.not.exist(err);
|
487 | users.should.have.property('length', 0);
|
488 | done();
|
489 | });
|
490 | });
|
491 |
|
492 | bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
493 | 'should support string "gt" that is satisfied', function(done) {
|
494 | User.find({where: {name: {'gt': 'Paul McCartney'},
|
495 | }}, function(err, users) {
|
496 | should.not.exist(err);
|
497 | users.should.have.property('length', 3);
|
498 | for (let ix = 0; ix < users.length; ix++) {
|
499 | users[ix].name.should.be.greaterThan('Paul McCartney');
|
500 | }
|
501 | done();
|
502 | });
|
503 | });
|
504 |
|
505 | bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
506 | 'should support string "lt" that is satisfied', function(done) {
|
507 | User.find({where: {name: {'lt': 'Paul McCartney'},
|
508 | }}, function(err, users) {
|
509 | should.not.exist(err);
|
510 | users.should.have.property('length', 2);
|
511 | for (let ix = 0; ix < users.length; ix++) {
|
512 | users[ix].name.should.be.lessThan('Paul McCartney');
|
513 | }
|
514 | done();
|
515 | });
|
516 | });
|
517 |
|
518 | it('should support boolean "gte" that is satisfied', function(done) {
|
519 | User.find({where: {vip: {'gte': true},
|
520 | }}, function(err, users) {
|
521 | should.not.exist(err);
|
522 | users.should.have.property('length', 3);
|
523 | for (let ix = 0; ix < users.length; ix++) {
|
524 | users[ix].name.should.be.oneOf(['John Lennon', 'Stuart Sutcliffe', 'Paul McCartney']);
|
525 | users[ix].vip.should.be.true();
|
526 | }
|
527 | done();
|
528 | });
|
529 | });
|
530 |
|
531 | it('should support boolean "gt" that is not satisfied', function(done) {
|
532 | User.find({where: {vip: {'gt': true},
|
533 | }}, function(err, users) {
|
534 | should.not.exist(err);
|
535 | users.should.have.property('length', 0);
|
536 | done();
|
537 | });
|
538 | });
|
539 |
|
540 | it('should support boolean "gt" that is satisfied', function(done) {
|
541 | User.find({where: {vip: {'gt': false},
|
542 | }}, function(err, users) {
|
543 | should.not.exist(err);
|
544 | users.should.have.property('length', 3);
|
545 | for (let ix = 0; ix < users.length; ix++) {
|
546 | users[ix].name.should.be.oneOf(['John Lennon', 'Stuart Sutcliffe', 'Paul McCartney']);
|
547 | users[ix].vip.should.be.true(users[ix].name + ' should be VIP');
|
548 | }
|
549 | done();
|
550 | });
|
551 | });
|
552 |
|
553 | it('should support boolean "lt" that is satisfied', function(done) {
|
554 | User.find({where: {vip: {'lt': true},
|
555 | }}, function(err, users) {
|
556 | should.not.exist(err);
|
557 | users.should.have.property('length', 2);
|
558 | for (let ix = 0; ix < users.length; ix++) {
|
559 | users[ix].name.should.be.oneOf(['Ringo Starr', 'George Harrison']);
|
560 | users[ix].vip.should.be.false(users[ix].name + ' should not be VIP');
|
561 | }
|
562 | done();
|
563 | });
|
564 | });
|
565 |
|
566 | bdd.itIf(connectorCapabilities.supportInq, 'supports non-empty inq', function() {
|
567 |
|
568 | return User.find({where: {seq: {inq: [0, 1, 100]}}})
|
569 | .then(result => {
|
570 | const seqsFound = result.map(r => r.seq);
|
571 | should(seqsFound).eql([0, 1]);
|
572 | });
|
573 | });
|
574 |
|
575 | bdd.itIf(connectorCapabilities.supportInq, 'supports empty inq', function() {
|
576 | return User.find({where: {seq: {inq: []}}})
|
577 | .then(result => {
|
578 | const seqsFound = result.map(r => r.seq);
|
579 | should(seqsFound).eql([]);
|
580 | });
|
581 | });
|
582 |
|
583 | const itWhenIlikeSupported = connectorCapabilities.ilike;
|
584 | bdd.describeIf(itWhenIlikeSupported, 'ilike', function() {
|
585 | it('should support "like" that is satisfied',
|
586 | function(done) {
|
587 | User.find({where: {name: {like: 'John'}}},
|
588 | function(err, users) {
|
589 | if (err) return done(err);
|
590 | users.length.should.equal(1);
|
591 | users[0].name.should.equal('John Lennon');
|
592 | done();
|
593 | });
|
594 | });
|
595 |
|
596 | it('should sanitize invalid usage of like', async () => {
|
597 | const users = await User.find({where: {tag: {like: '['}}});
|
598 | users.should.have.length(1);
|
599 | users[0].should.have.property('name', 'John Lennon');
|
600 | });
|
601 |
|
602 | it('should support "like" that is not satisfied',
|
603 | function(done) {
|
604 | User.find({where: {name: {like: 'Bob'}}},
|
605 | function(err, users) {
|
606 | if (err) return done(err);
|
607 | users.length.should.equal(0);
|
608 | done();
|
609 | });
|
610 | });
|
611 | it('should support "ilike" that is satisfied', function(done) {
|
612 | User.find({where: {name: {ilike: 'john'}}},
|
613 | function(err, users) {
|
614 | if (err) return done(err);
|
615 | users.length.should.equal(1);
|
616 | users[0].name.should.equal('John Lennon');
|
617 | done();
|
618 | });
|
619 | });
|
620 | it('should support "ilike" that is not satisfied', function(done) {
|
621 | User.find({where: {name: {ilike: 'bob'}}}, function(err, users) {
|
622 | if (err) return done(err);
|
623 | users.length.should.equal(0);
|
624 | done();
|
625 | });
|
626 | });
|
627 |
|
628 | it('should properly sanitize invalid ilike filter', async () => {
|
629 | const users = await User.find({where: {name: {ilike: '['}}});
|
630 | users.should.be.empty();
|
631 | });
|
632 | });
|
633 |
|
634 | const itWhenNilikeSupported = connectorCapabilities.nilike !== false;
|
635 | bdd.describeIf(itWhenNilikeSupported, 'nilike', function() {
|
636 | it('should support "nlike" that is satisfied', function(done) {
|
637 | User.find({where: {name: {nlike: 'John'}}},
|
638 | function(err, users) {
|
639 | if (err) return done(err);
|
640 | users.length.should.equal(5);
|
641 | users[0].name.should.equal('Paul McCartney');
|
642 | done();
|
643 | });
|
644 | });
|
645 |
|
646 | it('should support "nilike" that is satisfied', function(done) {
|
647 | User.find({where: {name: {nilike: 'john'}}},
|
648 | function(err, users) {
|
649 | if (err) return done(err);
|
650 | users.length.should.equal(5);
|
651 | users[0].name.should.equal('Paul McCartney');
|
652 | done();
|
653 | });
|
654 | });
|
655 | });
|
656 |
|
657 | describe('geo queries', function() {
|
658 | describe('near filter', function() {
|
659 | it('supports a basic "near" query', function(done) {
|
660 | User.find({
|
661 | where: {
|
662 | addressLoc: {
|
663 | near: {lat: 29.9, lng: -90.07},
|
664 | },
|
665 | },
|
666 | }, function(err, users) {
|
667 | if (err) done(err);
|
668 | users.should.have.property('length', 3);
|
669 | users[0].name.should.equal('John Lennon');
|
670 | users[0].should.be.instanceOf(User);
|
671 | users[0].addressLoc.should.not.be.null();
|
672 | done();
|
673 | });
|
674 | });
|
675 |
|
676 | it('supports "near" inside a coumpound query with "and"', function(done) {
|
677 | User.find({
|
678 | where: {
|
679 | and: [
|
680 | {
|
681 | addressLoc: {
|
682 | near: {lat: 29.9, lng: -90.07},
|
683 | },
|
684 | },
|
685 | {
|
686 | vip: true,
|
687 | },
|
688 | ],
|
689 | },
|
690 | }, function(err, users) {
|
691 | if (err) done(err);
|
692 | users.should.have.property('length', 2);
|
693 | users[0].name.should.equal('John Lennon');
|
694 | users[0].should.be.instanceOf(User);
|
695 | users[0].addressLoc.should.not.be.null();
|
696 | users[0].vip.should.be.true();
|
697 | done();
|
698 | });
|
699 | });
|
700 |
|
701 | it('supports "near" inside a complex coumpound query with multiple "and"', function(done) {
|
702 | User.find({
|
703 | where: {
|
704 | and: [
|
705 | {
|
706 | and: [
|
707 | {
|
708 | addressLoc: {
|
709 | near: {lat: 29.9, lng: -90.07},
|
710 | },
|
711 | },
|
712 | {
|
713 | order: 2,
|
714 | },
|
715 | ],
|
716 | },
|
717 | {
|
718 | vip: true,
|
719 | },
|
720 | ],
|
721 | },
|
722 | }, function(err, users) {
|
723 | if (err) done(err);
|
724 | users.should.have.property('length', 1);
|
725 | users[0].name.should.equal('John Lennon');
|
726 | users[0].should.be.instanceOf(User);
|
727 | users[0].addressLoc.should.not.be.null();
|
728 | users[0].vip.should.be.true();
|
729 | users[0].order.should.equal(2);
|
730 | done();
|
731 | });
|
732 | });
|
733 |
|
734 | it('supports multiple "near" queries with "or"', function(done) {
|
735 | User.find({
|
736 | where: {
|
737 | or: [
|
738 | {
|
739 | addressLoc: {
|
740 | near: {lat: 29.9, lng: -90.04},
|
741 | maxDistance: 300,
|
742 | },
|
743 | },
|
744 | {
|
745 | addressLoc: {
|
746 | near: {lat: 22.97, lng: -88.03},
|
747 | maxDistance: 50,
|
748 | },
|
749 | },
|
750 | ],
|
751 | },
|
752 | }, function(err, users) {
|
753 | if (err) done(err);
|
754 | users.should.have.property('length', 2);
|
755 | users[0].addressLoc.should.not.be.null();
|
756 | users[0].name.should.equal('Paul McCartney');
|
757 | users[0].should.be.instanceOf(User);
|
758 | users[1].addressLoc.should.not.equal(null);
|
759 | users[1].name.should.equal('John Lennon');
|
760 | done();
|
761 | });
|
762 | });
|
763 |
|
764 | it('supports multiple "near" queries with "or" ' +
|
765 | 'inside a coumpound query with "and"', function(done) {
|
766 | User.find({
|
767 | where: {
|
768 | and: [
|
769 | {
|
770 | or: [
|
771 | {
|
772 | addressLoc: {
|
773 | near: {lat: 29.9, lng: -90.04},
|
774 | maxDistance: 300,
|
775 | },
|
776 | },
|
777 | {
|
778 | addressLoc: {
|
779 | near: {lat: 22.7, lng: -89.03},
|
780 | maxDistance: 50,
|
781 | },
|
782 | },
|
783 | ],
|
784 | },
|
785 | {
|
786 | vip: true,
|
787 | },
|
788 | ],
|
789 | },
|
790 | }, function(err, users) {
|
791 | if (err) done(err);
|
792 | users.should.have.property('length', 1);
|
793 | users[0].addressLoc.should.not.be.null();
|
794 | users[0].name.should.equal('John Lennon');
|
795 | users[0].should.be.instanceOf(User);
|
796 | users[0].vip.should.be.true();
|
797 | done();
|
798 | });
|
799 | });
|
800 | });
|
801 | });
|
802 |
|
803 | it('should only include fields as specified', function(done) {
|
804 | let remaining = 0;
|
805 |
|
806 | function sample(fields) {
|
807 | return {
|
808 | expect: function(arr) {
|
809 | remaining++;
|
810 | User.find({fields: fields}, function(err, users) {
|
811 | remaining--;
|
812 | if (err) return done(err);
|
813 |
|
814 | should.exists(users);
|
815 |
|
816 | if (remaining === 0) {
|
817 | done();
|
818 | }
|
819 |
|
820 | users.forEach(function(user) {
|
821 | const obj = user.toObject();
|
822 |
|
823 | Object.keys(obj)
|
824 | .forEach(function(key) {
|
825 |
|
826 | if (obj[key] !== undefined && arr.indexOf(key) === -1) {
|
827 | console.log('Given fields:', fields);
|
828 | console.log('Got:', key, obj[key]);
|
829 | console.log('Expected:', arr);
|
830 | throw new Error('should not include data for key: ' + key);
|
831 | }
|
832 | });
|
833 | });
|
834 | });
|
835 | },
|
836 | };
|
837 | }
|
838 |
|
839 | sample({name: true}).expect(['name']);
|
840 | sample({name: false}).expect([
|
841 | 'id', 'seq', 'email', 'role', 'order', 'birthday', 'vip', 'address', 'friends', 'addressLoc', 'tag',
|
842 | ]);
|
843 | sample({name: false, id: true}).expect(['id']);
|
844 | sample({id: true}).expect(['id']);
|
845 | sample('id').expect(['id']);
|
846 | sample(['id']).expect(['id']);
|
847 | sample(['email']).expect(['email']);
|
848 | });
|
849 |
|
850 | it('should ignore non existing properties when excluding', function(done) {
|
851 | return User.find({fields: {notExist: false}}, (err, users) => {
|
852 | if (err) return done(err);
|
853 | users.forEach(user => {
|
854 | switch (user.seq) {
|
855 | case 0:
|
856 | case 1:
|
857 | Object.keys(user.__data).should.containDeep(['id', 'seq', 'name', 'order', 'role',
|
858 | 'birthday', 'vip', 'address', 'friends']);
|
859 | break;
|
860 | case 4:
|
861 | Object.keys(user.__data).should.containDeep(['id', 'seq', 'name', 'order']);
|
862 | break;
|
863 | default:
|
864 | Object.keys(user.__data).should.containDeep(['id', 'seq', 'name', 'order', 'vip']);
|
865 | }
|
866 | });
|
867 | done();
|
868 | });
|
869 | });
|
870 |
|
871 | const describeWhenNestedSupported = connectorCapabilities.nestedProperty;
|
872 | bdd.describeIf(describeWhenNestedSupported, 'query with nested property', function() {
|
873 | it('should support nested property in query', function(done) {
|
874 | User.find({where: {'address.city': 'San Jose'}}, function(err, users) {
|
875 | if (err) return done(err);
|
876 | users.length.should.be.equal(1);
|
877 | for (let i = 0; i < users.length; i++) {
|
878 | users[i].address.city.should.be.eql('San Jose');
|
879 | }
|
880 | done();
|
881 | });
|
882 | });
|
883 |
|
884 | it('should support nested property with regex over arrays in query', function(done) {
|
885 | User.find({where: {'friends.name': {regexp: /^Ringo/}}}, function(err, users) {
|
886 | if (err) return done(err);
|
887 | users.length.should.be.equal(2);
|
888 | const expectedUsers = ['John Lennon', 'Paul McCartney'];
|
889 | expectedUsers.indexOf(users[0].name).should.not.equal(-1);
|
890 | expectedUsers.indexOf(users[1].name).should.not.equal(-1);
|
891 | done();
|
892 | });
|
893 | });
|
894 |
|
895 | it('should support nested property with gt in query', function(done) {
|
896 | User.find({where: {'address.city': {gt: 'San'}}}, function(err, users) {
|
897 | if (err) return done(err);
|
898 | users.length.should.be.equal(2);
|
899 | for (let i = 0; i < users.length; i++) {
|
900 | users[i].address.state.should.be.eql('CA');
|
901 | }
|
902 | done();
|
903 | });
|
904 | });
|
905 |
|
906 | bdd.itIf(connectorCapabilities.adhocSort,
|
907 | 'should support nested property for order in query',
|
908 | function(done) {
|
909 | User.find({where: {'address.state': 'CA'}, order: 'address.city DESC'},
|
910 | function(err, users) {
|
911 | if (err) return done(err);
|
912 | users.length.should.be.equal(2);
|
913 | users[0].address.city.should.be.eql('San Mateo');
|
914 | users[1].address.city.should.be.eql('San Jose');
|
915 | done();
|
916 | });
|
917 | });
|
918 |
|
919 | it('should support multi-level nested array property in query', function(done) {
|
920 | User.find({where: {'address.tags.tag': 'business'}}, function(err, users) {
|
921 | if (err) return done(err);
|
922 | users.length.should.be.equal(1);
|
923 | users[0].address.tags[0].tag.should.be.equal('business');
|
924 | users[0].address.tags[1].tag.should.be.equal('rent');
|
925 | done();
|
926 | });
|
927 | });
|
928 |
|
929 | it('should fail when querying with an invalid value for a type',
|
930 | function(done) {
|
931 | User.find({where: {birthday: 'notadate'}}, function(err, users) {
|
932 | should.exist(err);
|
933 | err.message.should.equal('Invalid date: notadate');
|
934 | done();
|
935 | });
|
936 | });
|
937 | });
|
938 |
|
939 | it('preserves empty values from the database', async () => {
|
940 |
|
941 |
|
942 |
|
943 | const Player = db.define('Player', {name: String});
|
944 |
|
945 | await db.automigrate('Player');
|
946 | const created = await Player.create({name: 'Pen'});
|
947 |
|
948 |
|
949 | Player.defineProperty('active', {
|
950 | type: Boolean,
|
951 | default: false,
|
952 | });
|
953 | await db.autoupdate('Player');
|
954 |
|
955 |
|
956 | const found = await Player.findOne();
|
957 | should(found.toObject().active).be.oneOf([
|
958 | undefined,
|
959 | null,
|
960 | ]);
|
961 | });
|
962 |
|
963 | describe('check __parent relationship in embedded models', () => {
|
964 | createTestSetupForParentRef(() => User.modelBuilder);
|
965 | it('should fill the parent in embedded model', async () => {
|
966 | const user = await User.findOne({where: {name: 'John Lennon'}});
|
967 | user.should.have.property('address');
|
968 | should(user.address).have.property('__parent');
|
969 | should(user.address.__parent).be.instanceof(User).and.equal(user);
|
970 | });
|
971 | it('should assign the container model as parent in list property', async () => {
|
972 | const user = await User.findOne({where: {name: 'John Lennon'}});
|
973 | user.should.have.property('friends');
|
974 | should(user.friends).have.property('parent');
|
975 | should(user.friends.parent).be.instanceof(User).and.equal(user);
|
976 | });
|
977 | it('should have the complete chain of parents available in embedded list element', async () => {
|
978 | const user = await User.findOne({where: {name: 'John Lennon'}});
|
979 | user.friends.forEach((userFriend) => {
|
980 | userFriend.should.have.property('__parent');
|
981 | should(userFriend.__parent).equal(user);
|
982 | });
|
983 | });
|
984 | });
|
985 | });
|
986 |
|
987 | describe('count', function() {
|
988 | before(seed);
|
989 |
|
990 | it('should query total count', function(done) {
|
991 | User.count(function(err, n) {
|
992 | should.not.exist(err);
|
993 | should.exist(n);
|
994 | n.should.equal(6);
|
995 | done();
|
996 | });
|
997 | });
|
998 |
|
999 | it('should query filtered count', function(done) {
|
1000 | User.count({role: 'lead'}, function(err, n) {
|
1001 | should.not.exist(err);
|
1002 | should.exist(n);
|
1003 | n.should.equal(2);
|
1004 | done();
|
1005 | });
|
1006 | });
|
1007 | });
|
1008 |
|
1009 | describe('findOne', function() {
|
1010 | before(seed);
|
1011 |
|
1012 | bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
1013 | 'should find first record (default sort by id)', function(done) {
|
1014 | User.all({order: 'id'}, function(err, users) {
|
1015 | User.findOne(function(e, u) {
|
1016 | should.not.exist(e);
|
1017 | should.exist(u);
|
1018 | u.id.toString().should.equal(users[0].id.toString());
|
1019 | done();
|
1020 | });
|
1021 | });
|
1022 | });
|
1023 |
|
1024 | bdd.itIf(connectorCapabilities.adhocSort, 'should find first record', function(done) {
|
1025 | User.findOne({order: 'order'}, function(e, u) {
|
1026 | should.not.exist(e);
|
1027 | should.exist(u);
|
1028 | u.order.should.equal(1);
|
1029 | u.name.should.equal('Paul McCartney');
|
1030 | done();
|
1031 | });
|
1032 | });
|
1033 |
|
1034 | bdd.itIf(connectorCapabilities.adhocSort, 'should find last record', function(done) {
|
1035 | User.findOne({order: 'order DESC'}, function(e, u) {
|
1036 | should.not.exist(e);
|
1037 | should.exist(u);
|
1038 | u.order.should.equal(6);
|
1039 | u.name.should.equal('Ringo Starr');
|
1040 | done();
|
1041 | });
|
1042 | });
|
1043 |
|
1044 | bdd.itIf(connectorCapabilities.adhocSort, 'should find last record in filtered set', function(done) {
|
1045 | User.findOne({
|
1046 | where: {role: 'lead'},
|
1047 | order: 'order DESC',
|
1048 | }, function(e, u) {
|
1049 | should.not.exist(e);
|
1050 | should.exist(u);
|
1051 | u.order.should.equal(2);
|
1052 | u.name.should.equal('John Lennon');
|
1053 | done();
|
1054 | });
|
1055 | });
|
1056 |
|
1057 | it('should work even when find by id', function(done) {
|
1058 | User.findOne(function(e, u) {
|
1059 | User.findOne({where: {id: u.id}}, function(err, user) {
|
1060 | should.not.exist(err);
|
1061 | should.exist(user);
|
1062 | done();
|
1063 | });
|
1064 | });
|
1065 | });
|
1066 | });
|
1067 |
|
1068 | describe('exists', function() {
|
1069 | before(seed);
|
1070 |
|
1071 | it('should check whether record exist', function(done) {
|
1072 | User.findOne(function(e, u) {
|
1073 | User.exists(u.id, function(err, exists) {
|
1074 | should.not.exist(err);
|
1075 | should.exist(exists);
|
1076 | exists.should.be.ok;
|
1077 | done();
|
1078 | });
|
1079 | });
|
1080 | });
|
1081 |
|
1082 | it('should check whether record not exist', function(done) {
|
1083 | const unknownId = uid.fromConnector(db) || 42;
|
1084 | User.destroyAll(function() {
|
1085 | User.exists(unknownId, function(err, exists) {
|
1086 | should.not.exist(err);
|
1087 | exists.should.not.be.ok;
|
1088 | done();
|
1089 | });
|
1090 | });
|
1091 | });
|
1092 | });
|
1093 |
|
1094 | describe('updateAll', function() {
|
1095 | let numAndDateModel, numAndDateArrayModel;
|
1096 |
|
1097 | before(function() {
|
1098 | numAndDateModel = db.define('numAndDateModel', {
|
1099 | dateProp: Date,
|
1100 | numProp: Number,
|
1101 | });
|
1102 |
|
1103 | numAndDateArrayModel = db.define('numAndDateArrMod', {
|
1104 | dateArray: [Date],
|
1105 | numArray: [Number],
|
1106 | });
|
1107 | return db.automigrate(['numAndDateModel', 'numAndDateArrMod']);
|
1108 | });
|
1109 |
|
1110 | it('coerces primitive datatypes on update', async () => {
|
1111 | const createDate = new Date('2019-02-21T12:00:00').toISOString();
|
1112 | const createData = {
|
1113 | dateProp: createDate,
|
1114 | numProp: '1',
|
1115 | };
|
1116 | const updateDate = new Date('2019-04-15T12:00:00').toISOString();
|
1117 | const updateData = {
|
1118 | dateProp: updateDate,
|
1119 | numProp: '3',
|
1120 | };
|
1121 | const created = await numAndDateModel.create(createData);
|
1122 | const updated = await numAndDateModel.updateAll({id: created.id}, updateData);
|
1123 | const found = await numAndDateModel.findById(created.id);
|
1124 | found.dateProp.should.deepEqual(new Date(updateDate));
|
1125 | found.numProp.should.equal(3);
|
1126 | });
|
1127 |
|
1128 |
|
1129 | bdd.itIf(connectorCapabilities.supportsArrays !== false,
|
1130 | 'coerces primitive array datatypes on update', async () => {
|
1131 | const createDate = new Date('2019-02-21T12:00:00').toISOString();
|
1132 | const createData = {
|
1133 | dateArray: [createDate, createDate],
|
1134 | numArray: ['1', '2'],
|
1135 | };
|
1136 | const updateDate = new Date('2019-04-15T12:00:00').toISOString();
|
1137 | const updateData = {
|
1138 | dateArray: [updateDate, updateDate],
|
1139 | numArray: ['3', '4'],
|
1140 | };
|
1141 | const created = await numAndDateArrayModel.create(createData);
|
1142 | const updated = await numAndDateArrayModel.updateAll({id: created.id}, updateData);
|
1143 | const found = await numAndDateArrayModel.findById(created.id);
|
1144 | found.dateArray[0].should.deepEqual(new Date(updateDate));
|
1145 | found.dateArray[1].should.deepEqual(new Date(updateDate));
|
1146 | found.numArray[0].should.equal(3);
|
1147 | found.numArray[1].should.equal(4);
|
1148 | });
|
1149 | });
|
1150 |
|
1151 | context('regexp operator', function() {
|
1152 | const invalidDataTypes = [0, true, {}, [], Function, null];
|
1153 |
|
1154 | before(seed);
|
1155 |
|
1156 | it('should return an error for invalid data types', function(done) {
|
1157 |
|
1158 |
|
1159 | async.each(invalidDataTypes, function(v, cb) {
|
1160 | User.find({where: {name: {regexp: v}}}, function(err, users) {
|
1161 | should.exist(err);
|
1162 | cb();
|
1163 | });
|
1164 | }, done);
|
1165 | });
|
1166 | });
|
1167 | });
|
1168 |
|
1169 |
|
1170 | describe.skip('queries', function() {
|
1171 | let Todo;
|
1172 |
|
1173 | before(function prepDb(done) {
|
1174 | db = getSchema();
|
1175 | Todo = db.define('Todo', {
|
1176 | id: false,
|
1177 | content: {type: 'string'},
|
1178 | }, {
|
1179 | idInjection: false,
|
1180 | });
|
1181 | db.automigrate(['Todo'], done);
|
1182 | });
|
1183 | beforeEach(function resetFixtures(done) {
|
1184 | db = getSchema();
|
1185 | Todo.destroyAll(function() {
|
1186 | Todo.create([
|
1187 | {content: 'Buy eggs'},
|
1188 | {content: 'Buy milk'},
|
1189 | {content: 'Buy sausages'},
|
1190 | ], done);
|
1191 | });
|
1192 | });
|
1193 |
|
1194 | context('that do not require an id', function() {
|
1195 | it('should work for create', function(done) {
|
1196 | Todo.create({content: 'Buy ham'}, function(err) {
|
1197 | should.not.exist(err);
|
1198 | done();
|
1199 | });
|
1200 | });
|
1201 |
|
1202 | it('should work for updateOrCreate/upsert', function(done) {
|
1203 | const aliases = ['updateOrCreate', 'upsert'];
|
1204 | async.each(aliases, function(alias, cb) {
|
1205 | Todo[alias]({content: 'Buy ham'}, function(err) {
|
1206 | should.not.exist(err);
|
1207 | cb();
|
1208 | });
|
1209 | }, done);
|
1210 | });
|
1211 |
|
1212 | it('should work for findOrCreate', function(done) {
|
1213 | Todo.findOrCreate({content: 'Buy ham'}, function(err) {
|
1214 | should.not.exist(err);
|
1215 | done();
|
1216 | });
|
1217 | });
|
1218 |
|
1219 | it('should work for exists', function(done) {
|
1220 | Todo.exists({content: 'Buy ham'}, function(err) {
|
1221 | should.not.exist(err);
|
1222 | done();
|
1223 | });
|
1224 | });
|
1225 |
|
1226 | it('should work for find', function(done) {
|
1227 | Todo.find(function(err) {
|
1228 | should.not.exist(err);
|
1229 | done();
|
1230 | });
|
1231 | });
|
1232 |
|
1233 | it('should work for findOne', function(done) {
|
1234 | Todo.findOne(function(err) {
|
1235 | should.not.exist(err);
|
1236 | done();
|
1237 | });
|
1238 | });
|
1239 |
|
1240 | it('should work for deleteAll/destroyAll/remove', function(done) {
|
1241 |
|
1242 |
|
1243 | const aliases = ['deleteAll', 'destroyAll', 'remove'];
|
1244 | async.each(aliases, function(alias, cb) {
|
1245 | Todo[alias](function(err) {
|
1246 | should.not.exist(err);
|
1247 | cb();
|
1248 | });
|
1249 | }, done);
|
1250 | });
|
1251 |
|
1252 | it('should work for update/updateAll', function(done) {
|
1253 | Todo.update({content: 'Buy ham'}, function(err) {
|
1254 | should.not.exist(err);
|
1255 | done();
|
1256 | });
|
1257 | });
|
1258 |
|
1259 | it('should work for count', function(done) {
|
1260 | Todo.count({content: 'Buy eggs'}, function(err) {
|
1261 | should.not.exist(err);
|
1262 | done();
|
1263 | });
|
1264 | });
|
1265 | });
|
1266 |
|
1267 | context('that require an id', function() {
|
1268 | const expectedErrMsg = 'Primary key is missing for the Todo model';
|
1269 |
|
1270 | it('should return an error for findById', function(done) {
|
1271 | Todo.findById(1, function(err) {
|
1272 | should.exist(err);
|
1273 | err.message.should.equal(expectedErrMsg);
|
1274 | done();
|
1275 | });
|
1276 | });
|
1277 |
|
1278 | it('should return an error for findByIds', function(done) {
|
1279 | Todo.findByIds([1, 2], function(err) {
|
1280 | should.exist(err);
|
1281 | err.message.should.equal(expectedErrMsg);
|
1282 | done();
|
1283 | });
|
1284 | });
|
1285 |
|
1286 | it('should return an error for deleteById/destroyById/removeById',
|
1287 | function(done) {
|
1288 | const aliases = ['deleteById', 'destroyById', 'removeById'];
|
1289 | async.each(aliases, function(alias, cb) {
|
1290 | Todo[alias](1, function(err) {
|
1291 | should.exist(err);
|
1292 | err.message.should.equal(expectedErrMsg);
|
1293 | cb();
|
1294 | });
|
1295 | }, done);
|
1296 | });
|
1297 |
|
1298 | it('should return an error for instance.save', function(done) {
|
1299 | const todo = new Todo();
|
1300 | todo.content = 'Buy ham';
|
1301 | todo.save(function(err) {
|
1302 | should.exist(err);
|
1303 | err.message.should.equal(expectedErrMsg);
|
1304 | done();
|
1305 | });
|
1306 | });
|
1307 |
|
1308 | it('should return an error for instance.delete', function(done) {
|
1309 | Todo.findOne(function(err, todo) {
|
1310 | todo.delete(function(err) {
|
1311 | should.exist(err);
|
1312 | err.message.should.equal(expectedErrMsg);
|
1313 | done();
|
1314 | });
|
1315 | });
|
1316 | });
|
1317 |
|
1318 | it('should return an error for instance.updateAttribute', function(done) {
|
1319 | Todo.findOne(function(err, todo) {
|
1320 | todo.updateAttribute('content', 'Buy ham', function(err) {
|
1321 | should.exist(err);
|
1322 | err.message.should.equal(expectedErrMsg);
|
1323 | done();
|
1324 | });
|
1325 | });
|
1326 | });
|
1327 |
|
1328 | it('should return an error for instance.updateAttributes', function(done) {
|
1329 | Todo.findOne(function(err, todo) {
|
1330 | todo.updateAttributes({content: 'Buy ham'}, function(err) {
|
1331 | should.exist(err);
|
1332 | err.message.should.equal(expectedErrMsg);
|
1333 | done();
|
1334 | });
|
1335 | });
|
1336 | });
|
1337 | });
|
1338 | });
|
1339 |
|
1340 | function seed(done) {
|
1341 | const beatles = [
|
1342 | {
|
1343 | seq: 0,
|
1344 | name: 'John Lennon',
|
1345 | email: 'john@b3atl3s.co.uk',
|
1346 | role: 'lead',
|
1347 | birthday: new Date('1980-12-08'),
|
1348 | order: 2,
|
1349 | vip: true,
|
1350 | tag: '[singer]',
|
1351 | address: {
|
1352 | street: '123 A St',
|
1353 | city: 'San Jose',
|
1354 | state: 'CA',
|
1355 | zipCode: '95131',
|
1356 | tags: [
|
1357 | {tag: 'business'},
|
1358 | {tag: 'rent'},
|
1359 | ],
|
1360 | },
|
1361 | friends: [
|
1362 | {name: 'Paul McCartney'},
|
1363 | {name: 'George Harrison'},
|
1364 | {name: 'Ringo Starr'},
|
1365 | ],
|
1366 | addressLoc: {lat: 29.97, lng: -90.03},
|
1367 | },
|
1368 | {
|
1369 | seq: 1,
|
1370 | name: 'Paul McCartney',
|
1371 | email: 'paul@b3atl3s.co.uk',
|
1372 | role: 'lead',
|
1373 | birthday: new Date('1942-06-18'),
|
1374 | order: 1,
|
1375 | vip: true,
|
1376 | address: {
|
1377 | street: '456 B St',
|
1378 | city: 'San Mateo',
|
1379 | state: 'CA',
|
1380 | zipCode: '94065',
|
1381 | },
|
1382 | friends: [
|
1383 | {name: 'John Lennon'},
|
1384 | {name: 'George Harrison'},
|
1385 | {name: 'Ringo Starr'},
|
1386 | ],
|
1387 | addressLoc: {lat: 22.97, lng: -88.03},
|
1388 | },
|
1389 | {
|
1390 | seq: 2,
|
1391 | name: 'George Harrison',
|
1392 | birthday: null,
|
1393 | order: 5,
|
1394 | vip: false,
|
1395 | addressLoc: {lat: 22.7, lng: -89.03},
|
1396 | },
|
1397 | {seq: 3, name: 'Ringo Starr', order: 6, birthday: null, vip: false},
|
1398 | {seq: 4, name: 'Pete Best', order: 4, birthday: null},
|
1399 | {seq: 5, name: 'Stuart Sutcliffe', order: 3, birthday: null, vip: true},
|
1400 | ];
|
1401 |
|
1402 | async.series([
|
1403 | User.destroyAll.bind(User),
|
1404 | function(cb) {
|
1405 | async.each(beatles, User.create.bind(User), cb);
|
1406 | },
|
1407 | ], done);
|
1408 | }
|
1409 |
|
1410 | function nextAfterDelay(ctx, next) {
|
1411 | const randomTimeoutTrigger = Math.floor(Math.random() * 100);
|
1412 | setTimeout(function() { process.nextTick(next); }, randomTimeoutTrigger);
|
1413 | }
|