sharedb 4.1.4 → 5.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/lib/backend.js +1 -1
- package/lib/db/memory.js +17 -3
- package/package.json +1 -1
- package/test/client/snapshot-version-request.js +46 -1
- package/test/db-memory.js +80 -12
package/lib/backend.js
CHANGED
|
@@ -909,7 +909,7 @@ Backend.prototype._fetchSnapshotByTimestamp = function(collection, id, timestamp
|
|
|
909
909
|
};
|
|
910
910
|
|
|
911
911
|
Backend.prototype._buildSnapshotFromOps = function(id, startingSnapshot, ops, callback) {
|
|
912
|
-
var snapshot = startingSnapshot || new Snapshot(id, 0, null, undefined, null);
|
|
912
|
+
var snapshot = util.clone(startingSnapshot) || new Snapshot(id, 0, null, undefined, null);
|
|
913
913
|
var error = ot.applyOps(snapshot, ops, {_normalizeLegacyJson0Ops: true});
|
|
914
914
|
callback(error, snapshot);
|
|
915
915
|
};
|
package/lib/db/memory.js
CHANGED
|
@@ -84,10 +84,12 @@ MemoryDB.prototype.getOps = function(collection, id, from, to, options, callback
|
|
|
84
84
|
if (typeof callback !== 'function') throw new Error('Callback required');
|
|
85
85
|
util.nextTick(function() {
|
|
86
86
|
var opLog = db._getOpLogSync(collection, id);
|
|
87
|
-
if (
|
|
88
|
-
|
|
87
|
+
if (!from) from = 0;
|
|
88
|
+
if (to == null) to = opLog.length;
|
|
89
|
+
var ops = clone(opLog.slice(from, to).filter(Boolean));
|
|
90
|
+
if (ops.length < to - from) {
|
|
91
|
+
return callback(new Error('Missing ops'));
|
|
89
92
|
}
|
|
90
|
-
var ops = clone(opLog.slice(from, to));
|
|
91
93
|
if (!includeMetadata) {
|
|
92
94
|
for (var i = 0; i < ops.length; i++) {
|
|
93
95
|
delete ops[i].m;
|
|
@@ -97,6 +99,18 @@ MemoryDB.prototype.getOps = function(collection, id, from, to, options, callback
|
|
|
97
99
|
});
|
|
98
100
|
};
|
|
99
101
|
|
|
102
|
+
MemoryDB.prototype.deleteOps = function(collection, id, from, to, options, callback) {
|
|
103
|
+
if (typeof callback !== 'function') throw new Error('Callback required');
|
|
104
|
+
var db = this;
|
|
105
|
+
util.nextTick(function() {
|
|
106
|
+
var opLog = db._getOpLogSync(collection, id);
|
|
107
|
+
if (!from) from = 0;
|
|
108
|
+
if (to == null) to = opLog.length;
|
|
109
|
+
for (var i = from; i < to; i++) opLog[i] = null;
|
|
110
|
+
callback(null);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
100
114
|
// The memory database query function returns all documents in a collection
|
|
101
115
|
// regardless of query by default
|
|
102
116
|
MemoryDB.prototype.query = function(collection, query, fields, options, callback) {
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ var sinon = require('sinon');
|
|
|
6
6
|
var async = require('async');
|
|
7
7
|
var json0v2 = require('ot-json0-v2').type;
|
|
8
8
|
var types = require('../../lib/types');
|
|
9
|
+
var clone = require('../../lib/util').clone;
|
|
9
10
|
|
|
10
11
|
describe('SnapshotVersionRequest', function() {
|
|
11
12
|
var backend;
|
|
@@ -144,7 +145,18 @@ describe('SnapshotVersionRequest', function() {
|
|
|
144
145
|
|
|
145
146
|
it('errors if asking for a version that does not exist', function(done) {
|
|
146
147
|
backend.connect().fetchSnapshot('books', 'don-quixote', 4, function(error, snapshot) {
|
|
147
|
-
expect(error
|
|
148
|
+
expect(error).to.be.ok;
|
|
149
|
+
expect(snapshot).to.equal(undefined);
|
|
150
|
+
done();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('errors if asking for a version that does not exist if the DB adapter does not error', function(done) {
|
|
155
|
+
sinon.stub(MemoryDb.prototype, 'getOps').callsFake(function(collection, id, from, to, options, callback) {
|
|
156
|
+
callback(null, []);
|
|
157
|
+
});
|
|
158
|
+
backend.connect().fetchSnapshot('books', 'don-quixote', 4, function(error, snapshot) {
|
|
159
|
+
expect(error).to.be.ok;
|
|
148
160
|
expect(snapshot).to.equal(undefined);
|
|
149
161
|
done();
|
|
150
162
|
});
|
|
@@ -440,6 +452,39 @@ describe('SnapshotVersionRequest', function() {
|
|
|
440
452
|
], done);
|
|
441
453
|
});
|
|
442
454
|
|
|
455
|
+
it('does not mutate the milestone snapshot', function(done) {
|
|
456
|
+
var connection = backendWithMilestones.connect();
|
|
457
|
+
var doc = connection.get('books', 'mocking-bird');
|
|
458
|
+
var milestoneDb = backendWithMilestones.milestoneDb;
|
|
459
|
+
var milestone;
|
|
460
|
+
|
|
461
|
+
async.waterfall([
|
|
462
|
+
doc.create.bind(doc, {title: 'To Kill a Mocking Bird'}),
|
|
463
|
+
doc.submitOp.bind(doc, {p: ['author'], oi: 'Harper Lea'}),
|
|
464
|
+
doc.submitOp.bind(doc, {p: ['author'], od: 'Harper Lea', oi: 'Harper Lee'}),
|
|
465
|
+
milestoneDb.getMilestoneSnapshot.bind(milestoneDb, 'books', 'mocking-bird', 3),
|
|
466
|
+
function(snapshot, next) {
|
|
467
|
+
milestone = clone(snapshot);
|
|
468
|
+
next();
|
|
469
|
+
},
|
|
470
|
+
function(next) {
|
|
471
|
+
// Internally, this calls ot.applyOps(), which mutates the snapshot it's passed.
|
|
472
|
+
// This call shouldn't cause the in-memory milestone snapshot to be mutated.
|
|
473
|
+
connection.fetchSnapshot('books', 'mocking-bird', 3, next);
|
|
474
|
+
},
|
|
475
|
+
function(snapshot, next) {
|
|
476
|
+
expect(snapshot.v).to.equal(3);
|
|
477
|
+
expect(snapshot.data).to.eql({title: 'To Kill a Mocking Bird', author: 'Harper Lee'});
|
|
478
|
+
next();
|
|
479
|
+
},
|
|
480
|
+
milestoneDb.getMilestoneSnapshot.bind(milestoneDb, 'books', 'mocking-bird', 3),
|
|
481
|
+
function(snapshot, next) {
|
|
482
|
+
expect(snapshot).to.eql(milestone);
|
|
483
|
+
next();
|
|
484
|
+
}
|
|
485
|
+
], done);
|
|
486
|
+
});
|
|
487
|
+
|
|
443
488
|
describe('with version null', function() {
|
|
444
489
|
it('fetches a latest version', function(done) {
|
|
445
490
|
var doc = backendWithMilestones.connect().get('books', 'mocking-bird');
|
package/test/db-memory.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
var expect = require('chai').expect;
|
|
2
|
+
var Backend = require('../lib/backend');
|
|
2
3
|
var DB = require('../lib/db');
|
|
3
4
|
var BasicQueryableMemoryDB = require('./BasicQueryableMemoryDB');
|
|
5
|
+
var async = require('async');
|
|
4
6
|
|
|
5
7
|
describe('DB base class', function() {
|
|
6
8
|
it('can call db.close() without callback', function() {
|
|
@@ -54,17 +56,83 @@ describe('DB base class', function() {
|
|
|
54
56
|
});
|
|
55
57
|
});
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
describe('MemoryDB', function() {
|
|
60
|
+
// Run all the DB-based tests against the BasicQueryableMemoryDB.
|
|
61
|
+
require('./db')({
|
|
62
|
+
create: function(options, callback) {
|
|
63
|
+
if (typeof options === 'function') {
|
|
64
|
+
callback = options;
|
|
65
|
+
options = null;
|
|
66
|
+
}
|
|
67
|
+
var db = new BasicQueryableMemoryDB(options);
|
|
68
|
+
callback(null, db);
|
|
69
|
+
},
|
|
70
|
+
getQuery: function(options) {
|
|
71
|
+
return {filter: options.query, sort: options.sort};
|
|
63
72
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('deleteOps', function() {
|
|
76
|
+
describe('with some ops', function() {
|
|
77
|
+
var backend;
|
|
78
|
+
var db;
|
|
79
|
+
var connection;
|
|
80
|
+
var doc;
|
|
81
|
+
|
|
82
|
+
beforeEach(function(done) {
|
|
83
|
+
backend = new Backend();
|
|
84
|
+
db = backend.db;
|
|
85
|
+
connection = backend.connect();
|
|
86
|
+
doc = connection.get('dogs', 'fido');
|
|
87
|
+
|
|
88
|
+
async.waterfall([
|
|
89
|
+
doc.create.bind(doc, {name: 'Fido'}),
|
|
90
|
+
doc.submitOp.bind(doc, [{p: ['tricks'], oi: ['fetch']}]),
|
|
91
|
+
db.getOps.bind(db, 'dogs', 'fido', null, null, null),
|
|
92
|
+
function(ops, next) {
|
|
93
|
+
expect(ops).to.have.length(2);
|
|
94
|
+
next();
|
|
95
|
+
}
|
|
96
|
+
], done);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('deletes all ops', function(done) {
|
|
100
|
+
async.waterfall([
|
|
101
|
+
db.deleteOps.bind(db, 'dogs', 'fido', null, null, null),
|
|
102
|
+
function(next) {
|
|
103
|
+
db.getOps('dogs', 'fido', null, null, null, function(error) {
|
|
104
|
+
expect(error.message).to.equal('Missing ops');
|
|
105
|
+
next();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
], done);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('deletes some ops', function(done) {
|
|
112
|
+
async.waterfall([
|
|
113
|
+
db.deleteOps.bind(db, 'dogs', 'fido', 0, 1, null),
|
|
114
|
+
db.getOps.bind(db, 'dogs', 'fido', 1, 2, null),
|
|
115
|
+
function(ops, next) {
|
|
116
|
+
expect(ops).to.have.length(1);
|
|
117
|
+
expect(ops[0].op).to.eql([{p: ['tricks'], oi: ['fetch']}]);
|
|
118
|
+
db.getOps('dogs', 'fido', 0, 1, null, function(error) {
|
|
119
|
+
expect(error.message).to.equal('Missing ops');
|
|
120
|
+
next();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
], done);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('submits more ops after deleting ops', function(done) {
|
|
127
|
+
async.series([
|
|
128
|
+
db.deleteOps.bind(db, 'dogs', 'fido', null, null, null),
|
|
129
|
+
doc.submitOp.bind(doc, [{p: ['tricks', 1], li: 'sit'}]),
|
|
130
|
+
function(next) {
|
|
131
|
+
expect(doc.data.tricks).to.eql(['fetch', 'sit']);
|
|
132
|
+
next();
|
|
133
|
+
}
|
|
134
|
+
], done);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
70
138
|
});
|