replicache icon indicating copy to clipboard operation
replicache copied to clipboard

RFE: Add a non syncing key space and a ephemeral key space

Open arv opened this issue 2 years ago • 10 comments

We should provide a way to store data in Replicache that is not synced.

It would also be nice to have ephemeral (in memory, not shared between tabs) key space for things like selection state etc. That way the application can use the same paradigms for everything.

One strawman is to have specific key spaces in the key value store that behaves differently.

arv avatar Sep 09 '21 07:09 arv

Just want to add that this is added it may be useful to allow mutators to be tagged as local-only or ephemeral-only so they don't need to be kept around and sent to the server. If this was done, we should be sure to visibly error on any attempted writes outside the annotated bounds to flag bad annotations.

whiten avatar Sep 09 '21 15:09 whiten

We can detect what keys a mutation touches and based on that determine if it needs to be part of the push.

But that does raise a valid point that I did not think about before.

This needs a design doc. Maybe there is a better approach than key spaces?

arv avatar Sep 09 '21 16:09 arv

One potential use of this feature I have in mind is to maintain custom indexes. For example with https://fusejs.io/, one could implement FTS in userspace with this system 🤯.

aboodman avatar Oct 01 '21 00:10 aboodman

Some constraints in the design space wrt unsynced (I'll call it "local" from here on out) storage:

  • people will frequently want to modify local storage transactionally with synced storage
  • every single keywise api that exists in the system needs to exist for local storage, incl:
    • put, get, scan (plus all the features of scan), del

The best design is @whiten's original design where a subset of the keyspace is designated as local, e.g., /l/*. Unfortunately this is not possible backward compatibly as we did not reserve any characters of the keyspace or setup any way to do namespace :-|.

An alternate option would be to accept an array everyplace a key can be specified, e.g., get(["local", "foo"]) can be specified in addition to get("foo") or get(["synced", "foo"]).

aboodman avatar Mar 25 '22 10:03 aboodman

Yet another alternate option would be to have some separate interface on {Read|Write}Transaction like:

addPerson: async (tx: WriteTransaction, args: Person) => {
  await tx.put(args.id, args);
  // covering index on age
  await tx.local.put(`byAge/${args.age}/${args.id}`, args);
},

local would have the entire ReadTransaction/WriteTransaction interface except not clientID.

aboodman avatar Mar 25 '22 11:03 aboodman

I don't like the array idea.

I kind of like the .local idea but the type defs gets a bit weird:

interface WriteTransaction {
  readonly local: Omit<WriteTransaction, 'local' | 'clientID'>;
  ...
}

arv avatar Mar 25 '22 12:03 arv

Regarding a designated keyspace, could a reserved prefix be declared (or opted out of) in ReplicacheOptions? In the 9.* series you'd probably want to make that setting required to use the feature, but either with the 10.0 release or an "options version" setting you could default to /local/ or whatever if not specified.

whiten avatar Mar 25 '22 19:03 whiten

These are good idea, thanks @whiten .

Maybe the thing to do is have a enableLocalKeys option in ReplicacheOptions and when enabled, the synced keyspace is prefixed with /s/ and the local features are available. When not, the keyspace behaves as today. We print a warning or whatever about enableLocalKeys becoming the default over several versions and eventually flip it?

aboodman avatar Mar 25 '22 20:03 aboodman

I wouldn't want to let users choose their local prefix because I don't get the point of that. Why would anyone care to configure that vs us just choosing that it's /l/?

aboodman avatar Mar 25 '22 20:03 aboodman

Sounds reasonable. Opting in to it for 10.x and log warnings if not opted in and key starts with the prefix and then in 11 or 12 make it default.

arv avatar Mar 26 '22 20:03 arv