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.
- package/.eslintrc.js +49 -0
- package/.github/workflows/test.yml +58 -0
- package/LICENSE +21 -0
- package/README.md +205 -59
- package/index.js +367 -129
- package/mongodb.js +3 -0
- package/op-link-validator.js +78 -0
- package/package.json +25 -11
- package/src/middleware/actions.js +9 -0
- package/src/middleware/middlewareHandler.js +66 -0
- package/test/mocha.opts +1 -0
- package/test/setup.js +10 -0
- package/test/test_get_ops.js +135 -0
- package/test/test_get_ops_without_strict_linking.js +189 -0
- package/test/test_mongo.js +121 -45
- package/test/test_mongo_middleware.js +469 -0
- package/test/test_op_link_validator.js +159 -0
- package/test/test_skip_poll.js +8 -5
- package/.npmignore +0 -4
- package/.travis.yml +0 -27
package/test/test_mongo.js
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
var expect = require('
|
|
2
|
-
var
|
|
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(
|
|
10
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
84
|
-
|
|
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
|
|
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(
|
|
158
|
-
var snapshot = {type: 'json0', v: 1, data: {}, id:
|
|
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
|
|
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).
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
});
|