forked from cli/cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmerge.go
More file actions
94 lines (79 loc) · 2.21 KB
/
merge.go
File metadata and controls
94 lines (79 loc) · 2.21 KB
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
package multigraphql
import (
"bytes"
"fmt"
"io"
"regexp"
"sort"
"strings"
)
// PreparedQuery represents a Query with associated variable values
type PreparedQuery struct {
variableValues map[string]interface{}
Query
}
var identifier = regexp.MustCompile(`\$[a-zA-Z]\w*`)
// Merge combines multiple queries into one while avoiding variable collisions
func Merge(queries ...PreparedQuery) (string, map[string]interface{}) {
out := &bytes.Buffer{}
queryStrings := []string{}
allVariables := map[string]string{}
allValues := map[string]interface{}{}
seenFragments := map[string]struct{}{"": {}}
for i, q := range queries {
renames := mergeVariables(allVariables, q.variables, func(k string) string {
return fmt.Sprintf("%s_%03d", k, i)
})
for key, value := range q.variableValues {
if newKey, exists := renames[key]; exists {
key = newKey
}
allValues[key] = value
}
if _, seen := seenFragments[q.fragments]; !seen {
fmt.Fprintln(out, q.fragments)
seenFragments[q.fragments] = struct{}{}
}
finalQuery := renameVariables(q.query, renames)
queryStrings = append(queryStrings, fmt.Sprintf("multi_%03d: %s", i, finalQuery))
}
fmt.Fprint(out, "query")
writeVariables(out, allVariables)
fmt.Fprintf(out, " {\n\t%s\n}", strings.Join(queryStrings, "\n\t"))
return out.String(), allValues
}
func mergeVariables(dest, src map[string]string, keyGen func(string) string) map[string]string {
renames := map[string]string{}
for key, value := range src {
if _, exists := dest[key]; exists {
newKey := keyGen(key)
renames[key] = newKey
key = newKey
}
dest[key] = value
}
return renames
}
func renameVariables(q string, dictionary map[string]string) string {
return identifier.ReplaceAllStringFunc(q, func(v string) string {
if newName, exists := dictionary[v[1:]]; exists {
return "$" + newName
}
return v
})
}
func writeVariables(out io.Writer, variables map[string]string) {
if len(variables) == 0 {
return
}
vars := []string{}
for key, value := range variables {
vars = append(vars, fmt.Sprintf("$%s: %s", key, value))
}
sort.Sort(sort.StringSlice(vars))
fmt.Fprint(out, "(\n")
for _, v := range vars {
fmt.Fprintf(out, "\t%s\n", v)
}
fmt.Fprint(out, ")")
}