VOL-1175: Added proxy CRUD for new data model

Change-Id: Ie218a2567746d87a951f23aa6b774b2f01541cf9
diff --git a/db/model/non_persisted_revision.go b/db/model/non_persisted_revision.go
new file mode 100644
index 0000000..26d25a0
--- /dev/null
+++ b/db/model/non_persisted_revision.go
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package model
+
+import (
+	"bytes"
+	"crypto/md5"
+	"fmt"
+	"reflect"
+	"sort"
+	"github.com/opencord/voltha-go/common/log"
+)
+
+var (
+	RevisionCache = make(map[string]interface{})
+)
+
+type NonPersistedRevision struct {
+	Config   *DataRevision
+	Children map[string][]Revision
+	Hash     string
+	Branch   *Branch
+	WeakRef  string
+}
+
+func NewNonPersistedRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
+	cr := &NonPersistedRevision{}
+	cr.Branch = branch
+	cr.Config = NewDataRevision(data)
+	cr.Children = children
+	cr.Finalize()
+
+	return cr
+}
+
+func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
+	npr.Config = config
+}
+
+func (npr *NonPersistedRevision) GetConfig() *DataRevision {
+	return npr.Config
+}
+
+func (npr *NonPersistedRevision) SetChildren(children map[string][]Revision) {
+	npr.Children = children
+}
+
+func (npr *NonPersistedRevision) GetChildren() map[string][]Revision {
+	return npr.Children
+}
+
+func (npr *NonPersistedRevision) SetHash(hash string) {
+	npr.Hash = hash
+}
+
+func (npr *NonPersistedRevision) GetHash() string {
+	return npr.Hash
+}
+
+func (npr *NonPersistedRevision) ClearHash() {
+	npr.Hash = ""
+}
+
+func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
+	npr.Branch = branch
+}
+
+func (npr *NonPersistedRevision) GetBranch() *Branch {
+	return npr.Branch
+}
+
+func (npr *NonPersistedRevision) GetData() interface{} {
+	if npr.Config == nil {
+		return nil
+	}
+	return npr.Config.Data
+}
+
+func (npr *NonPersistedRevision) GetNode() *Node {
+	return npr.Branch.Node
+}
+
+func (npr *NonPersistedRevision) Finalize() {
+	npr.SetHash(npr.hashContent())
+
+	if _, exists := RevisionCache[npr.Hash]; !exists {
+		RevisionCache[npr.Hash] = npr
+	}
+	if _, exists := RevisionCache[npr.Config.Hash]; !exists {
+		RevisionCache[npr.Config.Hash] = npr.Config
+	} else {
+		npr.Config = RevisionCache[npr.Config.Hash].(*DataRevision)
+	}
+}
+
+func (npr *NonPersistedRevision) hashContent() string {
+	var buffer bytes.Buffer
+	var childrenKeys []string
+
+	if npr.Config != nil {
+		buffer.WriteString(npr.Config.Hash)
+	}
+
+	for key, _ := range npr.Children {
+		childrenKeys = append(childrenKeys, key)
+	}
+	sort.Strings(childrenKeys)
+
+	if npr.Children != nil && len(npr.Children) > 0 {
+		// Loop through sorted Children keys
+		for _, key := range childrenKeys {
+			for _, child := range npr.Children[key] {
+				if child != nil && child.GetHash() != "" {
+					buffer.WriteString(child.GetHash())
+				}
+			}
+		}
+	}
+
+	return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
+}
+
+func (npr *NonPersistedRevision) Get(depth int) interface{} {
+	originalData := npr.GetData()
+	data := reflect.ValueOf(originalData).Interface()
+
+	if depth != 0 {
+		for fieldName, field := range ChildrenFields(npr.GetData()) {
+			childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
+			if field.IsContainer {
+				for _, rev := range npr.Children[fieldName] {
+					childData := rev.Get(depth - 1)
+					childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
+					//fmt.Printf("data:%+v, dataHolder:%+v\n", childData, childDataHolder)
+				}
+			} else {
+				rev := npr.Children[fieldName][0]
+				childData := rev.Get(depth - 1)
+				childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
+				//fmt.Printf("data:%+v, dataHolder:%+v\n", childData, childDataHolder)
+			}
+			// Merge child data with cloned object
+			reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
+		}
+	}
+	return data
+}
+
+func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
+	newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
+	newRev.SetBranch(branch)
+	log.Debugf("newRev config : %+v, npr: %+v", newRev.GetConfig(), npr)
+	newRev.SetConfig(NewDataRevision(data))
+	newRev.Finalize()
+
+	return &newRev
+}
+
+func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
+	newChildren := make(map[string][]Revision)
+	for entryName, childrenEntry := range npr.Children {
+		for _, revisionEntry := range childrenEntry {
+			newEntry := reflect.ValueOf(revisionEntry).Interface().(Revision)
+			newChildren[entryName] = append(newChildren[entryName], newEntry)
+		}
+	}
+	newChildren[name] = children
+
+	newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
+	newRev.SetBranch(branch)
+	newRev.SetChildren(newChildren)
+	newRev.Finalize()
+
+	return &newRev
+}
+
+func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
+	newRev := reflect.ValueOf(npr).Interface().(NonPersistedRevision)
+	newRev.SetBranch(branch)
+	newRev.SetChildren(children)
+	newRev.Finalize()
+
+	return &newRev
+}