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'); +}); 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.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(); +}); diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index f0ea9066..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); } @@ -56,6 +57,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();