yorkie-team/yorkie

Modify the set operation to handle nested object values

chacha912 opened this issue · 2 comments

Description:

Currently, the set operation is designed to create an empty object when the value is an object, which means it cannot handle nested objects. As a result, when generating a reverse operation for the set operation during an undo operation, if the existing value is an object, it doesn't set the value correctly.

For example, suppose the document is {"shape":{"point":{"x":0,"y":0}}}. If you update the "point" using doc.update((root) => {root.shape.point = { x: 1, y: 1 }}), the undo operation results in [ 'Remove x', 'Remove y', 'Set point: {x:0, y:0}' ]. When this undo operation is applied to another peer, the value point: {x:0, y:0} is not set correctly. (Refer to the test code (which should ensure convergence of peer's document after undoing nested objects) for more information.)

To address this issue, two approaches can be considered. One option is to refactor Set point: {x:0, y:0} into ['Set point: {}', 'Set point.x:0', 'Set point.y:0'] by breaking it down. Alternatively, we can modify the set operation to support setting CRDTObject, which is the approach we have chosen to resolve this issue.
Therefore, it is necessary to modify the set operation to enable the setting of nested objects, similar to how CRDTTree handles it.

function fromElementSimple(pbElementSimple: PbJSONElementSimple): CRDTElement {
  switch (pbElementSimple.getType()) {
    case PbValueType.VALUE_TYPE_JSON_OBJECT:
      // As-is: CRDTObject is created with an empty RHT.
      return CRDTObject.create(fromTimeTicket(pbElementSimple.getCreatedAt())!);
    case PbValueType.VALUE_TYPE_TREE:
      return bytesToTree(pbElementSimple.getValue_asU8())!;
    // ...
  }
}

function bytesToTree(bytes?: Uint8Array): CRDTTree {
  const pbElement = PbJSONElement.deserializeBinary(bytes);
  return fromTree(pbElement.getTree()!);
}

+) When deleting an object, 'removedAt' marking is not applied to nested objects.
The undo for moving a rectangle targets the nested object 'Point.' It should be checked to prevent the creation of a reverse operation.

Related to #652

Why:

When undoing, the set operation should be able to set the CRDT object.

Related to #431.

SDKs: