From 385b17e8fb68d386d1d0c0c927b27aab57387f38 Mon Sep 17 00:00:00 2001 From: Yourim Cha Date: Wed, 29 Mar 2023 17:45:58 +0900 Subject: [PATCH] Specify the doc.subscribe event value - add operation --- public/multi.html | 20 +++++-- src/document/change/change.ts | 6 +- src/document/document.ts | 62 +++++++++++--------- src/document/operation/add_operation.ts | 32 ++++++---- src/document/operation/increase_operation.ts | 8 ++- src/document/operation/operation.ts | 13 +++- 6 files changed, 88 insertions(+), 53 deletions(-) diff --git a/public/multi.html b/public/multi.html index 38946b0b5..fd115a3e6 100644 --- a/public/multi.html +++ b/public/multi.html @@ -162,8 +162,10 @@

yorkie document

// const newTodo = event.value[0].change.operations[0].value.getValue() // addTodo(text); displayTodos(); - todoInput.value = ''; - todoInput.focus(); + if (event.type === 'local-change') { + todoInput.value = ''; + todoInput.focus(); + } }); function displayTodos() { @@ -175,9 +177,17 @@

yorkie document

} function addTodo(text) { - const addItem = document.createElement('li'); - addItem.innerHTML = `${text}`; - todoList.appendChild(addItem); + const newTodo = document.createElement('li'); + const todoText = document.createElement('span'); + todoText.classList.add('item_name'); + todoText.textContent = text; + const deleteButton = document.createElement('button'); + deleteButton.classList.add('trash'); + deleteButton.textContent = '🗑'; + + newTodo.appendChild(todoText); + newTodo.appendChild(deleteButton); + todoList.appendChild(newTodo); } function handleAddTodo() { diff --git a/src/document/change/change.ts b/src/document/change/change.ts index 31d66380e..478716dfd 100644 --- a/src/document/change/change.ts +++ b/src/document/change/change.ts @@ -17,13 +17,13 @@ import { ActorID } from '@yorkie-js-sdk/src/document/time/actor_id'; import { Operation, - ExecuteOperationResult, + Modified, } from '@yorkie-js-sdk/src/document/operation/operation'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { ChangeID } from '@yorkie-js-sdk/src/document/change/change_id'; export type ExecuteChangeResult = { - modified: Array; + modified: Array; }; /** @@ -91,7 +91,7 @@ export class Change { * `execute` executes the operations of this change to the given root. */ public execute(root: CRDTRoot): ExecuteChangeResult { - const operationResult: Array = []; + const operationResult: Array = []; for (const operation of this.operations) { const result = operation.execute(root); if (result) operationResult.push(result); diff --git a/src/document/document.ts b/src/document/document.ts index da63c1e9a..b38faa1e9 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -45,7 +45,11 @@ import { InitialCheckpoint, } from '@yorkie-js-sdk/src/document/change/checkpoint'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; -import { ExecuteOperationResult } from '@yorkie-js-sdk/src/document/operation/operation'; +import { + Modified, + AddOpModified, + IncreaseOpModified, +} from '@yorkie-js-sdk/src/document/operation/operation'; import { JSONObject } from './json/object'; import { Trie } from '../util/trie'; @@ -128,10 +132,12 @@ export interface SnapshotEvent extends BaseDocEvent { */ export type ChangeInfo = { message: string; - modified: Array; + updates: Array; }; - -type ExecuteResult = Omit & { path: string }; +type UpdateDelta = + | ModifiedWithPath + | ModifiedWithPath; +type ModifiedWithPath = Omit & { path: string }; /** * `LocalChangeEvent` is an event that occurs when the document is changed @@ -252,13 +258,6 @@ export class Document { const changeResult = change.execute(this.root).modified; this.localChanges.push(change); this.changeID = change.getID(); - const modified = changeResult.map(({ type, element, value }) => { - return { - type, - value, - path: this.root.createSubPaths(element)!.join('.'), - }; - }); this.changeID = this.changeID.syncLamport(change.getID().getLamport()); if (this.eventStreamObserver) { @@ -267,7 +266,9 @@ export class Document { value: [ { message: change.getMessage() || '', - modified, + updates: changeResult.map((modified) => + this.getUpdateDelta(modified), + ), }, ], }); @@ -306,17 +307,17 @@ export class Document { } const changes: Array = []; - event.value.forEach(({ message, modified }) => { - const targetModified: Array = []; - modified.forEach((result) => { + event.value.forEach(({ message, updates }) => { + const targetUpdates: Array = []; + updates.forEach((result) => { if (this.isSameElementOrChildOf(result.path, target)) { - targetModified.push(result); + targetUpdates.push(result); } }); - targetModified.length && + targetUpdates.length && changes.push({ message, - modified: targetModified, + updates: targetUpdates, }); }); changes.length && @@ -593,18 +594,10 @@ export class Document { const changeInfos: Array = []; for (const change of changes) { - const modified = change - .execute(this.root) - .modified.map(({ type, element, value }) => { - return { - type, - value, - path: this.root.createSubPaths(element)!.join('.'), - }; - }); + const changeResult = change.execute(this.root).modified; changeInfos.push({ message: change.getMessage() || '', - modified, + updates: changeResult.map((modified) => this.getUpdateDelta(modified)), }); this.changeID = this.changeID.syncLamport(change.getID().getLamport()); } @@ -654,4 +647,17 @@ export class Document { } return pathTrie.findPrefixes().map((element) => element.join('.')); } + + private getUpdateDelta(modified: Modified): UpdateDelta { + const delta = {} as UpdateDelta; + for (const key of Object.keys(modified)) { + if (key === 'element') { + delta.path = this.root.createSubPaths(modified[key])!.join('.'); + } else { + const k = key as keyof Omit; + delta[k] = modified[k] as any; + } + } + return delta; + } } diff --git a/src/document/operation/add_operation.ts b/src/document/operation/add_operation.ts index 35238e349..2eccc9de8 100644 --- a/src/document/operation/add_operation.ts +++ b/src/document/operation/add_operation.ts @@ -19,7 +19,11 @@ import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; -import { Operation } from '@yorkie-js-sdk/src/document/operation/operation'; +import { Primitive } from '@yorkie-js-sdk/src/document/crdt/primitive'; +import { + Operation, + Modified, +} from '@yorkie-js-sdk/src/document/operation/operation'; /** * `AddOperation` is an operation representing adding an element to an Array. @@ -54,20 +58,24 @@ export class AddOperation extends Operation { /** * `execute` executes this operation on the given `CRDTRoot`. */ - public execute(root: CRDTRoot): void { + public execute(root: CRDTRoot): Modified { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); - if (parentObject instanceof CRDTArray) { - const array = parentObject as CRDTArray; - const value = this.value.deepcopy(); - array.insertAfter(this.prevCreatedAt, value); - root.registerElement(value, array); - } else { - if (!parentObject) { - logger.fatal(`fail to find ${this.getParentCreatedAt()}`); - } - + if (!parentObject) { + logger.fatal(`fail to find ${this.getParentCreatedAt()}`); + } + if (!(parentObject instanceof CRDTArray)) { logger.fatal(`fail to execute, only array can execute add`); } + const array = parentObject as CRDTArray; + const value = this.value.deepcopy(); + array.insertAfter(this.prevCreatedAt, value); + root.registerElement(value, array); + return { + type: 'add', + element: this.getEffectedCreatedAt(), + value: value instanceof Primitive ? value.getValue() : value, + index: array.subPathOf(this.getEffectedCreatedAt())!, + }; } /** diff --git a/src/document/operation/increase_operation.ts b/src/document/operation/increase_operation.ts index abd581507..1993c2c9a 100644 --- a/src/document/operation/increase_operation.ts +++ b/src/document/operation/increase_operation.ts @@ -14,14 +14,16 @@ * limitations under the License. */ -import { Operation } from '@yorkie-js-sdk/src/document/operation/operation'; +import { + Operation, + Modified, +} from '@yorkie-js-sdk/src/document/operation/operation'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { Primitive } from '@yorkie-js-sdk/src/document/crdt/primitive'; import { logger } from '@yorkie-js-sdk/src/util/logger'; import { CRDTCounter } from '@yorkie-js-sdk/src/document/crdt/counter'; -import { ExecuteOperationResult } from '@yorkie-js-sdk/src/document/operation/operation'; /** * `IncreaseOperation` represents an operation that increments a numeric value to Counter. @@ -53,7 +55,7 @@ export class IncreaseOperation extends Operation { /** * `execute` executes this operation on the given `CRDTRoot`. */ - public execute(root: CRDTRoot): ExecuteOperationResult { + public execute(root: CRDTRoot): Modified { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { logger.fatal(`fail to find ${this.getParentCreatedAt()}`); diff --git a/src/document/operation/operation.ts b/src/document/operation/operation.ts index 75e8ef25b..962e5ec4b 100644 --- a/src/document/operation/operation.ts +++ b/src/document/operation/operation.ts @@ -17,12 +17,21 @@ import { ActorID } from '@yorkie-js-sdk/src/document/time/actor_id'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; +import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; +import { PrimitiveValue } from '@yorkie-js-sdk/src/document/crdt/primitive'; -export type ExecuteOperationResult = { +export type AddOpModified = { + type: 'add'; + element: TimeTicket; + value: CRDTElement | PrimitiveValue; + index: string; +}; +export type IncreaseOpModified = { type: 'increase'; element: TimeTicket; value: number; }; +export type Modified = AddOpModified | IncreaseOpModified; /** * `Operation` represents an operation to be executed on a document. @@ -71,5 +80,5 @@ export abstract class Operation { /** * `execute` executes this operation on the given `CRDTRoot`. */ - public abstract execute(root: CRDTRoot): ExecuteOperationResult; + public abstract execute(root: CRDTRoot): Modified | void; }