-
Notifications
You must be signed in to change notification settings - Fork 450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add preventInvertInRollback option #443
Add preventInvertInRollback option #443
Conversation
@antoinelyset thanks for the Pull Request! We've discussed this, and we believe this conceptually live at the JSON1 level. The thing is that the OT Type interface should act as a guarantee. If a type has implemented an optional method like Our suggestions for moving forwards with this issue:
That obviously doesn't fix your issue right now. In the meantime we suggest:
|
Thanks for your quick answer. I will ask what we can do in the JSON1 repo. |
Hi! json1 and sharedb original author here. I think can do better than those options. The problem isn't that json1 is broken. The problem is that json1 has both invertible and non-invertible operations. Non-invertible operations come from two sources:
To make matter worse, there's no flag in an operation which specifies whether or not its invertible. This is a flaw in the design. json1 has two methods to help here:
I had sharedb in mind when I wrote json1 (and if it existed when sharedb was written, we would have used it). Its been a long time since I looked at the code, but sharejs should be able to use the makeInvertible method in json1 to restore invertibility information in the undo / rollback stack, since the state is known by sharedb when the operation is created. > doc = {a:'hi'}
> op = json1.removeOp(['a'])
[ 'a', { r: true } ]
> json1.makeInvertible(op, doc)
[ 'a', { r: 'hi' } ] |
All in all, it sounds like inversion is a bit "unreliable" from the perspective of ShareDB consuming an API — that is ShareDB has no idea of whether or not it should be able to apply an inversion to any given op. This is also true of @josephg we could potentially track an in-memory undo stack (this would incidentally make In an ideal world, my suggestion would be to default to hard rollback, and make invertible fallback opt-in. However, that would be a breaking change, so we probably can't go down that route. Perhaps this PR is then the most pragmatic solution. @ericyhwang had raised the concern that it's a bit awkward to use as a consumer: you have to set whether you want an inverted rollback on each document. However, on reflection, I think it's possible that some consumers might use different documents/collections in different ways (perhaps they use invertible ops on one, but not on another?). It's a bit awkward, but applying it at this level gives consumers the greatest granularity of control. My only other thought is that we could perhaps offer an event before rollback (which might also be nice for logging). This would also let consumers decide per-op if they want to soft rollback or not. A potential API might look like: doc.on('before rollback', (event) => {
if (consumerNotWantInvert(event.op)) {
event.hardRollback();
}
}); |
Sure - happy to defer to your opinion on what sharedb should do. The rollback infrastructure is from after my time, and I wasn't in those design meetings. Otherwise if there's any changes you'd like to see in json1, let me know / file an issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
var pauseSubmit = false; | ||
var fireSubmit; | ||
var invertHaveBeenCalled = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't help but notice a grammar issue. Suggest to simplify this name.
var invertHaveBeenCalled = false; | |
var invertCalled = false; |
// Wrap invert to test that it has been called | ||
var originalInvert = doc2.type.invert; | ||
doc2.type.invert = function(op) { | ||
invertHaveBeenCalled = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invertHaveBeenCalled = true; | |
invertCalled = true; |
}); | ||
}, | ||
function(next) { | ||
expect(invertHaveBeenCalled).to.eql(!preventInvertInRollback); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect(invertHaveBeenCalled).to.eql(!preventInvertInRollback); | |
expect(invertCalled).to.eql(!preventInvertInRollback); |
My try at adding an option to improve support for JSON1. #442
I heavily relied on a previous spec, so it may be possible to simplify it.