UNPKG

19.2 kBJavaScriptView Raw
1// Copyright IBM Corp. 2015,2019. All Rights Reserved.
2// Node module: loopback-datasource-juggler
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6// This test written in mocha+should.js
7'use strict';
8
9/* global getSchema:false */
10const should = require('./init.js');
11const async = require('async');
12let db, User, options, filter;
13
14describe('crud-with-options', function() {
15 before(function(done) {
16 db = getSchema();
17 User = db.define('User', {
18 id: {type: Number, id: true},
19 seq: {type: Number, index: true},
20 name: {type: String, index: true, sort: true},
21 email: {type: String, index: true},
22 birthday: {type: Date, index: true},
23 role: {type: String, index: true},
24 order: {type: Number, index: true, sort: true},
25 vip: {type: Boolean},
26 address: {type: {city: String, area: String}},
27 });
28 options = {};
29 filter = {fields: ['name', 'id']};
30
31 db.automigrate(['User'], done);
32 });
33
34 describe('findById', function() {
35 before(function(done) {
36 User.destroyAll(done);
37 });
38
39 it('should allow findById(id, options, cb)', function(done) {
40 User.findById(1, options, function(err, u) {
41 should.not.exist(u);
42 should.not.exist(err);
43 done();
44 });
45 });
46
47 it('should allow findById(id, filter, cb)', function(done) {
48 User.findById(1, filter, function(err, u) {
49 should.not.exist(u);
50 should.not.exist(err);
51 done();
52 });
53 });
54
55 it('should allow findById(id)', function() {
56 User.findById(1);
57 });
58
59 it('should allow findById(id, filter)', function() {
60 User.findById(1, filter);
61 });
62
63 it('should allow findById(id, options)', function() {
64 User.findById(1, options);
65 });
66
67 it('should allow findById(id, filter, options)', function() {
68 User.findById(1, filter, options);
69 });
70
71 it('should throw when invalid filter are provided for findById',
72 function(done) {
73 (function() {
74 User.findById(1, '123', function(err, u) {
75 });
76 }).should.throw('The filter argument must be an object');
77 done();
78 });
79
80 it('should throw when invalid options are provided for findById',
81 function(done) {
82 (function() {
83 User.findById(1, filter, '123', function(err, u) {
84 });
85 }).should.throw('The options argument must be an object');
86 done();
87 });
88
89 it('should report an invalid id via callback for findById',
90 function(done) {
91 User.findById(undefined, {}, function(err, u) {
92 err.should.be.eql(
93 new Error('Model::findById requires the id argument'),
94 );
95 done();
96 });
97 });
98
99 it('should allow findById(id, filter, cb) for a matching id',
100 function(done) {
101 User.create({name: 'x', email: 'x@y.com'}, function(err, u) {
102 should.not.exist(err);
103 should.exist(u.id);
104 User.findById(u.id, filter, function(err, u) {
105 should.exist(u);
106 should.not.exist(err);
107 u.should.be.an.instanceOf(User);
108 u.should.have.property('name', 'x');
109 u.should.have.property('email', undefined);
110 done();
111 });
112 });
113 });
114
115 it('should allow findById(id, options, cb) for a matching id',
116 function(done) {
117 User.create({name: 'y', email: 'y@y.com'}, function(err, u) {
118 should.not.exist(err);
119 should.exist(u.id);
120 User.findById(u.id, options, function(err, u) {
121 should.exist(u);
122 should.not.exist(err);
123 u.should.be.an.instanceOf(User);
124 u.should.have.property('name', 'y');
125 u.should.have.property('email', 'y@y.com');
126 done();
127 });
128 });
129 });
130
131 it('should allow findById(id, filter, options, cb) for a matching id',
132 function(done) {
133 User.create({name: 'z', email: 'z@y.com'}, function(err, u) {
134 should.not.exist(err);
135 should.exist(u.id);
136 User.findById(u.id, filter, options, function(err, u) {
137 should.exist(u);
138 should.not.exist(err);
139 u.should.be.an.instanceOf(User);
140 u.should.have.property('name', 'z');
141 u.should.have.property('email', undefined);
142 done();
143 });
144 });
145 });
146
147 it('should allow promise-style findById',
148 function(done) {
149 User.create({id: 15, name: 'w', email: 'w@y.com'}).then(function(u) {
150 should.exist(u.id);
151 return User.findById(u.id).then(function(u) {
152 should.exist(u);
153 u.should.be.an.instanceOf(User);
154 u.should.have.property('name', 'w');
155 u.should.have.property('email', 'w@y.com');
156 return u;
157 });
158 }).then(function(u) {
159 should.exist(u);
160 should.exist(u.id);
161 return User.findById(u.id, filter).then(function(u) {
162 should.exist(u);
163 u.should.be.an.instanceOf(User);
164 u.should.have.property('name', 'w');
165 u.should.have.property('email', undefined);
166 return u;
167 });
168 }).then(function(u) {
169 should.exist(u);
170 should.exist(u.id);
171 return User.findById(u.id, options).then(function(u) {
172 should.exist(u);
173 u.should.be.an.instanceOf(User);
174 u.should.have.property('name', 'w');
175 u.should.have.property('email', 'w@y.com');
176 return u;
177 });
178 }).then(function(u) {
179 should.exist(u);
180 should.exist(u.id);
181 return User.findById(u.id, filter, options).then(function(u) {
182 should.exist(u);
183 u.should.be.an.instanceOf(User);
184 u.should.have.property('name', 'w');
185 u.should.have.property('email', undefined);
186 done();
187 });
188 }).catch(function(err) {
189 done(err);
190 });
191 });
192 });
193
194 describe('findByIds', function() {
195 before(function(done) {
196 const people = [
197 {id: 1, name: 'a', vip: true},
198 {id: 2, name: 'b'},
199 {id: 3, name: 'c'},
200 {id: 4, name: 'd', vip: true},
201 {id: 5, name: 'e'},
202 {id: 6, name: 'f'},
203 ];
204 // Use automigrate so that serial keys are 1-6
205 db.automigrate(['User'], function(err) {
206 User.create(people, options, function(err, users) {
207 done();
208 });
209 });
210 });
211
212 it('should allow findByIds(ids, cb)', function(done) {
213 User.findByIds([3, 2, 1], function(err, users) {
214 should.exist(users);
215 should.not.exist(err);
216 const names = users.map(function(u) { return u.name; });
217 names.should.eql(['c', 'b', 'a']);
218 done();
219 });
220 });
221
222 it('should allow findByIds(ids, filter, options, cb)',
223 function(done) {
224 User.findByIds([4, 3, 2, 1],
225 {where: {vip: true}}, options, function(err, users) {
226 should.exist(users);
227 should.not.exist(err);
228 const names = users.map(function(u) {
229 return u.name;
230 });
231 names.should.eql(['d', 'a']);
232 done();
233 });
234 });
235 });
236
237 describe('find', function() {
238 before(seed);
239
240 it('should allow find(cb)', function(done) {
241 User.find(function(err, users) {
242 should.exists(users);
243 should.not.exists(err);
244 users.should.have.lengthOf(6);
245 done();
246 });
247 });
248
249 it('should allow find(filter, cb)', function(done) {
250 User.find({limit: 3}, function(err, users) {
251 should.exists(users);
252 should.not.exists(err);
253 users.should.have.lengthOf(3);
254 done();
255 });
256 });
257
258 it('should allow find(filter, options, cb)', function(done) {
259 User.find({}, options, function(err, users) {
260 should.exists(users);
261 should.not.exists(err);
262 users.should.have.lengthOf(6);
263 done();
264 });
265 });
266
267 it('should allow find(filter, options)', function() {
268 User.find({limit: 3}, options);
269 });
270
271 it('should allow find(filter)', function() {
272 User.find({limit: 3});
273 });
274
275 it('should skip trailing undefined args', function(done) {
276 User.find({limit: 3}, function(err, users) {
277 should.exists(users);
278 should.not.exists(err);
279 users.should.have.lengthOf(3);
280 done();
281 }, undefined, undefined);
282 });
283
284 it('should throw on an invalid query arg', function() {
285 (function() {
286 User.find('invalid query', function(err, users) {
287 // noop
288 });
289 }).should.throw('The query argument must be an object');
290 });
291
292 it('should throw on an invalid options arg', function() {
293 (function() {
294 User.find({limit: 3}, 'invalid option', function(err, users) {
295 // noop
296 });
297 }).should.throw('The options argument must be an object');
298 });
299
300 it('should throw on an invalid cb arg', function() {
301 (function() {
302 User.find({limit: 3}, {}, 'invalid cb');
303 }).should.throw('The cb argument must be a function');
304 });
305 });
306
307 describe('count', function() {
308 before(seed);
309
310 it('should allow count(cb)', function(done) {
311 User.count(function(err, n) {
312 should.not.exist(err);
313 should.exist(n);
314 n.should.equal(6);
315 done();
316 });
317 });
318
319 it('should allow count(where, cb)', function(done) {
320 User.count({role: 'lead'}, function(err, n) {
321 should.not.exist(err);
322 should.exist(n);
323 n.should.equal(2);
324 done();
325 });
326 });
327
328 it('should allow count(where, options, cb)', function(done) {
329 User.count({role: 'lead'}, options, function(err, n) {
330 should.not.exist(err);
331 should.exist(n);
332 n.should.equal(2);
333 done();
334 });
335 });
336 });
337
338 describe('findOne', function() {
339 before(seed);
340
341 it('should allow findOne(cb)', function(done) {
342 User.find({order: 'id'}, function(err, users) {
343 User.findOne(function(e, u) {
344 should.not.exist(e);
345 should.exist(u);
346 u.id.toString().should.equal(users[0].id.toString());
347 done();
348 });
349 });
350 });
351
352 it('should allow findOne(filter, options, cb)', function(done) {
353 User.findOne({order: 'order'}, options, function(e, u) {
354 should.not.exist(e);
355 should.exist(u);
356 u.order.should.equal(1);
357 u.name.should.equal('Paul McCartney');
358 done();
359 });
360 });
361
362 it('should allow findOne(filter, cb)', function(done) {
363 User.findOne({order: 'order'}, function(e, u) {
364 should.not.exist(e);
365 should.exist(u);
366 u.order.should.equal(1);
367 u.name.should.equal('Paul McCartney');
368 done();
369 });
370 });
371
372 it('should allow trailing undefined args', function(done) {
373 User.findOne({order: 'order'}, function(e, u) {
374 should.not.exist(e);
375 should.exist(u);
376 u.order.should.equal(1);
377 u.name.should.equal('Paul McCartney');
378 done();
379 }, undefined);
380 });
381 });
382
383 describe('exists', function() {
384 before(seed);
385
386 it('should allow exists(id, cb)', function(done) {
387 User.findOne(function(e, u) {
388 User.exists(u.id, function(err, exists) {
389 should.not.exist(err);
390 should.exist(exists);
391 exists.should.be.ok;
392 done();
393 });
394 });
395 });
396
397 it('should allow exists(id, options, cb)', function(done) {
398 User.destroyAll(function() {
399 User.exists(42, options, function(err, exists) {
400 should.not.exist(err);
401 exists.should.not.be.ok;
402 done();
403 });
404 });
405 });
406 });
407
408 describe('save', function() {
409 it('should allow save(options, cb)', function(done) {
410 const options = {foo: 'bar'};
411 let opts;
412
413 User.observe('after save', function(ctx, next) {
414 opts = ctx.options;
415 next();
416 });
417
418 const u = new User();
419 u.save(options, function(err) {
420 should.not.exist(err);
421 options.should.equal(opts);
422 done();
423 });
424 });
425 });
426
427 describe('destroyAll with options', function() {
428 beforeEach(seed);
429
430 it('should allow destroyAll(where, options, cb)', function(done) {
431 User.destroyAll({name: 'John Lennon'}, options, function(err) {
432 should.not.exist(err);
433 User.find({where: {name: 'John Lennon'}}, function(err, data) {
434 should.not.exist(err);
435 data.length.should.equal(0);
436 User.find({where: {name: 'Paul McCartney'}}, function(err, data) {
437 should.not.exist(err);
438 data.length.should.equal(1);
439 done();
440 });
441 });
442 });
443 });
444
445 it('should allow destroyAll(where, cb)', function(done) {
446 User.destroyAll({name: 'John Lennon'}, function(err) {
447 should.not.exist(err);
448 User.find({where: {name: 'John Lennon'}}, function(err, data) {
449 should.not.exist(err);
450 data.length.should.equal(0);
451 User.find({where: {name: 'Paul McCartney'}}, function(err, data) {
452 should.not.exist(err);
453 data.length.should.equal(1);
454 done();
455 });
456 });
457 });
458 });
459
460 it('should allow destroyAll(cb)', function(done) {
461 User.destroyAll(function(err) {
462 should.not.exist(err);
463 User.find({where: {name: 'John Lennon'}}, function(err, data) {
464 should.not.exist(err);
465 data.length.should.equal(0);
466 User.find({where: {name: 'Paul McCartney'}}, function(err, data) {
467 should.not.exist(err);
468 data.length.should.equal(0);
469 done();
470 });
471 });
472 });
473 });
474 });
475
476 describe('updateAll ', function() {
477 beforeEach(seed);
478
479 it('should allow updateAll(where, data, cb)', function(done) {
480 User.update({name: 'John Lennon'}, {name: 'John Smith'}, function(err) {
481 should.not.exist(err);
482 User.find({where: {name: 'John Lennon'}}, function(err, data) {
483 should.not.exist(err);
484 data.length.should.equal(0);
485 User.find({where: {name: 'John Smith'}}, function(err, data) {
486 should.not.exist(err);
487 data.length.should.equal(1);
488 done();
489 });
490 });
491 });
492 });
493
494 it('should allow updateAll(where, data, options, cb)', function(done) {
495 User.update({name: 'John Lennon'}, {name: 'John Smith'}, options,
496 function(err) {
497 should.not.exist(err);
498 User.find({where: {name: 'John Lennon'}}, function(err, data) {
499 should.not.exist(err);
500 data.length.should.equal(0);
501 User.find({where: {name: 'John Smith'}}, function(err, data) {
502 should.not.exist(err);
503 data.length.should.equal(1);
504 done();
505 });
506 });
507 });
508 });
509
510 it('should allow updateAll(data, cb)', function(done) {
511 User.update({name: 'John Smith'}, function() {
512 User.find({where: {name: 'John Lennon'}}, function(err, data) {
513 should.not.exist(err);
514 data.length.should.equal(0);
515 User.find({where: {name: 'John Smith'}}, function(err, data) {
516 should.not.exist(err);
517 data.length.should.equal(6);
518 done();
519 });
520 });
521 });
522 });
523 });
524
525 describe('updateAttributes', function() {
526 beforeEach(seed);
527 it('preserves document properties not modified by the patch', function() {
528 return User.findOne({where: {name: 'John Lennon'}})
529 .then(function(user) {
530 return user.updateAttributes({address: {city: 'Volos'}});
531 })
532 .then(function() {
533 return User.findOne({where: {name: 'John Lennon'}}); // retrieve the user again from the db
534 })
535 .then(function(updatedUser) {
536 updatedUser.address.city.should.equal('Volos');
537 should(updatedUser.address.area).not.be.exactly(null);
538 should(updatedUser.address.area).be.undefined();
539 });
540 });
541 });
542});
543
544describe('upsertWithWhere', function() {
545 beforeEach(seed);
546 it('rejects upsertWithWhere (options,cb)', function(done) {
547 try {
548 User.upsertWithWhere({}, function(err) {
549 if (err) return done(err);
550 });
551 } catch (ex) {
552 ex.message.should.equal('The data argument must be an object');
553 done();
554 }
555 });
556
557 it('rejects upsertWithWhere (cb)', function(done) {
558 try {
559 User.upsertWithWhere(function(err) {
560 if (err) return done(err);
561 });
562 } catch (ex) {
563 ex.message.should.equal('The where argument must be an object');
564 done();
565 }
566 });
567
568 it('allows upsertWithWhere by accepting where,data and cb as arguments', function(done) {
569 User.upsertWithWhere({name: 'John Lennon'}, {name: 'John Smith'}, function(err) {
570 if (err) return done(err);
571 User.find({where: {name: 'John Lennon'}}, function(err, data) {
572 if (err) return done(err);
573 data.length.should.equal(0);
574 User.find({where: {name: 'John Smith'}}, function(err, data) {
575 if (err) return done(err);
576 data.length.should.equal(1);
577 data[0].name.should.equal('John Smith');
578 data[0].email.should.equal('john@b3atl3s.co.uk');
579 data[0].role.should.equal('lead');
580 data[0].order.should.equal(2);
581 data[0].vip.should.equal(true);
582 done();
583 });
584 });
585 });
586 });
587
588 it('allows upsertWithWhere by accepting where, data, options, and cb as arguments', function(done) {
589 options = {};
590 User.upsertWithWhere({name: 'John Lennon'}, {name: 'John Smith'}, options, function(err) {
591 if (err) return done(err);
592 User.find({where: {name: 'John Smith'}}, function(err, data) {
593 if (err) return done(err);
594 data.length.should.equal(1);
595 data[0].name.should.equal('John Smith');
596 data[0].seq.should.equal(0);
597 data[0].email.should.equal('john@b3atl3s.co.uk');
598 data[0].role.should.equal('lead');
599 data[0].order.should.equal(2);
600 data[0].vip.should.equal(true);
601 done();
602 });
603 });
604 });
605});
606
607function seed(done) {
608 const beatles = [
609 {
610 id: 0,
611 seq: 0,
612 name: 'John Lennon',
613 email: 'john@b3atl3s.co.uk',
614 role: 'lead',
615 birthday: new Date('1980-12-08'),
616 order: 2,
617 vip: true,
618 },
619 {
620 id: 1,
621 seq: 1,
622 name: 'Paul McCartney',
623 email: 'paul@b3atl3s.co.uk',
624 role: 'lead',
625 birthday: new Date('1942-06-18'),
626 order: 1,
627 vip: true,
628 },
629 {id: 2, seq: 2, name: 'George Harrison', order: 5, vip: false},
630 {id: 3, seq: 3, name: 'Ringo Starr', order: 6, vip: false},
631 {id: 4, seq: 4, name: 'Pete Best', order: 4},
632 {id: 5, seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true},
633 ];
634
635 async.series([
636 User.destroyAll.bind(User),
637 function(cb) {
638 async.each(beatles, User.create.bind(User), cb);
639 },
640 ], done);
641}