blob: 77e0cc7f7d2fd880fd5e0550f18da919fce71717 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040016package model
17
18import (
19 "fmt"
20 "github.com/golang/protobuf/proto"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040021 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040022 "reflect"
23 "strings"
24)
25
26const (
27 NONE string = "none"
28)
29
30type Node struct {
31 root *Root
32 Type interface{}
33 Branches map[string]*Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -040034 Tags map[string]Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040035 Proxy *Proxy
36 EventBus *EventBus
37 AutoPrune bool
38}
39
Stephane Barbarie694e2b92018-09-07 12:17:36 -040040type ChangeTuple struct {
41 Type CallbackType
42 Data interface{}
43}
44
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040045func NewNode(root *Root, initialData interface{}, autoPrune bool, txid string) *Node {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040046 n := &Node{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040047
Stephane Barbarieec0919b2018-09-05 14:14:29 -040048 n.root = root
49 n.Branches = make(map[string]*Branch)
50 n.Tags = make(map[string]Revision)
51 n.Proxy = nil
52 n.EventBus = nil
53 n.AutoPrune = autoPrune
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040054
55 if IsProtoMessage(initialData) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040056 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040057 dataCopy := proto.Clone(initialData.(proto.Message))
Stephane Barbarieec0919b2018-09-05 14:14:29 -040058 n.initialize(dataCopy, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040059 } else if reflect.ValueOf(initialData).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040060 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040061 } else {
62 // not implemented error
63 fmt.Errorf("cannot process initial data - %+v", initialData)
64 }
65
Stephane Barbarieec0919b2018-09-05 14:14:29 -040066 return n
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040067}
68
Stephane Barbarieec0919b2018-09-05 14:14:29 -040069func (n *Node) MakeNode(data interface{}, txid string) *Node {
70 return NewNode(n.root, data, true, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040071}
72
Stephane Barbarieec0919b2018-09-05 14:14:29 -040073func (n *Node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
74 return n.root.MakeRevision(branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040075}
76
Stephane Barbarie694e2b92018-09-07 12:17:36 -040077func (n *Node) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040078 if _, ok := branch.Revisions[revision.GetHash()]; !ok {
79 branch.Revisions[revision.GetHash()] = revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040080 }
81
Stephane Barbarieec0919b2018-09-05 14:14:29 -040082 if branch.Latest == nil || revision.GetHash() != branch.Latest.GetHash() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040083 branch.Latest = revision
84 }
85
86 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040087 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -040088 for _, change := range changeAnnouncement {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040089 // TODO: Invoke callback
Stephane Barbarie694e2b92018-09-07 12:17:36 -040090 fmt.Printf("invoking callback - changeType: %+v, data:%+v\n", change.Type, change.Data)
91 n.root.addCallback(n.Proxy.InvokeCallbacks, change.Type, change.Data, true)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092 }
93 }
94
Stephane Barbarie694e2b92018-09-07 12:17:36 -040095 for _, change := range changeAnnouncement {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040096 // TODO: send notifications
Stephane Barbarie694e2b92018-09-07 12:17:36 -040097 fmt.Printf("sending notification - changeType: %+v, data:%+v\n", change.Type, change.Data)
98 n.root.addNotificationCallback(n.makeEventBus().Advertise, change.Type, change.Data, revision.GetHash())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040099 }
100 }
101}
102
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400103func (n *Node) Latest() Revision {
104 if branch, exists := n.Branches[NONE]; exists {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400105 return branch.Latest
106 }
107 return nil
108}
109
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400110func (n *Node) GetHash(hash string) Revision {
111 return n.Branches[NONE].Revisions[hash]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400112}
113
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400114func (n *Node) initialize(data interface{}, txid string) {
115 var children map[string][]Revision
116 children = make(map[string][]Revision)
117 for fieldName, field := range ChildrenFields(n.Type) {
118 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400119
120 if fieldValue.IsValid() {
121 if field.IsContainer {
122 if field.Key != "" {
123 var keysSeen []string
124
125 for i := 0; i < fieldValue.Len(); i++ {
126 v := fieldValue.Index(i)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400127 rev := n.MakeNode(v.Interface(), txid).Latest()
128 _, key := GetAttributeValue(v.Interface(), field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400129 for _, k := range keysSeen {
130 if k == key.String() {
131 fmt.Errorf("duplicate key - %s", k)
132 }
133 }
134 children[fieldName] = append(children[fieldName], rev)
135 keysSeen = append(keysSeen, key.String())
136 }
137
138 } else {
139 for i := 0; i < fieldValue.Len(); i++ {
140 v := fieldValue.Index(i)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400141 children[fieldName] = append(children[fieldName], n.MakeNode(v.Interface(), txid).Latest())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400142 }
143 }
144 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400145 children[fieldName] = append(children[fieldName], n.MakeNode(fieldValue.Interface(), txid).Latest())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400146 }
147 } else {
148 fmt.Errorf("field is invalid - %+v", fieldValue)
149 }
150 }
151 // FIXME: ClearField??? No such method in go protos. Reset?
152 //data.ClearField(field_name)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400153 branch := NewBranch(n, "", nil, n.AutoPrune)
154 rev := n.MakeRevision(branch, data, children)
155 n.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400156
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400157 if txid == "" {
158 n.Branches[NONE] = branch
159 } else {
160 n.Branches[txid] = branch
161 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400162}
163
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400164//
165// Get operation
166//
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400167func (n *Node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400168 if deep {
169 depth = -1
170 }
171
172 for strings.HasPrefix(path, "/") {
173 path = path[1:]
174 }
175
176 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400177 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400178
179 // FIXME: should empty txid be cleaned up?
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400180 if branch = n.Branches[txid]; txid == "" || branch == nil {
181 branch = n.Branches[NONE]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400182 }
183
184 if hash != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400185 rev = branch.Revisions[hash]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400186 } else {
187 rev = branch.Latest
188 }
189
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400190 return n.get(rev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400191}
192
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400193func (n *Node) findRevByKey(revs []Revision, keyName string, value string) (int, Revision) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400194 for i, rev := range revs {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400195 dataValue := reflect.ValueOf(rev.GetData())
196 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400197
198 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
199
200 if fieldValue.Interface().(string) == value {
201 return i, rev
202 }
203 }
204
205 fmt.Errorf("key %s=%s not found", keyName, value)
206
207 return -1, nil
208}
209
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400210func (n *Node) get(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400211 if path == "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400212 return n.doGet(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400213 }
214
215 partition := strings.SplitN(path, "/", 2)
216 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400217
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400218 if len(partition) < 2 {
219 path = ""
220 } else {
221 path = partition[1]
222 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400223
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400224 names := ChildrenFields(n.Type)
225 field := names[name]
226
227 if field != nil && field.IsContainer {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400228 if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400229 children := rev.GetChildren()[name]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400230 if path != "" {
231 partition = strings.SplitN(path, "/", 2)
232 key := partition[0]
233 path = ""
234 key = field.KeyFromStr(key).(string)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400235 if _, childRev := n.findRevByKey(children, field.Key, key); childRev == nil {
236 return nil
237 } else {
238 childNode := childRev.GetNode()
239 return childNode.get(childRev, path, depth)
240 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400241 } else {
242 var response []interface{}
243 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400244 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400245 value := childNode.doGet(childRev, depth)
246 response = append(response, value)
247 }
248 return response
249 }
250 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400251 var response []interface{}
252 if path != "" {
253 // TODO: raise error
254 return response
255 }
256 for _, childRev := range rev.GetChildren()[name] {
257 childNode := childRev.GetNode()
258 value := childNode.doGet(childRev, depth)
259 response = append(response, value)
260 }
261 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400262 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400263 } else {
264 c1 := rev.GetChildren()[name]
265 childRev := c1[0]
266 childNode := childRev.GetNode()
267 return childNode.get(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400268 }
269 return nil
270}
271
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400272func (n *Node) doGet(rev Revision, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400273 msg := rev.Get(depth)
274
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400275 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400276 log.Debug("invoking proxy GET Callbacks")
277 msg = n.Proxy.InvokeCallbacks(GET, msg, false)
278
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400279 }
280 return msg
281}
282
283//
284// Update operation
285//
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400286func (n *Node) Update(path string, data interface{}, strict bool, txid string, makeBranch t_makeBranch) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400287 // FIXME: is this required ... a bit overkill to take out a "/"
288 for strings.HasPrefix(path, "/") {
289 path = path[1:]
290 }
291
292 var branch *Branch
293 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400294 if txid == "" {
295 branch = n.Branches[NONE]
296 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400297 branch = makeBranch(n)
298 }
299
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400300 log.Debugf("Branch data : %+v, Passed data: %+v", branch.Latest.GetData(), data)
301
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400302 if path == "" {
303 return n.doUpdate(branch, data, strict)
304 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400305
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400306 // TODO missing some code here...
307 rev := branch.Latest
308
309 partition := strings.SplitN(path, "/", 2)
310 name := partition[0]
311
312 if len(partition) < 2 {
313 path = ""
314 } else {
315 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400316 }
317
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400318 field := ChildrenFields(n.Type)[name]
319 var children []Revision
320
321 if field.IsContainer {
322 if path == "" {
323 fmt.Errorf("cannot update a list\n")
324 } else if field.Key != "" {
325 partition := strings.SplitN(path, "/", 2)
326 key := partition[0]
327 if len(partition) < 2 {
328 path = ""
329 } else {
330 path = partition[1]
331 }
332 key = field.KeyFromStr(key).(string)
333 // TODO. Est-ce que le copy ne fonctionne pas? dois-je plutôt faire un clone de chaque item?
334 for _, v := range rev.GetChildren()[name] {
335 revCopy := reflect.ValueOf(v).Interface().(Revision)
336 children = append(children, revCopy)
337 }
338 idx, childRev := n.findRevByKey(children, field.Key, key)
339 childNode := childRev.GetNode()
340 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
341 if newChildRev.GetHash() == childRev.GetHash() {
342 if newChildRev != childRev {
343 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
344 newChildRev.ClearHash()
345 }
346 return branch.Latest
347 }
348 if _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0); newKey.Interface().(string) != key {
349 fmt.Errorf("cannot change key field\n")
350 }
351 children[idx] = newChildRev
352 rev = rev.UpdateChildren(name, children, branch)
353 n.root.MakeLatest(branch, rev, nil)
354 return rev
355 } else {
356 fmt.Errorf("cannot index into container with no keys\n")
357 }
358 } else {
359 childRev := rev.GetChildren()[name][0]
360 childNode := childRev.GetNode()
361 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
362 rev = rev.UpdateChildren(name, []Revision{newChildRev}, branch)
363 n.root.MakeLatest(branch, rev, nil)
364 return rev
365 }
366 return nil
367}
368
369func (n *Node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
370 log.Debugf("Comparing types - expected: %+v, actual: %+v", reflect.ValueOf(n.Type).Type(), reflect.TypeOf(data))
371
372 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
373 // TODO raise error
374 fmt.Errorf("data does not match type: %+v", n.Type)
375 return nil
376 }
377
378 // TODO: validate that this actually works
379 //if n.hasChildren(data) {
380 // return nil
381 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400382
383 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400384 log.Debug("invoking proxy PRE_UPDATE Callbacks")
385 n.Proxy.InvokeCallbacks(PRE_UPDATE, data, false)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400386 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400387 if !reflect.DeepEqual(branch.Latest.GetData(), data) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400388 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400389 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400390 fmt.Println("checking access violations")
391 }
392 rev := branch.Latest.UpdateData(data, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400393 n.root.MakeLatest(branch, rev, nil) // TODO -> changeAnnouncement needs to be a tuple (CallbackType.
394 // POST_UPDATE, rev.data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400395 return rev
396 } else {
397 return branch.Latest
398 }
399}
400
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400401//
402// Add operation
403//
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400404func (n *Node) Add(path string, data interface{}, txid string, makeBranch t_makeBranch) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400405 for strings.HasPrefix(path, "/") {
406 path = path[1:]
407 }
408 if path == "" {
409 // TODO raise error
410 fmt.Errorf("cannot add for non-container mode\n")
411 }
412
413 var branch *Branch
414 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400415 if txid == "" {
416 branch = n.Branches[NONE]
417 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400418 branch = makeBranch(n)
419 }
420
421 rev := branch.Latest
422
423 partition := strings.SplitN(path, "/", 2)
424 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400425
426 if len(partition) < 2 {
427 path = ""
428 } else {
429 path = partition[1]
430 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400431
432 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400433 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400434
435 if field.IsContainer {
436 if path == "" {
437 if field.Key != "" {
438 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400439 log.Debug("invoking proxy PRE_ADD Callbacks")
440 n.Proxy.InvokeCallbacks(PRE_ADD, data, false)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400441 }
442
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400443 for _, v := range rev.GetChildren()[name] {
444 revCopy := reflect.ValueOf(v).Interface().(Revision)
445 children = append(children, revCopy)
446 }
447 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400448 if _, rev := n.findRevByKey(children, field.Key, key.String()); rev != nil {
449 // TODO raise error
450 fmt.Errorf("duplicate key found: %s", key.String())
451 }
452
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400453 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400454 children = append(children, childRev)
455 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400456 n.root.MakeLatest(branch, rev, nil) // TODO -> changeAnnouncement needs to be a tuple (CallbackType.
457 // POST_ADD, rev.data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400458 return rev
459 } else {
460 fmt.Errorf("cannot add to non-keyed container\n")
461 }
462 } else if field.Key != "" {
463 partition := strings.SplitN(path, "/", 2)
464 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400465 if len(partition) < 2 {
466 path = ""
467 } else {
468 path = partition[1]
469 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400470 key = field.KeyFromStr(key).(string)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400471 copy(children, rev.GetChildren()[name])
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400472 idx, childRev := n.findRevByKey(children, field.Key, key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400473 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400474 newChildRev := childNode.Add(path, data, txid, makeBranch)
475 children[idx] = newChildRev
476 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400477 n.root.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400478 return rev
479 } else {
480 fmt.Errorf("cannot add to non-keyed container\n")
481 }
482 } else {
483 fmt.Errorf("cannot add to non-container field\n")
484 }
485 return nil
486}
487
488//
489// Remove operation
490//
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400491func (n *Node) Remove(path string, txid string, makeBranch t_makeBranch) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400492 for strings.HasPrefix(path, "/") {
493 path = path[1:]
494 }
495 if path == "" {
496 // TODO raise error
497 fmt.Errorf("cannot remove for non-container mode\n")
498 }
499 var branch *Branch
500 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400501 if txid == "" {
502 branch = n.Branches[NONE]
503 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400504 branch = makeBranch(n)
505 }
506
507 rev := branch.Latest
508
509 partition := strings.SplitN(path, "/", 2)
510 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400511 if len(partition) < 2 {
512 path = ""
513 } else {
514 path = partition[1]
515 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400516
517 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400518 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400519 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400520
521 if field.IsContainer {
522 if path == "" {
523 fmt.Errorf("cannot remove without a key\n")
524 } else if field.Key != "" {
525 partition := strings.SplitN(path, "/", 2)
526 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400527 if len(partition) < 2 {
528 path = ""
529 } else {
530 path = partition[1]
531 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400532 key = field.KeyFromStr(key).(string)
533 if path != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400534 for _, v := range rev.GetChildren()[name] {
535 newV := reflect.ValueOf(v).Interface().(Revision)
536 children = append(children, newV)
537 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400538 idx, childRev := n.findRevByKey(children, field.Key, key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400539 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400540 newChildRev := childNode.Remove(path, txid, makeBranch)
541 children[idx] = newChildRev
542 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400543 n.root.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400544 return rev
545 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400546 for _, v := range rev.GetChildren()[name] {
547 newV := reflect.ValueOf(v).Interface().(Revision)
548 children = append(children, newV)
549 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400550 idx, childRev := n.findRevByKey(children, field.Key, key)
551 if n.Proxy != nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400552 data := childRev.GetData()
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400553 n.Proxy.InvokeCallbacks(PRE_REMOVE, data, false)
554 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400555 } else {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400556 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData()})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400557 }
558 children = append(children[:idx], children[idx+1:]...)
559 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400560 n.root.MakeLatest(branch, rev, postAnnouncement)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400561 return rev
562 }
563 } else {
564 fmt.Errorf("cannot add to non-keyed container\n")
565 }
566 } else {
567 fmt.Errorf("cannot add to non-container field\n")
568 }
569
570 return nil
571}
572
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400573// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
574
575type t_makeBranch func(*Node) *Branch
576
577func (n *Node) makeTxBranch(txid string) *Branch {
578 branchPoint := n.Branches[NONE].Latest
579 branch := NewBranch(n, txid, branchPoint, true)
580 n.Branches[txid] = branch
581 return branch
582}
583
584func (n *Node) deleteTxBranch(txid string) {
585 delete(n.Branches, txid)
586}
587
588func (n *Node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
589 f := func(rev Revision) Revision {
590 childBranch := rev.GetBranch()
591
592 if childBranch.Txid == txid {
593 rev = childBranch.Node.mergeTxBranch(txid, dryRun)
594 }
595
596 return rev
597 }
598 return f
599}
600
601func (n *Node) mergeTxBranch(txid string, dryRun bool) Revision {
602 srcBranch := n.Branches[txid]
603 dstBranch := n.Branches[NONE]
604
605 forkRev := srcBranch.Origin
606 srcRev := srcBranch.Latest
607 dstRev := dstBranch.Latest
608
609 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
610
611 if !dryRun {
612 n.root.MakeLatest(dstBranch, rev, changes)
613 delete(n.Branches, txid)
614 }
615
616 return rev
617}
618
619// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
620
621//func (n *Node) diff(hash1, hash2, txid string) {
622// branch := n.Branches[txid]
623// rev1 := branch.get(hash1)
624// rev2 := branch.get(hash2)
625//
626// if rev1.GetHash() == rev2.GetHash() {
627// // empty patch
628// } else {
629// // translate data to json and generate patch
630// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
631// patch.
632// }
633//}
634
635// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
636
637// TODO: is tag mgmt used in the python implementation? Need to validate
638
639// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
640
641func (n *Node) hasChildren(data interface{}) bool {
642 for fieldName, field := range ChildrenFields(n.Type) {
643 _, fieldValue := GetAttributeValue(data, fieldName, 0)
644
645 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
646 log.Error("cannot update external children")
647 return true
648 }
649 }
650
651 return false
652}
653
654// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
655
656func (n *Node) GetProxy(path string, exclusive bool) *Proxy {
657 return n.getProxy(path, n.root, path, exclusive)
658}
659func (n *Node) getProxy(path string, root *Root, fullPath string, exclusive bool) *Proxy {
660 for strings.HasPrefix(path, "/") {
661 path = path[1:]
662 }
663 if path == "" {
664 return n.makeProxy(n.root, path, exclusive)
665 }
666
667 rev := n.Branches[NONE].Latest
668 partition := strings.SplitN(path, "/", 2)
669 name := partition[0]
670 path = partition[1]
671
672 field := ChildrenFields(n.Type)[name]
673 if field.IsContainer {
674 if path == "" {
675 log.Error("cannot proxy a container field")
676 }
677 if field.Key != "" {
678 partition := strings.SplitN(path, "/", 2)
679 key := partition[0]
680 path = partition[1]
681 key = field.KeyFromStr(key).(string)
682 children := rev.GetChildren()[name]
683 _, childRev := n.findRevByKey(children, field.Key, key)
684 childNode := childRev.GetNode()
685 return childNode.getProxy(path, root, fullPath, exclusive)
686 }
687 log.Error("cannot index into container with no keys")
688 } else {
689 childRev := rev.GetChildren()[name][0]
690 childNode := childRev.GetNode()
691 return childNode.getProxy(path, root, fullPath, exclusive)
692 }
693
694 return nil
695}
696
697func (n *Node) makeProxy(root *Root, fullPath string, exclusive bool) *Proxy {
698 if n.Proxy == nil {
699 n.Proxy = NewProxy(root, n, fullPath, exclusive)
700 } else {
701 if n.Proxy.Exclusive {
702 log.Error("node is already owned exclusively")
703 }
704 }
705 return n.Proxy
706}
707
708func (n *Node) makeEventBus() *EventBus {
709 if n.EventBus == nil {
710 n.EventBus = NewEventBus()
711 }
712 return n.EventBus
713}
714
715// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Persistence Loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
716
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400717func (n *Node) LoadLatest(kvStore *Backend, hash string) {
718 branch := NewBranch(n, "", nil, n.AutoPrune)
719 pr := &PersistedRevision{}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400720 rev := pr.Load(branch, kvStore, n.Type, hash)
721 n.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400722 n.Branches[NONE] = branch
723}