sharedb-mongo 1.0.0-beta.8 → 2.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 +70 -61
- package/index.js +275 -128
- package/mongodb.js +3 -0
- package/op-link-validator.js +8 -8
- package/package.json +25 -12
- 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 +66 -69
- package/test/test_mongo.js +121 -45
- package/test/test_mongo_middleware.js +469 -0
- package/test/test_op_link_validator.js +49 -49
- package/test/test_skip_poll.js +8 -5
- package/.travis.yml +0 -27
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
var async = require('async');
|
|
2
|
+
var sinon = require('sinon');
|
|
3
|
+
var chai = require('chai');
|
|
4
|
+
chai.use(require('sinon-chai'));
|
|
5
|
+
var expect = chai.expect;
|
|
6
|
+
var ShareDbMongo = require('..');
|
|
7
|
+
var mongodb = require('./../mongodb');
|
|
8
|
+
var Collection = mongodb.Collection;
|
|
9
|
+
|
|
10
|
+
var mongoUrl = process.env.TEST_MONGO_URL || 'mongodb://localhost:27017/test';
|
|
11
|
+
var BEFORE_EDIT = ShareDbMongo.MiddlewareActions.beforeOverwrite;
|
|
12
|
+
var BEFORE_CREATE = ShareDbMongo.MiddlewareActions.beforeCreate;
|
|
13
|
+
var BEFORE_SNAPSHOT_LOOKUP = ShareDbMongo.MiddlewareActions.beforeSnapshotLookup;
|
|
14
|
+
|
|
15
|
+
function create(callback) {
|
|
16
|
+
var db = new ShareDbMongo(mongoUrl);
|
|
17
|
+
db.getDbs(function(err, mongo) {
|
|
18
|
+
if (err) return callback(err);
|
|
19
|
+
mongo.dropDatabase(function(err) {
|
|
20
|
+
if (err) return callback(err);
|
|
21
|
+
callback(null, db, mongo);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('mongo db middleware', function() {
|
|
27
|
+
var sandbox = sinon.createSandbox();
|
|
28
|
+
var db;
|
|
29
|
+
|
|
30
|
+
beforeEach(function(done) {
|
|
31
|
+
sandbox.spy(Collection.prototype, 'find');
|
|
32
|
+
create(function(err, createdDb) {
|
|
33
|
+
if (err) return done(err);
|
|
34
|
+
db = createdDb;
|
|
35
|
+
done();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(function(done) {
|
|
40
|
+
sandbox.restore();
|
|
41
|
+
db.close(done);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('error handling', function() {
|
|
45
|
+
it('throws error when no action is given', function() {
|
|
46
|
+
function invalidAction() {
|
|
47
|
+
db.use(null, function(_request, next) {
|
|
48
|
+
next();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
expect(invalidAction).to.throw();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('throws error when no handler is given', function() {
|
|
55
|
+
function invalidAction() {
|
|
56
|
+
db.use('someAction');
|
|
57
|
+
}
|
|
58
|
+
expect(invalidAction).to.throw();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('throws error on unrecognized action name', function() {
|
|
62
|
+
function invalidAction() {
|
|
63
|
+
db.use('someAction', function(_request, next) {
|
|
64
|
+
next();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
expect(invalidAction).to.throw();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe(BEFORE_EDIT, function() {
|
|
72
|
+
it('has the expected properties on the request object', function(done) {
|
|
73
|
+
db.use(BEFORE_EDIT, function(request, next) {
|
|
74
|
+
expect(request).to.have.all.keys([
|
|
75
|
+
'action',
|
|
76
|
+
'collectionName',
|
|
77
|
+
'documentToWrite',
|
|
78
|
+
'op',
|
|
79
|
+
'options',
|
|
80
|
+
'query'
|
|
81
|
+
]);
|
|
82
|
+
expect(request.action).to.equal(BEFORE_EDIT);
|
|
83
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
84
|
+
expect(request.documentToWrite.foo).to.equal('fuzz');
|
|
85
|
+
expect(request.op.op).to.exist;
|
|
86
|
+
expect(request.options.testOptions).to.equal('yes');
|
|
87
|
+
expect(request.query._id).to.equal('test1');
|
|
88
|
+
next();
|
|
89
|
+
done();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
93
|
+
var editOp = {v: 2, op: [{p: ['foo'], oi: 'bar', oi: 'baz'}], m: {ts: Date.now()}};
|
|
94
|
+
var newSnapshot = {type: 'json0', id: 'test1', v: 2, data: {foo: 'fuzz'}};
|
|
95
|
+
|
|
96
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
97
|
+
if (err) return done(err);
|
|
98
|
+
db.commit('testcollection', snapshot.id, editOp, newSnapshot, {testOptions: 'yes'}, function(err) {
|
|
99
|
+
if (err) return done(err);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should augment query filter and write to the document when commit is called', function(done) {
|
|
105
|
+
// Augment the query. The original query looks up the document by id, wheras this middleware
|
|
106
|
+
// changes it to use the `foo` property. The end result still returns the same document. The next
|
|
107
|
+
// middleware ensures we attached it to the request.
|
|
108
|
+
// We can't truly change which document is returned from the query because MongoDB will not allow
|
|
109
|
+
// the immutable fields such as `_id` to be changed.
|
|
110
|
+
db.use(BEFORE_EDIT, function(request, next) {
|
|
111
|
+
request.query.foo = 'bar';
|
|
112
|
+
next();
|
|
113
|
+
});
|
|
114
|
+
// Attach this middleware to check that the original one is passing the context
|
|
115
|
+
// correctly. Commit will be called after this.
|
|
116
|
+
db.use(BEFORE_EDIT, function(request, next) {
|
|
117
|
+
expect(request.query).to.deep.equal({
|
|
118
|
+
_id: 'test1',
|
|
119
|
+
_v: 1,
|
|
120
|
+
foo: 'bar'
|
|
121
|
+
});
|
|
122
|
+
next();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
126
|
+
var editOp = {v: 2, op: [{p: ['foo'], oi: 'bar', oi: 'baz'}], m: {ts: Date.now()}};
|
|
127
|
+
var newSnapshot = {type: 'json0', id: 'test1', v: 2, data: {foo: 'baz'}};
|
|
128
|
+
|
|
129
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
130
|
+
if (err) return done(err);
|
|
131
|
+
expectDocumentToContainFoo('bar', function() {
|
|
132
|
+
db.commit('testcollection', snapshot.id, editOp, newSnapshot, null, function(err) {
|
|
133
|
+
if (err) return done(err);
|
|
134
|
+
// Ensure the value is updated as expected
|
|
135
|
+
expectDocumentToContainFoo('baz', done);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should augment the written document when commit is called', function(done) {
|
|
143
|
+
// Change the written value of foo to be `fuzz`
|
|
144
|
+
db.use(BEFORE_EDIT, function(request, next) {
|
|
145
|
+
request.documentToWrite.foo = 'fuzz';
|
|
146
|
+
next();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
150
|
+
|
|
151
|
+
// Issue a commit to change `bar` to `baz`
|
|
152
|
+
var editOp = {v: 2, op: [{p: ['foo'], oi: 'bar', oi: 'baz'}], m: {ts: Date.now()}};
|
|
153
|
+
var newSnapshot = {type: 'json0', id: 'test1', v: 2, data: {foo: 'baz'}};
|
|
154
|
+
|
|
155
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
156
|
+
if (err) return done(err);
|
|
157
|
+
expectDocumentToContainFoo('bar', function() {
|
|
158
|
+
db.commit('testcollection', snapshot.id, editOp, newSnapshot, null, function(err) {
|
|
159
|
+
if (err) return done(err);
|
|
160
|
+
// Ensure the value is updated as expected
|
|
161
|
+
expectDocumentToContainFoo('fuzz', done);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe(BEFORE_CREATE, function() {
|
|
168
|
+
it('has the expected properties on the request object', function(done) {
|
|
169
|
+
db.use(BEFORE_CREATE, function(request, next) {
|
|
170
|
+
expect(request).to.have.all.keys([
|
|
171
|
+
'action',
|
|
172
|
+
'collectionName',
|
|
173
|
+
'documentToWrite',
|
|
174
|
+
'op',
|
|
175
|
+
'options'
|
|
176
|
+
]);
|
|
177
|
+
expect(request.action).to.equal(BEFORE_CREATE);
|
|
178
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
179
|
+
expect(request.documentToWrite.foo).to.equal('bar');
|
|
180
|
+
expect(request.op).to.exist;
|
|
181
|
+
expect(request.options.testOptions).to.equal('baz');
|
|
182
|
+
next();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
186
|
+
|
|
187
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, {testOptions: 'baz'}, done);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should augment the written document when commit is called', function(done) {
|
|
191
|
+
// Change the written value of foo to be `fuzz`
|
|
192
|
+
db.use(BEFORE_CREATE, function(request, next) {
|
|
193
|
+
request.documentToWrite.foo = 'fuzz';
|
|
194
|
+
next();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
198
|
+
|
|
199
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
200
|
+
if (err) return done(err);
|
|
201
|
+
expectDocumentToContainFoo('fuzz', done);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('returns without writing when there was a middleware error', function(done) {
|
|
206
|
+
db.use(BEFORE_CREATE, function(_, next) {
|
|
207
|
+
next(new Error('Oh no!'));
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
211
|
+
|
|
212
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
213
|
+
expectDocumentNotToExist(function() {
|
|
214
|
+
if (err) return done();
|
|
215
|
+
done('Expected an error, did not get one');
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe(BEFORE_SNAPSHOT_LOOKUP, function() {
|
|
222
|
+
it('has the expected properties on the request object before getting a single snapshot', function(done) {
|
|
223
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
|
|
224
|
+
expect(request).to.have.all.keys([
|
|
225
|
+
'action',
|
|
226
|
+
'collectionName',
|
|
227
|
+
'options',
|
|
228
|
+
'query'
|
|
229
|
+
]);
|
|
230
|
+
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
|
|
231
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
232
|
+
expect(request.options.testOptions).to.equal('yes');
|
|
233
|
+
expect(request.query._id).to.equal('test1');
|
|
234
|
+
next();
|
|
235
|
+
done();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
239
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
240
|
+
if (err) return done(err);
|
|
241
|
+
db.getSnapshot('testcollection', 'test1', null, {testOptions: 'yes'}, function(err, doc) {
|
|
242
|
+
if (err) return done(err);
|
|
243
|
+
expect(doc).to.exist;
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('passes triggeredBy = submitRequest when fields has $submit = true', function(done) {
|
|
249
|
+
var middlewareSpy = sinon.spy(function(request, next) {
|
|
250
|
+
expect(request).to.have.all.keys([
|
|
251
|
+
'action',
|
|
252
|
+
'collectionName',
|
|
253
|
+
'options',
|
|
254
|
+
'query',
|
|
255
|
+
'triggeredBy'
|
|
256
|
+
]);
|
|
257
|
+
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
|
|
258
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
259
|
+
expect(request.options.testOptions).to.equal('yes');
|
|
260
|
+
expect(request.triggeredBy).to.equal('submitRequest');
|
|
261
|
+
expect(request.query._id).to.equal('test1');
|
|
262
|
+
// test that when we set findOptions in the middleware, they get passed to the Mongo driver.
|
|
263
|
+
request.findOptions = {
|
|
264
|
+
maxTimeMS: 999
|
|
265
|
+
};
|
|
266
|
+
next();
|
|
267
|
+
});
|
|
268
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, middlewareSpy);
|
|
269
|
+
|
|
270
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
271
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
272
|
+
if (err) return done(err);
|
|
273
|
+
db.getSnapshot('testcollection', 'test1', {
|
|
274
|
+
$submit: true
|
|
275
|
+
}, {testOptions: 'yes'}, function(err, doc) {
|
|
276
|
+
if (err) return done(err);
|
|
277
|
+
expect(doc).to.exist;
|
|
278
|
+
expect(middlewareSpy).to.have.been.calledOnceWith(sinon.match.object, sinon.match.func);
|
|
279
|
+
expect(Collection.prototype.find).to.have.been.calledOnceWith({
|
|
280
|
+
_id: snapshot.id
|
|
281
|
+
}, {
|
|
282
|
+
maxTimeMS: 999
|
|
283
|
+
});
|
|
284
|
+
done();
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('has the expected properties on the request object before getting ops', function(done) {
|
|
290
|
+
var middlewareSpy = sinon.spy(function(request, next) {
|
|
291
|
+
expect(request).to.have.all.keys([
|
|
292
|
+
'action',
|
|
293
|
+
'collectionName',
|
|
294
|
+
'options',
|
|
295
|
+
'query'
|
|
296
|
+
]);
|
|
297
|
+
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
|
|
298
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
299
|
+
expect(request.options.testOptions).to.equal('yes');
|
|
300
|
+
expect(request.query._id).to.deep.equal('test2');
|
|
301
|
+
next();
|
|
302
|
+
});
|
|
303
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, middlewareSpy);
|
|
304
|
+
|
|
305
|
+
var snapshot = {type: 'json0', id: 'test2', v: 1, data: {foo: 'bar'}};
|
|
306
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
307
|
+
if (err) return done(err);
|
|
308
|
+
db.getOps('testcollection', 'test2', 0, 1, {testOptions: 'yes'}, function(err) {
|
|
309
|
+
if (err) return done(err);
|
|
310
|
+
/*
|
|
311
|
+
Don't finalize the test in the middleware - since getOps will make queries *after* the middleware is fired.
|
|
312
|
+
If we call done() in the middleware, we'll close the db connection, and then getOps will call _getOps()
|
|
313
|
+
which will throw a "db connection closed" error.
|
|
314
|
+
*/
|
|
315
|
+
expect(middlewareSpy).to.have.been.calledOnceWith(sinon.match.object, sinon.match.func);
|
|
316
|
+
done();
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('has the expected properties on the request object before getting ops bulk', function(done) {
|
|
322
|
+
var middlewareSpy = sinon.spy(function(request, next) {
|
|
323
|
+
expect(request).to.have.all.keys([
|
|
324
|
+
'action',
|
|
325
|
+
'collectionName',
|
|
326
|
+
'options',
|
|
327
|
+
'query'
|
|
328
|
+
]);
|
|
329
|
+
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
|
|
330
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
331
|
+
expect(request.options.testOptions).to.equal('yes');
|
|
332
|
+
expect(request.query._id).to.deep.equal({$in: ['test2']});
|
|
333
|
+
next();
|
|
334
|
+
});
|
|
335
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, middlewareSpy);
|
|
336
|
+
|
|
337
|
+
var snapshot = {type: 'json0', id: 'test2', v: 1, data: {foo: 'bar'}};
|
|
338
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
339
|
+
if (err) return done(err);
|
|
340
|
+
db.getOpsBulk('testcollection', {
|
|
341
|
+
test2: 0
|
|
342
|
+
}, {
|
|
343
|
+
test2: 1
|
|
344
|
+
}, {testOptions: 'yes'}, function(err) {
|
|
345
|
+
if (err) return done(err);
|
|
346
|
+
/*
|
|
347
|
+
Don't finalize the test in the middleware - since getOps will make queries *after* the middleware is fired.
|
|
348
|
+
If we call done() in the middleware, we'll close the db connection, and then getOps will call _getOps()
|
|
349
|
+
which will throw a "db connection closed" error.
|
|
350
|
+
*/
|
|
351
|
+
expect(middlewareSpy).to.have.been.calledOnceWith(sinon.match.object, sinon.match.func);
|
|
352
|
+
done();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('has the expected properties on the request object before getting bulk snapshots', function(done) {
|
|
358
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
|
|
359
|
+
expect(request).to.have.all.keys([
|
|
360
|
+
'action',
|
|
361
|
+
'collectionName',
|
|
362
|
+
'options',
|
|
363
|
+
'query'
|
|
364
|
+
]);
|
|
365
|
+
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
|
|
366
|
+
expect(request.collectionName).to.equal('testcollection');
|
|
367
|
+
expect(request.options.testOptions).to.equal('yes');
|
|
368
|
+
expect(request.query._id).to.deep.equal({$in: ['test1']});
|
|
369
|
+
next();
|
|
370
|
+
done();
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
|
|
374
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
|
|
375
|
+
if (err) return done(err);
|
|
376
|
+
db.getSnapshotBulk('testcollection', ['test1'], null, {testOptions: 'yes'}, function(err, doc) {
|
|
377
|
+
if (err) return done(err);
|
|
378
|
+
expect(doc).to.exist;
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should augment the query when getSnapshot is called', function(done) {
|
|
384
|
+
var snapshots = [
|
|
385
|
+
{type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}},
|
|
386
|
+
{type: 'json0', id: 'test2', v: 1, data: {foo: 'baz'}}
|
|
387
|
+
];
|
|
388
|
+
|
|
389
|
+
async.each(snapshots, function(snapshot, cb) {
|
|
390
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, cb);
|
|
391
|
+
}, function(err) {
|
|
392
|
+
if (err) return done(err);
|
|
393
|
+
db.getSnapshot('testcollection', 'test1', null, null, function(err, doc) {
|
|
394
|
+
if (err) return done(err);
|
|
395
|
+
expect(doc.data).eql({
|
|
396
|
+
foo: 'bar'
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Change the query to look for baz and not bar
|
|
400
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
|
|
401
|
+
request.query = {_id: 'test2'};
|
|
402
|
+
next();
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
db.getSnapshot('testcollection', 'test1', null, null, function(err, doc) {
|
|
406
|
+
if (err) return done(err);
|
|
407
|
+
expect(doc.data).eql({
|
|
408
|
+
foo: 'baz'
|
|
409
|
+
});
|
|
410
|
+
done();
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it('should augment the query when getSnapshotBulk is called', function(done) {
|
|
417
|
+
var snapshots = [
|
|
418
|
+
{type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}},
|
|
419
|
+
{type: 'json0', id: 'test2', v: 1, data: {foo: 'baz'}}
|
|
420
|
+
];
|
|
421
|
+
|
|
422
|
+
async.each(snapshots, function(snapshot, cb) {
|
|
423
|
+
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, cb);
|
|
424
|
+
}, function(err) {
|
|
425
|
+
if (err) return done(err);
|
|
426
|
+
db.getSnapshotBulk('testcollection', ['test1', 'test2'], null, null, function(err, docs) {
|
|
427
|
+
if (err) return done(err);
|
|
428
|
+
expect(docs.test1.data.foo).to.equal('bar');
|
|
429
|
+
expect(docs.test2.data.foo).to.equal('baz');
|
|
430
|
+
|
|
431
|
+
// Change the query to look for baz and not bar
|
|
432
|
+
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
|
|
433
|
+
request.query = {_id: {$in: ['test2']}};
|
|
434
|
+
next();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
db.getSnapshotBulk('testcollection', ['test1', 'test2'], null, null, function(err, docs) {
|
|
438
|
+
if (err) return done(err);
|
|
439
|
+
expect(docs.test1.data).not.to.exist;
|
|
440
|
+
expect(docs.test2.data.foo).to.equal('baz');
|
|
441
|
+
done();
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
function expectDocumentToContainFoo(valueOfFoo, cb) {
|
|
449
|
+
var query = {_id: 'test1'};
|
|
450
|
+
|
|
451
|
+
db.query('testcollection', query, null, null, function(err, results) {
|
|
452
|
+
if (err) return done(err);
|
|
453
|
+
expect(results[0].data).eql({
|
|
454
|
+
foo: valueOfFoo
|
|
455
|
+
});
|
|
456
|
+
cb();
|
|
457
|
+
});
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
function expectDocumentNotToExist(cb) {
|
|
461
|
+
var query = {_id: 'test1'};
|
|
462
|
+
|
|
463
|
+
db.query('testcollection', query, null, null, function(err, results) {
|
|
464
|
+
if (err) return cb(err);
|
|
465
|
+
expect(results).to.be.empty;
|
|
466
|
+
cb();
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
});
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
var OpLinkValidator = require('../op-link-validator');
|
|
2
|
-
var expect = require('
|
|
2
|
+
var expect = require('chai').expect;
|
|
3
3
|
|
|
4
|
-
describe('OpLinkValidator', function
|
|
5
|
-
it('starts with no unique op', function
|
|
4
|
+
describe('OpLinkValidator', function() {
|
|
5
|
+
it('starts with no unique op', function() {
|
|
6
6
|
var validator = new OpLinkValidator();
|
|
7
7
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
8
|
-
expect(opWithUniqueVersion).to.
|
|
8
|
+
expect(opWithUniqueVersion).to.equal(null);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
it('starts not at the end of the list', function
|
|
11
|
+
it('starts not at the end of the list', function() {
|
|
12
12
|
var validator = new OpLinkValidator();
|
|
13
|
-
expect(validator.isAtEndOfList()).to.
|
|
13
|
+
expect(validator.isAtEndOfList()).to.equal(false);
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
it('has no unique op with just one op', function
|
|
16
|
+
it('has no unique op with just one op', function() {
|
|
17
17
|
var op = {v: 1};
|
|
18
18
|
var validator = new OpLinkValidator();
|
|
19
19
|
|
|
20
20
|
validator.push(op);
|
|
21
21
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
22
22
|
|
|
23
|
-
expect(opWithUniqueVersion).to.
|
|
23
|
+
expect(opWithUniqueVersion).to.equal(null);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it('has a unique op with just two different ops', function
|
|
26
|
+
it('has a unique op with just two different ops', function() {
|
|
27
27
|
var op1 = {v: 1};
|
|
28
28
|
var op2 = {v: 2};
|
|
29
29
|
var validator = new OpLinkValidator();
|
|
@@ -32,22 +32,22 @@ describe('OpLinkValidator', function () {
|
|
|
32
32
|
validator.push(op2);
|
|
33
33
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
34
34
|
|
|
35
|
-
expect(opWithUniqueVersion).to.
|
|
35
|
+
expect(opWithUniqueVersion).to.equal(op1);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
it('does not have a uniquye op with just two identical ops', function
|
|
39
|
-
var op1 = {
|
|
40
|
-
var op2 = {
|
|
38
|
+
it('does not have a uniquye op with just two identical ops', function() {
|
|
39
|
+
var op1 = {v: 1};
|
|
40
|
+
var op2 = {v: 1};
|
|
41
41
|
var validator = new OpLinkValidator();
|
|
42
42
|
|
|
43
43
|
validator.push(op1);
|
|
44
44
|
validator.push(op2);
|
|
45
45
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
46
46
|
|
|
47
|
-
expect(opWithUniqueVersion).to.
|
|
47
|
+
expect(opWithUniqueVersion).to.equal(null);
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
it('has a unique op with three ops with different versions', function
|
|
50
|
+
it('has a unique op with three ops with different versions', function() {
|
|
51
51
|
var op1 = {v: 1};
|
|
52
52
|
var op2 = {v: 2};
|
|
53
53
|
var op3 = {v: 3};
|
|
@@ -58,24 +58,24 @@ describe('OpLinkValidator', function () {
|
|
|
58
58
|
validator.push(op3);
|
|
59
59
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
60
60
|
|
|
61
|
-
expect(opWithUniqueVersion).to.
|
|
61
|
+
expect(opWithUniqueVersion).to.equal(op2);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('is not at the end of the list with three ops', function
|
|
65
|
-
var op1 = {
|
|
66
|
-
var op2 = {
|
|
67
|
-
var op3 = {
|
|
64
|
+
it('is not at the end of the list with three ops', function() {
|
|
65
|
+
var op1 = {v: 1};
|
|
66
|
+
var op2 = {v: 2};
|
|
67
|
+
var op3 = {v: 3};
|
|
68
68
|
var validator = new OpLinkValidator();
|
|
69
69
|
|
|
70
70
|
validator.push(op1);
|
|
71
71
|
validator.push(op2);
|
|
72
72
|
validator.push(op3);
|
|
73
73
|
|
|
74
|
-
expect(validator.isAtEndOfList()).to.
|
|
74
|
+
expect(validator.isAtEndOfList()).to.equal(false);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it('does not have a unique op with three ops with the same version', function
|
|
78
|
-
var op = {
|
|
77
|
+
it('does not have a unique op with three ops with the same version', function() {
|
|
78
|
+
var op = {v: 1};
|
|
79
79
|
var validator = new OpLinkValidator();
|
|
80
80
|
|
|
81
81
|
validator.push(op);
|
|
@@ -83,13 +83,13 @@ describe('OpLinkValidator', function () {
|
|
|
83
83
|
validator.push(op);
|
|
84
84
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
85
85
|
|
|
86
|
-
expect(opWithUniqueVersion).to.
|
|
86
|
+
expect(opWithUniqueVersion).to.equal(null);
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
it('does not have a unique op if the first two ops are the same', function
|
|
90
|
-
var op1 = {
|
|
91
|
-
var op2 = {
|
|
92
|
-
var op3 = {
|
|
89
|
+
it('does not have a unique op if the first two ops are the same', function() {
|
|
90
|
+
var op1 = {v: 1};
|
|
91
|
+
var op2 = {v: 1};
|
|
92
|
+
var op3 = {v: 2};
|
|
93
93
|
var validator = new OpLinkValidator();
|
|
94
94
|
|
|
95
95
|
validator.push(op1);
|
|
@@ -97,13 +97,13 @@ describe('OpLinkValidator', function () {
|
|
|
97
97
|
validator.push(op3);
|
|
98
98
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
99
99
|
|
|
100
|
-
expect(opWithUniqueVersion).to.
|
|
100
|
+
expect(opWithUniqueVersion).to.equal(null);
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
it('does not have a unique op if the last two ops are the same', function
|
|
104
|
-
var op1 = {
|
|
105
|
-
var op2 = {
|
|
106
|
-
var op3 = {
|
|
103
|
+
it('does not have a unique op if the last two ops are the same', function() {
|
|
104
|
+
var op1 = {v: 1};
|
|
105
|
+
var op2 = {v: 2};
|
|
106
|
+
var op3 = {v: 2};
|
|
107
107
|
var validator = new OpLinkValidator();
|
|
108
108
|
|
|
109
109
|
validator.push(op1);
|
|
@@ -111,17 +111,17 @@ describe('OpLinkValidator', function () {
|
|
|
111
111
|
validator.push(op3);
|
|
112
112
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
113
113
|
|
|
114
|
-
expect(opWithUniqueVersion).to.
|
|
114
|
+
expect(opWithUniqueVersion).to.equal(null);
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
it('has a unique op in a long chain', function
|
|
118
|
-
var op1 = {
|
|
119
|
-
var op2 = {
|
|
120
|
-
var op3 = {
|
|
121
|
-
var op4 = {
|
|
122
|
-
var op5 = {
|
|
123
|
-
var op6 = {
|
|
124
|
-
var op7 = {
|
|
117
|
+
it('has a unique op in a long chain', function() {
|
|
118
|
+
var op1 = {v: 1};
|
|
119
|
+
var op2 = {v: 1};
|
|
120
|
+
var op3 = {v: 1};
|
|
121
|
+
var op4 = {v: 2};
|
|
122
|
+
var op5 = {v: 2};
|
|
123
|
+
var op6 = {v: 3};
|
|
124
|
+
var op7 = {v: 4};
|
|
125
125
|
var validator = new OpLinkValidator();
|
|
126
126
|
|
|
127
127
|
validator.push(op1);
|
|
@@ -133,12 +133,12 @@ describe('OpLinkValidator', function () {
|
|
|
133
133
|
validator.push(op7);
|
|
134
134
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
135
135
|
|
|
136
|
-
expect(opWithUniqueVersion).to.
|
|
136
|
+
expect(opWithUniqueVersion).to.equal(op6);
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
it('has a unique op with two ops and a current op of null', function
|
|
140
|
-
var op1 = {
|
|
141
|
-
var op2 = {
|
|
139
|
+
it('has a unique op with two ops and a current op of null', function() {
|
|
140
|
+
var op1 = {v: 1};
|
|
141
|
+
var op2 = {v: 2};
|
|
142
142
|
var op3 = null;
|
|
143
143
|
var validator = new OpLinkValidator();
|
|
144
144
|
|
|
@@ -147,13 +147,13 @@ describe('OpLinkValidator', function () {
|
|
|
147
147
|
validator.push(op3);
|
|
148
148
|
var opWithUniqueVersion = validator.opWithUniqueVersion();
|
|
149
149
|
|
|
150
|
-
expect(opWithUniqueVersion).to.
|
|
150
|
+
expect(opWithUniqueVersion).to.equal(op2);
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
-
it('is at the end of the list with a current op of null', function
|
|
153
|
+
it('is at the end of the list with a current op of null', function() {
|
|
154
154
|
var op = null;
|
|
155
155
|
var validator = new OpLinkValidator();
|
|
156
156
|
validator.push(op);
|
|
157
|
-
expect(validator.isAtEndOfList()).to.
|
|
157
|
+
expect(validator.isAtEndOfList()).to.equal(true);
|
|
158
158
|
});
|
|
159
159
|
});
|