blob: 75f69154e9c40e3c0012f0b80cfe222b59c8afa0 [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
Stephane Barbariee16186c2018-09-11 10:46:34 -040018// TODO: proper error handling
19// TODO: proper logging
20
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040021import (
22 "fmt"
23 "github.com/golang/protobuf/proto"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040024 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040025 "reflect"
26 "strings"
27)
28
29const (
30 NONE string = "none"
31)
32
Stephane Barbarie06c4a742018-10-01 11:09:32 -040033type Node interface {
34 MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple)
35
36 // CRUD functions
37 Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision
38 Get(path string, hash string, depth int, deep bool, txid string) interface{}
39 Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision
40 Remove(path string, txid string, makeBranch MakeBranchFunction) Revision
41
42 MakeBranch(txid string) *Branch
43 DeleteBranch(txid string)
44 MergeBranch(txid string, dryRun bool) (Revision, error)
45
46 MakeTxBranch() string
47 DeleteTxBranch(txid string)
48 FoldTxBranch(txid string)
49
50 GetProxy(path string, exclusive bool) *Proxy
51}
52
53type node struct {
54 root *root
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040055 Type interface{}
56 Branches map[string]*Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -040057 Tags map[string]Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040058 Proxy *Proxy
59 EventBus *EventBus
60 AutoPrune bool
61}
62
Stephane Barbarie694e2b92018-09-07 12:17:36 -040063type ChangeTuple struct {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040064 Type CallbackType
65 PreviousData interface{}
66 LatestData interface{}
Stephane Barbarie694e2b92018-09-07 12:17:36 -040067}
68
Stephane Barbarie06c4a742018-10-01 11:09:32 -040069func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
70 n := &node{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040071
Stephane Barbarieec0919b2018-09-05 14:14:29 -040072 n.root = root
73 n.Branches = make(map[string]*Branch)
74 n.Tags = make(map[string]Revision)
75 n.Proxy = nil
76 n.EventBus = nil
77 n.AutoPrune = autoPrune
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040078
79 if IsProtoMessage(initialData) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040080 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040081 dataCopy := proto.Clone(initialData.(proto.Message))
Stephane Barbarieec0919b2018-09-05 14:14:29 -040082 n.initialize(dataCopy, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040083 } else if reflect.ValueOf(initialData).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040084 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040085 } else {
86 // not implemented error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040087 log.Errorf("cannot process initial data - %+v", initialData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040088 }
89
Stephane Barbarieec0919b2018-09-05 14:14:29 -040090 return n
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040091}
92
Stephane Barbarie06c4a742018-10-01 11:09:32 -040093func (n *node) MakeNode(data interface{}, txid string) *node {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040094 return NewNode(n.root, data, true, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040095}
96
Stephane Barbarie06c4a742018-10-01 11:09:32 -040097func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040098 return n.root.MakeRevision(branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040099}
100
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400101func (n *node) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
102 n.makeLatest(branch, revision, changeAnnouncement)
103}
104func (n *node) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400105 if _, ok := branch.Revisions[revision.GetHash()]; !ok {
106 branch.Revisions[revision.GetHash()] = revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400107 }
108
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400109 if branch.Latest == nil || revision.GetHash() != branch.Latest.GetHash() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400110 branch.Latest = revision
111 }
112
113 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400114 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400115 for _, change := range changeAnnouncement {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400116 log.Debugf("invoking callback - changeType: %+v, previous:%+v, latest: %+v\n", change.Type,
117 change.PreviousData, change.LatestData)
118 n.root.AddCallback(n.Proxy.InvokeCallbacks, change.Type, change.PreviousData, change.LatestData, true)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400119 }
120 }
121
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400122 for _, change := range changeAnnouncement {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400123 log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v\n", change.Type,
124 change.PreviousData,
125 change.LatestData)
126 n.root.AddNotificationCallback(n.makeEventBus().Advertise, change.Type, change.PreviousData, change.LatestData, revision.GetHash())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400127 }
128 }
129}
130
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400131func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400132 var branch *Branch
133 var exists bool
134
135 if len(txid) > 0 && txid[0] != "" {
136 if branch, exists = n.Branches[txid[0]]; exists {
137 return branch.Latest
138 }
139 } else if branch, exists = n.Branches[NONE]; exists {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400140 return branch.Latest
141 }
142 return nil
143}
144
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400145func (n *node) GetHash(hash string) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400146 return n.Branches[NONE].Revisions[hash]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400147}
148
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400149func (n *node) initialize(data interface{}, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400150 var children map[string][]Revision
151 children = make(map[string][]Revision)
152 for fieldName, field := range ChildrenFields(n.Type) {
153 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400154
155 if fieldValue.IsValid() {
156 if field.IsContainer {
157 if field.Key != "" {
158 var keysSeen []string
159
160 for i := 0; i < fieldValue.Len(); i++ {
161 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400162
163 rev := n.MakeNode(v.Interface(), txid).Latest(txid)
164
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400165 _, key := GetAttributeValue(v.Interface(), field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400166 for _, k := range keysSeen {
167 if k == key.String() {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400168 log.Errorf("duplicate key - %s", k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400169 }
170 }
171 children[fieldName] = append(children[fieldName], rev)
172 keysSeen = append(keysSeen, key.String())
173 }
174
175 } else {
176 for i := 0; i < fieldValue.Len(); i++ {
177 v := fieldValue.Index(i)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400178 children[fieldName] = append(children[fieldName], n.MakeNode(v.Interface(), txid).Latest())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400179 }
180 }
181 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400182 children[fieldName] = append(children[fieldName], n.MakeNode(fieldValue.Interface(), txid).Latest())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400183 }
184 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400185 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400186 }
187 }
188 // FIXME: ClearField??? No such method in go protos. Reset?
189 //data.ClearField(field_name)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400190 branch := NewBranch(n, "", nil, n.AutoPrune)
191 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400192 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400193
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400194 if txid == "" {
195 n.Branches[NONE] = branch
196 } else {
197 n.Branches[txid] = branch
198 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400199}
200
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400201func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
202 for i, rev := range revs {
203 dataValue := reflect.ValueOf(rev.GetData())
204 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
205
206 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
207
208 log.Debugf("fieldValue: %+v, type: %+v, value: %+v", fieldValue.Interface(), fieldValue.Type(), value)
209 a := fmt.Sprintf("%s", fieldValue.Interface())
210 b := fmt.Sprintf("%s", value)
211 if a == b {
212 return i, rev
213 }
214 }
215
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400216 log.Errorf("key %s=%s not found", keyName, value)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400217
218 return -1, nil
219}
220
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400221//
222// Get operation
223//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400224func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400225 if deep {
226 depth = -1
227 }
228
229 for strings.HasPrefix(path, "/") {
230 path = path[1:]
231 }
232
233 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400234 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400235
236 // FIXME: should empty txid be cleaned up?
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400237 if branch = n.Branches[txid]; txid == "" || branch == nil {
238 branch = n.Branches[NONE]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400239 }
240
241 if hash != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400242 rev = branch.Revisions[hash]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400243 } else {
244 rev = branch.Latest
245 }
246
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400247 return n.getPath(rev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400248}
249
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400250func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400251 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400252 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400253 }
254
255 partition := strings.SplitN(path, "/", 2)
256 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400257
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400258 if len(partition) < 2 {
259 path = ""
260 } else {
261 path = partition[1]
262 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400263
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400264 names := ChildrenFields(n.Type)
265 field := names[name]
266
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400267 if field.IsContainer {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400268 if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400269 children := rev.GetChildren()[name]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400270 if path != "" {
271 partition = strings.SplitN(path, "/", 2)
272 key := partition[0]
273 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400274 keyValue := field.KeyFromStr(key)
275 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400276 return nil
277 } else {
278 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400279 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400280 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400281 } else {
282 var response []interface{}
283 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400284 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400285 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400286 response = append(response, value)
287 }
288 return response
289 }
290 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400291 var response []interface{}
292 if path != "" {
293 // TODO: raise error
294 return response
295 }
296 for _, childRev := range rev.GetChildren()[name] {
297 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400298 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400299 response = append(response, value)
300 }
301 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400302 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400303 } else {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400304 childRev := rev.GetChildren()[name][0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400305 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400306 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400307 }
308 return nil
309}
310
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400311func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400312 msg := rev.Get(depth)
313
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400314 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400315 log.Debug("invoking proxy GET Callbacks")
316 msg = n.Proxy.InvokeCallbacks(GET, msg, false)
317
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400318 }
319 return msg
320}
321
322//
323// Update operation
324//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400325func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400326 // FIXME: is this required ... a bit overkill to take out a "/"
327 for strings.HasPrefix(path, "/") {
328 path = path[1:]
329 }
330
331 var branch *Branch
332 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400333 if txid == "" {
334 branch = n.Branches[NONE]
335 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400336 branch = makeBranch(n)
337 }
338
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400339 log.Debugf("Branch data : %+v, Passed data: %+v", branch.Latest.GetData(), data)
340
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400341 if path == "" {
342 return n.doUpdate(branch, data, strict)
343 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400344
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400345 // TODO missing some code here...
346 rev := branch.Latest
347
348 partition := strings.SplitN(path, "/", 2)
349 name := partition[0]
350
351 if len(partition) < 2 {
352 path = ""
353 } else {
354 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400355 }
356
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400357 field := ChildrenFields(n.Type)[name]
358 var children []Revision
359
360 if field.IsContainer {
361 if path == "" {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400362 log.Errorf("cannot update a list\n")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400363 } else if field.Key != "" {
364 partition := strings.SplitN(path, "/", 2)
365 key := partition[0]
366 if len(partition) < 2 {
367 path = ""
368 } else {
369 path = partition[1]
370 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400371 keyValue := field.KeyFromStr(key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400372 // TODO. Est-ce que le copy ne fonctionne pas? dois-je plutôt faire un clone de chaque item?
373 for _, v := range rev.GetChildren()[name] {
374 revCopy := reflect.ValueOf(v).Interface().(Revision)
375 children = append(children, revCopy)
376 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400377 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400378 childNode := childRev.GetNode()
379 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
380 if newChildRev.GetHash() == childRev.GetHash() {
381 if newChildRev != childRev {
382 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
383 newChildRev.ClearHash()
384 }
385 return branch.Latest
386 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400387
388 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
389 log.Debugf("newKey is %s", newKey.Interface())
390 _newKeyType := fmt.Sprintf("%s", newKey)
391 _keyValueType := fmt.Sprintf("%s", keyValue)
392 if _newKeyType != _keyValueType {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400393 log.Errorf("cannot change key field\n")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400394 }
395 children[idx] = newChildRev
396 rev = rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400397 branch.Latest.Drop(txid, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400398 n.root.MakeLatest(branch, rev, nil)
399 return rev
400 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400401 log.Errorf("cannot index into container with no keys\n")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400402 }
403 } else {
404 childRev := rev.GetChildren()[name][0]
405 childNode := childRev.GetNode()
406 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
407 rev = rev.UpdateChildren(name, []Revision{newChildRev}, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400408 branch.Latest.Drop(txid, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400409 n.root.MakeLatest(branch, rev, nil)
410 return rev
411 }
412 return nil
413}
414
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400415func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400416 log.Debugf("Comparing types - expected: %+v, actual: %+v", reflect.ValueOf(n.Type).Type(), reflect.TypeOf(data))
417
418 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
419 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400420 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400421 return nil
422 }
423
424 // TODO: validate that this actually works
425 //if n.hasChildren(data) {
426 // return nil
427 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400428
429 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400430 log.Debug("invoking proxy PRE_UPDATE Callbacks")
431 n.Proxy.InvokeCallbacks(PRE_UPDATE, data, false)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400432 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400433 if !reflect.DeepEqual(branch.Latest.GetData(), data) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400434 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400435 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400436 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400437 }
438 rev := branch.Latest.UpdateData(data, branch)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400439 changes := []ChangeTuple{{POST_UPDATE, branch.Latest.GetData(), rev.GetData()}}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400440 branch.Latest.Drop(branch.Txid, true)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400441 n.root.MakeLatest(branch, rev, changes)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400442 return rev
443 } else {
444 return branch.Latest
445 }
446}
447
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400448//
449// Add operation
450//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400451func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400452 for strings.HasPrefix(path, "/") {
453 path = path[1:]
454 }
455 if path == "" {
456 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400457 log.Errorf("cannot add for non-container mode\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400458 }
459
460 var branch *Branch
461 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400462 if txid == "" {
463 branch = n.Branches[NONE]
464 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400465 branch = makeBranch(n)
466 }
467
468 rev := branch.Latest
469
470 partition := strings.SplitN(path, "/", 2)
471 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400472
473 if len(partition) < 2 {
474 path = ""
475 } else {
476 path = partition[1]
477 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400478
479 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400480 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400481
482 if field.IsContainer {
483 if path == "" {
484 if field.Key != "" {
485 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400486 log.Debug("invoking proxy PRE_ADD Callbacks")
487 n.Proxy.InvokeCallbacks(PRE_ADD, data, false)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400488 }
489
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400490 for _, v := range rev.GetChildren()[name] {
491 revCopy := reflect.ValueOf(v).Interface().(Revision)
492 children = append(children, revCopy)
493 }
494 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400495 if _, rev := n.findRevByKey(children, field.Key, key.String()); rev != nil {
496 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400497 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400498 }
499
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400500 childRev := n.MakeNode(data, txid).Latest(txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400501 children = append(children, childRev)
502 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400503 changes := []ChangeTuple{{POST_ADD, branch.Latest.GetData(), rev.GetData()}}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400504 branch.Latest.Drop(txid, false)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400505 n.root.MakeLatest(branch, rev, changes)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400506 return rev
507 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400508 log.Errorf("cannot add to non-keyed container\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400509 }
510 } else if field.Key != "" {
511 partition := strings.SplitN(path, "/", 2)
512 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400513 if len(partition) < 2 {
514 path = ""
515 } else {
516 path = partition[1]
517 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400518 keyValue := field.KeyFromStr(key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400519 copy(children, rev.GetChildren()[name])
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400520 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400521 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400522 newChildRev := childNode.Add(path, data, txid, makeBranch)
523 children[idx] = newChildRev
524 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400525 branch.Latest.Drop(txid, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400526 n.root.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400527 return rev
528 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400529 log.Errorf("cannot add to non-keyed container\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400530 }
531 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400532 log.Errorf("cannot add to non-container field\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400533 }
534 return nil
535}
536
537//
538// Remove operation
539//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400540func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400541 for strings.HasPrefix(path, "/") {
542 path = path[1:]
543 }
544 if path == "" {
545 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400546 log.Errorf("cannot remove for non-container mode\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400547 }
548 var branch *Branch
549 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400550 if txid == "" {
551 branch = n.Branches[NONE]
552 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400553 branch = makeBranch(n)
554 }
555
556 rev := branch.Latest
557
558 partition := strings.SplitN(path, "/", 2)
559 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400560 if len(partition) < 2 {
561 path = ""
562 } else {
563 path = partition[1]
564 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400565
566 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400567 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400568 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400569
570 if field.IsContainer {
571 if path == "" {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400572 log.Errorf("cannot remove without a key\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400573 } else if field.Key != "" {
574 partition := strings.SplitN(path, "/", 2)
575 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400576 if len(partition) < 2 {
577 path = ""
578 } else {
579 path = partition[1]
580 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400581 keyValue := field.KeyFromStr(key)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400582 if path != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400583 for _, v := range rev.GetChildren()[name] {
584 newV := reflect.ValueOf(v).Interface().(Revision)
585 children = append(children, newV)
586 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400587 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400588 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400589 newChildRev := childNode.Remove(path, txid, makeBranch)
590 children[idx] = newChildRev
591 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400592 branch.Latest.Drop(txid, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400593 n.root.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400594 return rev
595 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400596 for _, v := range rev.GetChildren()[name] {
597 newV := reflect.ValueOf(v).Interface().(Revision)
598 children = append(children, newV)
599 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400600 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400601 if n.Proxy != nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400602 data := childRev.GetData()
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400603 n.Proxy.InvokeCallbacks(PRE_REMOVE, data, false)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400604 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400605 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400606 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400607 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400608 childRev.Drop(txid, true)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400609 children = append(children[:idx], children[idx+1:]...)
610 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400611 branch.Latest.Drop(txid, false)
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400612 n.root.MakeLatest(branch, rev, postAnnouncement)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400613 return rev
614 }
615 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400616 log.Errorf("cannot add to non-keyed container\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400617 }
618 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400619 log.Errorf("cannot add to non-container field\n")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400620 }
621
622 return nil
623}
624
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400625// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
626
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400627type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400628
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400629func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400630 branchPoint := n.Branches[NONE].Latest
631 branch := NewBranch(n, txid, branchPoint, true)
632 n.Branches[txid] = branch
633 return branch
634}
635
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400636func (n *node) DeleteBranch(txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400637 delete(n.Branches, txid)
638}
639
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400640func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400641 f := func(rev Revision) Revision {
642 childBranch := rev.GetBranch()
643
644 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400645 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400646 }
647
648 return rev
649 }
650 return f
651}
652
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400653func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400654 srcBranch := n.Branches[txid]
655 dstBranch := n.Branches[NONE]
656
657 forkRev := srcBranch.Origin
658 srcRev := srcBranch.Latest
659 dstRev := dstBranch.Latest
660
661 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
662
663 if !dryRun {
664 n.root.MakeLatest(dstBranch, rev, changes)
665 delete(n.Branches, txid)
666 }
667
Stephane Barbariee16186c2018-09-11 10:46:34 -0400668 // TODO: return proper error when one occurs
669 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400670}
671
672// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
673
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400674//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400675// branch := n.Branches[txid]
676// rev1 := branch.get(hash1)
677// rev2 := branch.get(hash2)
678//
679// if rev1.GetHash() == rev2.GetHash() {
680// // empty patch
681// } else {
682// // translate data to json and generate patch
683// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
684// patch.
685// }
686//}
687
688// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
689
690// TODO: is tag mgmt used in the python implementation? Need to validate
691
692// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
693
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400694func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400695 for fieldName, field := range ChildrenFields(n.Type) {
696 _, fieldValue := GetAttributeValue(data, fieldName, 0)
697
698 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
699 log.Error("cannot update external children")
700 return true
701 }
702 }
703
704 return false
705}
706
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400707// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400708
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400709func (n *node) GetProxy(path string, exclusive bool) *Proxy {
710 r := NewRoot(n.Type, n.root.KvStore)
711 r.node = *n
712 r.KvStore = n.root.KvStore
713
714 return n.getProxy(path, r, path, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400715}
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400716func (n *node) getProxy(path string, root Root, fullPath string, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400717 for strings.HasPrefix(path, "/") {
718 path = path[1:]
719 }
720 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400721 return n.makeProxy(root, path, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400722 }
723
724 rev := n.Branches[NONE].Latest
725 partition := strings.SplitN(path, "/", 2)
726 name := partition[0]
727 path = partition[1]
728
729 field := ChildrenFields(n.Type)[name]
730 if field.IsContainer {
731 if path == "" {
732 log.Error("cannot proxy a container field")
733 }
734 if field.Key != "" {
735 partition := strings.SplitN(path, "/", 2)
736 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400737 if len(partition) < 2 {
738 path = ""
739 } else {
740 path = partition[1]
741 }
742 keyValue := field.KeyFromStr(key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400743 children := rev.GetChildren()[name]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400744 _, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400745 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400746
747 r := NewRoot(childNode.Type, n.root.KvStore)
748 r.node = *childNode
749 r.KvStore = childNode.root.KvStore
750
751 return childNode.getProxy(path, r, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400752 }
753 log.Error("cannot index into container with no keys")
754 } else {
755 childRev := rev.GetChildren()[name][0]
756 childNode := childRev.GetNode()
757 return childNode.getProxy(path, root, fullPath, exclusive)
758 }
759
760 return nil
761}
762
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400763func (n *node) makeProxy(root Root, fullPath string, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400764 if n.Proxy == nil {
765 n.Proxy = NewProxy(root, n, fullPath, exclusive)
766 } else {
767 if n.Proxy.Exclusive {
768 log.Error("node is already owned exclusively")
769 }
770 }
771 return n.Proxy
772}
773
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400774func (n *node) makeEventBus() *EventBus {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400775 if n.EventBus == nil {
776 n.EventBus = NewEventBus()
777 }
778 return n.EventBus
779}
780
781// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Persistence Loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
782
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400783func (n *node) LoadLatest(kvStore *Backend, hash string) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400784 branch := NewBranch(n, "", nil, n.AutoPrune)
785 pr := &PersistedRevision{}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400786 rev := pr.Load(branch, kvStore, n.Type, hash)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400787 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400788 n.Branches[NONE] = branch
789}
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400790
791func (n *node) MakeTxBranch() string {
792 return n.root.MakeTxBranch()
793}
794func (n *node) FoldTxBranch(txid string) {
795 n.root.FoldTxBranch(txid)
796}
797func (n *node) DeleteTxBranch(txid string) {
798 n.root.DeleteTxBranch(txid)
799}