sharedb-mongo 1.0.0-beta.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,19 @@
1
- var expect = require('expect.js');
2
- var mongodb = require('mongodb');
3
- var ShareDbMongo = require('../index');
1
+ var expect = require('chai').expect;
2
+ var ShareDbMongo = require('..');
4
3
  var getQuery = require('sharedb-mingo-memory/get-query');
4
+ var async = require('async');
5
5
 
6
6
  var mongoUrl = process.env.TEST_MONGO_URL || 'mongodb://localhost:27017/test';
7
7
 
8
8
  function create(callback) {
9
- var db = ShareDbMongo({mongo: function(shareDbCallback) {
10
- mongodb.connect(mongoUrl, function(err, mongo) {
9
+ var db = new ShareDbMongo(mongoUrl);
10
+ db.getDbs(function(err, mongo) {
11
+ if (err) return callback(err);
12
+ mongo.dropDatabase(function(err) {
11
13
  if (err) return callback(err);
12
- mongo.dropDatabase(function(err) {
13
- if (err) return callback(err);
14
- shareDbCallback(null, mongo);
15
- callback(null, db, mongo);
16
- });
14
+ callback(null, db, mongo);
17
15
  });
18
- }});
16
+ });
19
17
  };
20
18
 
21
19
  require('sharedb/test/db')({create: create, getQuery: getQuery});
@@ -43,10 +41,10 @@ describe('mongo db', function() {
43
41
  mongo.collection('o_testcollection').indexInformation(function(err, indexes) {
44
42
  if (err) return done(err);
45
43
  // Index for getting document(s) ops
46
- expect(indexes['d_1_v_1']).ok();
44
+ expect(indexes['d_1_v_1']).ok;
47
45
  // Index for checking committed op(s) by src and seq
48
- expect(indexes['src_1_seq_1_v_1']).ok();
49
- done()
46
+ expect(indexes['src_1_seq_1_v_1']).ok;
47
+ done();
50
48
  });
51
49
  });
52
50
  });
