This repository has been archived by the owner on Jun 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmerger.go
129 lines (109 loc) · 3.15 KB
/
merger.go
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
package distnano
import (
"encoding/json"
"log"
"sort"
)
// asKey is a function that encodes c's path or x and y values as a string to
// be used as a key in a map. This is necessary to produce quick aggregations
// on keys.
func (c Child) asKey() string {
// Want to ignore values that are being aggregated over.
c.Val = nil
c.Children = nil
b, err := json.Marshal(c)
if err != nil {
log.Fatalf("Got %v encoding child %v", err, c)
}
return string(b)
}
// mergeChildren merges the children array by aggregating "val"s at the base
// level and using either path as key or x and y as keys.
func mergeChildren(dest, src []Child) []Child {
if dest == nil || src == nil {
if dest == nil {
return src
}
return dest
}
// Store pointers to children accesible by key.
destMap := make(map[string]*Child)
for i, child := range dest {
destMap[child.asKey()] = &dest[i]
}
// For each child in src, merge with the destMap.
for i, child := range src {
key := child.asKey()
// If the key already exists in the map, we want to merge with that
// key. Otherwise, we simply add it.
if _, e := destMap[key]; e {
// If the child doesn't have a Val, it necessarily has something in
// its []Child field. We therefore initiate a recursive merge.
// Otherwise, the semantics of merging is to add to the value.
if child.Val == nil {
destMap[key].Children =
mergeChildren(destMap[key].Children, child.Children)
} else {
*(destMap[key].Val) += *(child.Val)
}
} else {
destMap[key] = &src[i]
}
}
// We now want to create a new []Child slice from our [string]*Child map.
result := make([]Child, 0, len(destMap))
for _, v := range destMap {
// Note that result is not reallocated on each iteration because its
// capacity was specified.
result = append(result, *v)
}
return result
}
// merge merges src into dest according to the API.md document found in
// github.com/laurolins/nanocube.
func mergeNanocubeResponse(dest, src *NanocubeResponse) {
if dest.Layers == nil {
dest.Layers = []string{}
}
if dest.Root.Val != nil {
if src.Root.Val != nil {
*(dest.Root.Val) += *(src.Root.Val)
}
return
} else if src.Root.Val != nil {
dest.Root.Val = src.Root.Val
}
dest.Root.Children = mergeChildren(dest.Root.Children, src.Root.Children)
}
func mergeFields(dest, src []Field) []Field {
if len(dest) != len(src) {
log.Fatal("Schema fields not the same length")
}
for i := 0; i < len(dest); i++ {
// Merge the valname maps together.
for k, v := range src[i].Valnames {
dest[i].Valnames[k] += v
}
keys := make(sort.StringSlice, 0, len(dest[i].Valnames))
for k, _ := range dest[i].Valnames {
keys = append(keys, k)
}
// The semantics of the schema call is to respond with the index of the
// key in sorted order as the value.
keys.Sort()
for j := 0; j < len(keys); j++ {
dest[i].Valnames[keys[j]] = j
}
}
return dest
}
func mergeSchemaResponse(dest, src *SchemaResponse) {
for _, md := range dest.Metadata {
// Every node will have a different filename, so this key value pair is
// not necessary.
if md.Key == "name" {
md.Value = ""
}
}
dest.Fields = mergeFields(dest.Fields, src.Fields)
}