UNPKG

30 kBJavaScriptView Raw
1// Copyright IBM Corp. 2014,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'use strict';
7const jdb = require('../');
8const DataSource = jdb.DataSource;
9const path = require('path');
10const fs = require('fs');
11const assert = require('assert');
12const async = require('async');
13const should = require('./init.js');
14const Memory = require('../lib/connectors/memory').Memory;
15
16describe('Memory connector', function() {
17 const file = path.join(__dirname, 'memory.json');
18
19 function readModels(done) {
20 fs.readFile(file, function(err, data) {
21 const json = JSON.parse(data.toString());
22 assert(json.models);
23 assert(json.ids.User);
24 done(err, json);
25 });
26 }
27
28 before(function(done) {
29 fs.unlink(file, function(err) {
30 if (!err || err.code === 'ENOENT') {
31 done();
32 }
33 });
34 });
35
36 describe('with file', function() {
37 let ds;
38
39 function createUserModel() {
40 const ds = new DataSource({
41 connector: 'memory',
42 file: file,
43 });
44
45 const User = ds.createModel('User', {
46 id: {
47 type: Number,
48 id: true,
49 generated: true,
50 },
51 name: String,
52 bio: String,
53 approved: Boolean,
54 joinedAt: Date,
55 age: Number,
56 });
57 return User;
58 }
59
60 let User;
61 const ids = [];
62
63 before(function() {
64 User = createUserModel();
65 ds = User.dataSource;
66 });
67
68 it('should allow multiple connects', function(done) {
69 ds.connected = false; // Change the state to force reconnect
70 async.times(10, function(n, next) {
71 ds.connect(next);
72 }, done);
73 });
74
75 it('should persist create', function(done) {
76 let count = 0;
77 async.eachSeries(['John1', 'John2', 'John3'], function(item, cb) {
78 User.create({name: item}, function(err, result) {
79 ids.push(result.id);
80 count++;
81 readModels(function(err, json) {
82 assert.equal(Object.keys(json.models.User).length, count);
83 cb(err);
84 });
85 });
86 }, done);
87 });
88
89 /**
90 * This test depends on the `should persist create`, which creates 3
91 * records and saves into the `memory.json`. The following test makes
92 * sure existing records won't be loaded out of sequence to override
93 * newly created ones.
94 */
95 it('should not have out of sequence read/write', function(done) {
96 // Create the new data source with the same file to simulate
97 // existing records
98 const User = createUserModel();
99 const ds = User.dataSource;
100
101 async.times(10, function(n, next) {
102 if (n === 10) {
103 // Make sure the connect finishes
104 return ds.connect(next);
105 }
106 ds.connect();
107 next();
108 }, function(err) {
109 async.eachSeries(['John4', 'John5'], function(item, cb) {
110 const count = 0;
111 User.create({name: item}, function(err, result) {
112 ids.push(result.id);
113 cb(err);
114 });
115 }, function(err) {
116 if (err) return done(err);
117 readModels(function(err, json) {
118 assert.equal(Object.keys(json.models.User).length, 5);
119 done();
120 });
121 });
122 });
123 });
124
125 it('should persist delete', function(done) {
126 // Force the data source to reconnect so that the updated records
127 // are reloaded
128 ds.disconnect(function() {
129 // Now try to delete one
130 User.deleteById(ids[0], function(err) {
131 if (err) {
132 return done(err);
133 }
134 readModels(function(err, json) {
135 if (err) {
136 return done(err);
137 }
138 assert.equal(Object.keys(json.models.User).length, 4);
139 done();
140 });
141 });
142 });
143 });
144
145 it('should persist upsert', function(done) {
146 User.upsert({id: ids[1], name: 'John'}, function(err, result) {
147 if (err) {
148 return done(err);
149 }
150 readModels(function(err, json) {
151 if (err) {
152 return done(err);
153 }
154 assert.equal(Object.keys(json.models.User).length, 4);
155 const user = JSON.parse(json.models.User[ids[1]]);
156 assert.equal(user.name, 'John');
157 assert(user.id === ids[1]);
158 done();
159 });
160 });
161 });
162
163 it('should persist update', function(done) {
164 User.update({id: ids[1]}, {name: 'John1'},
165 function(err, result) {
166 if (err) {
167 return done(err);
168 }
169 readModels(function(err, json) {
170 if (err) {
171 return done(err);
172 }
173 assert.equal(Object.keys(json.models.User).length, 4);
174 const user = JSON.parse(json.models.User[ids[1]]);
175 assert.equal(user.name, 'John1');
176 assert(user.id === ids[1]);
177 done();
178 });
179 });
180 });
181
182 // The saved memory.json from previous test should be loaded
183 it('should load from the json file', function(done) {
184 User.find(function(err, users) {
185 // There should be 2 records
186 assert.equal(users.length, 4);
187 done(err);
188 });
189 });
190 });
191
192 describe('Query for memory connector', function() {
193 const ds = new DataSource({
194 connector: 'memory',
195 });
196
197 const User = ds.define('User', {
198 seq: {type: Number, index: true},
199 name: {type: String, index: true, sort: true},
200 email: {type: String, index: true},
201 birthday: {type: Date, index: true},
202 role: {type: String, index: true},
203 order: {type: Number, index: true, sort: true},
204 tag: {type: String, index: true},
205 vip: {type: Boolean},
206 address: {
207 street: String,
208 city: String,
209 state: String,
210 zipCode: String,
211 tags: [
212 {
213 tag: String,
214 },
215 ],
216 },
217 friends: [
218 {
219 name: String,
220 },
221 ],
222 });
223
224 before(seed);
225 it('should allow to find using like', function(done) {
226 User.find({where: {name: {like: '%St%'}}}, function(err, posts) {
227 should.not.exist(err);
228 posts.should.have.property('length', 2);
229 done();
230 });
231 });
232
233 it('should properly sanitize like invalid query', async () => {
234 const users = await User.find({where: {tag: {like: '['}}});
235 users.should.have.length(1);
236 users[0].should.have.property('name', 'John Lennon');
237 });
238
239 it('should allow to find using like with regexp', function(done) {
240 User.find({where: {name: {like: /.*St.*/}}}, function(err, posts) {
241 should.not.exist(err);
242 posts.should.have.property('length', 2);
243 done();
244 });
245 });
246
247 it('should support like for no match', function(done) {
248 User.find({where: {name: {like: 'M%XY'}}}, function(err, posts) {
249 should.not.exist(err);
250 posts.should.have.property('length', 0);
251 done();
252 });
253 });
254
255 it('should allow to find using nlike', function(done) {
256 User.find({where: {name: {nlike: '%St%'}}}, function(err, posts) {
257 should.not.exist(err);
258 posts.should.have.property('length', 4);
259 done();
260 });
261 });
262
263 it('should sanitize nlike invalid query', async () => {
264 const users = await User.find({where: {name: {nlike: '['}}});
265 users.should.have.length(6);
266 });
267
268 it('should allow to find using nlike with regexp', function(done) {
269 User.find({where: {name: {nlike: /.*St.*/}}}, function(err, posts) {
270 should.not.exist(err);
271 posts.should.have.property('length', 4);
272 done();
273 });
274 });
275
276 it('should support nlike for no match', function(done) {
277 User.find({where: {name: {nlike: 'M%XY'}}}, function(err, posts) {
278 should.not.exist(err);
279 posts.should.have.property('length', 6);
280 done();
281 });
282 });
283
284 it('should throw if the like value is not string or regexp', function(done) {
285 User.find({where: {name: {like: 123}}}, function(err, posts) {
286 should.exist(err);
287 done();
288 });
289 });
290
291 it('should throw if the nlike value is not string or regexp', function(done) {
292 User.find({where: {name: {nlike: 123}}}, function(err, posts) {
293 should.exist(err);
294 done();
295 });
296 });
297
298 it('should throw if the inq value is not an array', function(done) {
299 User.find({where: {name: {inq: '12'}}}, function(err, posts) {
300 should.exist(err);
301 done();
302 });
303 });
304
305 it('should throw if the nin value is not an array', function(done) {
306 User.find({where: {name: {nin: '12'}}}, function(err, posts) {
307 should.exist(err);
308 done();
309 });
310 });
311
312 it('should throw if the between value is not an array', function(done) {
313 User.find({where: {name: {between: '12'}}}, function(err, posts) {
314 should.exist(err);
315 done();
316 });
317 });
318
319 it('should throw if the between value is not an array of length 2', function(done) {
320 User.find({where: {name: {between: ['12']}}}, function(err, posts) {
321 should.exist(err);
322 done();
323 });
324 });
325
326 it('should successfully extract 5 users from the db', function(done) {
327 User.find({where: {seq: {between: [1, 5]}}}, function(err, users) {
328 should(users.length).be.equal(5);
329 done();
330 });
331 });
332
333 it('should successfully extract 1 user (Lennon) from the db', function(done) {
334 User.find({where: {birthday: {between: [new Date(1970, 0), new Date(1990, 0)]}}},
335 function(err, users) {
336 should(users.length).be.equal(1);
337 should(users[0].name).be.equal('John Lennon');
338 done();
339 });
340 });
341
342 it('should successfully extract 2 users from the db', function(done) {
343 User.find({where: {birthday: {between: [new Date(1940, 0), new Date(1990, 0)]}}},
344 function(err, users) {
345 should(users.length).be.equal(2);
346 done();
347 });
348 });
349
350 it('should successfully extract 2 users using implied and', function(done) {
351 User.find({where: {role: 'lead', vip: true}}, function(err, users) {
352 should(users.length).be.equal(2);
353 should(users[0].name).be.equal('John Lennon');
354 should(users[1].name).be.equal('Paul McCartney');
355 done();
356 });
357 });
358
359 it('should successfully extract 2 users using implied and & and', function(done) {
360 User.find({where: {
361 name: 'John Lennon',
362 and: [{role: 'lead'}, {vip: true}],
363 }}, function(err, users) {
364 should(users.length).be.equal(1);
365 should(users[0].name).be.equal('John Lennon');
366 done();
367 });
368 });
369
370 it('should successfully extract 2 users using date range', function(done) {
371 User.find({where: {birthday: {between:
372 [new Date(1940, 0).toISOString(), new Date(1990, 0).toISOString()]}}},
373 function(err, users) {
374 should(users.length).be.equal(2);
375 done();
376 });
377 });
378
379 it('should successfully extract 0 user from the db', function(done) {
380 User.find({where: {birthday: {between: [new Date(1990, 0), Date.now()]}}},
381 function(err, users) {
382 should(users.length).be.equal(0);
383 done();
384 });
385 });
386
387 it('should successfully extract 2 users matching over array values', function(done) {
388 User.find({
389 where: {
390 children: {
391 regexp: /an/,
392 },
393 },
394 }, function(err, users) {
395 should.not.exist(err);
396 users.length.should.be.equal(2);
397 users[0].name.should.be.equal('John Lennon');
398 users[1].name.should.be.equal('George Harrison');
399 done();
400 });
401 });
402
403 it('should successfully extract 1 users matching over array values', function(done) {
404 User.find({
405 where: {
406 children: 'Dhani',
407 },
408 }, function(err, users) {
409 should.not.exist(err);
410 users.length.should.be.equal(1);
411 users[0].name.should.be.equal('George Harrison');
412 done();
413 });
414 });
415
416 it('should successfully extract 5 users matching a neq filter over array values', function(done) {
417 User.find({
418 where: {
419 children: {neq: 'Dhani'},
420 },
421 }, function(err, users) {
422 should.not.exist(err);
423 users.length.should.be.equal(5);
424 done();
425 });
426 });
427
428 it('should successfully extract 3 users with inq', function(done) {
429 User.find({
430 where: {seq: {inq: [0, 1, 5]}},
431 }, function(err, users) {
432 should.not.exist(err);
433 users.length.should.be.equal(3);
434 done();
435 });
436 });
437
438 it('should successfully extract 4 users with nin', function(done) {
439 User.find({
440 where: {seq: {nin: [2, 3]}},
441 }, function(err, users) {
442 should.not.exist(err);
443 users.length.should.be.equal(4);
444 done();
445 });
446 });
447
448 it('should count using date string', function(done) {
449 User.count({birthday: {lt: new Date(1990, 0).toISOString()}},
450 function(err, count) {
451 should(count).be.equal(2);
452 done();
453 });
454 });
455
456 it('should support order with multiple fields', function(done) {
457 User.find({order: 'vip ASC, seq DESC'}, function(err, posts) {
458 should.not.exist(err);
459 posts[0].seq.should.be.eql(4);
460 posts[1].seq.should.be.eql(3);
461 done();
462 });
463 });
464
465 it('should sort undefined values to the end when ordered DESC', function(done) {
466 User.find({order: 'vip ASC, order DESC'}, function(err, posts) {
467 should.not.exist(err);
468
469 posts[4].seq.should.be.eql(1);
470 posts[5].seq.should.be.eql(0);
471 done();
472 });
473 });
474
475 it('should throw if order has wrong direction', function(done) {
476 User.find({order: 'seq ABC'}, function(err, posts) {
477 should.exist(err);
478 done();
479 });
480 });
481
482 it('should support neq operator for number', function(done) {
483 User.find({where: {seq: {neq: 4}}}, function(err, users) {
484 should.not.exist(err);
485 users.length.should.be.equal(5);
486 for (let i = 0; i < users.length; i++) {
487 users[i].seq.should.not.be.equal(4);
488 }
489 done();
490 });
491 });
492
493 it('should support neq operator for string', function(done) {
494 User.find({where: {role: {neq: 'lead'}}}, function(err, users) {
495 should.not.exist(err);
496 users.length.should.be.equal(4);
497 for (let i = 0; i < users.length; i++) {
498 if (users[i].role) {
499 users[i].role.not.be.equal('lead');
500 }
501 }
502 done();
503 });
504 });
505
506 it('should support neq operator for null', function(done) {
507 User.find({where: {role: {neq: null}}}, function(err, users) {
508 should.not.exist(err);
509 users.length.should.be.equal(2);
510 for (let i = 0; i < users.length; i++) {
511 should.exist(users[i].role);
512 }
513 done();
514 });
515 });
516
517 it('should work when a regex is provided without the regexp operator',
518 function(done) {
519 User.find({where: {name: /John.*/i}}, function(err, users) {
520 should.not.exist(err);
521 users.length.should.equal(1);
522 users[0].name.should.equal('John Lennon');
523 done();
524 });
525 });
526
527 it('should support the regexp operator with regex strings', function(done) {
528 User.find({where: {name: {regexp: 'non$'}}}, function(err, users) {
529 should.not.exist(err);
530 users.length.should.equal(1);
531 users[0].name.should.equal('John Lennon');
532 done();
533 });
534 });
535
536 it('should support the regexp operator with regex literals', function(done) {
537 User.find({where: {name: {regexp: /^J/}}}, function(err, users) {
538 should.not.exist(err);
539 users.length.should.equal(1);
540 users[0].name.should.equal('John Lennon');
541 done();
542 });
543 });
544
545 it('should support the regexp operator with regex objects', function(done) {
546 User.find({where: {name: {regexp: new RegExp(/^J/)}}}, function(err,
547 users) {
548 should.not.exist(err);
549 users.length.should.equal(1);
550 users[0].name.should.equal('John Lennon');
551 done();
552 });
553 });
554
555 it('should deserialize values after saving in upsert', function(done) {
556 User.findOne({where: {seq: 1}}, function(err, paul) {
557 User.updateOrCreate({id: paul.id, name: 'Sir Paul McCartney'},
558 function(err, sirpaul) {
559 should.not.exist(err);
560 sirpaul.birthday.should.be.instanceOf(Date);
561 sirpaul.order.should.be.instanceOf(Number);
562 sirpaul.vip.should.be.instanceOf(Boolean);
563 done();
564 });
565 });
566 });
567
568 function seed(done) {
569 const beatles = [
570 {
571 seq: 0,
572 name: 'John Lennon',
573 email: 'john@b3atl3s.co.uk',
574 role: 'lead',
575 birthday: new Date('1980-12-08'),
576 vip: true,
577 tag: '[singer]',
578 address: {
579 street: '123 A St',
580 city: 'San Jose',
581 state: 'CA',
582 zipCode: '95131',
583 tags: [
584 {tag: 'business'},
585 {tag: 'rent'},
586 ],
587 },
588 friends: [
589 {name: 'Paul McCartney'},
590 {name: 'George Harrison'},
591 {name: 'Ringo Starr'},
592 ],
593 children: ['Sean', 'Julian'],
594 },
595 {
596 seq: 1,
597 name: 'Paul McCartney',
598 email: 'paul@b3atl3s.co.uk',
599 role: 'lead',
600 birthday: new Date('1942-06-18'),
601 order: 1,
602 vip: true,
603 address: {
604 street: '456 B St',
605 city: 'San Mateo',
606 state: 'CA',
607 zipCode: '94065',
608 },
609 friends: [
610 {name: 'John Lennon'},
611 {name: 'George Harrison'},
612 {name: 'Ringo Starr'},
613 ],
614 children: ['Stella', 'Mary', 'Heather', 'Beatrice', 'James'],
615 },
616 {seq: 2, name: 'George Harrison', order: 5, vip: false, children: ['Dhani']},
617 {seq: 3, name: 'Ringo Starr', order: 6, vip: false},
618 {seq: 4, name: 'Pete Best', order: 4, children: []},
619 {seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true},
620 ];
621
622 async.series([
623 User.destroyAll.bind(User),
624 function(cb) {
625 async.each(beatles, User.create.bind(User), cb);
626 },
627 ], done);
628 }
629 });
630
631 it('should use collection setting', function(done) {
632 const ds = new DataSource({
633 connector: 'memory',
634 });
635
636 const Product = ds.createModel('Product', {
637 name: String,
638 });
639
640 const Tool = ds.createModel('Tool', {
641 name: String,
642 }, {memory: {collection: 'Product'}});
643
644 const Widget = ds.createModel('Widget', {
645 name: String,
646 }, {memory: {collection: 'Product'}});
647
648 ds.connector.getCollection('Tool').should.equal('Product');
649 ds.connector.getCollection('Widget').should.equal('Product');
650
651 async.series([
652 function(next) {
653 Tool.create({name: 'Tool A'}, next);
654 },
655 function(next) {
656 Tool.create({name: 'Tool B'}, next);
657 },
658 function(next) {
659 Widget.create({name: 'Widget A'}, next);
660 },
661 ], function(err) {
662 Product.find(function(err, products) {
663 should.not.exist(err);
664 products.should.have.length(3);
665 products[0].toObject().should.eql({name: 'Tool A', id: 1});
666 products[1].toObject().should.eql({name: 'Tool B', id: 2});
667 products[2].toObject().should.eql({name: 'Widget A', id: 3});
668 done();
669 });
670 });
671 });
672
673 it('should refuse to create object with duplicate id', function(done) {
674 const ds = new DataSource({connector: 'memory'});
675 const Product = ds.define('ProductTest', {name: String}, {forceId: false});
676 ds.automigrate('ProductTest', function(err) {
677 if (err) return done(err);
678
679 Product.create({name: 'a-name'}, function(err, p) {
680 if (err) return done(err);
681 Product.create({id: p.id, name: 'duplicate'}, function(err) {
682 if (!err) {
683 return done(new Error('Create should have rejected duplicate id.'));
684 }
685 err.message.should.match(/duplicate/i);
686 err.statusCode.should.equal(409);
687 done();
688 });
689 });
690 });
691 });
692
693 describe('automigrate', function() {
694 let ds;
695 beforeEach(function() {
696 ds = new DataSource({
697 connector: 'memory',
698 });
699
700 ds.createModel('m1', {
701 name: String,
702 });
703 });
704
705 it('automigrate all models', function(done) {
706 ds.automigrate(function(err) {
707 done(err);
708 });
709 });
710
711 it('automigrate all models - promise variant', function(done) {
712 ds.automigrate()
713 .then(function(result) {
714 done();
715 })
716 .catch(function(err) {
717 done(err);
718 });
719 });
720
721 it('automigrate one model', function(done) {
722 ds.automigrate('m1', function(err) {
723 done(err);
724 });
725 });
726
727 it('automigrate one model - promise variant', function(done) {
728 ds.automigrate('m1')
729 .then(function(result) {
730 done();
731 })
732 .catch(function(err) {
733 done(err);
734 });
735 });
736
737 it('automigrate one or more models in an array', function(done) {
738 ds.automigrate(['m1'], function(err) {
739 done(err);
740 });
741 });
742
743 it('automigrate one or more models in an array - promise variant', function(done) {
744 ds.automigrate(['m1'])
745 .then(function(result) {
746 done();
747 })
748 .catch(function(err) {
749 done(err);
750 });
751 });
752
753 it('automigrate reports errors for models not attached', function(done) {
754 ds.automigrate(['m1', 'm2'], function(err) {
755 err.should.be.an.instanceOf(Error);
756 done();
757 });
758 });
759
760 it('automigrate reports errors for models not attached - promise variant', function(done) {
761 ds.automigrate(['m1', 'm2'])
762 .then(function() {
763 done(new Error('automigrate() should have failed'));
764 })
765 .catch(function(err) {
766 err.should.be.an.instanceOf(Error);
767 done();
768 });
769 });
770 });
771
772 describe('findOrCreate', function() {
773 let ds, Cars;
774 before(function() {
775 ds = new DataSource({connector: 'memory'});
776 Cars = ds.define('Cars', {
777 color: String,
778 });
779 });
780
781 it('should create a specific object once and in the subsequent calls it should find it', function(done) {
782 let creationNum = 0;
783 async.times(100, function(n, next) {
784 const initialData = {color: 'white'};
785 const query = {'where': initialData};
786 Cars.findOrCreate(query, initialData, function(err, car, created) {
787 if (created) creationNum++;
788 next(err, car);
789 });
790 }, function(err, cars) {
791 if (err) done(err);
792 Cars.find(function(err, data) {
793 if (err) done(err);
794 data.length.should.equal(1);
795 data[0].color.should.equal('white');
796 creationNum.should.equal(1);
797 done();
798 });
799 });
800 });
801 });
802
803 describe('automigrate when NO models are attached', function() {
804 let ds;
805 beforeEach(function() {
806 ds = new DataSource({
807 connector: 'memory',
808 });
809 });
810
811 it('automigrate does NOT report error when NO models are attached', function(done) {
812 ds.automigrate(function(err) {
813 done();
814 });
815 });
816
817 it('automigrate does NOT report error when NO models are attached - promise variant', function(done) {
818 ds.automigrate()
819 .then(done)
820 .catch(function(err) {
821 done(err);
822 });
823 });
824 });
825
826 describe('With mocked autoupdate', function() {
827 let ds, model;
828 beforeEach(function() {
829 ds = new DataSource({
830 connector: 'memory',
831 });
832
833 ds.connector.autoupdate = function(models, cb) {
834 process.nextTick(cb);
835 };
836
837 model = ds.createModel('m1', {
838 name: String,
839 });
840
841 ds.automigrate();
842
843 ds.createModel('m1', {
844 name: String,
845 address: String,
846 });
847 });
848
849 it('autoupdates all models', function(done) {
850 ds.autoupdate(function(err, result) {
851 done(err);
852 });
853 });
854
855 it('autoupdates all models - promise variant', function(done) {
856 ds.autoupdate()
857 .then(function(result) {
858 done();
859 })
860 .catch(function(err) {
861 done(err);
862 });
863 });
864
865 it('autoupdates one model', function(done) {
866 ds.autoupdate('m1', function(err) {
867 done(err);
868 });
869 });
870
871 it('autoupdates one model - promise variant', function(done) {
872 ds.autoupdate('m1')
873 .then(function(result) {
874 done();
875 })
876 .catch(function(err) {
877 done(err);
878 });
879 });
880
881 it('autoupdates one or more models in an array', function(done) {
882 ds.autoupdate(['m1'], function(err) {
883 done(err);
884 });
885 });
886
887 it('autoupdates one or more models in an array - promise variant', function(done) {
888 ds.autoupdate(['m1'])
889 .then(function(result) {
890 done();
891 })
892 .catch(function(err) {
893 done(err);
894 });
895 });
896
897 it('autoupdate reports errors for models not attached', function(done) {
898 ds.autoupdate(['m1', 'm2'], function(err) {
899 err.should.be.an.instanceOf(Error);
900 done();
901 });
902 });
903
904 it('autoupdate reports errors for models not attached - promise variant', function(done) {
905 ds.autoupdate(['m1', 'm2'])
906 .then(function() {
907 done(new Error('automigrate() should have failed'));
908 })
909 .catch(function(err) {
910 err.should.be.an.instanceOf(Error);
911 done();
912 });
913 });
914 });
915});
916
917describe('Optimized connector', function() {
918 const ds = new DataSource({connector: Memory});
919
920 require('./persistence-hooks.suite')(ds, should, {
921 replaceOrCreateReportsNewInstance: true,
922 });
923});
924
925describe('Unoptimized connector', function() {
926 const ds = new DataSource({connector: Memory});
927
928 // disable optimized methods
929 ds.connector.updateOrCreate = false;
930 ds.connector.findOrCreate = false;
931 ds.connector.upsertWithWhere = false;
932
933 // disable native location queries
934 ds.connector.buildNearFilter = false;
935
936 require('./persistence-hooks.suite')(ds, should, {
937 replaceOrCreateReportsNewInstance: true,
938 });
939});
940
941describe('Memory connector with options', function() {
942 const savedOptions = {};
943 let ds, Post;
944
945 before(function() {
946 ds = new DataSource({connector: 'memory'});
947 ds.connector.create = function(model, data, options, cb) {
948 savedOptions.create = options;
949 process.nextTick(function() {
950 cb(null, 1);
951 });
952 };
953
954 ds.connector.update = function(model, where, data, options, cb) {
955 savedOptions.update = options;
956 process.nextTick(function() {
957 cb(null, {count: 1});
958 });
959 };
960
961 ds.connector.all = function(model, filter, options, cb) {
962 savedOptions.find = options;
963 process.nextTick(function() {
964 cb(null, [{title: 't1', content: 'c1'}]);
965 });
966 };
967
968 Post = ds.define('Post', {
969 title: String,
970 content: String,
971 });
972 });
973
974 it('should receive options from the find method', function(done) {
975 const opts = {transaction: 'tx1'};
976 Post.find({where: {title: 't1'}}, opts, function(err, p) {
977 savedOptions.find.should.be.eql(opts);
978 done(err);
979 });
980 });
981
982 it('should treat first object arg as filter for find', function(done) {
983 const filter = {title: 't1'};
984 Post.find(filter, function(err, p) {
985 savedOptions.find.should.be.eql({});
986 done(err);
987 });
988 });
989
990 it('should receive options from the create method', function(done) {
991 const opts = {transaction: 'tx3'};
992 Post.create({title: 't1', content: 'c1'}, opts, function(err, p) {
993 savedOptions.create.should.be.eql(opts);
994 done(err);
995 });
996 });
997
998 it('should receive options from the update method', function(done) {
999 const opts = {transaction: 'tx4'};
1000 Post.update({title: 't1'}, {content: 'c1 --> c2'},
1001 opts, function(err, p) {
1002 savedOptions.update.should.be.eql(opts);
1003 done(err);
1004 });
1005 });
1006});
1007
1008describe('Memory connector with observers', function() {
1009 const ds = new DataSource({
1010 connector: 'memory',
1011 });
1012
1013 it('should have observer mixed into the connector', function() {
1014 ds.connector.observe.should.be.a.function;
1015 ds.connector.notifyObserversOf.should.be.a.function;
1016 });
1017
1018 it('should notify observers', function(done) {
1019 const events = [];
1020 ds.connector.execute = function(command, params, options, cb) {
1021 const self = this;
1022 const context = {command: command, params: params, options: options};
1023 self.notifyObserversOf('before execute', context, function(err) {
1024 process.nextTick(function() {
1025 if (err) return cb(err);
1026 events.push('execute');
1027 self.notifyObserversOf('after execute', context, function(err) {
1028 cb(err);
1029 });
1030 });
1031 });
1032 };
1033
1034 ds.connector.observe('before execute', function(context, next) {
1035 events.push('before execute');
1036 next();
1037 });
1038
1039 ds.connector.observe('after execute', function(context, next) {
1040 events.push('after execute');
1041 next();
1042 });
1043
1044 ds.connector.execute('test', [1, 2], {x: 2}, function(err) {
1045 if (err) return done(err);
1046 events.should.eql(['before execute', 'execute', 'after execute']);
1047 done();
1048 });
1049 });
1050});