Skip to content

Commit

Permalink
Merge Text and RichText
Browse files Browse the repository at this point in the history
  • Loading branch information
hackerwins committed Jan 5, 2023
1 parent 7f7ea60 commit e7f26c6
Show file tree
Hide file tree
Showing 27 changed files with 927 additions and 3,083 deletions.
16 changes: 8 additions & 8 deletions api/converter/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,21 @@ func TestConverter(t *testing.T) {
return nil
})
assert.NoError(t, err)
assert.Equal(t, `{"k1":"A"}`, doc.Marshal())
assert.Equal(t, `{"k1":[{"attrs":{},"val":"A"}]}`, doc.Marshal())

err = doc.Update(func(root *json.Object) error {
root.SetNewText("k1").Edit(0, 0, "B")
return nil
})
assert.NoError(t, err)
assert.Equal(t, `{"k1":"B"}`, doc.Marshal())
assert.Equal(t, `{"k1":[{"attrs":{},"val":"B"}]}`, doc.Marshal())

bytes, err := converter.ObjectToBytes(doc.RootObject())
assert.NoError(t, err)

obj, err = converter.BytesToObject(bytes)
assert.NoError(t, err)
assert.Equal(t, `{"k1":"B"}`, obj.Marshal())
assert.Equal(t, `{"k1":[{"attrs":{},"val":"B"}]}`, obj.Marshal())
})

