From 62e90634bef2e2d181d78e223b67f23af0f9ce14 Mon Sep 17 00:00:00 2001 From: devleejb Date: Sun, 3 Nov 2024 02:10:40 +0900 Subject: [PATCH 1/9] Change snapshot event publish data --- packages/sdk/src/document/document.ts | 37 ++++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/sdk/src/document/document.ts b/packages/sdk/src/document/document.ts index d4027b9fd..1c66e0fac 100644 --- a/packages/sdk/src/document/document.ts +++ b/packages/sdk/src/document/document.ts @@ -1180,11 +1180,26 @@ export class Document { } // NOTE(hackerwins): If the document has local changes, we need to apply - // them after applying the snapshot. We need to treat the local changes - // as remote changes because the application should apply the local - // changes to their own document. + // them after applying the snapshot, as local changes are not included in the snapshot data. + // Afterward, we should publish a snapshot event with the latest + // version of the document to ensure the user receives the most up-to-date snapshot. if (hasSnapshot) { - this.applyChanges(this.localChanges, OpSource.Remote); + this.applyChanges(this.localChanges, OpSource.Local); + this.publish([ + { + type: DocEventType.Snapshot, + source: OpSource.Remote, + value: { + serverSeq: pack.getCheckpoint().getServerSeq().toString(), + snapshot: this.isEnableDevtools() + ? converter.bytesToHex(pack.getSnapshot()!) + : undefined, + snapshotVector: converter.versionVectorToHex( + pack.getVersionVector()!, + ), + }, + }, + ]); } // 03. Update the checkpoint. @@ -1420,20 +1435,6 @@ export class Document { // drop clone because it is contaminated. this.clone = undefined; - - this.publish([ - { - type: DocEventType.Snapshot, - source: OpSource.Remote, - value: { - serverSeq: serverSeq.toString(), - snapshot: this.isEnableDevtools() - ? converter.bytesToHex(snapshot) - : undefined, - snapshotVector: converter.versionVectorToHex(snapshotVector), - }, - }, - ]); } /** From 195e195e96a4691da59904d4d8288aee1e97e855 Mon Sep 17 00:00:00 2001 From: devleejb Date: Sun, 3 Nov 2024 02:10:58 +0900 Subject: [PATCH 2/9] Change selection when applying snapshot --- examples/vanilla-codemirror6/src/main.ts | 60 ++++++++++++++++++++---- examples/vanilla-codemirror6/src/type.ts | 6 ++- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/examples/vanilla-codemirror6/src/main.ts b/examples/vanilla-codemirror6/src/main.ts index 131909325..8c917a007 100644 --- a/examples/vanilla-codemirror6/src/main.ts +++ b/examples/vanilla-codemirror6/src/main.ts @@ -1,6 +1,6 @@ /* eslint-disable jsdoc/require-jsdoc */ import yorkie, { DocEventType } from 'yorkie-js-sdk'; -import type { TextOperationInfo, EditOpInfo } from 'yorkie-js-sdk'; +import type { EditOpInfo, OperationInfo } from 'yorkie-js-sdk'; import { basicSetup, EditorView } from 'codemirror'; import { keymap } from '@codemirror/view'; import { @@ -8,10 +8,10 @@ import { markdownKeymap, markdownLanguage, } from '@codemirror/lang-markdown'; -import { Transaction } from '@codemirror/state'; +import { Transaction, TransactionSpec } from '@codemirror/state'; import { network } from './network'; import { displayLog, displayPeers } from './utils'; -import { YorkieDoc } from './type'; +import { YorkieDoc, YorkiePresence } from './type'; import './style.css'; const editorParentElem = document.getElementById('editor')!; @@ -28,7 +28,7 @@ async function main() { await client.activate(); // 02-1. create a document then attach it into the client. - const doc = new yorkie.Document( + const doc = new yorkie.Document( `codemirror6-${new Date() .toISOString() .substring(0, 10) @@ -55,10 +55,22 @@ async function main() { // 02-2. subscribe document event. const syncText = () => { const text = doc.getRoot().content; - view.dispatch({ + const selection = doc.getMyPresence().selection; + const transactionSpec: TransactionSpec = { changes: { from: 0, to: view.state.doc.length, insert: text.toString() }, annotations: [Transaction.remote.of(true)], - }); + }; + + if (selection) { + // Restore the cursor position when the text is replaced. + const cursor = text.posRangeToIndexRange(selection); + transactionSpec['selection'] = { + anchor: cursor[0], + head: cursor[1], + }; + } + + view.dispatch(transactionSpec); }; doc.subscribe((event) => { if (event.type === 'snapshot') { @@ -100,7 +112,36 @@ async function main() { } }); - // 03-2. create codemirror instance + // 03-2. define function that bind the selection with the codemirror(broadcast local selection to peers) + const selectionUpdateListener = EditorView.updateListener.of((viewUpdate) => { + const hasFocus = + viewUpdate.view.hasFocus && viewUpdate.view.dom.ownerDocument.hasFocus(); + const sel = hasFocus ? viewUpdate.state.selection.main : null; + + doc.update((root, presence) => { + if (sel && root.content) { + const selection = root.content.indexRangeToPosRange([ + sel.anchor, + sel.head, + ]); + + if ( + JSON.stringify(selection) !== + JSON.stringify(presence.get('selection')) + ) { + presence.set({ + selection, + }); + } + } else if (presence.get('selection')) { + presence.set({ + selection: undefined, + }); + } + }); + }); + + // 03-3. create codemirror instance const view = new EditorView({ doc: '', extensions: [ @@ -108,12 +149,13 @@ async function main() { markdown({ base: markdownLanguage }), keymap.of(markdownKeymap), updateListener, + selectionUpdateListener, ], parent: editorParentElem, }); - // 03-3. define event handler that apply remote changes to local - function handleOperations(operations: Array) { + // 03-4. define event handler that apply remote changes to local + function handleOperations(operations: Array) { for (const op of operations) { if (op.type === 'edit') { handleEditOp(op); diff --git a/examples/vanilla-codemirror6/src/type.ts b/examples/vanilla-codemirror6/src/type.ts index 969e44b29..9d9e52c41 100644 --- a/examples/vanilla-codemirror6/src/type.ts +++ b/examples/vanilla-codemirror6/src/type.ts @@ -1,5 +1,9 @@ -import { type Text } from 'yorkie-js-sdk'; +import { TextPosStructRange, type Text } from 'yorkie-js-sdk'; export type YorkieDoc = { content: Text; }; + +export type YorkiePresence = { + selection?: TextPosStructRange; +}; From 180fad7ee5d4793f64119d8ab6cf687f4464ca36 Mon Sep 17 00:00:00 2001 From: devleejb Date: Sun, 3 Nov 2024 13:27:59 +0900 Subject: [PATCH 3/9] Change description for editing handlers --- examples/vanilla-codemirror6/src/main.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/vanilla-codemirror6/src/main.ts b/examples/vanilla-codemirror6/src/main.ts index 8c917a007..fed802937 100644 --- a/examples/vanilla-codemirror6/src/main.ts +++ b/examples/vanilla-codemirror6/src/main.ts @@ -69,7 +69,6 @@ async function main() { head: cursor[1], }; } - view.dispatch(transactionSpec); }; doc.subscribe((event) => { @@ -110,10 +109,7 @@ async function main() { }); } } - }); - // 03-2. define function that bind the selection with the codemirror(broadcast local selection to peers) - const selectionUpdateListener = EditorView.updateListener.of((viewUpdate) => { const hasFocus = viewUpdate.view.hasFocus && viewUpdate.view.dom.ownerDocument.hasFocus(); const sel = hasFocus ? viewUpdate.state.selection.main : null; @@ -141,7 +137,7 @@ async function main() { }); }); - // 03-3. create codemirror instance + // 03-2. create codemirror instance const view = new EditorView({ doc: '', extensions: [ @@ -149,12 +145,11 @@ async function main() { markdown({ base: markdownLanguage }), keymap.of(markdownKeymap), updateListener, - selectionUpdateListener, ], parent: editorParentElem, }); - // 03-4. define event handler that apply remote changes to local + // 03-3. define event handler that apply remote changes to local function handleOperations(operations: Array) { for (const op of operations) { if (op.type === 'edit') { From e635d2f7185674c344d8d40ab49e8f9ad5338ed1 Mon Sep 17 00:00:00 2001 From: devleejb Date: Tue, 5 Nov 2024 19:29:48 +0900 Subject: [PATCH 4/9] Refactor `applySnapshot` to keep consistency --- packages/sdk/src/document/document.ts | 69 +++++++++++++++------------ 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/sdk/src/document/document.ts b/packages/sdk/src/document/document.ts index 0b097f8b2..8bc03e95a 100644 --- a/packages/sdk/src/document/document.ts +++ b/packages/sdk/src/document/document.ts @@ -1148,6 +1148,21 @@ export class Document { return targetPath.every((path, index) => path === nodePath[index]); } + /** + * `removeAppliedLocalChanges` removes local changes applied to the server. + * + * @param clientSeq - client sequence number to remove local changes before it + */ + private removeAppliedLocalChanges(clientSeq: number) { + while (this.localChanges.length) { + const change = this.localChanges[0]; + if (change.getID().getClientSeq() > clientSeq) { + break; + } + this.localChanges.shift(); + } + } + /** * `applyChangePack` applies the given change pack into this document. * 1. Remove local changes applied to server. @@ -1165,42 +1180,14 @@ export class Document { pack.getCheckpoint().getServerSeq(), pack.getVersionVector()!, pack.getSnapshot()!, + pack.getCheckpoint().getClientSeq(), ); } else if (pack.hasChanges()) { this.applyChanges(pack.getChanges(), OpSource.Remote); } // 02. Remove local changes applied to server. - while (this.localChanges.length) { - const change = this.localChanges[0]; - if (change.getID().getClientSeq() > pack.getCheckpoint().getClientSeq()) { - break; - } - this.localChanges.shift(); - } - - // NOTE(hackerwins): If the document has local changes, we need to apply - // them after applying the snapshot, as local changes are not included in the snapshot data. - // Afterward, we should publish a snapshot event with the latest - // version of the document to ensure the user receives the most up-to-date snapshot. - if (hasSnapshot) { - this.applyChanges(this.localChanges, OpSource.Local); - this.publish([ - { - type: DocEventType.Snapshot, - source: OpSource.Remote, - value: { - serverSeq: pack.getCheckpoint().getServerSeq().toString(), - snapshot: this.isEnableDevtools() - ? converter.bytesToHex(pack.getSnapshot()!) - : undefined, - snapshotVector: converter.versionVectorToHex( - pack.getVersionVector()!, - ), - }, - }, - ]); - } + this.removeAppliedLocalChanges(pack.getCheckpoint().getClientSeq()); // 03. Update the checkpoint. this.checkpoint = this.checkpoint.forward(pack.getCheckpoint()); @@ -1427,6 +1414,7 @@ export class Document { serverSeq: bigint, snapshotVector: VersionVector, snapshot?: Uint8Array, + clientSeq: number = -1, ) { const { root, presences } = converter.bytesToSnapshot

