-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathblock.go
More file actions
205 lines (177 loc) · 4.41 KB
/
block.go
File metadata and controls
205 lines (177 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package blocktree
import (
"errors"
"github.com/google/btree"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/xlab/treeprint"
)
var (
RootBlockID = uuid.MustParse("00000000-0000-0000-0000-000000000000")
)
type BlockID = uuid.UUID
type ParentID = uuid.UUID
type ChildID = uuid.UUID
type SpaceID = uuid.UUID
// Space is a collection of blocks
type Space struct {
ID SpaceID
Name string
}
func newSpace(spaceID SpaceID, name string) *Space {
return &Space{
ID: spaceID,
Name: name,
}
}
// BlockProps is a map of block properties
type BlockProps = map[string]interface{}
// BlockView is a view of the blocktree
type BlockView struct {
Type string
ID uuid.UUID
ParentID uuid.UUID
Children []*BlockView
Linked []*BlockView
Props *JsonDoc
Json *JsonDoc
Deleted bool
Erased bool
}
// BlockViewFromBlock creates a blockView from a block
func BlockViewFromBlock(block *Block) *BlockView {
return &BlockView{
Type: block.Type,
ID: block.ID,
ParentID: block.ParentID,
Props: block.Props,
Json: block.Json,
Deleted: block.Deleted,
Erased: block.Erased,
}
}
func blockViewFromBlocks(rootID BlockID, blocks []*Block) (*BlockView, error) {
var root *BlockView
children := make(map[BlockID]*btree.BTreeG[*Block])
linked := make(map[BlockID]*Set[*Block])
for _, block := range blocks {
if block.ID == rootID {
root = BlockViewFromBlock(block)
}
if block.Linked {
if _, ok := linked[block.ParentID]; !ok {
linked[block.ParentID] = NewSet[*Block]()
}
linked[block.ParentID].Add(block)
} else {
if _, ok := children[block.ParentID]; !ok {
children[block.ParentID] = btree.NewG(10, blockLessFunc)
}
logrus.Debugf("inserting block %v to parent %v", block.ID, block.ParentID)
children[block.ParentID].ReplaceOrInsert(block)
}
}
if root == nil {
return nil, errors.New("root block not found")
}
// build tree function
var build func(*BlockView)
build = func(block *BlockView) {
if children, ok := children[block.ID]; ok {
block.Children = make([]*BlockView, 0)
children.Ascend(func(item *Block) bool {
child := BlockViewFromBlock(item)
block.Children = append(block.Children, child)
build(child)
return true
})
}
if linked, ok := linked[block.ID]; ok {
block.Linked = make([]*BlockView, 0)
for _, item := range linked.ToSlice() {
child := BlockViewFromBlock(item)
block.Linked = append(block.Linked, child)
build(child)
}
}
}
// build tree
build(root)
return root, nil
}
func (b *BlockView) Print() {
var build func(treeprint.Tree, *BlockView)
build = func(tree treeprint.Tree, block *BlockView) {
v := tree.AddNode(block.ID.String())
if len(block.Children) > 0 {
children := v.AddBranch("children")
for _, child := range block.Children {
build(children, child)
}
}
if len(block.Linked) > 0 {
linked := v.AddBranch("linked")
for _, child := range block.Linked {
build(linked, child)
}
}
}
tree := treeprint.New()
build(tree, b)
logrus.Infof("tree: %v", tree.String())
}
// Block is a node in the blocktree
// blocks exist in a space and are linked to other blocks
type Block struct {
Type string
Table string
ID BlockID
ParentID ParentID
Index *FracIndex
Props *JsonDoc
Json *JsonDoc
Deleted bool // soft delete
Erased bool // permanent delete
Linked bool // linked blocks
UpdateFlags uint32
}
// NewBlock creates a new block
func NewBlock(blockID BlockID, parentID ParentID, blockType string) *Block {
return &Block{
Type: blockType,
ID: blockID,
ParentID: parentID,
Index: DefaultFracIndex(),
}
}
func (b *Block) mergeProps(props []byte) error {
if b.Props == nil {
b.Props = DefaultJsonDoc()
}
return b.Props.Apply(props)
}
// Clone creates a copy of the block
func (b *Block) Clone() *Block {
return &Block{
Type: b.Type,
ID: b.ID,
ParentID: b.ParentID,
Index: b.Index.Clone(),
Props: b.Props,
Json: b.Json.Clone(),
Deleted: b.Deleted,
Erased: b.Erased,
Linked: b.Linked,
}
}
// Less allows btree entry
func (b *Block) Less(other *Block) bool {
// linked blocks will have clashing index causing btree to block overwrite by id
if b.Index.Equals(other.Index) {
return b.ID.String() < other.ID.String()
}
return b.Index.Compare(other.Index) < 0
}
func blockLessFunc(a, b *Block) bool {
return a.Less(b)
}