From df3679aded4d7bc45f132bbad63bb2a14d3f1f3e Mon Sep 17 00:00:00 2001
From: Alec Gibson <12036746+alecgibson@users.noreply.github.com>
Date: Tue, 15 Jun 2021 18:12:42 +0100
Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20Rename=20`Doc`=20op=20events?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The `Doc` op events are currently a little confusing: a `json0` "op" can
be shattered into multiple "component ops".
In the current naming, the "op" emits a `'op batch'` event, and the
"op component" emits an `'op'` event.
However, calling the op an "op batch" is a little bit misleading,
because the "batch" is always an op representing a single version number
increase, and potentially considered a single conceptual change.
For example, a remote client might submit a single op:
```js
[
{p: ['a'], oi: 'foo'},
{p: ['b'], oi: 'bar'},
]
```
Under the **current** naming scheme, this emits the following events:
1 `'before op batch'`: `[{p: ['a'], oi: 'foo'}, {p: ['b'], oi: 'bar'}]`
2 `'before op'`: `[{p: ['a'], oi: 'foo'}]`
3 `'op'`: `[{p: ['a'], oi: 'foo'}]`
4 `'before op'`: `[{p: ['b'], oi: 'bar'}]`
5 `'op'`: `[{p: ['b'], oi: 'bar'}]`
6 `'op batch'`: `[{p: ['a'], oi: 'foo'}, {p: ['b'], oi: 'bar'}]`
This can be considered a little surprising, and you may expect the
`'op'` event to be emitted after the whole op (not its shattered
components) have been applied.
Under the **new** naming scheme, the following events are emitted:
1 `'beforeOp'`: `[{p: ['a'], oi: 'foo'}, {p: ['b'], oi: 'bar'}]`
2 `'beforeOpComponent'`: `[{p: ['a'], oi: 'foo'}]`
3 `'opComponent'`: `[{p: ['a'], oi: 'foo'}]`
4 `'beforeOpComponent'`: `[{p: ['b'], oi: 'bar'}]`
5 `'opComponent'`: `[{p: ['b'], oi: 'bar'}]`
6 `'op'`: `[{p: ['a'], oi: 'foo'}, {p: ['b'], oi: 'bar'}]`
This way, you get the `'op'` event after the whole op has been applied.
It also makes it more explicit that you're actively listening out for
the shattered op components where applicable.
Note that we also move the events to camelCase to be consistent with
the Backend middleware actions.
---
CHANGELOG.md | 5 ++++
docs/api/doc.md | 20 ++++++++--------
lib/client/doc.js | 16 ++++++-------
lib/client/presence/local-doc-presence.js | 4 ++--
lib/client/presence/remote-doc-presence.js | 4 ++--
test/client/doc.js | 14 +++++------
test/client/presence/doc-presence.js | 10 ++++----
test/client/projections.js | 4 ++--
test/client/subscribe.js | 28 +++++++++++-----------
9 files changed, 55 insertions(+), 50 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f0f7729c..b0e7539e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,11 @@
### Breaking changes
* Drop Node.js v10 support
+* Rename `Doc` op events:
+ * `before op batch` -> `beforeOp`
+ * `before op` -> `beforeOpComponent`
+ * `op` -> `opComponent`
+ * `op batch` -> `op`
## v1.0-beta
diff --git a/docs/api/doc.md b/docs/api/doc.md
index a94974e32..a5580f3f4 100644
--- a/docs/api/doc.md
+++ b/docs/api/doc.md
@@ -372,12 +372,12 @@ The document was created. The doc will now have a [`type`](#type--type)
> {{ page.copy.event_source }}
-### `'before op'`
+### `'beforeOpComponent'`
An operation is about to be applied to the [`data`](#data--object)
```js
-doc.on('before op', function(op, source) { ... })
+doc.on('beforeOpComponent', function(op, source) { ... })
```
`op` -- Object
@@ -388,20 +388,20 @@ doc.on('before op', function(op, source) { ... })
> {{ page.copy.event_source }}
-### `'op'`
+### `'opComponent'`
An operation was applied to the data.
```js
-doc.on('op', function(op, source) { ... })
+doc.on('opComponent', function(op, source) { ... })
```
{: .info }
-The difference between this event and [`'op batch'`](#op-batch) is that for [`json0`]({{ site.baseurl }}{% link types/json0.md %}), the op will be shattered into its constituent parts.
+The difference between this event and [`'op'`](#op) is that for [`json0`]({{ site.baseurl }}{% link types/json0.md %}), the op will be shattered into its constituent parts.
For example, `[{p: ['list', 0], li: 'a'}, {p: ['list', 1], li: 'b'}]` would be split into two components: `[{p: ['list', 0], li: 'a'}]` and `[{p: ['list', 1], li: 'b'}]`.
-The `'op'` event will be called once for each of these op components, but `'op batch'` will only be called once.
+The `'opComponent'` event will be called once for each of these op components, but `'op'` will only be called once.
`op` -- Object
@@ -411,12 +411,12 @@ The `'op'` event will be called once for each of these op components, but `'op b
> {{ page.copy.event_source }}
-### `'before op batch'`
+### `'beforeOp'`
A potentially multi-part operation is about to be applied to the [`data`](#data--object).
```js
-doc.on('before op batch', function(op, source) { ... })
+doc.on('beforeOp', function(op, source) { ... })
```
`op` -- Object
@@ -427,12 +427,12 @@ doc.on('before op batch', function(op, source) { ... })
> {{ page.copy.event_source }}
-### `'op batch'`
+### `'op'`
A potentially multi-part operation was applied to the [`data`](#data--object)
```js
-doc.on('op batch', function(op, source) { ... })
+doc.on('op', function(op, source) { ... })
```
`op` -- Object
diff --git a/lib/client/doc.js b/lib/client/doc.js
index e37023b2c..9db8384b5 100644
--- a/lib/client/doc.js
+++ b/lib/client/doc.js
@@ -589,7 +589,7 @@ Doc.prototype._otApply = function(op, source) {
// NB: If we need to add another argument to this event, we should consider
// the fact that the 'op' event has op.src as its 3rd argument
- this.emit('before op batch', op.op, source);
+ this.emit('beforeOp', op.op, source);
// Iteratively apply multi-component remote operations and rollback ops
// (source === false) for the default JSON0 OT type. It could use
@@ -620,19 +620,19 @@ Doc.prototype._otApply = function(op, source) {
if (transformErr) return this._hardRollback(transformErr);
}
// Apply the individual op component
- this.emit('before op', componentOp.op, source, op.src);
+ this.emit('beforeOpComponent', componentOp.op, source, op.src);
this.data = this.type.apply(this.data, componentOp.op);
- this.emit('op', componentOp.op, source, op.src);
+ this.emit('opComponent', componentOp.op, source, op.src);
}
- this.emit('op batch', op.op, source);
+ this.emit('op', op.op, source);
// Pop whatever was submitted since we started applying this op
this._popApplyStack(stackLength);
return;
}
- // The 'before op' event enables clients to pull any necessary data out of
+ // The 'beforeOpComponent' event enables clients to pull any necessary data out of
// the snapshot before it gets changed
- this.emit('before op', op.op, source, op.src);
+ this.emit('beforeOpComponent', op.op, source, op.src);
// Apply the operation to the local data, mutating it in place
this.data = this.type.apply(this.data, op.op);
// Emit an 'op' event once the local data includes the changes from the
@@ -640,8 +640,8 @@ Doc.prototype._otApply = function(op, source) {
// submission and before the server or other clients have received the op.
// For ops from other clients, this will be after the op has been
// committed to the database and published
- this.emit('op', op.op, source, op.src);
- this.emit('op batch', op.op, source);
+ this.emit('opComponent', op.op, source, op.src);
+ this.emit('op', op.op, source);
return;
}
diff --git a/lib/client/presence/local-doc-presence.js b/lib/client/presence/local-doc-presence.js
index fd690ba0a..d59fdc110 100644
--- a/lib/client/presence/local-doc-presence.js
+++ b/lib/client/presence/local-doc-presence.js
@@ -39,7 +39,7 @@ LocalDocPresence.prototype.submit = function(value, callback) {
};
LocalDocPresence.prototype.destroy = function(callback) {
- this._doc.removeListener('op', this._opHandler);
+ this._doc.removeListener('opComponent', this._opHandler);
this._doc.removeListener('create', this._createOrDelHandler);
this._doc.removeListener('del', this._createOrDelHandler);
this._doc.removeListener('load', this._loadHandler);
@@ -67,7 +67,7 @@ LocalDocPresence.prototype._sendPending = function() {
};
LocalDocPresence.prototype._registerWithDoc = function() {
- this._doc.on('op', this._opHandler);
+ this._doc.on('opComponent', this._opHandler);
this._doc.on('create', this._createOrDelHandler);
this._doc.on('del', this._createOrDelHandler);
this._doc.on('load', this._loadHandler);
diff --git a/lib/client/presence/remote-doc-presence.js b/lib/client/presence/remote-doc-presence.js
index 2fef91ffa..e75051058 100644
--- a/lib/client/presence/remote-doc-presence.js
+++ b/lib/client/presence/remote-doc-presence.js
@@ -31,7 +31,7 @@ RemoteDocPresence.prototype.receiveUpdate = function(message) {
};
RemoteDocPresence.prototype.destroy = function(callback) {
- this._doc.removeListener('op', this._opHandler);
+ this._doc.removeListener('opComponent', this._opHandler);
this._doc.removeListener('create', this._createDelHandler);
this._doc.removeListener('del', this._createDelHandler);
this._doc.removeListener('load', this._loadHandler);
@@ -40,7 +40,7 @@ RemoteDocPresence.prototype.destroy = function(callback) {
};
RemoteDocPresence.prototype._registerWithDoc = function() {
- this._doc.on('op', this._opHandler);
+ this._doc.on('opComponent', this._opHandler);
this._doc.on('create', this._createDelHandler);
this._doc.on('del', this._createDelHandler);
this._doc.on('load', this._loadHandler);
diff --git a/test/client/doc.js b/test/client/doc.js
index 84af1fb68..1082e5a7c 100644
--- a/test/client/doc.js
+++ b/test/client/doc.js
@@ -150,7 +150,7 @@ describe('Doc', function() {
expect(doc.data).eql({color: 'black'});
}
];
- doc.on('op', function(op, source) {
+ doc.on('opComponent', function(op, source) {
var handler = handlers.shift();
handler(op, source);
});
@@ -199,7 +199,7 @@ describe('Doc', function() {
expect(doc.data).eql({color: 'black', weight: 40, age: 5, owner: 'sue'});
}
];
- doc.on('op', function(op, source) {
+ doc.on('opComponent', function(op, source) {
var handler = handlers.shift();
handler(op, source);
});
@@ -250,7 +250,7 @@ describe('Doc', function() {
expect(doc.data).eql({tricks: ['shake', 'tug stick']});
}
];
- doc.on('op', function(op, source) {
+ doc.on('opComponent', function(op, source) {
var handler = handlers.shift();
handler(op, source);
});
@@ -277,13 +277,13 @@ describe('Doc', function() {
{p: ['tricks', 0], li: 'stand'}
];
- doc.on('before op batch', function(op, source) {
+ doc.on('beforeOp', function(op, source) {
expect(op).to.eql(submittedOp);
expect(source).to.be.true;
beforeOpBatchCount++;
});
- doc.on('op batch', function(op, source) {
+ doc.on('op', function(op, source) {
expect(op).to.eql(submittedOp);
expect(source).to.be.true;
expect(beforeOpBatchCount).to.equal(1);
@@ -304,13 +304,13 @@ describe('Doc', function() {
{p: ['tricks', 0], li: 'stand'}
];
- doc.on('before op batch', function(op, source) {
+ doc.on('beforeOp', function(op, source) {
expect(op).to.eql(submittedOp);
expect(source).to.be.false;
beforeOpBatchCount++;
});
- doc.on('op batch', function(op, source) {
+ doc.on('op', function(op, source) {
expect(op).to.eql(submittedOp);
expect(source).to.be.false;
expect(beforeOpBatchCount).to.equal(1);
diff --git a/test/client/presence/doc-presence.js b/test/client/presence/doc-presence.js
index 61b69eb94..dcccb2d35 100644
--- a/test/client/presence/doc-presence.js
+++ b/test/client/presence/doc-presence.js
@@ -284,7 +284,7 @@ describe('DocPresence', function() {
function(next) {
doc1.submitOp({index: 5, value: 'ern'}, errorHandler(done));
- doc2.once('op', function() {
+ doc2.once('opComponent', function() {
presencePauser.resume();
});
@@ -324,7 +324,7 @@ describe('DocPresence', function() {
// doc2 has received this op, so we know that when we finally receive our
// presence, it will be stale
doc1.submitOp({index: 5, value: 'ern'}, errorHandler(done));
- doc2.once('op', function() {
+ doc2.once('opComponent', function() {
next();
});
},
@@ -350,7 +350,7 @@ describe('DocPresence', function() {
doc1.submitOp({index: 0, value: 'The'}, function(error) {
if (error) return done(error);
doc1.submitOp({index: 3, value: ' '}, errorHandler(done));
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
// This will get fired for v3 and then v4, so check for the later one
if (doc1.version === 4 && doc2.version === 4) {
// Only once doc2 has received the ops, should we resume our
@@ -395,7 +395,7 @@ describe('DocPresence', function() {
},
function(next) {
doc1.submitOp({index: 5, value: 'ern'}, errorHandler(done));
- doc2.once('op', function() {
+ doc2.once('opComponent', function() {
next();
});
},
@@ -417,7 +417,7 @@ describe('DocPresence', function() {
], errorHandler(done));
};
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
if (doc2.version !== 5) return;
presencePauser.resume();
presence2.once('receive', function(id, presence) {
diff --git a/test/client/projections.js b/test/client/projections.js
index 8275b2bfd..d0634d4da 100644
--- a/test/client/projections.js
+++ b/test/client/projections.js
@@ -124,7 +124,7 @@ module.exports = function(options) {
var fido = connection2.get('dogs_summary', 'fido');
fido.subscribe(function(err) {
if (err) return done(err);
- fido.on('op', function() {
+ fido.on('opComponent', function() {
expect(fido.data).eql(expected);
expect(fido.version).eql(2);
done();
@@ -164,7 +164,7 @@ module.exports = function(options) {
var fido = connection2.get('dogs_summary', 'fido');
connection2.createSubscribeQuery('dogs_summary', matchAllQuery, null, function(err) {
if (err) return done(err);
- fido.on('op', function() {
+ fido.on('opComponent', function() {
expect(fido.data).eql(expected);
expect(fido.version).eql(2);
done();
diff --git a/test/client/subscribe.js b/test/client/subscribe.js
index 2ec2ab5d6..210ec3588 100644
--- a/test/client/subscribe.js
+++ b/test/client/subscribe.js
@@ -73,7 +73,7 @@ module.exports = function() {
return done();
}
// Add listeners on connection2 for remote operations.
- fido.on('before op', function(op) {
+ fido.on('beforeOpComponent', function(op) {
done(new Error('fido on connection2 should not have received any ops, got:' +
JSON.stringify(op)));
});
@@ -268,7 +268,7 @@ module.exports = function() {
return done();
}
// Add listeners on connection2 for those operations.
- fido.on('before op', function(op) {
+ fido.on('beforeOpComponent', function(op) {
done(new Error('fido on connection2 should not have received any ops, got:' +
JSON.stringify(op)));
});
@@ -436,7 +436,7 @@ module.exports = function() {
if (err) return done(err);
doc.submitOp({p: ['age'], na: 1}, function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
done();
});
doc2[method]();
@@ -603,7 +603,7 @@ module.exports = function() {
if (err) return done(err);
doc2.subscribe(function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
expect(doc2.version).eql(2);
expect(doc2.data).eql({age: 4});
done();
@@ -620,7 +620,7 @@ module.exports = function() {
if (err) return done(err);
doc2.subscribe(function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
done();
});
doc2.connection.close();
@@ -637,7 +637,7 @@ module.exports = function() {
if (err) return done(err);
doc2.subscribe(function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
done();
});
backend.suppressPublish = true;
@@ -653,7 +653,7 @@ module.exports = function() {
if (err) return done(err);
doc2.subscribe(function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
done();
});
doc2.unsubscribe(function(err) {
@@ -685,7 +685,7 @@ module.exports = function() {
if (error) return done(error);
done();
});
- doc.on('op', function() {
+ doc.on('opComponent', function() {
done(new Error('should not have received op'));
});
});
@@ -706,7 +706,7 @@ module.exports = function() {
if (err) return done(err);
doc2.subscribe(function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
done(new Error('Should not get op event'));
});
doc2.destroy(function(err) {
@@ -756,7 +756,7 @@ module.exports = function() {
}
], function(err) {
if (err) return done(err);
- fido.on('op', function() {
+ fido.on('opComponent', function() {
done();
});
doc.submitOp({p: ['age'], na: 1}, done);
@@ -774,7 +774,7 @@ module.exports = function() {
if (err) return done(err);
doc2.subscribe(function(err) {
if (err) return done(err);
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
expect(doc2.version).eql(2);
expect(doc2.data).eql({age: 4});
done();
@@ -800,7 +800,7 @@ module.exports = function() {
if (err) return done(err);
expect(doc2.wantSubscribe).to.be.true;
expect(doc2.subscribed).to.be.true;
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
done();
});
doc.submitOp({p: ['age'], na: 1});
@@ -820,7 +820,7 @@ module.exports = function() {
[{p: ['age'], na: 1}],
[{p: ['age'], na: 5}]
];
- doc2.on('op', function(op) {
+ doc2.on('opComponent', function(op) {
var item = expected.shift();
expect(op).eql(item);
if (expected.length) return;
@@ -852,7 +852,7 @@ module.exports = function() {
doc2.subscribe(function(err) {
if (err) return done(err);
var wait = 4;
- doc2.on('op', function() {
+ doc2.on('opComponent', function() {
if (--wait) return;
expect(doc2.version).eql(5);
expect(doc2.data).eql({age: 122});