forked from graph-gophers/graphql-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
queryops.go
149 lines (134 loc) · 3.77 KB
/
queryops.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package graphql
import (
"errors"
"github.com/weave-lab/graphql-go/internal/common"
"github.com/weave-lab/graphql-go/internal/exec/selected"
"github.com/weave-lab/graphql-go/internal/query"
)
const (
FieldSeparator = "_"
)
// QueryOp represents a summary of query's requested operations
// this may be used for field monitoring or in resolvers to avoid
// costly operations.
type QueryOp struct {
Name string `json:",omitempty"`
Type query.OperationType
Variables map[string]string `json:",omitempty"`
Fields []QueryFieldSummary `json:",omitempty"`
}
// QueryFieldSummary represents a summary of a field requested in the query.
type QueryFieldSummary struct {
Name string
Arguments map[string]string `json:",omitempty"`
}
func selectionToField(sel query.Selection) query.Field {
if field, ok := sel.(query.Field); ok {
return field
} else if field, ok := sel.(*query.Field); ok {
return *field
}
return query.Field{}
}
func parseQueryFields(field query.Field) []QueryFieldSummary {
args := []common.Argument(field.Arguments)
var fieldArgs map[string]string
if len(args) > 0 {
fieldArgs = make(map[string]string)
for _, arg := range args {
fieldArgs[arg.Name.Name] = arg.Value.String()
}
}
fields := make([]QueryFieldSummary, 0)
if len(field.Selections) > 0 {
for _, sel := range field.Selections {
rawField := selectionToField(sel)
subFields := parseQueryFields(rawField)
for _, sub := range subFields {
newArgs := sub.Arguments
if len(fieldArgs) > 0 {
for k, v := range fieldArgs {
if newArgs == nil {
newArgs = fieldArgs
break
}
//duplidate names will get overwritten
newArgs[k] = v
}
}
fields = append(fields, QueryFieldSummary{
Name: field.Name.Name + FieldSeparator + sub.Name,
Arguments: newArgs,
})
}
}
} else {
fields = append(fields, QueryFieldSummary{
Name: field.Name.Name,
Arguments: fieldArgs,
})
}
return fields
}
func ParseQueryOps(document interface{}) ([]QueryOp, error) {
doc, ok := document.(*query.Document)
if !ok {
return nil, errors.New("invalid value passed to ParseQueryOps expected a *query.Document")
}
ops := []*query.Operation(doc.Operations)
qops := make([]QueryOp, len(ops))
for i, op := range ops {
inputs := []*common.InputValue(op.Vars)
var args map[string]string
if len(inputs) > 0 {
args = make(map[string]string)
for _, input := range inputs {
if input != nil && input.Default != nil {
args[input.Name.Name] = input.Default.String()
}
}
}
fields := make([]QueryFieldSummary, 0, len(op.Selections))
for _, sel := range op.Selections {
rawField := selectionToField(sel)
fields = append(fields, parseQueryFields(rawField)...)
}
qops[i] = QueryOp{
Name: op.Name.Name,
Type: op.Type,
Variables: args,
Fields: fields,
}
}
return qops, nil
}
type QueryField struct {
Name string
Arguments map[string]interface{}
Subfields []selected.Selection
}
func parseResolverFields(field *selected.SchemaField) ([]QueryField, error) {
if field == nil {
return nil, errors.New("field must not be nil")
}
out := make([]QueryField, 0, len(field.Sels))
for _, sel := range field.Sels {
sf, ok := sel.(*selected.SchemaField) // TODO: technically this could be one of several things. Make this more robust?
if !ok {
return nil, errors.New("failed to parse subselection as QueryField")
}
out = append(out, QueryField{
Name: sf.Name,
Arguments: sf.Args,
Subfields: sf.Sels,
})
}
return out, nil
}
func ParseSubfields(field interface{}) ([]QueryField, error) {
f, ok := field.(*selected.SchemaField)
if !ok {
return nil, errors.New("invalid value passed to ParseCurrentField expected a *query.Field")
}
return parseResolverFields(f)
}