Skip to content

Commit

Permalink
Extract buildCRDTElement logic for constructing CRDTElement
Browse files Browse the repository at this point in the history
  • Loading branch information
chacha912 committed Nov 20, 2023
1 parent 21f6b2f commit 31251f4
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 193 deletions.
89 changes: 22 additions & 67 deletions src/document/json/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,14 @@ import {
CRDTContainer,
CRDTElement,
} from '@yorkie-js-sdk/src/document/crdt/element';
import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object';
import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array';
import {
Primitive,
PrimitiveValue,
} from '@yorkie-js-sdk/src/document/crdt/primitive';
import { ObjectProxy } from '@yorkie-js-sdk/src/document/json/object';
import { Primitive } from '@yorkie-js-sdk/src/document/crdt/primitive';
import {
JSONElement,
WrappedElement,
toWrappedElement,
toJSONElement,
buildCRDTElement,
} from '@yorkie-js-sdk/src/document/json/element';

/**
Expand Down Expand Up @@ -341,17 +337,8 @@ export class ArrayProxy {
): Array<CRDTElement> {
const elementArray: Array<CRDTElement> = [];
for (const v of value) {
const ticket = context.issueTimeTicket();
let elem: CRDTElement;
if (Primitive.isSupport(v)) {
elem = Primitive.of(v as PrimitiveValue, ticket);
} else if (Array.isArray(v)) {
elem = CRDTArray.create(ticket, ArrayProxy.buildArray(context, v));
} else if (typeof v === 'object') {
elem = CRDTObject.create(ticket, ObjectProxy.buildObject(context, v!));
} else {
throw new TypeError(`Unsupported type of value: ${typeof value}`);
}
const createdAt = context.issueTimeTicket();
const elem = buildCRDTElement(context, v, createdAt);
elementArray.push(elem);
}
return elementArray;
Expand Down Expand Up @@ -467,57 +454,25 @@ export class ArrayProxy {
prevCreatedAt: TimeTicket,
value: unknown,
): CRDTElement {
const ticket = context.issueTimeTicket();
if (Primitive.isSupport(value)) {
const primitive = Primitive.of(value as PrimitiveValue, ticket);
const clone = primitive.deepcopy();
target.insertAfter(prevCreatedAt, clone);
context.registerElement(clone, target);
context.push(
AddOperation.create(
target.getCreatedAt(),
prevCreatedAt,
primitive.deepcopy(),
ticket,
),
);
return primitive;
} else if (Array.isArray(value)) {
const array = CRDTArray.create(
ticket,
ArrayProxy.buildArray(context, value),
);
const clone = array.deepcopy();
target.insertAfter(prevCreatedAt, clone);
context.registerElement(clone, target);
context.push(
AddOperation.create(
target.getCreatedAt(),
prevCreatedAt,
array.deepcopy(),
ticket,
),
);
return array;
} else if (typeof value === 'object') {
const obj = CRDTObject.create(
ticket,
ObjectProxy.buildObject(context, value!),
);
target.insertAfter(prevCreatedAt, obj);
context.registerElement(obj, target);
context.push(
AddOperation.create(
target.getCreatedAt(),
prevCreatedAt,
obj.deepcopy(),
ticket,
),
);
return obj;
const createdAt = context.issueTimeTicket();
const element = buildCRDTElement(context, value, createdAt);
target.insertAfter(prevCreatedAt, element);
context.registerElement(element, target);
if (element instanceof CRDTContainer) {
element.getDescendants((elem, parent) => {
context.registerElement(elem, parent);
return false;
});
}

throw new TypeError(`Unsupported type of value: ${typeof value}`);
context.push(
AddOperation.create(
target.getCreatedAt(),
prevCreatedAt,
element.deepcopy(),
createdAt,
),
);
return element;
}

/**
Expand Down
46 changes: 46 additions & 0 deletions src/document/json/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ import {
CRDTCounter,
} from '@yorkie-js-sdk/src/document/crdt/counter';
import { CRDTTree } from '@yorkie-js-sdk/src/document/crdt/tree';
import { RGATreeSplit } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split';
import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket';

import {
JSONObject,
createJSONObject,
ObjectProxy,
} from '@yorkie-js-sdk/src/document/json/object';
import {
JSONArray,
createJSONArray,
ArrayProxy,
} from '@yorkie-js-sdk/src/document/json/array';
import { Text } from '@yorkie-js-sdk/src/document/json/text';
import { Counter } from '@yorkie-js-sdk/src/document/json/counter';
Expand Down Expand Up @@ -131,3 +135,45 @@ export function toJSONElement(

return wrappedElement;
}

/**
* `buildCRDTElement` constructs a CRDTElement from the given value.
*/
export function buildCRDTElement(
context: ChangeContext,
value: unknown,
createdAt: TimeTicket,
): CRDTElement {
let element: CRDTElement;
if (Primitive.isSupport(value)) {
element = Primitive.of(value as PrimitiveValue, createdAt);
} else if (Array.isArray(value)) {
element = CRDTArray.create(
createdAt,
ArrayProxy.buildArray(context, value),
);
} else if (typeof value === 'object') {
if (value instanceof Text) {
element = CRDTText.create(RGATreeSplit.create(), createdAt);
value.initialize(context, element as CRDTText);
} else if (value instanceof Counter) {
element = CRDTCounter.create(
value.getValueType(),
value.getValue(),
createdAt,
);
value.initialize(context, element as CRDTCounter);
} else if (value instanceof Tree) {
element = CRDTTree.create(value.buildRoot(context), createdAt);
value.initialize(context, element as CRDTTree);
} else {
element = CRDTObject.create(
createdAt,
ObjectProxy.buildObject(context, value!),
);
}
} else {
throw new TypeError(`Unsupported type of value: ${typeof value}`);
}
return element;
}
149 changes: 26 additions & 123 deletions src/document/json/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,15 @@ import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket';
import { SetOperation } from '@yorkie-js-sdk/src/document/operation/set_operation';
import { RemoveOperation } from '@yorkie-js-sdk/src/document/operation/remove_operation';
import { ChangeContext } from '@yorkie-js-sdk/src/document/change/context';
import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element';
import {
CRDTContainer,
CRDTElement,
} from '@yorkie-js-sdk/src/document/crdt/element';
import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object';
import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array';
import {
Primitive,
PrimitiveValue,
} from '@yorkie-js-sdk/src/document/crdt/primitive';
import { RGATreeSplit } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split';
import { CRDTText } from '@yorkie-js-sdk/src/document/crdt/text';
import { ArrayProxy } from '@yorkie-js-sdk/src/document/json/array';
import { Text } from '@yorkie-js-sdk/src/document/json/text';
import { toJSONElement } from '@yorkie-js-sdk/src/document/json/element';
import { CRDTCounter } from '@yorkie-js-sdk/src/document/crdt/counter';
import { Counter } from '@yorkie-js-sdk/src/document/json/counter';
import { CRDTTree } from '@yorkie-js-sdk/src/document/crdt/tree';
import { Tree } from '@yorkie-js-sdk/src/document/json/tree';
toJSONElement,
buildCRDTElement,
} from '@yorkie-js-sdk/src/document/json/element';

