Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/client/doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ Doc.prototype.ingestSnapshot = function(snapshot, callback) {
if (this.version > snapshot.v) return callback && callback();

this.version = snapshot.v;
this.data = snapshot.data;
var type = (snapshot.type === undefined) ? types.defaultType : snapshot.type;
this._setType(type);
this.data = (this.type && this.type.deserialize) ? this.type.deserialize(snapshot.data) : snapshot.data;
this.emit('load');
callback && callback();
};
Expand Down Expand Up @@ -552,7 +552,8 @@ Doc.prototype._otApply = function(op, source) {

if (op.create) {
this._setType(op.create.type);
this.data = this.type.create(op.create.data);
var method = (this.type.createDeserialized) ? 'createDeserialized' : 'create';
this.data = this.type[method](op.create.data);
this.emit('create', source);
return;
}
Expand Down
71 changes: 71 additions & 0 deletions test/client/submit.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
var async = require('async');
var expect = require('expect.js');
var types = require('../../lib/types');
var serializable_type = require('../ot-mock-serializable-json0').type;

types.register(serializable_type);

module.exports = function() {
describe('client submit', function() {
Expand Down Expand Up @@ -39,6 +43,16 @@ describe('client submit', function() {
});
});

it('can create a new doc with a serializable type', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
doc.create(serializable_type.serialize({age: 3}), serializable_type.uri, function(err) {
if (err) return done(err);
expect(doc.data).eql({age: 3});
expect(doc.version).eql(1);
done();
});
});

it('can create then delete then create a doc', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
doc.create({age: 3}, function(err) {
Expand Down Expand Up @@ -74,6 +88,19 @@ describe('client submit', function() {
});
});

it('can create then submit an op on a serializable type', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
doc.create(serializable_type.serialize({age: 3}), serializable_type.uri, function(err) {
if (err) return done(err);
doc.submitOp({p: ['age'], na: 2}, function(err) {
if (err) return done(err);
expect(doc.data).eql({age: 5});
expect(doc.version).eql(2);
done();
});
});
});

it('can create then submit an op sync', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
doc.create({age: 3});
Expand Down Expand Up @@ -140,6 +167,33 @@ describe('client submit', function() {
});
});

it('ops submitted sync get composed with a serializable type', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
doc.create(serializable_type.serialize({age: 3}), serializable_type.uri);
doc.submitOp({p: ['age'], na: 2});
doc.submitOp({p: ['age'], na: 2}, function(err) {
if (err) return done(err);
expect(doc.data).eql({age: 7});
// Version is 1 instead of 3, because the create and ops got composed
expect(doc.version).eql(1);
doc.submitOp({p: ['age'], na: 2});
doc.submitOp({p: ['age'], na: 2}, function(err) {
if (err) return done(err);
expect(doc.data).eql({age: 11});
// Ops get composed
expect(doc.version).eql(2);
doc.submitOp({p: ['age'], na: 2});
doc.del(function(err) {
if (err) return done(err);
expect(doc.data).eql(undefined);
// del DOES NOT get composed
expect(doc.version).eql(4);
done();
});
});
});
});

it('does not compose ops when doc.preventCompose is true', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
doc.preventCompose = true;
Expand Down Expand Up @@ -380,6 +434,23 @@ describe('client submit', function() {
});
});

it('can commit then fetch in a new connection to get the same data with a serializable type', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
var doc2 = this.backend.connect().get('dogs', 'fido');
doc.create(serializable_type.serialize({age: 3}), serializable_type.uri, function(err) {
if (err) return done(err);
doc2.fetch(function(err) {
if (err) return done(err);
expect(doc.data).eql({age: 3});
expect(doc2.data).eql({age: 3});
expect(doc.version).eql(1);
expect(doc2.version).eql(1);
expect(doc.data).not.equal(doc2.data);
done();
});
});
});

it('an op submitted concurrently is transformed by the first', function(done) {
var doc = this.backend.connect().get('dogs', 'fido');
var doc2 = this.backend.connect().get('dogs', 'fido');
Expand Down
62 changes: 62 additions & 0 deletions test/ot-mock-serializable-json0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
var ot_json0 = require('ot-json0').type;
var HEADER = '!HEADER!';

/** ot-mock-serializable-json0 is a simple wrapper around
* the ot-json0 type providing support for custom serialization
*/
var ot_mock_serializable_json0 = {
name: 'ot_mock_serializable_json0',
uri: 'http://sharejs.org/types/ot_mock_serializable_json0',

create: function( initialData ) {
if(!isSerialized(initialData)) {
throw new Error('SerializableJson0: initialData must be serialized');
}
return initialData;
},

createDeserialized: function(initialData) {
if(!isSerialized(initialData)) {
throw new Error('SerializableJson0: initialData must be serialized');
}
return ot_mock_serializable_json0.deserialize(initialData);
},

apply: function( data, op ) {
var is_serialized = isSerialized(data);
if(is_serialized) {
data = ot_mock_serializable_json0.deserialize(data);
}
data = ot_json0.apply(data, op);
if(is_serialized) {
data = ot_mock_serializable_json0.serialize(data);
}
return data;
},

transform: ot_json0.transform,
compose: ot_json0.compose,
invert: ot_json0.invert,
normalize: ot_json0.normalize,

serialize: function( data ) {
if(isSerialized(data)) {
throw new Error('SerializableJson0: cannot serialize an already serialized ot type instance');
}
return HEADER + JSON.stringify(data);
},

deserialize: function( data ) {
if(!isSerialized(data)) {
throw new Error('SerializableJson0: cannot deserialize an already deserialized ot type instance');
}
return JSON.parse( data.substring(HEADER.length) );
},

};

exports.type = ot_mock_serializable_json0;

function isSerialized( data ) {
return typeof data === 'string' && data.substring(0, HEADER.length) === HEADER;
}