sharedb 2.2.3 → 3.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 +19 -4
- package/lib/client/doc.js +2 -2
- package/package.json +1 -1
- package/test/client/doc.js +30 -0
- package/test/client/snapshot-timestamp-request.js +48 -0
- package/test/client/snapshot-version-request.js +54 -0
- package/test/ot.js +225 -93
package/lib/backend.js
CHANGED
|
@@ -772,6 +772,16 @@ Backend.prototype._fetchSnapshot = function(collection, id, version, callback) {
|
|
|
772
772
|
var db = this.db;
|
|
773
773
|
var backend = this;
|
|
774
774
|
|
|
775
|
+
var shouldGetLatestSnapshot = version === null;
|
|
776
|
+
if (shouldGetLatestSnapshot) {
|
|
777
|
+
return backend.db.getSnapshot(collection, id, null, null, function(error, snapshot) {
|
|
778
|
+
if (error) return callback(error);
|
|
779
|
+
|
|
780
|
+
callback(null, snapshot);
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
|
|
775
785
|
this.milestoneDb.getMilestoneSnapshot(collection, id, version, function(error, milestoneSnapshot) {
|
|
776
786
|
if (error) return callback(error);
|
|
777
787
|
|
|
@@ -833,6 +843,15 @@ Backend.prototype._fetchSnapshotByTimestamp = function(collection, id, timestamp
|
|
|
833
843
|
var from = 0;
|
|
834
844
|
var to = null;
|
|
835
845
|
|
|
846
|
+
var shouldGetLatestSnapshot = timestamp === null;
|
|
847
|
+
if (shouldGetLatestSnapshot) {
|
|
848
|
+
return backend.db.getSnapshot(collection, id, null, null, function(error, snapshot) {
|
|
849
|
+
if (error) return callback(error);
|
|
850
|
+
|
|
851
|
+
callback(null, snapshot);
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
|
|
836
855
|
milestoneDb.getMilestoneSnapshotAtOrBeforeTime(collection, id, timestamp, function(error, snapshot) {
|
|
837
856
|
if (error) return callback(error);
|
|
838
857
|
milestoneSnapshot = snapshot;
|
|
@@ -883,10 +902,6 @@ function pluckIds(snapshots) {
|
|
|
883
902
|
}
|
|
884
903
|
|
|
885
904
|
function filterOpsInPlaceBeforeTimestamp(ops, timestamp) {
|
|
886
|
-
if (timestamp === null) {
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
905
|
for (var i = 0; i < ops.length; i++) {
|
|
891
906
|
var op = ops[i];
|
|
892
907
|
var opTimestamp = op.m && op.m.ts;
|
package/lib/client/doc.js
CHANGED
|
@@ -624,6 +624,8 @@ Doc.prototype._otApply = function(op, source) {
|
|
|
624
624
|
for (var i = 0; i < op.op.length; i++) {
|
|
625
625
|
var component = op.op[i];
|
|
626
626
|
var componentOp = {op: [component]};
|
|
627
|
+
// Apply the individual op component
|
|
628
|
+
this.emit('before op', componentOp.op, source, op.src);
|
|
627
629
|
// Transform componentOp against any ops that have been submitted
|
|
628
630
|
// sychronously inside of an op event handler since we began apply of
|
|
629
631
|
// our operation
|
|
@@ -631,8 +633,6 @@ Doc.prototype._otApply = function(op, source) {
|
|
|
631
633
|
var transformErr = transformX(this.applyStack[j], componentOp);
|
|
632
634
|
if (transformErr) return this._hardRollback(transformErr);
|
|
633
635
|
}
|
|
634
|
-
// Apply the individual op component
|
|
635
|
-
this.emit('before op', componentOp.op, source, op.src);
|
|
636
636
|
this._setData(this.type.apply(this.data, componentOp.op));
|
|
637
637
|
this.emit('op', componentOp.op, source, op.src);
|
|
638
638
|
}
|
package/package.json
CHANGED
package/test/client/doc.js
CHANGED
|
@@ -214,6 +214,36 @@ describe('Doc', function() {
|
|
|
214
214
|
});
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
+
it('remote ops are transformed by ops submitted in `before op` event handlers', function(done) {
|
|
218
|
+
var doc = this.doc;
|
|
219
|
+
var doc2 = this.doc2;
|
|
220
|
+
var doc3 = this.doc3;
|
|
221
|
+
function beforeOpHandler(op, source) {
|
|
222
|
+
if (source) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
doc.off('before op', beforeOpHandler);
|
|
226
|
+
doc.submitOp({p: ['list', 0], li: 2}, {source: true});
|
|
227
|
+
}
|
|
228
|
+
function opHandler(op, source) {
|
|
229
|
+
if (source) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
doc.off('op', opHandler);
|
|
233
|
+
doc.submitOp({p: ['list', 0], li: 3}, {source: true});
|
|
234
|
+
}
|
|
235
|
+
doc2.submitOp({p: ['list'], oi: []}, function() {
|
|
236
|
+
doc.fetch(function() {
|
|
237
|
+
doc.on('before op', beforeOpHandler);
|
|
238
|
+
doc.on('op', opHandler);
|
|
239
|
+
doc2.submitOp([{p: ['list', 0], li: 1}, {p: ['list', 1], li: 42}], function() {
|
|
240
|
+
doc.fetch();
|
|
241
|
+
verifyConsistency(doc, doc2, doc3, [], done);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
217
247
|
it('remote multi component ops are transformed by ops submitted in `op` event handlers', function(done) {
|
|
218
248
|
var doc = this.doc;
|
|
219
249
|
var doc2 = this.doc2;
|
|
@@ -490,6 +490,54 @@ describe('SnapshotTimestampRequest', function() {
|
|
|
490
490
|
done();
|
|
491
491
|
});
|
|
492
492
|
});
|
|
493
|
+
|
|
494
|
+
describe('when timestamp is null', function() {
|
|
495
|
+
it('fetches latest snapshot', function(done) {
|
|
496
|
+
sinon.spy(milestoneDb, 'getMilestoneSnapshotAtOrBeforeTime');
|
|
497
|
+
sinon.spy(milestoneDb, 'getMilestoneSnapshotAtOrAfterTime');
|
|
498
|
+
sinon.spy(db, 'getOps');
|
|
499
|
+
|
|
500
|
+
backendWithMilestones.connect()
|
|
501
|
+
.fetchSnapshotByTimestamp('books', 'mocking-bird', null, function(error, snapshot) {
|
|
502
|
+
if (error) return done(error);
|
|
503
|
+
|
|
504
|
+
expect(milestoneDb.getMilestoneSnapshotAtOrBeforeTime.called).to.be.false;
|
|
505
|
+
expect(milestoneDb.getMilestoneSnapshotAtOrAfterTime.called).to.be.false;
|
|
506
|
+
expect(db.getOps.called).to.be.false;
|
|
507
|
+
|
|
508
|
+
expect(snapshot.v).to.equal(5);
|
|
509
|
+
expect(snapshot.data).to.eql({
|
|
510
|
+
title: 'To Kill a Mocking Bird',
|
|
511
|
+
author: 'Harper Lee',
|
|
512
|
+
year: 1960
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
done();
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it('returns error if getSnapshot fails', function(done) {
|
|
520
|
+
sinon.spy(milestoneDb, 'getMilestoneSnapshotAtOrBeforeTime');
|
|
521
|
+
sinon.spy(milestoneDb, 'getMilestoneSnapshotAtOrAfterTime');
|
|
522
|
+
sinon.spy(db, 'getOps');
|
|
523
|
+
|
|
524
|
+
sinon.stub(db, 'getSnapshot').callsFake(function(_collection, _id, _fields, _options, callback) {
|
|
525
|
+
callback(new Error('TEST_ERROR'));
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
backendWithMilestones.connect()
|
|
529
|
+
.fetchSnapshotByTimestamp('books', 'mocking-bird', null, function(error) {
|
|
530
|
+
expect(error.message).to.be.equal('TEST_ERROR');
|
|
531
|
+
|
|
532
|
+
expect(milestoneDb.getMilestoneSnapshotAtOrBeforeTime.called).to.be.false;
|
|
533
|
+
expect(milestoneDb.getMilestoneSnapshotAtOrAfterTime.called).to.be.false;
|
|
534
|
+
expect(db.getOps.called).to.be.false;
|
|
535
|
+
expect(db.getSnapshot.called).to.be.true;
|
|
536
|
+
|
|
537
|
+
done();
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
});
|
|
493
541
|
});
|
|
494
542
|
});
|
|
495
543
|
});
|
|
@@ -439,6 +439,60 @@ describe('SnapshotVersionRequest', function() {
|
|
|
439
439
|
}
|
|
440
440
|
], done);
|
|
441
441
|
});
|
|
442
|
+
|
|
443
|
+
describe('with version null', function() {
|
|
444
|
+
it('fetches a latest version', function(done) {
|
|
445
|
+
var doc = backendWithMilestones.connect().get('books', 'mocking-bird');
|
|
446
|
+
|
|
447
|
+
async.waterfall([
|
|
448
|
+
doc.create.bind(doc, {title: 'To Kill a Mocking Bird'}),
|
|
449
|
+
doc.submitOp.bind(doc, {p: ['author'], oi: 'Harper Lea'}),
|
|
450
|
+
doc.submitOp.bind(doc, {p: ['author'], od: 'Harper Lea', oi: 'Harper Lee'}),
|
|
451
|
+
function(next) {
|
|
452
|
+
sinon.spy(milestoneDb, 'getMilestoneSnapshot');
|
|
453
|
+
sinon.spy(db, 'getOps');
|
|
454
|
+
backendWithMilestones.connect().fetchSnapshot('books', 'mocking-bird', null, next);
|
|
455
|
+
},
|
|
456
|
+
function(snapshot, next) {
|
|
457
|
+
expect(milestoneDb.getMilestoneSnapshot.called).to.be.false;
|
|
458
|
+
expect(db.getOps.called).to.be.false;
|
|
459
|
+
expect(snapshot.v).to.equal(3);
|
|
460
|
+
expect(snapshot.data).to.eql({
|
|
461
|
+
title: 'To Kill a Mocking Bird',
|
|
462
|
+
author: 'Harper Lee'
|
|
463
|
+
});
|
|
464
|
+
next();
|
|
465
|
+
}
|
|
466
|
+
], done);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('return error if getSnapshot fails', function(done) {
|
|
470
|
+
var doc = backendWithMilestones.connect().get('books', 'mocking-bird');
|
|
471
|
+
|
|
472
|
+
async.waterfall([
|
|
473
|
+
doc.create.bind(doc, {title: 'To Kill a Mocking Bird'}),
|
|
474
|
+
doc.submitOp.bind(doc, {p: ['author'], oi: 'Harper Lea'}),
|
|
475
|
+
doc.submitOp.bind(doc, {p: ['author'], od: 'Harper Lea', oi: 'Harper Lee'}),
|
|
476
|
+
function(next) {
|
|
477
|
+
sinon.spy(milestoneDb, 'getMilestoneSnapshot');
|
|
478
|
+
sinon.spy(db, 'getOps');
|
|
479
|
+
sinon.stub(db, 'getSnapshot').callsFake(function(_collection, _id, _fields, _options, callback) {
|
|
480
|
+
callback(new Error('TEST_ERROR'));
|
|
481
|
+
});
|
|
482
|
+
backendWithMilestones.connect().fetchSnapshot('books', 'mocking-bird', null, function(error) {
|
|
483
|
+
expect(error.message).to.be.equal('TEST_ERROR');
|
|
484
|
+
next(null, null);
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
function(snapshot, next) {
|
|
488
|
+
expect(milestoneDb.getMilestoneSnapshot.called).to.be.false;
|
|
489
|
+
expect(db.getOps.called).to.be.false;
|
|
490
|
+
expect(db.getSnapshot.called).to.be.true;
|
|
491
|
+
next();
|
|
492
|
+
}
|
|
493
|
+
], done);
|
|
494
|
+
});
|
|
495
|
+
});
|
|
442
496
|
});
|
|
443
497
|
|
|
444
498
|
describe('invalid json0v2 path', function() {
|
package/test/ot.js
CHANGED
|
@@ -373,118 +373,250 @@ describe('ot', function() {
|
|
|
373
373
|
});
|
|
374
374
|
|
|
375
375
|
describe('applyOps', function() {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
376
|
+
describe('with normalization turned on', function() {
|
|
377
|
+
it('applies an op to a snapshot', function() {
|
|
378
|
+
var snapshot = {
|
|
379
|
+
type: 'http://sharejs.org/types/JSONv0',
|
|
380
|
+
data: {title: 'Wee Free Men'}
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
var ops = [
|
|
384
|
+
{
|
|
385
|
+
v: 1,
|
|
386
|
+
op: [{p: ['title', 0], si: 'The '}]
|
|
387
|
+
}
|
|
388
|
+
];
|
|
389
|
+
|
|
390
|
+
var error = ot.applyOps(snapshot, ops, {
|
|
391
|
+
_normalizeLegacyJson0Ops: true
|
|
392
|
+
});
|
|
393
|
+
expect(error).to.be.undefined;
|
|
394
|
+
expect(snapshot.data).to.eql({title: 'The Wee Free Men'});
|
|
395
|
+
expect(snapshot.v).to.equal(2);
|
|
396
|
+
});
|
|
381
397
|
|
|
382
|
-
|
|
383
|
-
{
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
398
|
+
it('applies multiple ops', function() {
|
|
399
|
+
var snapshot = {
|
|
400
|
+
type: 'http://sharejs.org/types/JSONv0',
|
|
401
|
+
data: {title: 'Wee Free Men'}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
var ops = [
|
|
405
|
+
{
|
|
406
|
+
v: 1,
|
|
407
|
+
op: [{p: ['title', 0], si: 'The '}]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
v: 2,
|
|
411
|
+
op: [{p: ['author'], oi: 'Terry Pratchett'}]
|
|
412
|
+
}
|
|
413
|
+
];
|
|
414
|
+
|
|
415
|
+
ot.applyOps(snapshot, ops, {
|
|
416
|
+
_normalizeLegacyJson0Ops: true
|
|
417
|
+
});
|
|
418
|
+
expect(snapshot.data).to.eql({
|
|
419
|
+
author: 'Terry Pratchett',
|
|
420
|
+
title: 'The Wee Free Men'
|
|
421
|
+
});
|
|
422
|
+
expect(snapshot.v).to.equal(3);
|
|
423
|
+
});
|
|
388
424
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
425
|
+
it('applies a del to a snapshot', function() {
|
|
426
|
+
var snapshot = {
|
|
427
|
+
type: 'http://sharejs.org/types/JSONv0',
|
|
428
|
+
data: {title: 'Wee Free Men'}
|
|
429
|
+
};
|
|
394
430
|
|
|
395
|
-
|
|
396
|
-
var snapshot = {
|
|
397
|
-
type: 'json0',
|
|
398
|
-
data: {title: 'Wee Free Men'}
|
|
399
|
-
};
|
|
431
|
+
var ops = [{v: 1, del: true}];
|
|
400
432
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
},
|
|
406
|
-
{
|
|
407
|
-
v: 2,
|
|
408
|
-
op: [{p: ['author'], oi: 'Terry Pratchett'}]
|
|
409
|
-
}
|
|
410
|
-
];
|
|
411
|
-
|
|
412
|
-
ot.applyOps(snapshot, ops);
|
|
413
|
-
expect(snapshot.data).to.eql({
|
|
414
|
-
author: 'Terry Pratchett',
|
|
415
|
-
title: 'The Wee Free Men'
|
|
433
|
+
ot.applyOps(snapshot, ops, {
|
|
434
|
+
_normalizeLegacyJson0Ops: true
|
|
435
|
+
});
|
|
436
|
+
expect(snapshot.data).to.be.undefined;
|
|
416
437
|
});
|
|
417
|
-
expect(snapshot.v).to.equal(3);
|
|
418
|
-
});
|
|
419
438
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
439
|
+
it('applies a create to a snapshot', function() {
|
|
440
|
+
var snapshot = {};
|
|
441
|
+
var ops = [
|
|
442
|
+
{
|
|
443
|
+
v: 1,
|
|
444
|
+
create: {
|
|
445
|
+
type: 'http://sharejs.org/types/JSONv0',
|
|
446
|
+
data: {title: 'Wee Free Men'}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
];
|
|
425
450
|
|
|
426
|
-
|
|
451
|
+
ot.applyOps(snapshot, ops, {
|
|
452
|
+
_normalizeLegacyJson0Ops: true
|
|
453
|
+
});
|
|
454
|
+
expect(snapshot.data).to.eql({title: 'Wee Free Men'});
|
|
455
|
+
});
|
|
427
456
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
457
|
+
it('returns an error if the snapshot has an unknown type', function() {
|
|
458
|
+
var snapshot = {type: 'unknown-type', data: {}};
|
|
459
|
+
var ops = [
|
|
460
|
+
{
|
|
461
|
+
v: 1,
|
|
462
|
+
op: [{p: ['title'], oi: 'Title'}]
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
var error = ot.applyOps(snapshot, ops, {
|
|
466
|
+
_normalizeLegacyJson0Ops: true
|
|
467
|
+
});
|
|
468
|
+
expect(error.code).to.equal(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED);
|
|
469
|
+
});
|
|
431
470
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
471
|
+
it('returns an error if a create op has an unknown type', function() {
|
|
472
|
+
var snapshot = {};
|
|
473
|
+
var ops = [
|
|
474
|
+
{
|
|
475
|
+
v: 1,
|
|
476
|
+
create: {
|
|
477
|
+
type: 'unknown-type',
|
|
478
|
+
data: {}
|
|
479
|
+
}
|
|
440
480
|
}
|
|
441
|
-
|
|
442
|
-
|
|
481
|
+
];
|
|
482
|
+
var error = ot.applyOps(snapshot, ops, {
|
|
483
|
+
_normalizeLegacyJson0Ops: true
|
|
484
|
+
});
|
|
485
|
+
expect(error.code).to.equal(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED);
|
|
486
|
+
});
|
|
443
487
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
488
|
+
it('catches and returns an error thrown by type.apply', function() {
|
|
489
|
+
var snapshot = {
|
|
490
|
+
type: 'http://sharejs.org/types/JSONv0',
|
|
491
|
+
data: {title: 'Wee Free Men'}
|
|
492
|
+
};
|
|
447
493
|
|
|
448
|
-
|
|
449
|
-
var snapshot = {type: 'unknown-type', data: {}};
|
|
450
|
-
var ops = [
|
|
451
|
-
{
|
|
494
|
+
var ops = [{
|
|
452
495
|
v: 1,
|
|
453
|
-
op: [{p: ['title'],
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
496
|
+
op: [{p: ['title'], li: 'not a list'}]
|
|
497
|
+
}];
|
|
498
|
+
|
|
499
|
+
var error = ot.applyOps(snapshot, ops, {
|
|
500
|
+
_normalizeLegacyJson0Ops: true
|
|
501
|
+
});
|
|
502
|
+
expect(error.code).to.equal(ERROR_CODE.ERR_OT_OP_NOT_APPLIED);
|
|
503
|
+
});
|
|
458
504
|
});
|
|
459
505
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
506
|
+
describe('with normalization turned off', function() {
|
|
507
|
+
it('applies an op to a snapshot', function() {
|
|
508
|
+
var snapshot = {
|
|
509
|
+
type: 'json0',
|
|
510
|
+
data: {title: 'Wee Free Men'}
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
var ops = [
|
|
514
|
+
{
|
|
515
|
+
v: 1,
|
|
516
|
+
op: [{p: ['title', 0], si: 'The '}]
|
|
468
517
|
}
|
|
469
|
-
|
|
470
|
-
];
|
|
471
|
-
var error = ot.applyOps(snapshot, ops);
|
|
472
|
-
expect(error.code).to.equal(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED);
|
|
473
|
-
});
|
|
518
|
+
];
|
|
474
519
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
};
|
|
520
|
+
var error = ot.applyOps(snapshot, ops);
|
|
521
|
+
expect(error).to.be.undefined;
|
|
522
|
+
expect(snapshot.data).to.eql({title: 'The Wee Free Men'});
|
|
523
|
+
expect(snapshot.v).to.equal(2);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('applies multiple ops', function() {
|
|
527
|
+
var snapshot = {
|
|
528
|
+
type: 'json0',
|
|
529
|
+
data: {title: 'Wee Free Men'}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
var ops = [
|
|
533
|
+
{
|
|
534
|
+
v: 1,
|
|
535
|
+
op: [{p: ['title', 0], si: 'The '}]
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
v: 2,
|
|
539
|
+
op: [{p: ['author'], oi: 'Terry Pratchett'}]
|
|
540
|
+
}
|
|
541
|
+
];
|
|
542
|
+
|
|
543
|
+
ot.applyOps(snapshot, ops);
|
|
544
|
+
expect(snapshot.data).to.eql({
|
|
545
|
+
author: 'Terry Pratchett',
|
|
546
|
+
title: 'The Wee Free Men'
|
|
547
|
+
});
|
|
548
|
+
expect(snapshot.v).to.equal(3);
|
|
549
|
+
});
|
|
480
550
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
551
|
+
it('applies a del to a snapshot', function() {
|
|
552
|
+
var snapshot = {
|
|
553
|
+
type: 'json0',
|
|
554
|
+
data: {title: 'Wee Free Men'}
|
|
555
|
+
};
|
|
485
556
|
|
|
486
|
-
|
|
487
|
-
|
|
557
|
+
var ops = [{v: 1, del: true}];
|
|
558
|
+
|
|
559
|
+
ot.applyOps(snapshot, ops);
|
|
560
|
+
expect(snapshot.data).to.be.undefined;
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it('applies a create to a snapshot', function() {
|
|
564
|
+
var snapshot = {};
|
|
565
|
+
var ops = [
|
|
566
|
+
{
|
|
567
|
+
v: 1,
|
|
568
|
+
create: {
|
|
569
|
+
type: 'json0',
|
|
570
|
+
data: {title: 'Wee Free Men'}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
];
|
|
574
|
+
|
|
575
|
+
ot.applyOps(snapshot, ops);
|
|
576
|
+
expect(snapshot.data).to.eql({title: 'Wee Free Men'});
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
it('returns an error if the snapshot has an unknown type', function() {
|
|
580
|
+
var snapshot = {type: 'unknown-type', data: {}};
|
|
581
|
+
var ops = [
|
|
582
|
+
{
|
|
583
|
+
v: 1,
|
|
584
|
+
op: [{p: ['title'], oi: 'Title'}]
|
|
585
|
+
}
|
|
586
|
+
];
|
|
587
|
+
var error = ot.applyOps(snapshot, ops);
|
|
588
|
+
expect(error.code).to.equal(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED);
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
it('returns an error if a create op has an unknown type', function() {
|
|
592
|
+
var snapshot = {};
|
|
593
|
+
var ops = [
|
|
594
|
+
{
|
|
595
|
+
v: 1,
|
|
596
|
+
create: {
|
|
597
|
+
type: 'unknown-type',
|
|
598
|
+
data: {}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
];
|
|
602
|
+
var error = ot.applyOps(snapshot, ops);
|
|
603
|
+
expect(error.code).to.equal(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('catches and returns an error thrown by type.apply', function() {
|
|
607
|
+
var snapshot = {
|
|
608
|
+
type: 'json0',
|
|
609
|
+
data: {title: 'Wee Free Men'}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
var ops = [{
|
|
613
|
+
v: 1,
|
|
614
|
+
op: [{p: ['title'], li: 'not a list'}]
|
|
615
|
+
}];
|
|
616
|
+
|
|
617
|
+
var error = ot.applyOps(snapshot, ops);
|
|
618
|
+
expect(error.code).to.equal(ERROR_CODE.ERR_OT_OP_NOT_APPLIED);
|
|
619
|
+
});
|
|
488
620
|
});
|
|
489
621
|
});
|
|
490
622
|
});
|