├── LICENSE ├── node.go ├── README.md ├── ns_test.go └── ns.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ara Israelyan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /node.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ara Israelyan. All rights reserved. 2 | // Use of this source code is governed by a MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | 6 | package nestedset 7 | 8 | // NodeInterface is the interface implemented by types that can be used by nodes in nested set 9 | type NodeInterface interface { 10 | Type() string // Returns type of node 11 | Name() string // Returns name of node 12 | 13 | Id() int64 // Returns id of node 14 | Level() int64 // Returns level of node 15 | Left() int64 // Returns left of node 16 | Right() int64 // Returns right of node 17 | 18 | SetId(int64) // Sets node id 19 | SetName(string) // Sets node name 20 | SetLevel(int64) // Sets node level 21 | SetLeft(int64) // Sets node left 22 | SetRight(int64) // Sets node right 23 | } 24 | 25 | // Node represents generic node type with NodeInterface implementation 26 | type Node struct { 27 | NodeId int64 `json:"id"` 28 | NodeName string `json:"node_name"` 29 | NodeLevel int64 `json:"level"` 30 | NodeLeft int64 `json:"left"` 31 | NodeRight int64 `json:"right"` 32 | } 33 | 34 | // NewNode returns a new Node instance 35 | func NewNode() *Node { 36 | return &Node{} 37 | } 38 | 39 | // Type implements NodeInterface.Type() and returns "generic" type 40 | func (n Node) Type() string { 41 | return "generic" 42 | } 43 | 44 | func (n Node) Name() string { 45 | return n.NodeName 46 | } 47 | 48 | func (n Node) Id() int64 { 49 | return n.NodeId 50 | } 51 | 52 | func (n Node) Level() int64 { 53 | 54 | return n.NodeLevel 55 | } 56 | 57 | func (n Node) Left() int64 { 58 | return n.NodeLeft 59 | } 60 | 61 | func (n Node) Right() int64 { 62 | return n.NodeRight 63 | } 64 | 65 | func (n *Node) SetId(id int64) { 66 | n.NodeId = id 67 | } 68 | 69 | func (n *Node) SetName(name string) { 70 | n.NodeName = name 71 | } 72 | 73 | func (n *Node) SetLevel(level int64) { 74 | n.NodeLevel = level 75 | } 76 | 77 | func (n *Node) SetLeft(left int64) { 78 | n.NodeLeft = left 79 | } 80 | 81 | func (n *Node) SetRight(right int64) { 82 | n.NodeRight = right 83 | } 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nestedset 2 | Package for manage nested sets in golang projects. 3 | 4 | ### Install 5 | 6 | ``` 7 | go get github.com/juggleru/nestedset 8 | ``` 9 | 10 | ### Usage 11 | 12 | To manage in nested set your data types add to your type `*Node` and init it. 13 | ```go 14 | package main 15 | 16 | import ( 17 | "github.com/juggleru/nestedset" 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type MySomeType struct { 23 | *nestedset.Node // add it to your any type 24 | 25 | // type vars 26 | MyId string 27 | MyName string 28 | } 29 | 30 | // Init it in instance creation 31 | func NewMySomeType() *MySomeType { 32 | return &MySomeType{ 33 | Node: nestedset.NewNode(), 34 | } 35 | } 36 | 37 | // You can redefine NodeInterface functions 38 | 39 | // Return your type 40 | func (t *MySomeType) Type() string { 41 | return "mysometype" 42 | } 43 | 44 | // Return your inner id 45 | func (t *MySomeType) Id() string { 46 | return t.MyId 47 | } 48 | 49 | // Return your inner name 50 | func (t *MySomeType) Name() string { 51 | return t.MyName 52 | } 53 | 54 | // Set your inner id or generate it 55 | func (t *MySomeType) SetId(id int) { 56 | t.MyId = id // or t.MyId = getSomeNewId() 57 | } 58 | 59 | // Set your inner name 60 | func (t *MySomeType) SetName(name string) { 61 | t.MyName = name 62 | } 63 | 64 | func main() { 65 | 66 | ns := nestedset.NewNestedSet() 67 | 68 | // create 3 new nodes 69 | node1 := NewMySomeType() 70 | node1.MyName = "Node 1" 71 | node2 := NewMySomeType() 72 | node2.MyName = "Node 2" 73 | node3 := NewMySomeType() 74 | node3.MyName = "Node 3" 75 | 76 | ns.Add(node1, nil) // add node to root 77 | ns.Add(node2, nil) // add node to root 78 | ns.Add(node3, node1) // add node to node1 79 | 80 | ns.Move(node3, node2) // move node3 from node1 to node2 81 | 82 | branch := ns.Branch(nil) // get full tree 83 | 84 | // print tree with indents 85 | for _, n := range branch { 86 | fmt.Print(strings.Repeat("..", n.Level())) 87 | fmt.Printf("%s lvl:%d, left:%d, right:%d\n", n.Name(), n.Level(), n.Left(), n.Right()) 88 | } 89 | } 90 | ``` 91 | ### Documentation 92 | 93 | https://godoc.org/github.com/juggleru/nestedset 94 | 95 | ### TODO 96 | 97 | Add implementation moving node up/down in same branch. 98 | 99 | ### Support 100 | 101 | Ether: 0x33c9d1A034DA2a19CAD113cBd8ebE4Ba0a835e39 102 | 103 | Buy Me A Coffee 104 | -------------------------------------------------------------------------------- /ns_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ara Israelyan. All rights reserved. 2 | // Use of this source code is governed by a MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | 6 | package nestedset 7 | 8 | import ( 9 | "fmt" 10 | "testing" 11 | ) 12 | 13 | var ( 14 | ns *NestedSet 15 | nodes []NodeInterface 16 | ) 17 | 18 | func createTestNestedSet(t *testing.T) { 19 | 20 | ns = NewNestedSet() 21 | 22 | nodes = make([]NodeInterface, 0) 23 | 24 | nodes = append(nodes, ns.rootNode) 25 | 26 | for i := 1; i <= 6; i++ { 27 | n := NewNode() 28 | n.NodeName = fmt.Sprintf("node %d", i) 29 | nodes = append(nodes, n) 30 | } 31 | 32 | err := ns.Add(nodes[1], nil) 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | err = ns.Add(nodes[2], nodes[1]) 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | err = ns.Add(nodes[3], nodes[0]) 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | err = ns.Add(nodes[4], nodes[3]) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | err = ns.Add(nodes[5], nodes[1]) 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | err = ns.Add(nodes[6], nodes[4]) 53 | if err != nil { 54 | t.Fatal(err) 55 | } 56 | 57 | } 58 | 59 | func checkNode(t *testing.T, node NodeInterface, level, left, right int64) { 60 | if node.Level() != level { 61 | t.Errorf("Invalid level for node '%s', expected %d, get %d", node.Name(), right, node.Level()) 62 | } 63 | if node.Left() != left { 64 | t.Errorf("Invalid left for node '%s', expected %d, get %d", node.Name(), left, node.Left()) 65 | } 66 | if node.Right() != right { 67 | t.Errorf("Invalid right for node '%s', expected %d, get %d", node.Name(), right, node.Right()) 68 | } 69 | } 70 | 71 | func TestNestedSet_Add(t *testing.T) { 72 | 73 | createTestNestedSet(t) 74 | 75 | checkNode(t, nodes[0], 0, 0, 13) 76 | checkNode(t, nodes[1], 1, 1, 6) 77 | checkNode(t, nodes[2], 2, 2, 3) 78 | checkNode(t, nodes[3], 1, 7, 12) 79 | checkNode(t, nodes[4], 2, 8, 11) 80 | checkNode(t, nodes[5], 2, 4, 5) 81 | checkNode(t, nodes[6], 3, 9, 10) 82 | 83 | } 84 | 85 | func TestNestedSet_Delete(t *testing.T) { 86 | 87 | createTestNestedSet(t) 88 | 89 | err := ns.Delete(nodes[1]) 90 | if err != nil { 91 | t.Fatal(err) 92 | } 93 | 94 | if ns.exists(nodes[1]) { 95 | t.Fatalf("Error deleting node '%s'", nodes[0].Name()) 96 | } 97 | if ns.exists(nodes[2]) { 98 | t.Fatalf("Error deleting node '%s'", nodes[2].Name()) 99 | } 100 | if ns.exists(nodes[5]) { 101 | t.Fatalf("Error deleting node '%s'", nodes[3].Name()) 102 | } 103 | 104 | checkNode(t, nodes[0], 0, 0, 7) 105 | checkNode(t, nodes[3], 1, 1, 6) 106 | checkNode(t, nodes[4], 2, 2, 5) 107 | checkNode(t, nodes[6], 3, 3, 4) 108 | 109 | } 110 | 111 | func TestNestedSet_Move(t *testing.T) { 112 | 113 | createTestNestedSet(t) 114 | 115 | ns.Move(nodes[4], nodes[2]) 116 | 117 | checkNode(t, nodes[0], 0, 0, 13) 118 | checkNode(t, nodes[1], 1, 1, 10) 119 | checkNode(t, nodes[2], 2, 2, 7) 120 | checkNode(t, nodes[3], 1, 11, 12) 121 | checkNode(t, nodes[4], 3, 3, 6) 122 | checkNode(t, nodes[5], 2, 8, 9) 123 | checkNode(t, nodes[6], 4, 4, 5) 124 | 125 | } 126 | 127 | func TestNestedSet_Branch(t *testing.T) { 128 | 129 | branch := ns.Branch(nodes[1]) 130 | if branch == nil { 131 | t.Error("Returned nil branch for node 1") 132 | return 133 | } 134 | printBranch(branch) 135 | 136 | } 137 | 138 | func printBranch(branch []NodeInterface) { 139 | 140 | for _, n := range branch { 141 | var i int64 142 | for i = 0; i < n.Level(); i++ { 143 | fmt.Print("..") 144 | } 145 | fmt.Printf("%s lvl:%d, left:%d, right:%d\n", n.Name(), n.Level(), n.Left(), n.Right()) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /ns.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ara Israelyan. All rights reserved. 2 | // Use of this source code is governed by a MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | 6 | /* 7 | Package nestedset provides types and functions for manage nested sets. 8 | 9 | Usage: 10 | 11 | package main 12 | 13 | import ( 14 | "github.com/juggleru/nestedset" 15 | "fmt" 16 | "strings" 17 | ) 18 | 19 | type MySomeType struct { 20 | *nestedset.Node // add it to your any type 21 | 22 | // type vars 23 | MyId string 24 | MyName string 25 | } 26 | 27 | // Init it in instance creation 28 | func NewMySomeType() *MySomeType { 29 | return &MySomeType{ 30 | Node: nestedset.NewNode(), 31 | } 32 | } 33 | 34 | // You can redefine NodeInterface functions 35 | 36 | // Return your type 37 | func (t *MySomeType) Type() string { 38 | return "mysometype" 39 | } 40 | 41 | // Return your inner id 42 | func (t *MySomeType) Id() string { 43 | return t.MyId 44 | } 45 | 46 | // Return your inner name 47 | func (t *MySomeType) Name() string { 48 | return t.MyName 49 | } 50 | 51 | // Set your inner id or generate it 52 | func (t *MySomeType) SetId(id int) { 53 | t.MyId = id // or t.MyId = getSomeNewId() 54 | } 55 | 56 | // Set your inner name 57 | func (t *MySomeType) SetName(name string) { 58 | t.MyName = name 59 | } 60 | 61 | func main() { ns := nestedset.NewNestedSet() 62 | 63 | // create 3 new nodes 64 | node1 := NewMySomeType() 65 | node1.MyName = "Node 1" 66 | node2 := NewMySomeType() 67 | node2.MyName = "Node 2" 68 | node3 := NewMySomeType() 69 | node3.MyName = "Node 3" 70 | 71 | ns.Add(node1, nil) // add node to root 72 | ns.Add(node2, nil) // add node to root 73 | ns.Add(node3, node1) // add node to node1 74 | 75 | ns.Move(node3, node2) // move node3 from node1 to node2 76 | 77 | branch := ns.Branch(nil) // get full tree 78 | 79 | // print tree with indents 80 | for _, n := range branch { 81 | fmt.Print(strings.Repeat("..", n.Level())) 82 | fmt.Printf("%s lvl:%d, left:%d, right:%d\n", n.Name(), n.Level(), n.Left(), n.Right()) 83 | } 84 | } 85 | */ 86 | package nestedset 87 | 88 | import ( 89 | "encoding/json" 90 | "errors" 91 | "sort" 92 | "sync" 93 | ) 94 | 95 | // SortedNodes represent nodes array sorted by left value. 96 | type SortedNodes []NodeInterface 97 | 98 | func (sn SortedNodes) Len() int { return len(sn) } 99 | func (sn SortedNodes) Swap(i, j int) { sn[i], sn[j] = sn[j], sn[i] } 100 | func (sn SortedNodes) Less(i, j int) bool { return sn[i].Left() < sn[j].Left() } 101 | 102 | // NestedSet represents a nested set management type. 103 | type NestedSet struct { 104 | nodes []NodeInterface 105 | rootNode NodeInterface 106 | maxId int64 107 | mutex sync.Mutex 108 | } 109 | 110 | // NewNestedSet creates and returns a new instance of NestedSet with root node. 111 | func NewNestedSet() *NestedSet { 112 | 113 | s := NestedSet{ 114 | nodes: make([]NodeInterface, 0), 115 | rootNode: NewNode(), 116 | } 117 | 118 | s.rootNode.SetRight(1) 119 | s.rootNode.SetName("Root node") 120 | s.nodes = append(s.nodes, s.rootNode) 121 | 122 | return &s 123 | } 124 | 125 | // Overrides json.Marshaller.MarshalJSON(). 126 | func (s NestedSet) MarshalJSON() ([]byte, error) { 127 | return json.MarshalIndent(s.nodes, "", " ") 128 | } 129 | 130 | // Adds new node to nested set. If `parent` nil, add node to root node. 131 | func (s *NestedSet) Add(newNode, parent NodeInterface) error { 132 | 133 | s.mutex.Lock() 134 | defer s.mutex.Unlock() 135 | 136 | if parent != nil { 137 | if !s.exists(parent) { 138 | return errors.New("Parent node not found in structure") 139 | } 140 | 141 | } else { 142 | parent = s.rootNode 143 | } 144 | 145 | level := parent.Level() + 1 146 | right := parent.Right() 147 | 148 | newNode.SetLevel(level) 149 | s.maxId++ 150 | newNode.SetId(s.maxId) 151 | newNode.SetLeft(right) 152 | newNode.SetRight(right + 1) 153 | 154 | for _, n := range s.nodes { 155 | 156 | if n.Right() >= right { 157 | n.SetRight(n.Right() + 2) 158 | if n.Left() > right { 159 | n.SetLeft(n.Left() + 2) 160 | } 161 | } 162 | } 163 | 164 | s.nodes = append(s.nodes, newNode) 165 | 166 | return nil 167 | } 168 | 169 | // Deletes node from nested set. 170 | func (s *NestedSet) Delete(node NodeInterface) error { 171 | 172 | s.mutex.Lock() 173 | defer s.mutex.Unlock() 174 | 175 | if node == nil || node == s.rootNode { 176 | return errors.New("Can't delete root node") 177 | } 178 | 179 | if !s.exists(node) { 180 | return errors.New("Node not found in structure") 181 | } 182 | 183 | newNodes := make([]NodeInterface, 0) 184 | 185 | for _, n := range s.nodes { 186 | 187 | if n.Left() < node.Left() || n.Right() > node.Right() { 188 | 189 | if n.Right() > node.Right() { 190 | n.SetRight(n.Right() - (node.Right() - node.Left() + 1)) 191 | } 192 | 193 | if n.Left() > node.Left() { 194 | n.SetLeft(n.Left() - (node.Right() - node.Left() + 1)) 195 | } 196 | 197 | newNodes = append(newNodes, n) 198 | 199 | } 200 | } 201 | 202 | s.nodes = newNodes 203 | 204 | return nil 205 | } 206 | 207 | // Moves node and its branch to another parent node. 208 | func (s *NestedSet) Move(node, parent NodeInterface) error { 209 | 210 | s.mutex.Lock() 211 | defer s.mutex.Unlock() 212 | 213 | if node.Level() == 0 { 214 | return errors.New("Can't move root node") 215 | } 216 | 217 | if parent == nil { 218 | parent = s.rootNode 219 | } 220 | 221 | if parent.Left() >= node.Left() && parent.Right() <= node.Right() { 222 | return errors.New("Can't move branch to node within itself") 223 | } 224 | 225 | currentParent := s.parent(node) 226 | if currentParent == nil { 227 | return errors.New("Parent node not found, the structure broken") 228 | } 229 | if currentParent == parent { 230 | return errors.New("Moving in same branch not implemented") 231 | } 232 | 233 | level := node.Level() 234 | left := node.Left() 235 | right := node.Right() 236 | levelUp := parent.Level() 237 | rightNear := parent.Right() - 1 238 | skewLevel := levelUp - level + 1 239 | skewTree := right - left + 1 240 | skewEdit := rightNear - left + 1 241 | isUp := rightNear < right 242 | 243 | toUpdate := s.branch(node) 244 | 245 | if isUp { 246 | for _, n := range s.nodes { 247 | 248 | if n.Right() < left && n.Right() > rightNear { 249 | n.SetRight(n.Right() + skewTree) 250 | } 251 | if n.Left() < left && n.Left() > rightNear { 252 | n.SetLeft(n.Left() + skewTree) 253 | } 254 | } 255 | } else { 256 | skewEdit = rightNear - left + 1 - skewTree 257 | 258 | for _, n := range s.nodes { 259 | 260 | if n.Right() > right && n.Right() <= rightNear { 261 | n.SetRight(n.Right() - skewTree) 262 | } 263 | 264 | if n.Left() > right && n.Left() <= rightNear { 265 | n.SetLeft(n.Left() - skewTree) 266 | } 267 | } 268 | } 269 | 270 | for _, n := range toUpdate { 271 | n.SetLeft(n.Left() + skewEdit) 272 | n.SetRight(n.Right() + skewEdit) 273 | n.SetLevel(n.Level() + skewLevel) 274 | } 275 | 276 | return nil 277 | } 278 | 279 | // Returns parent for node. 280 | func (s *NestedSet) Parent(node NodeInterface) NodeInterface { 281 | 282 | s.mutex.Lock() 283 | defer s.mutex.Unlock() 284 | 285 | return s.parent(node) 286 | } 287 | 288 | func (s *NestedSet) parent(node NodeInterface) NodeInterface { 289 | 290 | for _, n := range s.nodes { 291 | if n.Left() <= node.Left() && n.Right() >= node.Right() && n.Level() == (node.Level()-1) { 292 | return n 293 | } 294 | } 295 | 296 | return nil 297 | } 298 | 299 | // Finds and returns node by id. 300 | func (s *NestedSet) FindById(id int64) NodeInterface { 301 | 302 | s.mutex.Lock() 303 | defer s.mutex.Unlock() 304 | 305 | for _, n := range s.nodes { 306 | if n.Id() == id { 307 | return n 308 | } 309 | } 310 | 311 | return nil 312 | } 313 | 314 | // Returns branch for node, including itself. 315 | func (s *NestedSet) Branch(node NodeInterface) []NodeInterface { 316 | 317 | s.mutex.Lock() 318 | defer s.mutex.Unlock() 319 | 320 | return s.branch(node) 321 | } 322 | 323 | func (s *NestedSet) branch(node NodeInterface) []NodeInterface { 324 | 325 | sort.Sort(SortedNodes(s.nodes)) 326 | 327 | var res []NodeInterface 328 | 329 | // Return full tree 330 | if node == nil { 331 | res = make([]NodeInterface, len(s.nodes)) 332 | copy(res, s.nodes) 333 | return res 334 | } 335 | 336 | if !s.exists(node) { 337 | return nil 338 | } 339 | 340 | res = make([]NodeInterface, 0) 341 | 342 | for _, n := range s.nodes { 343 | if n.Left() >= node.Left() && n.Right() <= node.Right() { 344 | res = append(res, n) 345 | } 346 | } 347 | 348 | return res 349 | } 350 | 351 | func (s *NestedSet) exists(node NodeInterface) bool { 352 | 353 | bFound := false 354 | for _, n := range s.nodes { 355 | if n == node { 356 | bFound = true 357 | break 358 | } 359 | } 360 | 361 | return bFound 362 | } 363 | --------------------------------------------------------------------------------