@@ -55,9 +53,9 @@ describe('mongo db', function() {
55
53
  var db = this.db;
56
54
  this.mongo.collection('testcollection').createIndex({x: 1}, {unique: true}, function(err) {
57
55
  if (err) return done(err);
58
- db.commit('testcollection', 'foo', {v: 0, create: {}}, {v: 1, data: {x: 7}}, null, function(err, succeeded) {
56
+ db.commit('testcollection', 'foo', {v: 0, create: {}}, {v: 1, data: {x: 7}}, null, function(err) {
59
57
  if (err) return done(err);
60
- db.commit('testcollection', 'bar', {v: 0, create: {}}, {v: 1, data: {x: 7}}, null, function(err, succeeded) {
58
+ db.commit('testcollection', 'bar', {v: 0, create: {}}, {v: 1, data: {x: 7}}, null, function(err) {
61
59
  expect(err && err.code).equal(11000);
62
60
  done();
63
61
  });
@@ -70,9 +68,9 @@ describe('mongo db', function() {
70
68
  it('does not allow editing the system collection', function(done) {
71
69
  var db = this.db;
72
70
  db.commit('system', 'test', {v: 0, create: {}}, {}, null, function(err) {
73
- expect(err).ok();
71
+ expect(err).ok;
74
72
  db.getSnapshot('system', 'test', null, null, function(err) {
75
- expect(err).ok();
73
+ expect(err).ok;
76
74
  done();
77
75
  });
78
76
  });
@@ -80,26 +78,68 @@ describe('mongo db', function() {
80
78
  });
81
79
 
82
80
  describe('query', function() {
83
- // Run query tests for the types of queries supported by ShareDBMingo
84
- require('sharedb-mingo-memory/test/query')();
81
+ it('$count should count documents', function(done) {
82
+ var snapshots = [
83
+ {type: 'json0', id: 'test1', v: 1, data: {x: 1, y: 1}},
84
+ {type: 'json0', id: 'test2', v: 1, data: {x: 2, y: 2}},
85
+ {type: 'json0', id: 'test3', v: 1, data: {x: 3, y: 2}}
86
+ ];
87
+ var query = {$count: true, y: 2};
88
+
89
+ var db = this.db;
90
+ async.each(snapshots, function(snapshot, cb) {
91
+ db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, cb);
92
+ }, function(err) {
93
+ if (err) return done(err);
94
+ db.query('testcollection', query, null, null, function(err, results, extra) {
95
+ if (err) return done(err);
96
+
97
+ expect(results).eql([]);
98
+ expect(extra).eql(2);
99
+ done();
100
+ });
101
+ });
102
+ });
103
+
104
+ it('$sort, $skip and $limit should order, skip and limit', function(done) {
105
+ var snapshots = [
106
+ {type: 'json0', v: 1, data: {x: 1}, id: 'test1', m: null},
107
+ {type: 'json0', v: 1, data: {x: 3}, id: 'test2', m: null}, // intentionally added out of sort order
108
+ {type: 'json0', v: 1, data: {x: 2}, id: 'test3', m: null}
109
+ ];
110
+ var query = {$sort: {x: 1}, $skip: 1, $limit: 1};
111
+
112
+ var db = this.db;
113
+ async.each(snapshots, function(snapshot, cb) {
114
+ db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, cb);
115
+ }, function(err) {
116
+ if (err) return done(err);
117
+
118
+ db.query('testcollection', query, null, null, function(err, results) {
119
+ if (err) throw err;
120
+ expect(results).eql([snapshots[2]]);
121
+ done();
122
+ });
123
+ });
124
+ });
85
125
 
86
126
  it('does not allow $where queries', function(done) {
87
- this.db.query('testcollection', {$where: 'true'}, null, null, function(err, results) {
88
- expect(err).ok();
127
+ this.db.query('testcollection', {$where: 'true'}, null, null, function(err) {
128
+ expect(err).ok;
89
129
  done();
90
130
  });
91
131
  });
92
132
 
93
133
  it('queryPollDoc does not allow $where queries', function(done) {
94
134
  this.db.queryPollDoc('testcollection', 'somedoc', {$where: 'true'}, null, function(err) {
95
- expect(err).ok();
135
+ expect(err).ok;
96
136
  done();
97
137
  });
98
138
  });
99
139
 
100
140
  it('$query is deprecated', function(done) {
101
141
  this.db.query('testcollection', {$query: {}}, null, null, function(err) {
102
- expect(err).ok();
142
+ expect(err).ok;
103
143
  expect(err.code).eql(4106);
104
144
  done();
105
145
  });
@@ -107,7 +147,7 @@ describe('mongo db', function() {
107
147
 
108
148
  it('only one collection operation allowed', function(done) {
109
149
  this.db.query('testcollection', {$distinct: {y: 1}, $aggregate: {}}, null, null, function(err) {
110
- expect(err).ok();
150
+ expect(err).ok;
111
151
  expect(err.code).eql(4108);
112
152
  done();
113
153
  });
@@ -115,7 +155,7 @@ describe('mongo db', function() {
115
155
 
116
156
  it('only one cursor operation allowed', function(done) {
117
157
  this.db.query('testcollection', {$count: true, $explain: true}, null, null, function(err) {
118
- expect(err).ok();
158
+ expect(err).ok;
119
159
  expect(err.code).eql(4109);
120
160
  done();
121
161
  });
@@ -123,7 +163,7 @@ describe('mongo db', function() {
123
163
 
124
164
  it('cursor transform can\'t run after collection operation', function(done) {
125
165
  this.db.query('testcollection', {$distinct: {y: 1}, $sort: {y: 1}}, null, null, function(err) {
126
- expect(err).ok();
166
+ expect(err).ok;
127
167
  expect(err.code).eql(4110);
128
168
  done();
129
169
  });
@@ -131,7 +171,7 @@ describe('mongo db', function() {
131
171
 
132
172
  it('cursor operation can\'t run after collection operation', function(done) {
133
173
  this.db.query('testcollection', {$distinct: {y: 1}, $count: true}, null, null, function(err) {
134
- expect(err).ok();
174
+ expect(err).ok;
135
175
  expect(err.code).eql(4110);
136
176
  done();
137
177
  });
@@ -139,7 +179,7 @@ describe('mongo db', function() {
139
179
 
140
180
  it('non-object $readPref should return error', function(done) {
141
181
  this.db.query('testcollection', {$readPref: true}, null, null, function(err) {
142
- expect(err).ok();
182
+ expect(err).ok;
143
183
  expect(err.code).eql(4107);
144
184
  done();
145
185
  });
@@ -148,14 +188,14 @@ describe('mongo db', function() {
148
188
  it('malformed $mapReduce should return error', function(done) {
149
189
  this.db.allowJSQueries = true; // required for $mapReduce
150
190
  this.db.query('testcollection', {$mapReduce: true}, null, null, function(err) {
151
- expect(err).ok();
191
+ expect(err).ok;
152
192
  expect(err.code).eql(4107);
153
193
  done();
154
194
  });
155
195
  });
156
196
 
157
- describe('queryPollDoc correctly filters on _id', function(done) {
158
- var snapshot = {type: 'json0', v: 1, data: {}, id: "test"};
197
+ describe('queryPollDoc correctly filters on _id', function() {
198
+ var snapshot = {type: 'json0', v: 1, data: {}, id: 'test'};
159
199
 
160
200
  beforeEach(function(done) {
161
201
  this.db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, done);
@@ -251,11 +291,11 @@ describe('mongo db', function() {
251
291
 
252
292
  it('does not let you run $aggregate queries without options.allowAggregateQueries', function(done) {
253
293
  var query = {$aggregate: [
254
- {$group: {_id: '$y',count: {$sum: 1}}},
294
+ {$group: {_id: '$y', count: {$sum: 1}}},
255
295
  {$sort: {count: 1}}
256
296
  ]};
257
- this.db.query('testcollection', query, null, null, function(err, results) {
258
- expect(err).ok();
297
+ this.db.query('testcollection', query, null, null, function(err) {
298
+ expect(err).ok;
259
299
  done();
260
300
  });
261
301
  });
@@ -286,7 +326,7 @@ describe('mongo db', function() {
286
326
  }
287
327
  };
288
328
  db.query('testcollection', query, null, null, function(err) {
289
- expect(err).ok();
329
+ expect(err).ok;
290
330
  done();
291
331
  });
292
332
  });
@@ -322,7 +362,7 @@ describe('mongo db', function() {
322
362
  };
323
363
  db.query('testcollection', query, null, null, function(err, results, extra) {
324
364
  if (err) return done(err);
325
- expect(extra).eql([{_id: 'a', value: 12}, {_id: 'b', value: 15}]);
365
+ expect(extra).to.have.deep.members([{_id: 'a', value: 12}, {_id: 'b', value: 15}]);
326
366
  done();
327
367
  });
328
368
  });
@@ -335,11 +375,11 @@ describe('mongo db', function() {
335
375
  describe('mongo db connection', function() {
336
376
  describe('via url string', function() {
337
377
  beforeEach(function(done) {
338
- this.db = ShareDbMongo({mongo: mongoUrl});
378
+ this.db = new ShareDbMongo({mongo: mongoUrl});
339
379
 
340
380
  // This will enqueue the callback, testing the 'pendingConnect'
341
381
  // logic.
342
- this.db.getDbs(function(err, mongo, mongoPoll) {
382
+ this.db.getDbs(function(err, mongo) {
343
383
  if (err) return done(err);
344
384
  mongo.dropDatabase(function(err) {
345
385
  if (err) return done(err);
@@ -353,7 +393,7 @@ describe('mongo db connection', function() {
353
393
  });
354
394
 
355
395
  it('commit and query', function(done) {
356
- var snapshot = {type: 'json0', v: 1, data: {}, id: "test", m: null};
396
+ var snapshot = {type: 'json0', v: 1, data: {}, id: 'test', m: null};
357
397
  var db = this.db;
358
398
 
359
399
  db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
@@ -370,7 +410,7 @@ describe('mongo db connection', function() {
370
410
  describe('via url string with mongoPoll and pollDelay option', function() {
371
411
  beforeEach(function(done) {
372
412
  this.pollDelay = 1000;
373
- this.db = ShareDbMongo({mongo: mongoUrl, mongoPoll: mongoUrl, pollDelay: this.pollDelay});
413
+ this.db = new ShareDbMongo({mongo: mongoUrl, mongoPoll: mongoUrl, pollDelay: this.pollDelay});
374
414
  done();
375
415
  });
376
416
 
@@ -382,7 +422,7 @@ describe('mongo db connection', function() {
382
422
  var db = this.db;
383
423
  var pollDelay = this.pollDelay;
384
424
 
385
- var snapshot = {type: 'json0', v: 1, data: {}, id: "test"};
425
+ var snapshot = {type: 'json0', v: 1, data: {}, id: 'test'};
386
426
  var timeBeforeCommit = new Date;
387
427
  db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
388
428
  if (err) return done(err);
@@ -482,20 +522,54 @@ describe('parse query', function() {
482
522
  doesNotModify({foo: {$in: [1, 2, 3]}});
483
523
  addsType({foo: {$in: [null, 2, 3]}});
484
524
  doesNotModify({foo: {$in: [null, 2, 3]}, bar: 1});
485
- })
525
+ });
486
526
 
487
- it('top-level $and', function() {
527
+ it('top-level $and alone', function() {
488
528
  doesNotModify({$and: [{foo: {$ne: null}}, {bar: {$ne: null}}]});
489
529
  doesNotModify({$and: [{foo: {$ne: 1}}, {bar: {$ne: null}}]});
490
530
  addsType({$and: [{foo: {$ne: 1}}, {bar: {$ne: 1}}]});
491
531
  });
492
532
 
493
- it('top-level $or', function() {
533
+ describe('top-level $and with other conditions', function() {
534
+ // If the top-level $and could match a deleted doc, it should continue looking at the other
535
+ // top-level conditions.
536
+ it('does not add _type for "field: nonNullValue"', function() {
537
+ doesNotModify({$and: [{foo: {$ne: true}}], bar: 1});
538
+ });
539
+ });
540
+
541
+ it('top-level $or alone', function() {
494
542
  doesNotModify({$or: [{foo: {$ne: null}}, {bar: {$ne: null}}]});
495
543
  addsType({$or: [{foo: {$ne: 1}}, {bar: {$ne: null}}]});
496
544
  addsType({$or: [{foo: {$ne: 1}}, {bar: {$ne: 1}}]});
497
545
  });
498
546
 
547
+ describe('top-level $or with other conditions', function() {
548
+ // With conditions at top level that don't match deleted docs, the $or doesn't matter.
549
+ it('does not add _type for "field: nonNullValue"', function() {
550
+ doesNotModify({$or: [{foo: {$ne: true}}], bar: 1});
551
+ });
552
+ it('does not add _type for $in with nonNullValues', function() {
553
+ doesNotModify({$or: [{foo: {$ne: true}}], bar: {$in: ['a', 'b']}});
554
+ });
555
+ // If the other conditions could match deleted docs, then the $or _does_ matter.
556
+ it('adds _type for "field: null"', function() {
557
+ addsType({$or: [{foo: {$ne: true}}], bar: null});
558
+ });
559
+ it('adds _type for $in with a null value', function() {
560
+ addsType({$or: [{foo: {$ne: true}}], bar: {$in: ['a', 'b', null]}});
561
+ });
562
+ it('does not add _type when all $or branches do not match deleted docs', function() {
563
+ doesNotModify({
564
+ $or: [
565
+ {foo: {$ne: null}},
566
+ {bar: 1}
567
+ ],
568
+ baz: null
569
+ });
570
+ });
571
+ });
572
+
499
573
  it('malformed queries', function() {
500
574
  // if we don't understand the query, definitely don't mark it as
501
575
  // "safe as is"
@@ -505,6 +579,8 @@ describe('parse query', function() {
505
579
  addsType({foo: {$bad: 1}});
506
580
  addsType({$bad: [2, 3]});
507
581
  addsType({$and: [[{foo: 1}]]});
582
+ addsType({$and: 1});
583
+ addsType({$expr: {$gt: {$subtract: ['$endDate', '$startDate']}}});
508
584
  });
509
585
  });
510
586
  });