sharedb-mongo 1.0.0 → 2.1.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/.github/workflows/test.yml +8 -3
- package/index.js +202 -175
- package/package.json +6 -5
- package/test/test_get_ops.js +9 -7
- package/test/test_get_ops_without_strict_linking.js +25 -11
- package/test/test_mongo.js +17 -12
- package/test/test_mongo_middleware.js +5 -4
|
@@ -7,17 +7,22 @@ on:
|
|
|
7
7
|
pull_request:
|
|
8
8
|
branches:
|
|
9
9
|
- master
|
|
10
|
+
# Allow manually triggering tests
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
branches:
|
|
13
|
+
- master
|
|
10
14
|
|
|
11
15
|
jobs:
|
|
12
16
|
test:
|
|
13
17
|
name: Node.js ${{ matrix.node }} + mongoDB ${{ matrix.mongodb }}
|
|
14
18
|
runs-on: ubuntu-latest
|
|
15
19
|
strategy:
|
|
20
|
+
fail-fast: false
|
|
16
21
|
matrix:
|
|
17
22
|
node:
|
|
18
|
-
- 12
|
|
19
23
|
- 14
|
|
20
24
|
- 16
|
|
25
|
+
- 18
|
|
21
26
|
mongodb:
|
|
22
27
|
- 4.0
|
|
23
28
|
- 4.2
|
|
@@ -30,8 +35,8 @@ jobs:
|
|
|
30
35
|
- 27017:27017
|
|
31
36
|
timeout-minutes: 10
|
|
32
37
|
steps:
|
|
33
|
-
- uses: actions/checkout@
|
|
34
|
-
- uses: actions/setup-node@
|
|
38
|
+
- uses: actions/checkout@v3
|
|
39
|
+
- uses: actions/setup-node@v3
|
|
35
40
|
with:
|
|
36
41
|
node-version: ${{ matrix.node }}
|
|
37
42
|
- name: Install
|
package/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
var async = require('async');
|
|
2
1
|
var mongodb = require('./mongodb');
|
|
3
2
|
var DB = require('sharedb').DB;
|
|
4
3
|
var OpLinkValidator = require('./op-link-validator');
|
|
@@ -55,15 +54,21 @@ function ShareDbMongo(mongo, options) {
|
|
|
55
54
|
// Track whether the close method has been called
|
|
56
55
|
this.closed = false;
|
|
57
56
|
|
|
57
|
+
this.mongo = null;
|
|
58
|
+
this._mongoClient = null;
|
|
59
|
+
this.mongoPoll = null;
|
|
60
|
+
this._mongoPollClient = null;
|
|
61
|
+
|
|
58
62
|
if (typeof mongo === 'string' || typeof mongo === 'function') {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
var self = this;
|
|
64
|
+
this._connection = this._connect(mongo, options)
|
|
65
|
+
.then(function(result) {
|
|
66
|
+
self.mongo = result.mongo;
|
|
67
|
+
self._mongoClient = result.mongoClient;
|
|
68
|
+
self.mongoPoll = result.mongoPoll;
|
|
69
|
+
self._mongoPollClient = result.mongoPollClient;
|
|
70
|
+
return result;
|
|
71
|
+
});
|
|
67
72
|
} else {
|
|
68
73
|
throw new Error('deprecated: pass mongo as url string or function with callback');
|
|
69
74
|
}
|
|
@@ -115,19 +120,10 @@ ShareDbMongo.prototype.getDbs = function(callback) {
|
|
|
115
120
|
var err = ShareDbMongo.alreadyClosedError();
|
|
116
121
|
return callback(err);
|
|
117
122
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.pendingConnect.push(callback);
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
ShareDbMongo.prototype._flushPendingConnect = function() {
|
|
126
|
-
var pendingConnect = this.pendingConnect;
|
|
127
|
-
this.pendingConnect = null;
|
|
128
|
-
for (var i = 0; i < pendingConnect.length; i++) {
|
|
129
|
-
pendingConnect[i](null, this.mongo, this.mongoPoll);
|
|
130
|
-
}
|
|
123
|
+
this._connection
|
|
124
|
+
.then(function(result) {
|
|
125
|
+
callback(null, result.mongo, result.mongoPoll);
|
|
126
|
+
}, callback);
|
|
131
127
|
};
|
|
132
128
|
|
|
133
129
|
function isLegacyMongoClient(client) {
|
|
@@ -145,72 +141,55 @@ ShareDbMongo.prototype._connect = function(mongo, options) {
|
|
|
145
141
|
//
|
|
146
142
|
// Throw errors in this function if we fail to connect, since we aren't
|
|
147
143
|
// implementing a way to retry
|
|
148
|
-
var
|
|
144
|
+
var connections = [connect(mongo, options.mongoOptions)];
|
|
149
145
|
var mongoPoll = options.mongoPoll;
|
|
150
|
-
if (mongoPoll)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
146
|
+
if (mongoPoll) connections.push(connect(mongoPoll, options.mongoPollOptions));
|
|
147
|
+
|
|
148
|
+
return Promise.all(connections).then(function(clients) {
|
|
149
|
+
var mongoClient = clients[0];
|
|
150
|
+
var mongoPollClient = clients[1];
|
|
151
|
+
var result = {
|
|
152
|
+
mongo: mongoClient,
|
|
153
|
+
mongoClient: mongoClient,
|
|
154
|
+
mongoPoll: mongoPollClient,
|
|
155
|
+
mongoPollClient: mongoPollClient
|
|
154
156
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
var mongoPollClient = results.mongoPollClient;
|
|
159
|
-
if (isLegacyMongoClient(mongoClient)) {
|
|
160
|
-
self.mongo = self._mongoClient = mongoClient;
|
|
161
|
-
self.mongoPoll = self._mongoPollClient = mongoPollClient;
|
|
162
|
-
} else {
|
|
163
|
-
self.mongo = mongoClient.db();
|
|
164
|
-
self._mongoClient = mongoClient;
|
|
165
|
-
self.mongoPoll = mongoPollClient.db();
|
|
166
|
-
self._mongoPollClient = mongoPollClient;
|
|
167
|
-
}
|
|
168
|
-
self._flushPendingConnect();
|
|
169
|
-
});
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
var finish = function(err, client) {
|
|
173
|
-
if (err) throw err;
|
|
174
|
-
if (isLegacyMongoClient(client)) {
|
|
175
|
-
self.mongo = self._mongoClient = client;
|
|
176
|
-
} else {
|
|
177
|
-
self.mongo = client.db();
|
|
178
|
-
self._mongoClient = client;
|
|
157
|
+
if (!isLegacyMongoClient(mongoClient)) {
|
|
158
|
+
result.mongo = mongoClient.db();
|
|
159
|
+
if (mongoPollClient) result.mongoPoll = mongoPollClient.db();
|
|
179
160
|
}
|
|
180
|
-
|
|
181
|
-
};
|
|
182
|
-
if (typeof mongo === 'function') {
|
|
183
|
-
mongo(finish);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
// TODO: Don't pass options directly to mongodb.connect();
|
|
187
|
-
// only pass options.mongoOptions
|
|
188
|
-
var mongoOptions = options.mongoOptions || options;
|
|
189
|
-
connect(mongo, mongoOptions)(finish);
|
|
161
|
+
return result;
|
|
162
|
+
});
|
|
190
163
|
};
|
|
191
164
|
|
|
192
165
|
function connect(mongo, options) {
|
|
193
|
-
if (typeof mongo === 'function')
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
166
|
+
if (typeof mongo === 'function') {
|
|
167
|
+
return new Promise(function(resolve, reject) {
|
|
168
|
+
mongo(function(error, client) {
|
|
169
|
+
if (error) return reject(error);
|
|
170
|
+
resolve(client);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
options = Object.assign({}, options);
|
|
176
|
+
delete options.mongo;
|
|
177
|
+
delete options.mongoPoll;
|
|
178
|
+
delete options.mongoPollOptions;
|
|
179
|
+
delete options.pollDelay;
|
|
180
|
+
delete options.disableIndexCreation;
|
|
181
|
+
delete options.allowAllQueries;
|
|
182
|
+
delete options.allowJSQueries;
|
|
183
|
+
delete options.allowAllQueries;
|
|
184
|
+
delete options.allowAggregateQueries;
|
|
185
|
+
delete options.getOpsWithoutStrictLinking;
|
|
186
|
+
|
|
187
|
+
if (typeof mongodb.connect === 'function') {
|
|
188
|
+
return mongodb.connect(mongo, options);
|
|
189
|
+
} else {
|
|
190
|
+
var client = new mongodb.MongoClient(mongo, options);
|
|
191
|
+
return client.connect();
|
|
192
|
+
}
|
|
214
193
|
}
|
|
215
194
|
|
|
216
195
|
ShareDbMongo.prototype.close = function(callback) {
|
|
@@ -225,11 +204,13 @@ ShareDbMongo.prototype.close = function(callback) {
|
|
|
225
204
|
if (err && err.code === 5101) return callback();
|
|
226
205
|
if (err) return callback(err);
|
|
227
206
|
self.closed = true;
|
|
228
|
-
self._mongoClient.close(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
207
|
+
self._mongoClient.close()
|
|
208
|
+
.then(function() {
|
|
209
|
+
return self._mongoPollClient && self._mongoPollClient.close();
|
|
210
|
+
})
|
|
211
|
+
.then(function() {
|
|
212
|
+
callback(null);
|
|
213
|
+
}, callback);
|
|
233
214
|
});
|
|
234
215
|
};
|
|
235
216
|
|
|
@@ -280,14 +261,20 @@ ShareDbMongo.prototype._writeOp = function(collectionName, id, op, snapshot, cal
|
|
|
280
261
|
var doc = shallowClone(op);
|
|
281
262
|
doc.d = id;
|
|
282
263
|
doc.o = snapshot._opLink;
|
|
283
|
-
opCollection.insertOne(doc
|
|
264
|
+
opCollection.insertOne(doc)
|
|
265
|
+
.then(function(result) {
|
|
266
|
+
callback(null, result);
|
|
267
|
+
}, callback);
|
|
284
268
|
});
|
|
285
269
|
};
|
|
286
270
|
|
|
287
271
|
ShareDbMongo.prototype._deleteOp = function(collectionName, opId, callback) {
|
|
288
272
|
this.getOpCollection(collectionName, function(err, opCollection) {
|
|
289
273
|
if (err) return callback(err);
|
|
290
|
-
opCollection.deleteOne({_id: opId}
|
|
274
|
+
opCollection.deleteOne({_id: opId})
|
|
275
|
+
.then(function(result) {
|
|
276
|
+
callback(null, result);
|
|
277
|
+
}, callback);
|
|
291
278
|
});
|
|
292
279
|
};
|
|
293
280
|
|
|
@@ -301,17 +288,20 @@ ShareDbMongo.prototype._writeSnapshot = function(request, id, snapshot, opId, ca
|
|
|
301
288
|
if (middlewareErr) {
|
|
302
289
|
return callback(middlewareErr);
|
|
303
290
|
}
|
|
304
|
-
collection.insertOne(request.documentToWrite
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
291
|
+
collection.insertOne(request.documentToWrite)
|
|
292
|
+
.then(
|
|
293
|
+
function() {
|
|
294
|
+
callback(null, true);
|
|
295
|
+
},
|
|
296
|
+
function(err) {
|
|
297
|
+
// Return non-success instead of duplicate key error, since this is
|
|
298
|
+
// expected to occur during simultaneous creates on the same id
|
|
299
|
+
if (err.code === 11000 && /\b_id_\b/.test(err.message)) {
|
|
300
|
+
return callback(null, false);
|
|
301
|
+
}
|
|
302
|
+
return callback(err);
|
|
310
303
|
}
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
callback(null, true);
|
|
314
|
-
});
|
|
304
|
+
);
|
|
315
305
|
});
|
|
316
306
|
} else {
|
|
317
307
|
request.query = {_id: id, _v: request.documentToWrite._v - 1};
|
|
@@ -319,11 +309,11 @@ ShareDbMongo.prototype._writeSnapshot = function(request, id, snapshot, opId, ca
|
|
|
319
309
|
if (middlewareErr) {
|
|
320
310
|
return callback(middlewareErr);
|
|
321
311
|
}
|
|
322
|
-
collection.replaceOne(request.query, request.documentToWrite
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
312
|
+
collection.replaceOne(request.query, request.documentToWrite)
|
|
313
|
+
.then(function(result) {
|
|
314
|
+
var succeeded = !!result.modifiedCount;
|
|
315
|
+
callback(null, succeeded);
|
|
316
|
+
}, callback);
|
|
327
317
|
});
|
|
328
318
|
}
|
|
329
319
|
});
|
|
@@ -343,11 +333,11 @@ ShareDbMongo.prototype.getSnapshot = function(collectionName, id, fields, option
|
|
|
343
333
|
self._middleware.trigger(MiddlewareHandler.Actions.beforeSnapshotLookup, request, function(middlewareErr) {
|
|
344
334
|
if (middlewareErr) return callback(middlewareErr);
|
|
345
335
|
|
|
346
|
-
collection.find(request.query, request.findOptions).limit(1).project(projection).next(
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
336
|
+
collection.find(request.query, request.findOptions).limit(1).project(projection).next()
|
|
337
|
+
.then(function(doc) {
|
|
338
|
+
var snapshot = (doc) ? castToSnapshot(doc) : new MongoSnapshot(id, 0, null, undefined);
|
|
339
|
+
callback(null, snapshot);
|
|
340
|
+
}, callback);
|
|
351
341
|
});
|
|
352
342
|
});
|
|
353
343
|
};
|
|
@@ -363,20 +353,20 @@ ShareDbMongo.prototype.getSnapshotBulk = function(collectionName, ids, fields, o
|
|
|
363
353
|
self._middleware.trigger(MiddlewareHandler.Actions.beforeSnapshotLookup, request, function(middlewareErr) {
|
|
364
354
|
if (middlewareErr) return callback(middlewareErr);
|
|
365
355
|
|
|
366
|
-
collection.find(request.query, request.findOptions).project(projection).toArray(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
356
|
+
collection.find(request.query, request.findOptions).project(projection).toArray()
|
|
357
|
+
.then(function(docs) {
|
|
358
|
+
var snapshotMap = {};
|
|
359
|
+
for (var i = 0; i < docs.length; i++) {
|
|
360
|
+
var snapshot = castToSnapshot(docs[i]);
|
|
361
|
+
snapshotMap[snapshot.id] = snapshot;
|
|
362
|
+
}
|
|
363
|
+
for (var i = 0; i < ids.length; i++) {
|
|
364
|
+
var id = ids[i];
|
|
365
|
+
if (snapshotMap[id]) continue;
|
|
366
|
+
snapshotMap[id] = new MongoSnapshot(id, 0, null, undefined);
|
|
367
|
+
}
|
|
368
|
+
callback(null, snapshotMap);
|
|
369
|
+
}, callback);
|
|
380
370
|
});
|
|
381
371
|
});
|
|
382
372
|
};
|
|
@@ -423,14 +413,14 @@ ShareDbMongo.prototype.getOpCollection = function(collectionName, callback) {
|
|
|
423
413
|
// collection this won't be a problem, but this is a dangerous mechanism.
|
|
424
414
|
// Perhaps we should only warn instead of creating the indexes, especially
|
|
425
415
|
// when there is a lot of data in the collection.
|
|
426
|
-
collection.createIndex({d: 1, v: 1}, {background: true}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
416
|
+
collection.createIndex({d: 1, v: 1}, {background: true})
|
|
417
|
+
.then(function() {
|
|
418
|
+
return collection.createIndex({src: 1, seq: 1, v: 1}, {background: true});
|
|
419
|
+
})
|
|
420
|
+
.then(function() {
|
|
430
421
|
self.opIndexes[collectionName] = true;
|
|
431
422
|
callback(null, collection);
|
|
432
|
-
});
|
|
433
|
-
});
|
|
423
|
+
}, callback);
|
|
434
424
|
});
|
|
435
425
|
};
|
|
436
426
|
|
|
@@ -544,27 +534,27 @@ ShareDbMongo.prototype.getCommittedOpVersion = function(collectionName, id, snap
|
|
|
544
534
|
// Since ops are optimistically written prior to writing the snapshot, the
|
|
545
535
|
// op could end up being written multiple times or have been written but
|
|
546
536
|
// not count as committed if not backreferenced from the snapshot
|
|
547
|
-
opCollection.find(query).project(projection).sort(sort).limit(1).next(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
537
|
+
opCollection.find(query).project(projection).sort(sort).limit(1).next()
|
|
538
|
+
.then(function(doc) {
|
|
539
|
+
// If we find no op with the same src and seq, we definitely don't have
|
|
540
|
+
// any match. This should prevent us from accidentally querying a huge
|
|
541
|
+
// history of ops
|
|
542
|
+
if (!doc) return callback();
|
|
543
|
+
// If we do find an op with the same src and seq, we still have to get
|
|
544
|
+
// the ops from the snapshot to figure out if the op was actually
|
|
545
|
+
// committed already, and at what version in case of multiple matches
|
|
546
|
+
var from = doc.v;
|
|
547
|
+
self.getOpsToSnapshot(collectionName, id, from, snapshot, options, function(err, ops) {
|
|
548
|
+
if (err) return callback(err);
|
|
549
|
+
for (var i = ops.length; i--;) {
|
|
550
|
+
var item = ops[i];
|
|
551
|
+
if (op.src === item.src && op.seq === item.seq) {
|
|
552
|
+
return callback(null, item.v);
|
|
553
|
+
}
|
|
563
554
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
});
|
|
567
|
-
});
|
|
555
|
+
callback();
|
|
556
|
+
});
|
|
557
|
+
}, callback);
|
|
568
558
|
});
|
|
569
559
|
};
|
|
570
560
|
|
|
@@ -677,7 +667,10 @@ ShareDbMongo.prototype._getOps = function(collectionName, id, from, to, options,
|
|
|
677
667
|
// for tracking purposes
|
|
678
668
|
var projection = (options && options.metadata) ? {d: 0} : {d: 0, m: 0};
|
|
679
669
|
var sort = {v: 1};
|
|
680
|
-
opCollection.find(query).project(projection).sort(sort).toArray(
|
|
670
|
+
opCollection.find(query).project(projection).sort(sort).toArray()
|
|
671
|
+
.then(function(result) {
|
|
672
|
+
callback(null, result);
|
|
673
|
+
}, callback);
|
|
681
674
|
});
|
|
682
675
|
};
|
|
683
676
|
|
|
@@ -776,21 +769,23 @@ function getFirstOpWithUniqueVersion(cursor, opLinkValidator, callback) {
|
|
|
776
769
|
return closeCursor(cursor, callback, error, opWithUniqueVersion);
|
|
777
770
|
}
|
|
778
771
|
|
|
779
|
-
cursor.next(
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
772
|
+
cursor.next()
|
|
773
|
+
.then(
|
|
774
|
+
function(op) {
|
|
775
|
+
opLinkValidator.push(op);
|
|
776
|
+
getFirstOpWithUniqueVersion(cursor, opLinkValidator, callback);
|
|
777
|
+
},
|
|
778
|
+
function(error) {
|
|
779
|
+
closeCursor(cursor, callback, error);
|
|
780
|
+
}
|
|
781
|
+
);
|
|
787
782
|
}
|
|
788
783
|
|
|
789
784
|
function closeCursor(cursor, callback, error, returnValue) {
|
|
790
|
-
cursor.close(
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
785
|
+
cursor.close()
|
|
786
|
+
.then(function() {
|
|
787
|
+
callback(error, returnValue);
|
|
788
|
+
}, callback);
|
|
794
789
|
}
|
|
795
790
|
|
|
796
791
|
ShareDbMongo.prototype._getSnapshotOpLink = function(collectionName, id, options, callback) {
|
|
@@ -804,7 +799,10 @@ ShareDbMongo.prototype._getSnapshotOpLink = function(collectionName, id, options
|
|
|
804
799
|
request.query = query;
|
|
805
800
|
self._middleware.trigger(MiddlewareHandler.Actions.beforeSnapshotLookup, request, function(middlewareErr) {
|
|
806
801
|
if (middlewareErr) return callback(middlewareErr);
|
|
807
|
-
collection.find(query, request.findOptions).limit(1).project(projection).next(
|
|
802
|
+
collection.find(query, request.findOptions).limit(1).project(projection).next()
|
|
803
|
+
.then(function(result) {
|
|
804
|
+
callback(null, result);
|
|
805
|
+
}, callback);
|
|
808
806
|
});
|
|
809
807
|
});
|
|
810
808
|
};
|
|
@@ -820,7 +818,10 @@ ShareDbMongo.prototype._getSnapshotOpLinkBulk = function(collectionName, ids, op
|
|
|
820
818
|
request.query = query;
|
|
821
819
|
self._middleware.trigger(MiddlewareHandler.Actions.beforeSnapshotLookup, request, function(middlewareErr) {
|
|
822
820
|
if (middlewareErr) return callback(middlewareErr);
|
|
823
|
-
collection.find(query, request.findOptions).project(projection).toArray(
|
|
821
|
+
collection.find(query, request.findOptions).project(projection).toArray()
|
|
822
|
+
.then(function(result) {
|
|
823
|
+
callback(null, result);
|
|
824
|
+
}, callback);
|
|
824
825
|
});
|
|
825
826
|
});
|
|
826
827
|
};
|
|
@@ -882,7 +883,10 @@ ShareDbMongo.prototype._query = function(collection, inputQuery, projection, cal
|
|
|
882
883
|
// If no collection operation or cursor operations were used, return
|
|
883
884
|
// an array of snapshots that are passed in the "results" argument
|
|
884
885
|
// in the callback
|
|
885
|
-
cursor.toArray(
|
|
886
|
+
cursor.toArray()
|
|
887
|
+
.then(function(result) {
|
|
888
|
+
callback(null, result);
|
|
889
|
+
}, callback);
|
|
886
890
|
};
|
|
887
891
|
|
|
888
892
|
ShareDbMongo.prototype.query = function(collectionName, inputQuery, fields, options, callback) {
|
|
@@ -955,9 +959,10 @@ ShareDbMongo.prototype.queryPollDoc = function(collectionName, id, inputQuery, o
|
|
|
955
959
|
parsed.query._id = id;
|
|
956
960
|
}
|
|
957
961
|
|
|
958
|
-
collection.find(parsed.query).limit(1).project({_id: 1}).next(
|
|
959
|
-
|
|
960
|
-
|
|
962
|
+
collection.find(parsed.query).limit(1).project({_id: 1}).next()
|
|
963
|
+
.then(function(doc) {
|
|
964
|
+
callback(null, !!doc);
|
|
965
|
+
}, callback);
|
|
961
966
|
});
|
|
962
967
|
};
|
|
963
968
|
|
|
@@ -1482,36 +1487,58 @@ function getProjection(fields, options) {
|
|
|
1482
1487
|
|
|
1483
1488
|
var collectionOperationsMap = {
|
|
1484
1489
|
$distinct: function(collection, query, value, cb) {
|
|
1485
|
-
collection.distinct(value.field, query
|
|
1490
|
+
collection.distinct(value.field, query)
|
|
1491
|
+
.then(function(result) {
|
|
1492
|
+
cb(null, result);
|
|
1493
|
+
}, cb);
|
|
1486
1494
|
},
|
|
1487
1495
|
$aggregate: function(collection, query, value, cb) {
|
|
1488
1496
|
var cursor = collection.aggregate(value);
|
|
1489
|
-
cursor.toArray(
|
|
1497
|
+
cursor.toArray()
|
|
1498
|
+
.then(function(result) {
|
|
1499
|
+
cb(null, result);
|
|
1500
|
+
}, cb);
|
|
1490
1501
|
},
|
|
1491
1502
|
$mapReduce: function(collection, query, value, cb) {
|
|
1492
1503
|
if (typeof value !== 'object') {
|
|
1493
1504
|
var err = ShareDbMongo.malformedQueryOperatorError('$mapReduce');
|
|
1494
1505
|
return cb(err);
|
|
1495
1506
|
}
|
|
1507
|
+
// This function was removed in mongodb5:
|
|
1508
|
+
// https://github.com/mongodb/node-mongodb-native/pull/3511
|
|
1509
|
+
if (typeof collection.mapReduce !== 'function') {
|
|
1510
|
+
var err = ShareDbMongo.$mapReduceDisabledError();
|
|
1511
|
+
}
|
|
1496
1512
|
var mapReduceOptions = {
|
|
1497
1513
|
query: query,
|
|
1498
1514
|
out: {inline: 1},
|
|
1499
1515
|
scope: value.scope || {}
|
|
1500
1516
|
};
|
|
1501
|
-
collection.mapReduce(
|
|
1502
|
-
|
|
1517
|
+
collection.mapReduce(value.map, value.reduce, mapReduceOptions)
|
|
1518
|
+
.then(function(result) {
|
|
1519
|
+
cb(null, result);
|
|
1520
|
+
}, cb);
|
|
1503
1521
|
}
|
|
1504
1522
|
};
|
|
1505
1523
|
|
|
1506
1524
|
var cursorOperationsMap = {
|
|
1507
1525
|
$count: function(cursor, value, cb) {
|
|
1508
|
-
cursor.count(
|
|
1526
|
+
cursor.count()
|
|
1527
|
+
.then(function(result) {
|
|
1528
|
+
cb(null, result);
|
|
1529
|
+
}, cb);
|
|
1509
1530
|
},
|
|
1510
1531
|
$explain: function(cursor, verbosity, cb) {
|
|
1511
|
-
cursor.explain(verbosity
|
|
1532
|
+
cursor.explain(verbosity)
|
|
1533
|
+
.then(function(result) {
|
|
1534
|
+
cb(null, result);
|
|
1535
|
+
}, cb);
|
|
1512
1536
|
},
|
|
1513
1537
|
$map: function(cursor, fn, cb) {
|
|
1514
|
-
cursor.map(fn
|
|
1538
|
+
cursor.map(fn)
|
|
1539
|
+
.then(function(result) {
|
|
1540
|
+
cb(null, result);
|
|
1541
|
+
}, cb);
|
|
1515
1542
|
}
|
|
1516
1543
|
};
|
|
1517
1544
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sharedb-mongo",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "MongoDB database adapter for ShareDB",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"sharedb": "^1.9.1 || ^2.0.0"
|
|
7
|
+
"mongodb": "^2.1.2 || ^3.1.13 || ^4.0.0 || ^5.0.0",
|
|
8
|
+
"sharedb": "^1.9.1 || ^2.0.0 || ^3.0.0"
|
|
10
9
|
},
|
|
11
10
|
"devDependencies": {
|
|
12
11
|
"chai": "^4.2.0",
|
|
@@ -17,6 +16,7 @@
|
|
|
17
16
|
"mongodb2": "npm:mongodb@^2.1.2",
|
|
18
17
|
"mongodb3": "npm:mongodb@^3.0.0",
|
|
19
18
|
"mongodb4": "npm:mongodb@^4.0.0",
|
|
19
|
+
"mongodb5": "npm:mongodb@^5.0.0",
|
|
20
20
|
"nyc": "^14.1.1",
|
|
21
21
|
"ot-json1": "^1.0.1",
|
|
22
22
|
"sharedb-mingo-memory": "^1.1.1",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"test:mongodb2": "_SHAREDB_MONGODB_DRIVER=mongodb2 npm test",
|
|
31
31
|
"test:mongodb3": "_SHAREDB_MONGODB_DRIVER=mongodb3 npm test",
|
|
32
32
|
"test:mongodb4": "_SHAREDB_MONGODB_DRIVER=mongodb4 npm test",
|
|
33
|
-
"test:
|
|
33
|
+
"test:mongodb5": "_SHAREDB_MONGODB_DRIVER=mongodb5 npm test",
|
|
34
|
+
"test:all": "npm run test:mongodb2 && npm run test:mongodb3 && npm run test:mongodb4 && npm run test:mongodb5",
|
|
34
35
|
"test-cover": "nyc --temp-dir=coverage -r text -r lcov npm run test:all"
|
|
35
36
|
},
|
|
36
37
|
"repository": "git://github.com/share/sharedb-mongo.git",
|
package/test/test_get_ops.js
CHANGED
|
@@ -12,10 +12,11 @@ function create(options, callback) {
|
|
|
12
12
|
var db = new ShareDbMongo(mongoUrl, opts);
|
|
13
13
|
db.getDbs(function(err, mongo) {
|
|
14
14
|
if (err) return callback(err);
|
|
15
|
-
mongo.dropDatabase(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
mongo.dropDatabase()
|
|
16
|
+
.then(function() {
|
|
17
|
+
callback(null, db, mongo);
|
|
18
|
+
})
|
|
19
|
+
.catch(callback);
|
|
19
20
|
});
|
|
20
21
|
};
|
|
21
22
|
|
|
@@ -62,7 +63,9 @@ function create(options, callback) {
|
|
|
62
63
|
|
|
63
64
|
commitOpChain(db, mongo, collection, id, ops, function(error) {
|
|
64
65
|
if (error) done(error);
|
|
65
|
-
mongo.collection('o_' + collection).deleteOne({v: 1}
|
|
66
|
+
mongo.collection('o_' + collection).deleteOne({v: 1}).then(function() {
|
|
67
|
+
done();
|
|
68
|
+
});
|
|
66
69
|
});
|
|
67
70
|
});
|
|
68
71
|
|
|
@@ -127,8 +130,7 @@ function commitOpChain(db, mongo, collection, id, ops, previousOpId, version, ca
|
|
|
127
130
|
var snapshot = {id: id, v: version + 1, type: 'json0', data: {}, m: null, _opLink: previousOpId};
|
|
128
131
|
db.commit(collection, id, op, snapshot, null, function(error) {
|
|
129
132
|
if (error) return callback(error);
|
|
130
|
-
mongo.collection('o_' + collection).find({d: id, v: version}).next(function(
|
|
131
|
-
if (error) return callback(error);
|
|
133
|
+
mongo.collection('o_' + collection).find({d: id, v: version}).next().then(function(op) {
|
|
132
134
|
commitOpChain(db, mongo, collection, id, ops, (op ? op._id : null), ++version, callback);
|
|
133
135
|
});
|
|
134
136
|
});
|
|
@@ -12,10 +12,11 @@ function create(callback) {
|
|
|
12
12
|
});
|
|
13
13
|
db.getDbs(function(err, mongo) {
|
|
14
14
|
if (err) return callback(err);
|
|
15
|
-
mongo.dropDatabase(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
mongo.dropDatabase()
|
|
16
|
+
.then(function() {
|
|
17
|
+
callback(null, db, mongo);
|
|
18
|
+
})
|
|
19
|
+
.catch(callback);
|
|
19
20
|
});
|
|
20
21
|
};
|
|
21
22
|
|
|
@@ -78,7 +79,11 @@ describe('getOpsWithoutStrictLinking: true', function() {
|
|
|
78
79
|
|
|
79
80
|
callInSeries([
|
|
80
81
|
function(next) {
|
|
81
|
-
mongo.collection('o_' + collection).insertOne(spuriousOp
|
|
82
|
+
mongo.collection('o_' + collection).insertOne(spuriousOp)
|
|
83
|
+
.then(function(result) {
|
|
84
|
+
next(null, result);
|
|
85
|
+
})
|
|
86
|
+
.catch(next);
|
|
82
87
|
},
|
|
83
88
|
function(result, next) {
|
|
84
89
|
db.getOps(collection, id, 0, 2, null, next);
|
|
@@ -99,7 +104,11 @@ describe('getOpsWithoutStrictLinking: true', function() {
|
|
|
99
104
|
|
|
100
105
|
callInSeries([
|
|
101
106
|
function(next) {
|
|
102
|
-
mongo.collection('o_' + collection).insertOne(spuriousOp
|
|
107
|
+
mongo.collection('o_' + collection).insertOne(spuriousOp)
|
|
108
|
+
.then(function(result) {
|
|
109
|
+
next(null, result);
|
|
110
|
+
})
|
|
111
|
+
.catch(next);
|
|
103
112
|
},
|
|
104
113
|
function(result, next) {
|
|
105
114
|
db.getOps(collection, id, 0, 2, null, next);
|
|
@@ -125,7 +134,11 @@ describe('getOpsWithoutStrictLinking: true', function() {
|
|
|
125
134
|
|
|
126
135
|
callInSeries([
|
|
127
136
|
function(next) {
|
|
128
|
-
mongo.collection('o_' + collection).insertMany(spuriousOps
|
|
137
|
+
mongo.collection('o_' + collection).insertMany(spuriousOps)
|
|
138
|
+
.then(function(result) {
|
|
139
|
+
next(null, result);
|
|
140
|
+
})
|
|
141
|
+
.catch(next);
|
|
129
142
|
},
|
|
130
143
|
function(result, next) {
|
|
131
144
|
db.getOps(collection, id, 0, 2, null, next);
|
|
@@ -160,10 +173,11 @@ function commitOpChain(db, mongo, collection, id, ops, previousOpId, version, ca
|
|
|
160
173
|
var snapshot = {id: id, v: version + 1, type: 'json0', data: {}, m: null, _opLink: previousOpId};
|
|
161
174
|
db.commit(collection, id, op, snapshot, null, function(error) {
|
|
162
175
|
if (error) return callback(error);
|
|
163
|
-
mongo.collection('o_' + collection).find({d: id, v: version}).next(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
176
|
+
mongo.collection('o_' + collection).find({d: id, v: version}).next()
|
|
177
|
+
.then(function(op) {
|
|
178
|
+
commitOpChain(db, mongo, collection, id, ops, op._id, ++version, callback);
|
|
179
|
+
})
|
|
180
|
+
.catch(callback);
|
|
167
181
|
});
|
|
168
182
|
}
|
|
169
183
|
|
package/test/test_mongo.js
CHANGED
|
@@ -9,10 +9,11 @@ function create(callback) {
|
|
|
9
9
|
var db = new ShareDbMongo(mongoUrl);
|
|
10
10
|
db.getDbs(function(err, mongo) {
|
|
11
11
|
if (err) return callback(err);
|
|
12
|
-
mongo.dropDatabase(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
mongo.dropDatabase()
|
|
13
|
+
.then(function() {
|
|
14
|
+
callback(null, db, mongo);
|
|
15
|
+
})
|
|
16
|
+
.catch(callback);
|
|
16
17
|
});
|
|
17
18
|
};
|
|
18
19
|
|
|
@@ -38,8 +39,7 @@ describe('mongo db', function() {
|
|
|
38
39
|
var mongo = this.mongo;
|
|
39
40
|
this.db.commit('testcollection', 'foo', {v: 0, create: {}}, {}, null, function(err) {
|
|
40
41
|
if (err) return done(err);
|
|
41
|
-
mongo.collection('o_testcollection').indexInformation(function(
|
|
42
|
-
if (err) return done(err);
|
|
42
|
+
mongo.collection('o_testcollection').indexInformation().then(function(indexes) {
|
|
43
43
|
// Index for getting document(s) ops
|
|
44
44
|
expect(indexes['d_1_v_1']).ok;
|
|
45
45
|
// Index for checking committed op(s) by src and seq
|
|
@@ -51,8 +51,7 @@ describe('mongo db', function() {
|
|
|
51
51
|
|
|
52
52
|
it('respects unique indexes', function(done) {
|
|
53
53
|
var db = this.db;
|
|
54
|
-
this.mongo.collection('testcollection').createIndex({x: 1}, {unique: true}
|
|
55
|
-
if (err) return done(err);
|
|
54
|
+
this.mongo.collection('testcollection').createIndex({x: 1}, {unique: true}).then(function() {
|
|
56
55
|
db.commit('testcollection', 'foo', {v: 0, create: {}}, {v: 1, data: {x: 7}}, null, function(err) {
|
|
57
56
|
if (err) return done(err);
|
|
58
57
|
db.commit('testcollection', 'bar', {v: 0, create: {}}, {v: 1, data: {x: 7}}, null, function(err) {
|
|
@@ -335,6 +334,11 @@ describe('mongo db', function() {
|
|
|
335
334
|
});
|
|
336
335
|
|
|
337
336
|
it('$mapReduce queries should work when allowJavaScriptQuery == true', function(done) {
|
|
337
|
+
if (process.env._SHAREDB_MONGODB_DRIVER === 'mongodb5') {
|
|
338
|
+
// This function was removed in mongodb5:
|
|
339
|
+
// https://github.com/mongodb/node-mongodb-native/pull/3511
|
|
340
|
+
return done();
|
|
341
|
+
}
|
|
338
342
|
var snapshots = [
|
|
339
343
|
{type: 'json0', v: 1, data: {player: 'a', round: 1, score: 5}},
|
|
340
344
|
{type: 'json0', v: 1, data: {player: 'a', round: 2, score: 7}},
|
|
@@ -381,10 +385,11 @@ describe('mongo db connection', function() {
|
|
|
381
385
|
// logic.
|
|
382
386
|
this.db.getDbs(function(err, mongo) {
|
|
383
387
|
if (err) return done(err);
|
|
384
|
-
mongo.dropDatabase(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
+
mongo.dropDatabase()
|
|
389
|
+
.then(function() {
|
|
390
|
+
done();
|
|
391
|
+
})
|
|
392
|
+
.catch(done);
|
|
388
393
|
});
|
|
389
394
|
});
|
|
390
395
|
|
|
@@ -16,10 +16,11 @@ function create(callback) {
|
|
|
16
16
|
var db = new ShareDbMongo(mongoUrl);
|
|
17
17
|
db.getDbs(function(err, mongo) {
|
|
18
18
|
if (err) return callback(err);
|
|
19
|
-
mongo.dropDatabase(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
mongo.dropDatabase()
|
|
20
|
+
.then(function() {
|
|
21
|
+
callback(null, db, mongo);
|
|
22
|
+
})
|
|
23
|
+
.catch(callback);
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
|