rocicorp / repc

The canonical Replicache client, implemented in Rust.
Other
31 stars 7 forks source link

Let's ditch JSON Patch #315

Closed aboodman closed 3 years ago

aboodman commented 3 years ago

As a part of #290 we accidentally (or at least non-consciously) made JSON Patch public API. It's a lot more general and powerful than we currently need, and makes using slash-separated keys painful.

Let's do something a lot narrower that only supports the features we actually have:

arv commented 3 years ago

One benefit of using JSON Patch is that it is a standard and servers can hopefully reuse existing libraries.

One thing that wasn't clear yesterday was that the path part actually uses JSON Pointer which is very limited. JSON Path on the other hand is very rich.

arv commented 3 years ago

Here is a mini design doc. We should document this somewhere:

Patch Format

This is inspired by JSON Patch. It is simplified a bit by not using JSON Pointer and reducing the operations.

Our patch format is JSON. It consists of an Array of individual operations. These operations are applied in order from start to end.

[
  {"op": "put", "key": "a", "value": true},
  {"op": "put", "key": "b", "value": 42},
  {"op": "del", "key": "b"},
  {"op": "clear"}
]

Operations

We support three operations, put, del and clear

{
  "op": "put",
  "key": "keyName",
  "value": 42
}

key must be a string and it is the key in the Replicache key-value-store. There is no escaping (except for the usual JSON escaping) going on for the key. value is any JSON value

Semantics:

The semantics of the above example is the same as:

tx.put("keyName", 42)
{
  "op": "del",
  "key": "keyName"
}

key must be a string and it is the key to remove the Replicache key-value-store. There is no escaping (except for the usual JSON escaping) going on for the key.

Semantics:

The semantics of the above example is the same as:

tx.del("keyName")
{
  "op": "clear",
}

Semantics:

The semantics of the above example is the same as:

for await (const key of tx.scan().keys()) {
  await tx.del(key);
}

TypeScript Type Definition

The patch can be expressed using the following TypeScript type definitions:

type Patch = Operation[];

type Operation = PutOperation | DelOperation | ClearOperation;

type PutOperation = {
  op: "put";
  key: string;
  value: JSONValue;
};

type DelOperation = {
  op: "del";
  key: string;
};

type ClearOperation = {
  op: "clear";
};
aboodman commented 3 years ago

Can we please s/add/put/g to make it clear that this also overwrites any existing entry with same name?

On Tue, Mar 2, 2021 at 1:39 PM Erik Arvidsson notifications@github.com wrote:

Here is a mini design doc. We should document this somewhere: Patch Format

This is inspired by JSON Patch https://tools.ietf.org/html/rfc6902. It is simplified a bit by not using JSON Pointer https://tools.ietf.org/html/rfc6901 and reducing the operations.

Our patch format is JSON. It consists of an Array of individual operations. These operations are applied in order from start to end.

[ {"op": "add", "key": "a", "value": true}, {"op": "add", "key": "b", "value": 42}, {"op": "remove", "key": "b"}, {"op": "clear"} ]

Operations

We support three operations, add, remove and clear

  • add - Sets a key-value in the Replicache key-value-store. This operation also requires key and value.

{ "op": "add", "key": "keyName", "value": 42 }

key must be a string and it is the key in the Replicache key-value-store value is any JSON value

  • remove - removes a key from the Replicache key-value-store. This operation requires a key property.

{ "op": "remove", "key": "keyName" }

key must be a string and it is the key to remove the Replicache key-value-store

  • clear - Clears the entire key-value-store. This operation does not take any other properties.

{ "op": "clear", }

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rocicorp/repc/issues/315#issuecomment-789303198, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAATUBGIDH6AAONWLND6RZTTBVZMJANCNFSM4YNW2IWA .

arv commented 3 years ago

OK. I was trying to reuse JSON Patch operators.

aboodman commented 3 years ago

In that case, replace ?

On Tue, Mar 2, 2021 at 1:43 PM Erik Arvidsson notifications@github.com wrote:

OK. I was trying to reuse JSON Patch operators.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rocicorp/repc/issues/315#issuecomment-789304517, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAATUBG6F6CS5PFL5EGZOXTTBVZYHANCNFSM4YNW2IWA .

arv commented 3 years ago

Ended up with put and del

phritz commented 3 years ago

This design sketch sounds great to me. I especially love for us how put/del/clear map directly to the underlying operations. This is gonna make the patches easier to craft and read.

aboodman commented 3 years ago

I like it too. I think this design implies that we need tx.clear() :).

phritz commented 3 years ago

I like it too. I think this design implies that we need tx.clear() :).

But we have it! As what I was calling an underlying operation, meaning one on the db tx, even if not on the dispatch tx: https://github.com/rocicorp/repc/blob/d5de8c6dabdb0c0ce1bf46555c22dea45f3f7519/src/db/write.rs#L235

arv commented 3 years ago

We do not expose it to js or to the RPC