Skip to content
This repository was archived by the owner on Apr 2, 2024. It is now read-only.

Commit e80fe46

Browse files
author
Alec Gibson
committed
Review markups
This change: - bypasses `_sanitizeOps` and instead uses `_sanitizeSnapshot` - adds timing to `Backend.fetchSnapshot` - throws for negative versions
1 parent b4764ac commit e80fe46

File tree

5 files changed

+72
-68
lines changed

5 files changed

+72
-68
lines changed

lib/backend.js

+29-27
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var MemoryPubSub = require('./pubsub/memory');
77
var ot = require('./ot');
88
var projections = require('./projections');
99
var QueryEmitter = require('./query-emitter');
10+
var Snapshot = require('./snapshot');
1011
var StreamSocket = require('./stream-socket');
1112
var SubmitRequest = require('./submit-request');
1213
var types = require('./types');
@@ -583,35 +584,39 @@ Backend.prototype.getChannels = function(collection, id) {
583584
};
584585

585586
Backend.prototype.fetchSnapshot = function(agent, index, id, version, callback) {
587+
var start = Date.now();
586588
var backend = this;
587-
this._fetchSnapshot(agent, index, id, version, function (error, snapshot) {
588-
if (error) return callback(error);
589-
590-
var request = {
591-
collection: index,
592-
id: id,
593-
v: snapshot.v,
594-
snapshots: snapshot.data ? [snapshot.data] : [],
595-
type: snapshot.type
596-
};
589+
var projection = this.projections[index];
590+
var collection = projection ? projection.target : index;
591+
var request = {
592+
agent: agent,
593+
index: index,
594+
collection: collection,
595+
id: id,
596+
version: version
597+
};
597598

598-
backend.trigger(backend.MIDDLEWARE_ACTIONS.readSnapshots, agent, request, function (error) {
599+
this._fetchSnapshot(collection, id, version, function (error, snapshot) {
600+
if (error) return callback(error);
601+
var snapshotProjection = backend._getSnapshotProjection(backend.db, projection);
602+
var snapshots = [snapshot];
603+
backend._sanitizeSnapshots(agent, snapshotProjection, collection, snapshots, function (error) {
599604
if (error) return callback(error);
600-
callback(null, {
601-
data: request.snapshots[0],
602-
v: request.v,
603-
type: request.type
604-
});
605+
backend.emit('timing', 'fetchSnapshot', Date.now() - start, request);
606+
callback(null, snapshot);
605607
});
606608
});
607609
};
608610

609-
Backend.prototype._fetchSnapshot = function (agent, index, id, version, callback) {
610-
this.getOps(agent, index, id, 0, version, function (error, ops) {
611+
Backend.prototype._fetchSnapshot = function (collection, id, version, callback) {
612+
// Bypass backend.getOps so that we don't call _sanitizeOps. We want to avoid this, because:
613+
// - we want to avoid the 'op' middleware, because we later use the 'readSnapshots' middleware in _sanitizeSnapshots
614+
// - we handle the projection in _sanitizeSnapshots
615+
this.db.getOps(collection, id, 0, version, null, function (error, ops) {
611616
if (error) return callback(error);
612617

613618
var type = null;
614-
var snapshot;
619+
var data;
615620
var fetchedVersion = 0;
616621

617622
for (var index = 0; index < ops.length; index++) {
@@ -621,12 +626,12 @@ Backend.prototype._fetchSnapshot = function (agent, index, id, version, callback
621626
if (op.create) {
622627
type = types.map[op.create.type];
623628
if (!type) return callback({ code: 4008, message: 'Unknown type' });
624-
snapshot = type.create(op.create.data);
629+
data = type.create(op.create.data);
625630
} else if (op.del) {
626-
snapshot = undefined;
631+
data = undefined;
627632
type = null;
628633
} else {
629-
snapshot = type.apply(snapshot, op.op);
634+
data = type.apply(data, op.op);
630635
}
631636
}
632637

@@ -636,11 +641,8 @@ Backend.prototype._fetchSnapshot = function (agent, index, id, version, callback
636641
return callback({ code: 4024, message: 'Requested version exceeds latest snapshot version' });
637642
}
638643

639-
callback(null, {
640-
data: snapshot,
641-
v: fetchedVersion,
642-
type: type
643-
});
644+
var snapshot = new Snapshot(id, fetchedVersion, type, data, null);
645+
callback(null, snapshot);
644646
});
645647
};
646648

lib/client/connection.js

+6-12
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ Connection.prototype.handleMessage = function(message) {
232232
return this._handleBulkMessage(message, '_handleUnsubscribe');
233233

234234
case 'nf':
235-
return this._handleSnapshot(err, message);
235+
return this._handleSnapshotFetch(err, message);
236236

237237
case 'f':
238238
var doc = this.getExisting(message.c, message.d);
@@ -537,15 +537,12 @@ Connection.prototype.hasPending = function() {
537537
return !!(
538538
this._firstDoc(hasPending) ||
539539
this._firstQuery(hasPending) ||
540-
this._firstSnapshotRequest(exists)
540+
this._firstSnapshotRequest()
541541
);
542542
};
543543
function hasPending(object) {
544544
return object.hasPending();
545545
}
546-
function exists(object) {
547-
return !!object;
548-
}
549546

550547
Connection.prototype.hasWritePending = function() {
551548
return !!this._firstDoc(hasWritePending);
@@ -569,7 +566,7 @@ Connection.prototype.whenNothingPending = function(callback) {
569566
query.once('ready', this._nothingPendingRetry(callback));
570567
return;
571568
}
572-
var snapshotRequest = this._firstSnapshotRequest(exists);
569+
var snapshotRequest = this._firstSnapshotRequest();
573570
if (snapshotRequest) {
574571
snapshotRequest.once('ready', this._nothingPendingRetry(callback));
575572
return;
@@ -607,12 +604,9 @@ Connection.prototype._firstQuery = function(fn) {
607604
}
608605
};
609606

610-
Connection.prototype._firstSnapshotRequest = function (fn) {
607+
Connection.prototype._firstSnapshotRequest = function () {
611608
for (var id in this._snapshotRequests) {
612-
var snapshotRequest = this._snapshotRequests[id];
613-
if (fn(snapshotRequest)) {
614-
return snapshotRequest;
615-
}
609+
return this._snapshotRequests[id];
616610
}
617611
};
618612

@@ -644,7 +638,7 @@ Connection.prototype.fetchSnapshot = function(collection, id, version, callback)
644638
snapshotRequest.send();
645639
};
646640

647-
Connection.prototype._handleSnapshot = function (error, message) {
641+
Connection.prototype._handleSnapshotFetch = function (error, message) {
648642
var snapshotRequest = this._snapshotRequests[message.id];
649643
if (!snapshotRequest) return;
650644
delete this._snapshotRequests[message.id];

lib/client/snapshot-request.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,33 @@ function SnapshotRequest(connection, requestId, collection, id, version, callbac
1111
throw new Error('Callback is required for SnapshotRequest');
1212
}
1313

14-
if (version != null && !util.isInteger(version)) {
15-
throw new Error('Snapshot version must be an integer');
14+
if (!this.isValidVersion(version)) {
15+
throw new Error('Snapshot version must be a positive integer or null');
1616
}
1717

1818
this.requestId = requestId;
1919
this.connection = connection;
2020
this.id = id;
2121
this.collection = collection;
22-
this.version = util.isInteger(version) ? Math.max(0, version) : null;
22+
this.version = version;
2323
this.callback = callback;
2424

2525
this.sent = false;
2626
}
2727
emitter.mixin(SnapshotRequest);
2828

29+
SnapshotRequest.prototype.isValidVersion = function (version) {
30+
if (version === null) {
31+
return true;
32+
}
33+
34+
if (!util.isInteger(version)) {
35+
return false;
36+
}
37+
38+
return version >= 0;
39+
}
40+
2941
SnapshotRequest.prototype.send = function () {
3042
if (!this.connection.canSend) {
3143
return;
@@ -52,11 +64,12 @@ SnapshotRequest.prototype._onConnectionStateChanged = function () {
5264
};
5365

5466
SnapshotRequest.prototype._handleResponse = function (error, message) {
67+
this.emit('ready');
68+
5569
if (error) {
5670
return this.callback(error);
5771
}
5872

5973
var snapshot = new Snapshot(this.id, message.v, message.type, message.data, null);
6074
this.callback(null, snapshot);
61-
this.emit('ready');
6275
};

test/client/snapshot-request.js

+16-21
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,13 @@ describe('SnapshotRequest', function () {
9696
});
9797
});
9898

99-
it('fetches the latest version if the version is undefined', function (done) {
100-
backend.connect().fetchSnapshot('books', 'don-quixote', undefined, function (error, snapshot) {
101-
if (error) return done(error);
102-
expect(snapshot).to.eql(v3);
103-
done();
99+
it('throws if the version is undefined', function () {
100+
var fetch = function () {
101+
backend.connect().fetchSnapshot('books', 'don-quixote', undefined, function () {});
102+
};
103+
104+
expect(fetch).to.throwError();
104105
});
105-
});
106106

107107
it('fetches the latest version when the optional version is not provided', function (done) {
108108
backend.connect().fetchSnapshot('books', 'don-quixote', function (error, snapshot) {
@@ -117,23 +117,23 @@ describe('SnapshotRequest', function () {
117117
backend.connect().fetchSnapshot('books', 'don-quixote');
118118
};
119119

120-
expect(fetch).to.throwError("Callback is required");
120+
expect(fetch).to.throwError();
121121
});
122122

123-
it('returns an empty snapshot if the version is -1', function (done) {
124-
backend.connect().fetchSnapshot('books', 'don-quixote', -1, function (error, snapshot) {
125-
if (error) return done(error);
126-
expect(snapshot).to.eql(v0);
127-
done();
128-
});
123+
it('throws if the version is -1', function () {
124+
var fetch = function () {
125+
backend.connect().fetchSnapshot('books', 'don-quixote', -1, function () {});
126+
};
127+
128+
expect(fetch).to.throwError();
129129
});
130130

131131
it('errors if the version is a string', function () {
132132
var fetch = function () {
133133
backend.connect().fetchSnapshot('books', 'don-quixote', 'foo', function () { });
134134
}
135135

136-
expect(fetch).to.throwError("version must be an integer");
136+
expect(fetch).to.throwError();
137137
});
138138

139139
it('errors if asking for a version that does not exist', function (done) {
@@ -223,12 +223,7 @@ describe('SnapshotRequest', function () {
223223
it('triggers the middleware', function (done) {
224224
backend.use(backend.MIDDLEWARE_ACTIONS.readSnapshots,
225225
function (request) {
226-
expect(request.collection).to.be('books');
227-
expect(request.id).to.be('don-quixote');
228-
expect(request.v).to.be(3);
229-
expect(request.snapshots).to.eql([v3.data]);
230-
expect(request.type).to.be('http://sharejs.org/types/JSONv0');
231-
226+
expect(request.snapshots[0]).to.eql(v3);
232227
done();
233228
}
234229
);
@@ -239,7 +234,7 @@ describe('SnapshotRequest', function () {
239234
it('can have its snapshot manipulated in the middleware', function (done) {
240235
backend.middleware[backend.MIDDLEWARE_ACTIONS.readSnapshots] = [
241236
function (request, callback) {
242-
request.snapshots[0].title = 'Alice in Wonderland';
237+
request.snapshots[0].data.title = 'Alice in Wonderland';
243238
callback();
244239
},
245240
];

test/db.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,10 @@ module.exports = function(options) {
789789
// test that getQuery({query: {}, sort: [['foo', 1], ['bar', -1]]})
790790
// sorts by foo first, then bar
791791
var snapshots = [
792-
{ type: 'json0', id: '0', v: 1, data: {foo: 1, bar: 1}, m: null },
793-
{ type: 'json0', id: '1', v: 1, data: { foo: 2, bar: 1 }, m: null },
794-
{ type: 'json0', id: '2', v: 1, data: { foo: 1, bar: 2 }, m: null },
795-
{ type: 'json0', id: '3', v: 1, data: { foo: 2, bar: 2 }, m: null }
792+
{type: 'json0', id: '0', v: 1, data: {foo: 1, bar: 1}, m: null},
793+
{type: 'json0', id: '1', v: 1, data: { foo: 2, bar: 1 }, m: null},
794+
{type: 'json0', id: '2', v: 1, data: { foo: 1, bar: 2 }, m: null},
795+
{type: 'json0', id: '3', v: 1, data: { foo: 2, bar: 2 }, m: null}
796796
];
797797
var db = this.db;
798798
var dbQuery = getQuery({query: {}, sort: [['foo', 1], ['bar', -1]]});

0 commit comments

Comments
 (0)