t.Run("snapshot test", func(t *testing.T) {
Expand Down Expand Up @@ -101,10 +101,10 @@ func TestConverter(t *testing.T) {
Edit(2, 3, "뭉게구")

// rich text
root.SetNewRichText("k4").
root.SetNewText("k4").
Edit(0, 0, "Hello world", nil).
Edit(6, 11, "sky", nil).
SetStyle(0, 5, map[string]string{"b": "1"})
Style(0, 5, map[string]string{"b": "1"})

// a counter
root.SetNewCounter("k5", 0).
Expand Down Expand Up @@ -163,10 +163,10 @@ func TestConverter(t *testing.T) {
Edit(1, 2, "늘").
Select(1, 2)

// plain text
root.SetNewRichText("k3").
// rich text
root.SetNewText("k3").
Edit(0, 0, "Hello World", nil).
SetStyle(0, 5, map[string]string{"b": "1"})
Style(0, 5, map[string]string{"b": "1"})

// counter
root.SetNewCounter("k4", 0).Increase(5)
Expand Down
81 changes: 7 additions & 74 deletions api/converter/from_bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ func fromJSONElement(pbElem *api.JSONElement) (crdt.Element, error) {
return fromJSONPrimitive(decoded.Primitive)
case *api.JSONElement_Text_:
return fromJSONText(decoded.Text)
case *api.JSONElement_RichText_:
return fromJSONRichText(decoded.RichText)
case *api.JSONElement_Counter_:
return fromJSONCounter(decoded.Counter)
default:
Expand Down Expand Up @@ -160,7 +158,9 @@ func fromJSONPrimitive(
return primitive, nil
}

func fromJSONText(pbText *api.JSONElement_Text) (*crdt.Text, error) {
func fromJSONText(
pbText *api.JSONElement_Text,
) (*crdt.Text, error) {
createdAt, err := fromTimeTicket(pbText.CreatedAt)
if err != nil {
return nil, err
Expand Down Expand Up @@ -206,54 +206,6 @@ func fromJSONText(pbText *api.JSONElement_Text) (*crdt.Text, error) {
return text, nil
}

func fromJSONRichText(
pbText *api.JSONElement_RichText,
) (*crdt.RichText, error) {
createdAt, err := fromTimeTicket(pbText.CreatedAt)
if err != nil {
return nil, err
}
movedAt, err := fromTimeTicket(pbText.MovedAt)
if err != nil {
return nil, err
}
removedAt, err := fromTimeTicket(pbText.RemovedAt)
if err != nil {
return nil, err
}

rgaTreeSplit := crdt.NewRGATreeSplit(crdt.InitialRichTextNode())

current := rgaTreeSplit.InitialHead()
for _, pbNode := range pbText.Nodes {
textNode, err := fromRichTextNode(pbNode)
if err != nil {
return nil, err
}
current = rgaTreeSplit.InsertAfter(current, textNode)
insPrevID, err := fromTextNodeID(pbNode.InsPrevId)
if err != nil {
return nil, err
}
if insPrevID != nil {
insPrevNode := rgaTreeSplit.FindNode(insPrevID)
if insPrevNode == nil {
panic("insPrevNode should be presence")
}
current.SetInsPrev(insPrevNode)
}
}

text := crdt.NewRichText(
rgaTreeSplit,
createdAt,
)
text.SetMovedAt(movedAt)
text.SetRemovedAt(removedAt)

return text, nil
}

func fromJSONCounter(pbCnt *api.JSONElement_Counter) (*crdt.Counter, error) {
createdAt, err := fromTimeTicket(pbCnt.CreatedAt)
if err != nil {
Expand Down Expand Up @@ -282,28 +234,9 @@ func fromJSONCounter(pbCnt *api.JSONElement_Counter) (*crdt.Counter, error) {
return counter, nil
}

func fromTextNode(pbTextNode *api.TextNode) (*crdt.RGATreeSplitNode[*crdt.TextValue], error) {
id, err := fromTextNodeID(pbTextNode.Id)
if err != nil {
return nil, err
}
textNode := crdt.NewRGATreeSplitNode(
id,
crdt.NewTextValue(pbTextNode.Value),
)
if pbTextNode.RemovedAt != nil {
removedAt, err := fromTimeTicket(pbTextNode.RemovedAt)
if err != nil {
return nil, err
}
textNode.Remove(removedAt, time.MaxTicket)
}
return textNode, nil
}

func fromRichTextNode(
pbNode *api.RichTextNode,
) (*crdt.RGATreeSplitNode[*crdt.RichTextValue], error) {
func fromTextNode(
pbNode *api.TextNode,
) (*crdt.RGATreeSplitNode[*crdt.TextValue], error) {
id, err := fromTextNodeID(pbNode.Id)
if err != nil {
return nil, err
Expand All @@ -320,7 +253,7 @@ func fromRichTextNode(

textNode := crdt.NewRGATreeSplitNode(
id,
crdt.NewRichTextValue(attrs, pbNode.Value),
crdt.NewTextValue(pbNode.Value, attrs),
)
if pbNode.RemovedAt != nil {
removedAt, err := fromTimeTicket(pbNode.RemovedAt)
Expand Down
48 changes: 2 additions & 46 deletions api/converter/from_pb.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,6 @@ func FromOperations(pbOps []*api.Operation) ([]operations.Operation, error) {
op, err = fromEdit(decoded.Edit)
case *api.Operation_Select_:
op, err = fromSelect(decoded.Select)
case *api.Operation_RichEdit_:
op, err = fromRichEdit(decoded.RichEdit)
case *api.Operation_Style_:
op, err = fromStyle(decoded.Style)
case *api.Operation_Increase_:
Expand Down Expand Up @@ -394,39 +392,6 @@ func fromRemove(pbRemove *api.Operation_Remove) (*operations.Remove, error) {
), nil
}

func fromEdit(pbEdit *api.Operation_Edit) (*operations.Edit, error) {
parentCreatedAt, err := fromTimeTicket(pbEdit.ParentCreatedAt)
if err != nil {
return nil, err
}
from, err := fromTextNodePos(pbEdit.From)
if err != nil {
return nil, err
}
to, err := fromTextNodePos(pbEdit.To)
if err != nil {
return nil, err
}
createdAtMapByActor, err := fromCreatedAtMapByActor(
pbEdit.CreatedAtMapByActor,
)
if err != nil {
return nil, err
}
executedAt, err := fromTimeTicket(pbEdit.ExecutedAt)
if err != nil {
return nil, err
}
return operations.NewEdit(
parentCreatedAt,
from,
to,
createdAtMapByActor,
pbEdit.Content,
executedAt,
), nil
}

func fromSelect(pbSelect *api.Operation_Select) (*operations.Select, error) {
parentCreatedAt, err := fromTimeTicket(pbSelect.ParentCreatedAt)
if err != nil {
Expand All @@ -452,7 +417,7 @@ func fromSelect(pbSelect *api.Operation_Select) (*operations.Select, error) {
), nil
}

func fromRichEdit(pbEdit *api.Operation_RichEdit) (*operations.RichEdit, error) {
func fromEdit(pbEdit *api.Operation_Edit) (*operations.Edit, error) {
parentCreatedAt, err := fromTimeTicket(pbEdit.ParentCreatedAt)
if err != nil {
return nil, err
Expand All @@ -475,7 +440,7 @@ func fromRichEdit(pbEdit *api.Operation_RichEdit) (*operations.RichEdit, error)
if err != nil {
return nil, err
}
return operations.NewRichEdit(
return operations.NewEdit(
parentCreatedAt,
from,
to,
Expand Down Expand Up @@ -631,15 +596,6 @@ func fromElement(pbElement *api.JSONElementSimple) (crdt.Element, error) {
crdt.NewRGATreeSplit(crdt.InitialTextNode()),
createdAt,
), nil
case api.ValueType_VALUE_TYPE_RICH_TEXT:
createdAt, err := fromTimeTicket(pbElement.CreatedAt)
if err != nil {
return nil, err
}
return crdt.NewInitialRichText(
crdt.NewRGATreeSplit(crdt.InitialRichTextNode()),
createdAt,
), nil
case api.ValueType_VALUE_TYPE_INTEGER_CNT:
fallthrough
case api.ValueType_VALUE_TYPE_LONG_CNT:
Expand Down
37 changes: 3 additions & 34 deletions api/converter/to_bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ func toJSONElement(elem crdt.Element) (*api.JSONElement, error) {
return toPrimitive(elem)
case *crdt.Text:
return toText(elem), nil
case *crdt.RichText:
return toRichText(elem), nil
case *crdt.Counter:
return toCounter(elem)
default:
Expand Down Expand Up @@ -121,17 +119,6 @@ func toText(text *crdt.Text) *api.JSONElement {
}
}

func toRichText(text *crdt.RichText) *api.JSONElement {
return &api.JSONElement{
Body: &api.JSONElement_RichText_{RichText: &api.JSONElement_RichText{
Nodes: toRichTextNodes(text.Nodes()),
CreatedAt: ToTimeTicket(text.CreatedAt()),
MovedAt: ToTimeTicket(text.MovedAt()),
RemovedAt: ToTimeTicket(text.RemovedAt()),
}},
}
}

func toCounter(counter *crdt.Counter) (*api.JSONElement, error) {
pbCounterType, err := toCounterType(counter.ValueType())
if err != nil {
Expand Down Expand Up @@ -182,37 +169,19 @@ func toRGANodes(rgaNodes []*crdt.RGATreeListNode) ([]*api.RGANode, error) {

func toTextNodes(textNodes []*crdt.RGATreeSplitNode[*crdt.TextValue]) []*api.TextNode {
var pbTextNodes []*api.TextNode
for _, textNode := range textNodes {
pbTextNode := &api.TextNode{
Id: toTextNodeID(textNode.ID()),
Value: textNode.String(),
RemovedAt: ToTimeTicket(textNode.RemovedAt()),
}

if textNode.InsPrevID() != nil {
pbTextNode.InsPrevId = toTextNodeID(textNode.InsPrevID())
}

pbTextNodes = append(pbTextNodes, pbTextNode)
}
return pbTextNodes
}

func toRichTextNodes(textNodes []*crdt.RGATreeSplitNode[*crdt.RichTextValue]) []*api.RichTextNode {
var pbTextNodes []*api.RichTextNode
for _, textNode := range textNodes {
value := textNode.Value()

attrs := make(map[string]*api.RichTextNodeAttr)
attrs := make(map[string]*api.TextNodeAttr)
for _, node := range value.Attrs().Nodes() {
attrs[node.Key()] = &api.RichTextNodeAttr{
attrs[node.Key()] = &api.TextNodeAttr{
Key: node.Key(),
Value: node.Value(),
UpdatedAt: ToTimeTicket(node.UpdatedAt()),
}
}

pbTextNode := &api.RichTextNode{
pbTextNode := &api.TextNode{
Id: toTextNodeID(textNode.ID()),
Attributes: attrs,
Value: value.Value(),
Expand Down
36 changes: 8 additions & 28 deletions api/converter/to_pb.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,6 @@ func ToOperations(ops []operations.Operation) ([]*api.Operation, error) {
pbOperation.Body, err = toEdit(op)
case *operations.Select:
pbOperation.Body, err = toSelect(op)
case *operations.RichEdit:
pbOperation.Body, err = toRichEdit(op)
case *operations.Style:
pbOperation.Body, err = toStyle(op)
case *operations.Increase:
Expand Down Expand Up @@ -352,15 +350,16 @@ func toRemove(remove *operations.Remove) (*api.Operation_Remove_, error) {
}, nil
}

func toEdit(edit *operations.Edit) (*api.Operation_Edit_, error) {
func toEdit(e *operations.Edit) (*api.Operation_Edit_, error) {
return &api.Operation_Edit_{
Edit: &api.Operation_Edit{
ParentCreatedAt: ToTimeTicket(edit.ParentCreatedAt()),
From: toTextNodePos(edit.From()),
To: toTextNodePos(edit.To()),
CreatedAtMapByActor: toCreatedAtMapByActor(edit.CreatedAtMapByActor()),
Content: edit.Content(),
ExecutedAt: ToTimeTicket(edit.ExecutedAt()),
ParentCreatedAt: ToTimeTicket(e.ParentCreatedAt()),
From: toTextNodePos(e.From()),
To: toTextNodePos(e.To()),
CreatedAtMapByActor: toCreatedAtMapByActor(e.CreatedAtMapByActor()),
Content: e.Content(),
Attributes: e.Attributes(),
ExecutedAt: ToTimeTicket(e.ExecutedAt()),
},
}, nil
}
Expand All @@ -376,20 +375,6 @@ func toSelect(s *operations.Select) (*api.Operation_Select_, error) {
}, nil
}

func toRichEdit(richEdit *operations.RichEdit) (*api.Operation_RichEdit_, error) {
return &api.Operation_RichEdit_{
RichEdit: &api.Operation_RichEdit{
ParentCreatedAt: ToTimeTicket(richEdit.ParentCreatedAt()),
From: toTextNodePos(richEdit.From()),
To: toTextNodePos(richEdit.To()),
CreatedAtMapByActor: toCreatedAtMapByActor(richEdit.CreatedAtMapByActor()),
Content: richEdit.Content(),
Attributes: richEdit.Attributes(),
ExecutedAt: ToTimeTicket(richEdit.ExecutedAt()),
},
}, nil
}

func toStyle(style *operations.Style) (*api.Operation_Style_, error) {
return &api.Operation_Style_{
Style: &api.Operation_Style{
Expand Down Expand Up @@ -445,11 +430,6 @@ func toJSONElementSimple(elem crdt.Element) (*api.JSONElementSimple, error) {
Type: api.ValueType_VALUE_TYPE_TEXT,
CreatedAt: ToTimeTicket(elem.CreatedAt()),
}, nil
case *crdt.RichText:
return &api.JSONElementSimple{
Type: api.ValueType_VALUE_TYPE_RICH_TEXT,
CreatedAt: ToTimeTicket(elem.CreatedAt()),
}, nil
case *crdt.Counter:
pbCounterType, err := toCounterType(elem.ValueType())
if err != nil {
Expand Down
Loading

1 comment on commit e7f26c6

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go Benchmark

Benchmark suite Current: e7f26c6 Previous: 44145aa Ratio
BenchmarkDocument/constructor_test 1229 ns/op 752 B/op 12 allocs/op 1544 ns/op 752 B/op 12 allocs/op 0.80
BenchmarkDocument/status_test 632.6 ns/op 720 B/op 10 allocs/op 818.6 ns/op 720 B/op 10 allocs/op 0.77
BenchmarkDocument/equals_test 11136 ns/op 5120 B/op 91 allocs/op 12465 ns/op 5120 B/op 91 allocs/op 0.89
BenchmarkDocument/nested_update_test 22390 ns/op 10961 B/op 251 allocs/op 28709 ns/op 10961 B/op 251 allocs/op 0.78
BenchmarkDocument/delete_test 28487 ns/op 13818 B/op 318 allocs/op 35479 ns/op 13818 B/op 318 allocs/op 0.80
BenchmarkDocument/object_test 10286 ns/op 5776 B/op 103 allocs/op 12529 ns/op 5776 B/op 103 allocs/op 0.82
BenchmarkDocument/array_test 35149 ns/op 10713 B/op 251 allocs/op 45148 ns/op 10713 B/op 251 allocs/op 0.78
BenchmarkDocument/text_test 39110 ns/op 14618 B/op 478 allocs/op
BenchmarkDocument/text_composition_test 39075 ns/op 17954 B/op 477 allocs/op
BenchmarkDocument/rich_text_test 96066 ns/op 33444 B/op 1071 allocs/op
BenchmarkDocument/counter_test 29378 ns/op 12041 B/op 304 allocs/op 35886 ns/op 12041 B/op 304 allocs/op 0.82
BenchmarkDocument/text_edit_gc_100 3984337 ns/op 1552855 B/op 17155 allocs/op 4965070 ns/op 1552819 B/op 17158 allocs/op 0.80
BenchmarkDocument/text_edit_gc_1000 312473260 ns/op 136633864 B/op 210733 allocs/op 409753114 ns/op 136685464 B/op 210938 allocs/op 0.76
BenchmarkDocument/text_split_gc_100 4704918 ns/op 2217315 B/op 16584 allocs/op 5885154 ns/op 2217391 B/op 16584 allocs/op 0.80
BenchmarkDocument/text_split_gc_1000 375040198 ns/op 214833794 B/op 211337 allocs/op 479373703 ns/op 214876034 B/op 211523 allocs/op 0.78
BenchmarkDocument/text_100 302827 ns/op 117861 B/op 5072 allocs/op 419547 ns/op 117860 B/op 5072 allocs/op 0.72
BenchmarkDocument/text_1000 3308003 ns/op 1152441 B/op 50076 allocs/op 4408353 ns/op 1152483 B/op 50076 allocs/op 0.75
BenchmarkDocument/array_1000 1683492 ns/op 1108334 B/op 11863 allocs/op 2220880 ns/op 1108034 B/op 11862 allocs/op 0.76
BenchmarkDocument/array_10000 18182847 ns/op 9984876 B/op 120716 allocs/op 24676753 ns/op 9983639 B/op 120709 allocs/op 0.74
BenchmarkDocument/array_gc_100 177422 ns/op 97551 B/op 1234 allocs/op 230719 ns/op 97522 B/op 1234 allocs/op 0.77
BenchmarkDocument/array_gc_1000 1948887 ns/op 1175640 B/op 12897 allocs/op 2504377 ns/op 1175685 B/op 12897 allocs/op 0.78
BenchmarkDocument/counter_1000 257722 ns/op 200964 B/op 5521 allocs/op 353604 ns/op 201016 B/op 5521 allocs/op 0.73
BenchmarkDocument/counter_10000 2774666 ns/op 2203881 B/op 59528 allocs/op 4219900 ns/op 2203929 B/op 59528 allocs/op 0.66
BenchmarkDocument/rich_text_100 296202 ns/op 115682 B/op 3983 allocs/op 389047 ns/op 115684 B/op 3983 allocs/op 0.76
BenchmarkDocument/rich_text_1000 3179985 ns/op 1130481 B/op 39087 allocs/op 4379594 ns/op 1130507 B/op 39087 allocs/op 0.73
BenchmarkDocument/object_1000 2413098 ns/op 1538938 B/op 11929 allocs/op 3330798 ns/op 1538580 B/op 11929 allocs/op 0.72
BenchmarkDocument/object_10000 30261122 ns/op 13482272 B/op 121250 allocs/op 44028729 ns/op 13485131 B/op 121256 allocs/op 0.69
BenchmarkRPC/client_to_server 778113288 ns/op 25452688 B/op 427270 allocs/op 1170000100 ns/op 25841960 B/op 422697 allocs/op 0.67
BenchmarkRPC/client_to_client_via_server 5028423025 ns/op 50751944 B/op 810882 allocs/op 5057066865 ns/op 50896872 B/op 813032 allocs/op 0.99
BenchmarkRPC/attach_large_document 1601054973 ns/op 2124546864 B/op 13645 allocs/op 1950688296 ns/op 2125183712 B/op 13618 allocs/op 0.82
BenchmarkRPC/adminCli_to_server 512647204 ns/op 18405472 B/op 303108 allocs/op 664873530 ns/op 18417824 B/op 303124 allocs/op 0.77
BenchmarkLocker 112.1 ns/op 16 B/op 1 allocs/op 156.2 ns/op 16 B/op 1 allocs/op 0.72
BenchmarkLockerParallel 105.3 ns/op 0 B/op 0 allocs/op 165.3 ns/op 0 B/op 0 allocs/op 0.64
BenchmarkLockerMoreKeys 333.1 ns/op 14 B/op 0 allocs/op 524.2 ns/op 13 B/op 0 allocs/op 0.64
BenchmarkSync/memory_sync_10_test 7027 ns/op 1340 B/op 39 allocs/op 9333 ns/op 1339 B/op 39 allocs/op 0.75
BenchmarkSync/memory_sync_100_test 58423 ns/op 9076 B/op 298 allocs/op 82188 ns/op 8816 B/op 281 allocs/op 0.71
BenchmarkSync/memory_sync_1000_test 578345 ns/op 83938 B/op 2716 allocs/op 847662 ns/op 82751 B/op 2631 allocs/op 0.68
BenchmarkSync/memory_sync_10000_test 6180583 ns/op 857888 B/op 27512 allocs/op 9480310 ns/op 855145 B/op 26958 allocs/op 0.65
BenchmarkSync/etcd_sync_100_test 0.2935 ns/op 0 B/op 0 allocs/op 0.403 ns/op 0 B/op 0 allocs/op 0.73
BenchmarkTextEditing 23848334807 ns/op 8435951664 B/op 19834257 allocs/op 36943639042 ns/op 8436290856 B/op 19835583 allocs/op 0.65

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.