Skip to content
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

Possibility to add revision to operations #11

Open
rkusa opened this issue Oct 31, 2014 · 4 comments
Open

Possibility to add revision to operations #11

rkusa opened this issue Oct 31, 2014 · 4 comments

Comments

@rkusa
Copy link

rkusa commented Oct 31, 2014

tl;dr I propose to add some special optional property to operations that indicate some kind of unique identifier or version/revision.

One scenario, where JSONPatch is really useful compared to working with complete states, are apps with collaborative functionalities.

Think of a collaborative application that is distributed through multiple servers, i.e., there are is no total order for incoming changes. For concurrent changes, one operation has to win against another and the result must be the same on every server.

That is, some operations need some kind of metadata. Taking for example the replace op. When implementing a map of data as a CRDT, one approach of doing so, is to track a version number for each property. This version number has to be included in the JSONPatch operation, e.g.:

{ "op": "replace", "path": "/foo", "value": "bar", "rev": 42 }

Another example is a OR-Set, which is, simply put, a list where (internally) each item has a unique id. A scenario where this is useful:

User A adds "foobar" (gets the unique id 123) to the list. Meanwhile another user, User B, also adds "foobar" (gets the unique id 456). However, User A immediately deletes its "foobar". This remove operation should not remove the "foobar" added by User B. In case of the OR-Set, User A removes "foobar" with the id 123 and therefore "foobar" with the id 456 is not affected.

I am currently solving this by creating operations as follows:

{ "op": "add", "path": "/list/123", "value": "foobar" }
{ "op": "remove", "path": "/list/123", "value": "foobar" }

However, without knowing that the underlying data structure of the list is a or-set an we are not working with an object, these operations are easy to get wrong.

I would propose to add some special optional property to operations that indicate some kind of unique identifier or version/revision.

@tomalec
Copy link

tomalec commented Sep 23, 2015

I have already specified the convention of Versioned JSON Patch https://github.com/tomalec/Versioned-JSON-Patch/blob/master/Versioned-JSON-Patch.md

The convention uses completely valid RFC6902 JSON Patch, version number storen in any given place in JSON document, and simply attaches this version in test + replace operation object for any JSON Patch sequence:

 [
     { "op": "test", "path": "/path/to/version", "value": 1 },
     { "op": "replace", "path": "/path/to/version", "value": 2 },
     { "op": "test", "path": "/a/b/c", "value": "foo" },
     ...
   ]

This let us build simple queue that makes sure that JSON Patch sequences are applied in correct order.

There is a

I have also defined multiple-versioned JSON Patch, for conflict resolution in concurrent, distributed environment: https://github.com/tomalec/Versioned-JSON-Patch/blob/master/Multiple-Versioned-JSON-Patch.md

Conceptually, it's the same thing, but requires a version node per each peer taking part in communication.

So far, for a year of extensive usage, it works like charm.

@mnot
Copy link
Member

mnot commented Sep 25, 2015

Take a look at HTTP ETags -- it's a way to assure that you don't overwrite changes without being so intrusive.

See:
http://www.w3.org/1999/04/Editing/

@tomalec
Copy link

tomalec commented Sep 25, 2015

Thanks,
But HTTP ETags solves it only when using HTTP, and we can use JSON Patch over other channels, even without network, so it would be nice to have versioning regardless of means of transportation.

Plus if the versions are in JSON Patch, the same entity which is responsible for applying it may decide how to handle queues/conflicts.

In regards, of being intrusive. It's Versioned JSON Patch, not Versioned JSON. So we need to add two operation objects to JSON Patch.
In out implementation of Queue, version does not need to be real node of the JSON document, as queue layer may, once processed, just remove it from the patch to be applied on base document.

@mitar
Copy link

mitar commented Oct 12, 2019

As I wrote in this comment in another issue I think versioning should be done at a different layer.

Maybe JSON patch could just reserve some keywords or explicitly allow adding more fields to the patch payload. The problem is that JSON is an array, Maybe we should make it an object with one property for steps of the patch, so:

{
  "context": <value>,
  "steps": [
    ...
  ]
}

This would make it much easier to extend. And add some global metadata to the whole set of steps. While additional metadata could go into each step as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants