yorkie-team / yorkie-js-sdk

Yorkie JavaScript SDK
https://yorkie.dev/docs/js-sdk
Apache License 2.0
142 stars 93 forks source link

Provide a method for getting the value from the remote-change path #445

Closed chacha912 closed 1 year ago

chacha912 commented 1 year ago

Description: I received a request asking for a way to directly get the value from a remote-change path. The requestor wants to be able to use the $.xxxx path to directly access the value.

Currently, when the $.obj.num path is changed, the value can be accessed using doc.getRoot().obj.num.

doc.subscribe((event) => {
  for (const changeInfo of event.value) {
    for (const path of changeInfo.paths) {      
      if (path.startsWith('$.obj.num')) {
        // root.obj.num is changed
        const num = doc.getRoot().obj.num;
      }
    }
  }
});

If the target path is managed as a constant, we need to extract the key from the path because the path starts with $..

const target = 'target'
const anotherTarget = 'target2'

doc.subscribe((event) => {
  for (const changeInfo of event.value) {
    for (const path of changeInfo.paths) { 
      switch (path) {
        case path.startsWith('$.' + target):
        case path.startsWith('$.' + anotherTarget):
       const key = path.split('.')[1];  // extract the key
           const targetValue = doc.getRoot()[key];
           // Do something
           break;
      }
    }
  }
});

A few solutions are as follows:

  1. Pass the updated value along with the path.

  2. Implement a getValueByPath method as suggested.

// as-is
const target = 'target'
if (path.startsWith('$.' + target)) {
  const key = path.split('.')[1];  // extract the key
  const targetValue = doc.getRoot()[key];
}

// to-be
const target = 'target'
if (path.startsWith('$.' + target)) {
  const targetValue = doc.getRoot().getValueByPath(path);
}
  1. Add a way to subscribe to each target individually. This approach would reduce the amount of code needed to check which part has been changed, as the change information can be accessed through event.value.
// to-be
doc.subscribe(target, (target) => {
   // Do something
})

Why:

chacha912 commented 1 year ago

I want to try the second approach first. Are there any other opinions?

hackerwins commented 1 year ago

How about taking the time to design and implement interface #3?

2 doesn't seem to be able to control the underlying complexity after all. I think it would be good to refer to the interface of Liveblocks.

https://liveblocks.io/docs/api-reference/liveblocks-client#Room.subscribe(storageItem)

hackerwins commented 1 year ago

I want to get a CRDTObject from the root object and execute toJS() after receiving a message with subscribe, but it's not possible.

This might be related to #444.