From 51b2c303360e9f0eb907be3603b760cb1a3d723e Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 14 Dec 2023 00:12:32 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(#232):=20=EC=A1=B0=EC=83=81=20?= =?UTF-8?q?=EB=85=B8=EB=93=9C=20=ED=8C=90=EB=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/tree.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index f0ea9066..772152a2 100644 --- a/nestjs-BE/server/src/crdt/tree.ts +++ b/nestjs-BE/server/src/crdt/tree.ts @@ -56,6 +56,15 @@ export class Tree { return { nodes: Array.from(this.nodes.values()) }; } + isAncestor(targetId: string, ancestorId: string) { + let curNode = this.nodes.get(targetId); + while (curNode) { + if (curNode.parentId === ancestorId) return true; + curNode = this.nodes.get(curNode.parentId); + } + return false; + } + static parse(json: string) { const { nodes } = JSON.parse(json); const tree = new Tree(); From 8b47b87de318dc8072f14f9f5e0c563bcd13171b Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 14 Dec 2023 00:13:48 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat(#232):=20=ED=8A=B8=EB=A6=AC=20?= =?UTF-8?q?=EC=88=9C=ED=99=98=20=EB=A7=89=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이동 시 조상 노드인지 판별 --- nestjs-BE/server/src/crdt/operation.ts | 4 ++++ nestjs-BE/server/src/crdt/tree.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/nestjs-BE/server/src/crdt/operation.ts b/nestjs-BE/server/src/crdt/operation.ts index ef2704c7..11d7c3af 100644 --- a/nestjs-BE/server/src/crdt/operation.ts +++ b/nestjs-BE/server/src/crdt/operation.ts @@ -141,6 +141,10 @@ export class OperationMove extends Operation { const node = tree.get(this.id); const oldParentId = node.parentId; + if (tree.isAncestor(this.parentId, this.id)) { + return { operation: this, oldParentId }; + } + tree.removeNode(this.id); tree.attachNode(this.id, this.parentId); return { operation: this, oldParentId }; diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index 772152a2..bcf7a0ae 100644 --- a/nestjs-BE/server/src/crdt/tree.ts +++ b/nestjs-BE/server/src/crdt/tree.ts @@ -41,6 +41,7 @@ export class Tree { const targetIndex = parentNode.children.indexOf(targetId); if (targetIndex !== -1) parentNode.children.splice(targetIndex, 1); + targetNode.parentId = '0'; return this.nodes.get(targetId); } From 9d1f94e9cf856d5e5f0cf9d9b0ad61c70ea9fc7b Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 14 Dec 2023 00:14:53 +0900 Subject: [PATCH 3/4] =?UTF-8?q?test(#232):=20=EC=A1=B0=EC=83=81=20?= =?UTF-8?q?=ED=8C=90=EB=B3=84=20=ED=95=A8=EC=88=98=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/tree.spec.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 nestjs-BE/server/src/crdt/tree.spec.ts diff --git a/nestjs-BE/server/src/crdt/tree.spec.ts b/nestjs-BE/server/src/crdt/tree.spec.ts new file mode 100644 index 00000000..cf9da0ce --- /dev/null +++ b/nestjs-BE/server/src/crdt/tree.spec.ts @@ -0,0 +1,19 @@ +import { Tree } from './tree'; + +it('isAncestor', () => { + const tree = new Tree(); + + tree.addNode('a', 'root', 'test'); + tree.addNode('b', 'a', 'test'); + tree.addNode('c', 'b', 'test'); + tree.addNode('d', 'a', 'test'); + tree.addNode('e', 'b', 'test'); + + expect(tree.isAncestor('c', 'a')).toBeTruthy(); + expect(tree.isAncestor('c', 'root')).toBeTruthy(); + expect(tree.isAncestor('d', 'root')).toBeTruthy(); + expect(tree.isAncestor('d', 'a')).toBeTruthy(); + expect(tree.isAncestor('c', 'e')).toBeFalsy(); + expect(tree.isAncestor('e', 'c')).toBeFalsy(); + expect(tree.isAncestor('c', 'd')).toBeFalsy(); +}); From aeed9772e0306ea22496a62cc3b0df9b1e5942ce Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 14 Dec 2023 00:21:35 +0900 Subject: [PATCH 4/4] =?UTF-8?q?test(#232):=20=EC=88=9C=ED=99=98=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/crdt-tree.spec.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nestjs-BE/server/src/crdt/crdt-tree.spec.ts b/nestjs-BE/server/src/crdt/crdt-tree.spec.ts index 98c02598..c02253ed 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.spec.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.spec.ts @@ -59,3 +59,18 @@ it('crdt tree 역직렬화', () => { expect(JSON.stringify(tree)).toEqual(JSON.stringify(parsedTree)); }); + +it('crdt tree 순환', () => { + const tree = new CrdtTree('1'); + + const op1 = tree.generateOperationAdd('a', 'root', 'hello'); + const op2 = tree.generateOperationAdd('b', 'root', 'hi'); + const op3 = tree.generateOperationAdd('c', 'a', 'good'); + const op4 = tree.generateOperationAdd('d', 'b', 'bad'); + const op5 = tree.generateOperationMove('a', 'b'); + const op6 = tree.generateOperationMove('b', 'a'); + + tree.applyOperations([op1, op2, op3, op4, op5, op6]); + + expect(tree.tree.get('b').parentId).toEqual('root'); +});