(snapshot); this.root = new CRDTRoot(root); @@ -1435,6 +1423,27 @@ export class Document { // drop clone because it is contaminated. this.clone = undefined; + + this.removeAppliedLocalChanges(clientSeq); + + // NOTE(hackerwins): If the document has local changes, we need to apply + // them after applying the snapshot, as local changes are not included in the snapshot data. + // Afterward, we should publish a snapshot event with the latest + // version of the document to ensure the user receives the most up-to-date snapshot. + this.applyChanges(this.localChanges, OpSource.Local); + this.publish([ + { + type: DocEventType.Snapshot, + source: OpSource.Remote, + value: { + serverSeq: serverSeq.toString(), + snapshot: this.isEnableDevtools() + ? converter.bytesToHex(snapshot) + : undefined, + snapshotVector: converter.versionVectorToHex(snapshotVector), + }, + }, + ]); } /** From 1b27196cc6b6f086ae6facd9730adb705e7f0b48 Mon Sep 17 00:00:00 2001 From: devleejb Date: Tue, 5 Nov 2024 20:58:08 +0900 Subject: [PATCH 5/9] Add snapshot test --- packages/sdk/test/integration/client_test.ts | 2 +- .../sdk/test/unit/document/document_test.ts | 38 ++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/sdk/test/integration/client_test.ts b/packages/sdk/test/integration/client_test.ts index 3ca1deb03..636590825 100644 --- a/packages/sdk/test/integration/client_test.ts +++ b/packages/sdk/test/integration/client_test.ts @@ -852,7 +852,7 @@ describe.sequential('Client', function () { await c2.sync(); // 01. c1 increases the counter for creating snapshot. - for (let i = 0; i < 500; i++) { + for (let i = 0; i < 1000; i++) { d1.update((r) => r.counter.increase(1)); } await c1.sync(); diff --git a/packages/sdk/test/unit/document/document_test.ts b/packages/sdk/test/unit/document/document_test.ts index e0c3bac6e..a0eac682e 100644 --- a/packages/sdk/test/unit/document/document_test.ts +++ b/packages/sdk/test/unit/document/document_test.ts @@ -22,8 +22,14 @@ import { import { Document, DocEventType } from '@yorkie-js-sdk/src/document/document'; import { OperationInfo } from '@yorkie-js-sdk/src/document/operation/operation'; -import { JSONArray, Text, Counter, Tree } from '@yorkie-js-sdk/src/yorkie'; +import yorkie, { + JSONArray, + Text, + Counter, + Tree, +} from '@yorkie-js-sdk/src/yorkie'; import { CounterType } from '@yorkie-js-sdk/src/document/crdt/counter'; +import { withTwoClientsAndDocuments } from '@yorkie-js-sdk/test/integration/integration_helper'; describe.sequential('Document', function () { afterEach(() => { @@ -1490,4 +1496,34 @@ describe.sequential('Document', function () { }); }); }); + + it('should publish snapshot event with up-to-date document', async function ({ + task, + }) { + type TestDoc = { counter: Counter }; + await withTwoClientsAndDocuments(async (c1, d1, c2, d2) => { + const eventCollector = new EventCollector(); + d2.subscribe((event) => { + if (event.type === DocEventType.Snapshot) { + eventCollector.add(d2.getRoot().counter.getValue()); + } + }); + + d1.update((r) => (r.counter = new Counter(yorkie.IntType, 0))); + await c1.sync(); + await c2.sync(); + + // 01. c1 increases the counter for creating snapshot. + for (let i = 0; i < 1000; i++) { + d1.update((r) => r.counter.increase(1)); + } + await c1.sync(); + + // 02. c2 receives the snapshot and increases the counter simultaneously. + c2.sync(); + d2.update((r) => r.counter.increase(1)); + + await eventCollector.waitAndVerifyNthEvent(1, 1001); + }, task.name); + }); }); From 35262cd5ff2fb0c25a8133e0afcf60601c4a95b6 Mon Sep 17 00:00:00 2001 From: devleejb Date: Tue, 5 Nov 2024 21:12:23 +0900 Subject: [PATCH 6/9] Fix CI failure --- packages/sdk/test/unit/document/document_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/test/unit/document/document_test.ts b/packages/sdk/test/unit/document/document_test.ts index a0eac682e..92da6816e 100644 --- a/packages/sdk/test/unit/document/document_test.ts +++ b/packages/sdk/test/unit/document/document_test.ts @@ -1505,7 +1505,7 @@ describe.sequential('Document', function () { const eventCollector = new EventCollector(); d2.subscribe((event) => { if (event.type === DocEventType.Snapshot) { - eventCollector.add(d2.getRoot().counter.getValue()); + eventCollector.add(d2.getRoot().counter.getValue() as number); } }); From 1e3f4a7b0c7755b8fe6fb205a2e9f81d0fb25ab1 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Wed, 6 Nov 2024 08:49:34 +0900 Subject: [PATCH 7/9] Clean up codes --- packages/sdk/src/document/document.ts | 155 +++++++++++++------------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/packages/sdk/src/document/document.ts b/packages/sdk/src/document/document.ts index 8bc03e95a..1f236aaa2 100644 --- a/packages/sdk/src/document/document.ts +++ b/packages/sdk/src/document/document.ts @@ -470,14 +470,14 @@ export type DocumentKey = string; type OperationInfoOfElement = TElement extends Text ? TextOperationInfo : TElement extends Counter - ? CounterOperationInfo - : TElement extends Tree - ? TreeOperationInfo - : TElement extends BaseArray - ? ArrayOperationInfo - : TElement extends BaseObject - ? ObjectOperationInfo - : OperationInfo; + ? CounterOperationInfo + : TElement extends Tree + ? TreeOperationInfo + : TElement extends BaseArray + ? ArrayOperationInfo + : TElement extends BaseObject + ? ObjectOperationInfo + : OperationInfo; /** * `OperationInfoOfInternal` represents the type of the operation info of the @@ -498,24 +498,24 @@ type OperationInfoOfInternal< > = TDepth extends 0 ? TElement : TKeyOrPath extends `${infer TFirst}.${infer TRest}` - ? TFirst extends keyof TElement - ? TElement[TFirst] extends BaseArray - ? OperationInfoOfInternal< - TElement[TFirst], - number, - DecreasedDepthOf - > - : OperationInfoOfInternal< - TElement[TFirst], - TRest, - DecreasedDepthOf - > - : OperationInfo - : TKeyOrPath extends keyof TElement - ? TElement[TKeyOrPath] extends BaseArray - ? ArrayOperationInfo - : OperationInfoOfElement - : OperationInfo; + ? TFirst extends keyof TElement + ? TElement[TFirst] extends BaseArray + ? OperationInfoOfInternal< + TElement[TFirst], + number, + DecreasedDepthOf + > + : OperationInfoOfInternal< + TElement[TFirst], + TRest, + DecreasedDepthOf + > + : OperationInfo + : TKeyOrPath extends keyof TElement + ? TElement[TKeyOrPath] extends BaseArray + ? ArrayOperationInfo + : OperationInfoOfElement + : OperationInfo; /** * `DecreasedDepthOf` represents the type of the decreased depth of the given depth. @@ -523,24 +523,24 @@ type OperationInfoOfInternal< type DecreasedDepthOf = Depth extends 10 ? 9 : Depth extends 9 - ? 8 - : Depth extends 8 - ? 7 - : Depth extends 7 - ? 6 - : Depth extends 6 - ? 5 - : Depth extends 5 - ? 4 - : Depth extends 4 - ? 3 - : Depth extends 3 - ? 2 - : Depth extends 2 - ? 1 - : Depth extends 1 - ? 0 - : -1; + ? 8 + : Depth extends 8 + ? 7 + : Depth extends 7 + ? 6 + : Depth extends 6 + ? 5 + : Depth extends 5 + ? 4 + : Depth extends 4 + ? 3 + : Depth extends 3 + ? 2 + : Depth extends 2 + ? 1 + : Depth extends 1 + ? 0 + : -1; /** * `PathOfInternal` represents the type of the path of the given element. @@ -552,29 +552,29 @@ type PathOfInternal< > = Depth extends 0 ? Prefix : TElement extends Record - ? { - [TKey in keyof TElement]: TElement[TKey] extends LeafElement - ? `${Prefix}${TKey & string}` - : TElement[TKey] extends BaseArray - ? - | `${Prefix}${TKey & string}` - | `${Prefix}${TKey & string}.${number}` - | PathOfInternal< - TArrayElement, - `${Prefix}${TKey & string}.${number}.`, - DecreasedDepthOf - > - : - | `${Prefix}${TKey & string}` - | PathOfInternal< - TElement[TKey], - `${Prefix}${TKey & string}.`, - DecreasedDepthOf - >; - }[keyof TElement] - : Prefix extends `${infer TRest}.` - ? TRest - : Prefix; + ? { + [TKey in keyof TElement]: TElement[TKey] extends LeafElement + ? `${Prefix}${TKey & string}` + : TElement[TKey] extends BaseArray + ? + | `${Prefix}${TKey & string}` + | `${Prefix}${TKey & string}.${number}` + | PathOfInternal< + TArrayElement, + `${Prefix}${TKey & string}.${number}.`, + DecreasedDepthOf + > + : + | `${Prefix}${TKey & string}` + | PathOfInternal< + TElement[TKey], + `${Prefix}${TKey & string}.`, + DecreasedDepthOf + >; + }[keyof TElement] + : Prefix extends `${infer TRest}.` + ? TRest + : Prefix; /** * `OperationInfoOf` represents the type of the operation info of the given @@ -1149,11 +1149,12 @@ export class Document { } /** - * `removeAppliedLocalChanges` removes local changes applied to the server. + * `removePushedLocalChanges` removes local changes that have been applied to + * the server from the local changes. * * @param clientSeq - client sequence number to remove local changes before it */ - private removeAppliedLocalChanges(clientSeq: number) { + private removePushedLocalChanges(clientSeq: number) { while (this.localChanges.length) { const change = this.localChanges[0]; if (change.getID().getClientSeq() > clientSeq) { @@ -1175,6 +1176,7 @@ export class Document { public applyChangePack(pack: ChangePack

): void { const hasSnapshot = pack.hasSnapshot(); + // 01. Apply snapshot or changes to the root object. if (hasSnapshot) { this.applySnapshot( pack.getCheckpoint().getServerSeq(), @@ -1182,22 +1184,20 @@ export class Document { pack.getSnapshot()!, pack.getCheckpoint().getClientSeq(), ); - } else if (pack.hasChanges()) { + } else { this.applyChanges(pack.getChanges(), OpSource.Remote); + this.removePushedLocalChanges(pack.getCheckpoint().getClientSeq()); } - // 02. Remove local changes applied to server. - this.removeAppliedLocalChanges(pack.getCheckpoint().getClientSeq()); - - // 03. Update the checkpoint. + // 02. Update the checkpoint. this.checkpoint = this.checkpoint.forward(pack.getCheckpoint()); - // 04. Do Garbage collection. + // 03. Do Garbage collection. if (!hasSnapshot) { this.garbageCollect(pack.getVersionVector()!); } - // 05. Filter detached client's lamport from version vector + // 04. Filter detached client's lamport from version vector if (!hasSnapshot) { this.filterVersionVector(pack.getVersionVector()!); } @@ -1424,7 +1424,7 @@ export class Document { // drop clone because it is contaminated. this.clone = undefined; - this.removeAppliedLocalChanges(clientSeq); + this.removePushedLocalChanges(clientSeq); // NOTE(hackerwins): If the document has local changes, we need to apply // them after applying the snapshot, as local changes are not included in the snapshot data. @@ -1699,6 +1699,7 @@ export class Document { if (event.type === DocEventType.Snapshot) { const { snapshot, serverSeq, snapshotVector } = event.value; if (!snapshot) return; + // TODO(hackerwins): We need to check the clientSeq of the snapshot. this.applySnapshot( BigInt(serverSeq), converter.hexToVersionVector(snapshotVector), From 23e48a760063445db26ca1df2a18a8456ceaa7d6 Mon Sep 17 00:00:00 2001 From: Yourim Cha Date: Wed, 6 Nov 2024 19:05:26 +0900 Subject: [PATCH 8/9] Change DefaultSnapshotThreshold value to 1000 in snapshot tests --- packages/sdk/test/helper/helper.ts | 1 + packages/sdk/test/integration/client_test.ts | 7 +++++-- packages/sdk/test/integration/presence_test.ts | 13 ++++++++----- packages/sdk/test/integration/snapshot_test.ts | 15 ++++++++------- packages/sdk/test/integration/tree_test.ts | 8 +++++--- packages/sdk/test/unit/document/document_test.ts | 8 ++++++-- 6 files changed, 33 insertions(+), 19 deletions(-) diff --git a/packages/sdk/test/helper/helper.ts b/packages/sdk/test/helper/helper.ts index 168f4eee1..22ffee59f 100644 --- a/packages/sdk/test/helper/helper.ts +++ b/packages/sdk/test/helper/helper.ts @@ -42,6 +42,7 @@ import { InitialActorID } from '@yorkie-js-sdk/src/document/time/actor_id'; import { VersionVector } from '@yorkie-js-sdk/src/document/time/version_vector'; export type Indexable = Record; +export const DefaultSnapshotThreshold = 1000; /** * EventCollector provides a utility to collect and manage events. diff --git a/packages/sdk/test/integration/client_test.ts b/packages/sdk/test/integration/client_test.ts index 636590825..ce9ac6cf7 100644 --- a/packages/sdk/test/integration/client_test.ts +++ b/packages/sdk/test/integration/client_test.ts @@ -25,7 +25,10 @@ import yorkie, { Tree, Text, } from '@yorkie-js-sdk/src/yorkie'; -import { EventCollector } from '@yorkie-js-sdk/test/helper/helper'; +import { + EventCollector, + DefaultSnapshotThreshold, +} from '@yorkie-js-sdk/test/helper/helper'; import { toDocKey, testRPCAddr, @@ -852,7 +855,7 @@ describe.sequential('Client', function () { await c2.sync(); // 01. c1 increases the counter for creating snapshot. - for (let i = 0; i < 1000; i++) { + for (let i = 0; i < DefaultSnapshotThreshold; i++) { d1.update((r) => r.counter.increase(1)); } await c1.sync(); diff --git a/packages/sdk/test/integration/presence_test.ts b/packages/sdk/test/integration/presence_test.ts index ec7f37f00..828283c30 100644 --- a/packages/sdk/test/integration/presence_test.ts +++ b/packages/sdk/test/integration/presence_test.ts @@ -11,7 +11,11 @@ import { testRPCAddr, toDocKey, } from '@yorkie-js-sdk/test/integration/integration_helper'; -import { EventCollector, deepSort } from '@yorkie-js-sdk/test/helper/helper'; +import { + EventCollector, + deepSort, + DefaultSnapshotThreshold, +} from '@yorkie-js-sdk/test/helper/helper'; describe('Presence', function () { afterEach(() => { @@ -32,18 +36,17 @@ describe('Presence', function () { const doc2 = new yorkie.Document<{}, PresenceType>(docKey); await c2.attach(doc2, { syncMode: SyncMode.Manual }); - const snapshotThreshold = 500; - for (let i = 0; i < snapshotThreshold; i++) { + for (let i = 0; i < DefaultSnapshotThreshold; i++) { doc1.update((root, p) => p.set({ key: `${i}` })); } assert.deepEqual(doc1.getPresenceForTest(c1.getID()!), { - key: `${snapshotThreshold - 1}`, + key: `${DefaultSnapshotThreshold - 1}`, }); await c1.sync(); await c2.sync(); assert.deepEqual(doc2.getPresenceForTest(c1.getID()!), { - key: `${snapshotThreshold - 1}`, + key: `${DefaultSnapshotThreshold - 1}`, }); }); diff --git a/packages/sdk/test/integration/snapshot_test.ts b/packages/sdk/test/integration/snapshot_test.ts index 686fa83ae..612d23c49 100644 --- a/packages/sdk/test/integration/snapshot_test.ts +++ b/packages/sdk/test/integration/snapshot_test.ts @@ -1,4 +1,5 @@ import { describe, it, assert } from 'vitest'; +import { DefaultSnapshotThreshold } from '@yorkie-js-sdk/test/helper/helper'; import { withTwoClientsAndDocuments } from '@yorkie-js-sdk/test/integration/integration_helper'; import { Text } from '@yorkie-js-sdk/src/yorkie'; @@ -6,8 +7,8 @@ describe('Snapshot', function () { it('should handle snapshot', async function ({ task }) { type TestDoc = Record & { key: string }; await withTwoClientsAndDocuments(async (c1, d1, c2, d2) => { - // 01. Updates 700 changes over snapshot threshold. - for (let idx = 0; idx < 700; idx++) { + // 01. Updates changes over snapshot threshold. + for (let idx = 0; idx < DefaultSnapshotThreshold; idx++) { d1.update((root) => { root[`${idx}`] = idx; }); @@ -30,7 +31,7 @@ describe('Snapshot', function () { it('should handle snapshot for text object', async function ({ task }) { await withTwoClientsAndDocuments<{ k1: Text }>(async (c1, d1, c2, d2) => { - for (let idx = 0; idx < 700; idx++) { + for (let idx = 0; idx < DefaultSnapshotThreshold; idx++) { d1.update((root) => { root.k1 = new Text(); }, 'set new doc by c1'); @@ -38,8 +39,8 @@ describe('Snapshot', function () { await c1.sync(); await c2.sync(); - // 01. Updates 500 changes over snapshot threshold by c1. - for (let idx = 0; idx < 500; idx++) { + // 01. Updates changes over snapshot threshold by c1. + for (let idx = 0; idx < DefaultSnapshotThreshold; idx++) { d1.update((root) => { root.k1.edit(idx, idx, 'x'); }); @@ -69,8 +70,8 @@ describe('Snapshot', function () { await c1.sync(); await c2.sync(); - // 01. Updates 700 changes over snapshot threshold by c1. - for (let idx = 0; idx < 700; idx++) { + // 01. Updates changes over snapshot threshold by c1. + for (let idx = 0; idx < DefaultSnapshotThreshold; idx++) { d1.update((root) => { root.k1.setStyle(0, 1, { bold: 'true' }); }); diff --git a/packages/sdk/test/integration/tree_test.ts b/packages/sdk/test/integration/tree_test.ts index 0c8621411..f1626acc7 100644 --- a/packages/sdk/test/integration/tree_test.ts +++ b/packages/sdk/test/integration/tree_test.ts @@ -21,7 +21,10 @@ import { toDocKey, withTwoClientsAndDocuments, } from '@yorkie-js-sdk/test/integration/integration_helper'; -import { EventCollector } from '@yorkie-js-sdk/test/helper/helper'; +import { + EventCollector, + DefaultSnapshotThreshold, +} from '@yorkie-js-sdk/test/helper/helper'; import { TreeEditOpInfo, TreeStyleOpInfo, @@ -1558,8 +1561,7 @@ describe('Tree.style', function () { await c2.attach(d2, { syncMode: SyncMode.Manual }); // Perform a dummy update to apply changes up to the snapshot threshold. - const snapshotThreshold = 500; - for (let idx = 0; idx < snapshotThreshold; idx++) { + for (let idx = 0; idx < DefaultSnapshotThreshold; idx++) { d1.update((root) => { root.num = 0; }); diff --git a/packages/sdk/test/unit/document/document_test.ts b/packages/sdk/test/unit/document/document_test.ts index 92da6816e..888551f0f 100644 --- a/packages/sdk/test/unit/document/document_test.ts +++ b/packages/sdk/test/unit/document/document_test.ts @@ -18,6 +18,7 @@ import { describe, it, assert, vi, afterEach } from 'vitest'; import { EventCollector, MaxVersionVector, + DefaultSnapshotThreshold, } from '@yorkie-js-sdk/test/helper/helper'; import { Document, DocEventType } from '@yorkie-js-sdk/src/document/document'; @@ -1514,7 +1515,7 @@ describe.sequential('Document', function () { await c2.sync(); // 01. c1 increases the counter for creating snapshot. - for (let i = 0; i < 1000; i++) { + for (let i = 0; i < DefaultSnapshotThreshold; i++) { d1.update((r) => r.counter.increase(1)); } await c1.sync(); @@ -1523,7 +1524,10 @@ describe.sequential('Document', function () { c2.sync(); d2.update((r) => r.counter.increase(1)); - await eventCollector.waitAndVerifyNthEvent(1, 1001); + await eventCollector.waitAndVerifyNthEvent( + 1, + DefaultSnapshotThreshold + 1, + ); }, task.name); }); }); From 2f23982ce12a004d2ade322e2e10c11f8ba0eced Mon Sep 17 00:00:00 2001 From: Yourim Cha Date: Wed, 6 Nov 2024 21:46:58 +0900 Subject: [PATCH 9/9] Apply prettier --- packages/sdk/src/document/document.ts | 134 +++++++++++++------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/packages/sdk/src/document/document.ts b/packages/sdk/src/document/document.ts index 1f236aaa2..5c13df33c 100644 --- a/packages/sdk/src/document/document.ts +++ b/packages/sdk/src/document/document.ts @@ -470,14 +470,14 @@ export type DocumentKey = string; type OperationInfoOfElement = TElement extends Text ? TextOperationInfo : TElement extends Counter - ? CounterOperationInfo - : TElement extends Tree - ? TreeOperationInfo - : TElement extends BaseArray - ? ArrayOperationInfo - : TElement extends BaseObject - ? ObjectOperationInfo - : OperationInfo; + ? CounterOperationInfo + : TElement extends Tree + ? TreeOperationInfo + : TElement extends BaseArray + ? ArrayOperationInfo + : TElement extends BaseObject + ? ObjectOperationInfo + : OperationInfo; /** * `OperationInfoOfInternal` represents the type of the operation info of the @@ -498,24 +498,24 @@ type OperationInfoOfInternal< > = TDepth extends 0 ? TElement : TKeyOrPath extends `${infer TFirst}.${infer TRest}` - ? TFirst extends keyof TElement - ? TElement[TFirst] extends BaseArray - ? OperationInfoOfInternal< - TElement[TFirst], - number, - DecreasedDepthOf - > - : OperationInfoOfInternal< - TElement[TFirst], - TRest, - DecreasedDepthOf - > - : OperationInfo - : TKeyOrPath extends keyof TElement - ? TElement[TKeyOrPath] extends BaseArray - ? ArrayOperationInfo - : OperationInfoOfElement - : OperationInfo; + ? TFirst extends keyof TElement + ? TElement[TFirst] extends BaseArray + ? OperationInfoOfInternal< + TElement[TFirst], + number, + DecreasedDepthOf + > + : OperationInfoOfInternal< + TElement[TFirst], + TRest, + DecreasedDepthOf + > + : OperationInfo + : TKeyOrPath extends keyof TElement + ? TElement[TKeyOrPath] extends BaseArray + ? ArrayOperationInfo + : OperationInfoOfElement + : OperationInfo; /** * `DecreasedDepthOf` represents the type of the decreased depth of the given depth. @@ -523,24 +523,24 @@ type OperationInfoOfInternal< type DecreasedDepthOf = Depth extends 10 ? 9 : Depth extends 9 - ? 8 - : Depth extends 8 - ? 7 - : Depth extends 7 - ? 6 - : Depth extends 6 - ? 5 - : Depth extends 5 - ? 4 - : Depth extends 4 - ? 3 - : Depth extends 3 - ? 2 - : Depth extends 2 - ? 1 - : Depth extends 1 - ? 0 - : -1; + ? 8 + : Depth extends 8 + ? 7 + : Depth extends 7 + ? 6 + : Depth extends 6 + ? 5 + : Depth extends 5 + ? 4 + : Depth extends 4 + ? 3 + : Depth extends 3 + ? 2 + : Depth extends 2 + ? 1 + : Depth extends 1 + ? 0 + : -1; /** * `PathOfInternal` represents the type of the path of the given element. @@ -552,29 +552,29 @@ type PathOfInternal< > = Depth extends 0 ? Prefix : TElement extends Record - ? { - [TKey in keyof TElement]: TElement[TKey] extends LeafElement - ? `${Prefix}${TKey & string}` - : TElement[TKey] extends BaseArray - ? - | `${Prefix}${TKey & string}` - | `${Prefix}${TKey & string}.${number}` - | PathOfInternal< - TArrayElement, - `${Prefix}${TKey & string}.${number}.`, - DecreasedDepthOf - > - : - | `${Prefix}${TKey & string}` - | PathOfInternal< - TElement[TKey], - `${Prefix}${TKey & string}.`, - DecreasedDepthOf - >; - }[keyof TElement] - : Prefix extends `${infer TRest}.` - ? TRest - : Prefix; + ? { + [TKey in keyof TElement]: TElement[TKey] extends LeafElement + ? `${Prefix}${TKey & string}` + : TElement[TKey] extends BaseArray + ? + | `${Prefix}${TKey & string}` + | `${Prefix}${TKey & string}.${number}` + | PathOfInternal< + TArrayElement, + `${Prefix}${TKey & string}.${number}.`, + DecreasedDepthOf + > + : + | `${Prefix}${TKey & string}` + | PathOfInternal< + TElement[TKey], + `${Prefix}${TKey & string}.`, + DecreasedDepthOf + >; + }[keyof TElement] + : Prefix extends `${infer TRest}.` + ? TRest + : Prefix; /** * `OperationInfoOf` represents the type of the operation info of the given