/**
* `JSONObject` represents a JSON object, but unlike regular JSON, it has time
Expand Down Expand Up @@ -155,106 +148,27 @@ export class ObjectProxy {
);
}

const ticket = context.issueTimeTicket();

const setAndRegister = function (elem: CRDTElement) {
const removed = target.set(key, elem, ticket);
context.registerElement(elem, target);
if (removed) {
context.registerRemovedElement(removed);
}
};

if (Primitive.isSupport(value)) {
const primitive = Primitive.of(value as PrimitiveValue, ticket);
setAndRegister(primitive);
context.push(
SetOperation.create(key, primitive, target.getCreatedAt(), ticket),
);
} else if (Array.isArray(value)) {
const array = CRDTArray.create(
ticket,
ArrayProxy.buildArray(context, value),
);
array.getDescendants((elem, parent) => {
const createdAt = context.issueTimeTicket();
const element = buildCRDTElement(context, value, createdAt);
const removed = target.set(key, element, createdAt);
context.registerElement(element, target);
if (removed) {
context.registerRemovedElement(removed);
}
if (element instanceof CRDTContainer) {
element.getDescendants((elem, parent) => {
context.registerElement(elem, parent);
return false;
});
setAndRegister(array);
context.push(
SetOperation.create(
key,
array.deepcopy(),
target.getCreatedAt(),
ticket,
),
);
} else if (typeof value === 'object') {
if (value instanceof Text) {
const text = CRDTText.create(RGATreeSplit.create(), ticket);
target.set(key, text, ticket);
context.registerElement(text, target);
context.push(
SetOperation.create(
key,
text.deepcopy(),
target.getCreatedAt(),
ticket,
),
);
value.initialize(context, text);
} else if (value instanceof Counter) {
const counter = CRDTCounter.create(
value.getValueType(),
value.getValue(),
ticket,
);
target.set(key, counter, ticket);
context.registerElement(counter, target);
context.push(
SetOperation.create(
key,
counter.deepcopy(),
target.getCreatedAt(),
ticket,
),
);
value.initialize(context, counter);
} else if (value instanceof Tree) {
const tree = CRDTTree.create(value.buildRoot(context), ticket);
target.set(key, tree, ticket);
context.registerElement(tree, target);
context.push(
SetOperation.create(
key,
tree.deepcopy(),
target.getCreatedAt(),
ticket,
),
);
value.initialize(context, tree);
} else {
const obj = CRDTObject.create(
ticket,
ObjectProxy.buildObject(context, value!),
);
obj.getDescendants((elem, parent) => {
context.registerElement(elem, parent);
return false;
});
setAndRegister(obj);
context.push(
SetOperation.create(
key,
obj.deepcopy(),
target.getCreatedAt(),
ticket,
),
);
}
} else {
logger.fatal(`unsupported type of value: ${typeof value}`);
}
context.push(
SetOperation.create(
key,
element.deepcopy(),
target.getCreatedAt(),
createdAt,
),
);
}

/**
Expand All @@ -276,19 +190,8 @@ export class ObjectProxy {
);
}

const ticket = context.issueTimeTicket();
let elem: CRDTElement;
if (Primitive.isSupport(v)) {
elem = Primitive.of(v as PrimitiveValue, ticket);
} else if (Array.isArray(v)) {
const array = ArrayProxy.buildArray(context, v);
elem = CRDTArray.create(ticket, array);
} else if (typeof v === 'object') {
const object = ObjectProxy.buildObject(context, v);
elem = CRDTObject.create(ticket, object);
} else {
throw new TypeError(`Unsupported type of value: ${typeof value}`);
}
const createdAt = context.issueTimeTicket();
const elem = buildCRDTElement(context, v, createdAt);
elementObject[k] = elem;
}
return elementObject;
Expand Down
12 changes: 11 additions & 1 deletion src/document/operation/add_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

import { logger } from '@yorkie-js-sdk/src/util/logger';
import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket';
import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element';
import {
CRDTContainer,
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 {
Expand Down Expand Up @@ -69,6 +72,13 @@ export class AddOperation extends Operation {
const value = this.value.deepcopy();
array.insertAfter(this.prevCreatedAt, value);
root.registerElement(value, array);
if (value instanceof CRDTContainer) {
value.getDescendants((elem, parent) => {
root.registerElement(elem, parent);
return false;
});
}

return {
opInfos: [
{
Expand Down
Loading

0 comments on commit 31251f4

Please sign in to comment.