...
1 package encoder
2
3 import (
4 "context"
5 "fmt"
6 "reflect"
7 )
8
9 var (
10 Marshal func(interface{}) ([]byte, error)
11 Unmarshal func([]byte, interface{}) error
12 )
13
14 type FieldQuery struct {
15 Name string
16 Fields []*FieldQuery
17 hash string
18 }
19
20 func (q *FieldQuery) Hash() string {
21 if q.hash != "" {
22 return q.hash
23 }
24 b, _ := Marshal(q)
25 q.hash = string(b)
26 return q.hash
27 }
28
29 func (q *FieldQuery) MarshalJSON() ([]byte, error) {
30 if q.Name != "" {
31 if len(q.Fields) > 0 {
32 return Marshal(map[string][]*FieldQuery{q.Name: q.Fields})
33 }
34 return Marshal(q.Name)
35 }
36 return Marshal(q.Fields)
37 }
38
39 func (q *FieldQuery) QueryString() (FieldQueryString, error) {
40 b, err := Marshal(q)
41 if err != nil {
42 return "", err
43 }
44 return FieldQueryString(b), nil
45 }
46
47 type FieldQueryString string
48
49 func (s FieldQueryString) Build() (*FieldQuery, error) {
50 var query interface{}
51 if err := Unmarshal([]byte(s), &query); err != nil {
52 return nil, err
53 }
54 return s.build(reflect.ValueOf(query))
55 }
56
57 func (s FieldQueryString) build(v reflect.Value) (*FieldQuery, error) {
58 switch v.Type().Kind() {
59 case reflect.String:
60 return s.buildString(v)
61 case reflect.Map:
62 return s.buildMap(v)
63 case reflect.Slice:
64 return s.buildSlice(v)
65 case reflect.Interface:
66 return s.build(reflect.ValueOf(v.Interface()))
67 }
68 return nil, fmt.Errorf("failed to build field query")
69 }
70
71 func (s FieldQueryString) buildString(v reflect.Value) (*FieldQuery, error) {
72 b := []byte(v.String())
73 switch b[0] {
74 case '[', '{':
75 var query interface{}
76 if err := Unmarshal(b, &query); err != nil {
77 return nil, err
78 }
79 if str, ok := query.(string); ok {
80 return &FieldQuery{Name: str}, nil
81 }
82 return s.build(reflect.ValueOf(query))
83 }
84 return &FieldQuery{Name: string(b)}, nil
85 }
86
87 func (s FieldQueryString) buildSlice(v reflect.Value) (*FieldQuery, error) {
88 fields := make([]*FieldQuery, 0, v.Len())
89 for i := 0; i < v.Len(); i++ {
90 def, err := s.build(v.Index(i))
91 if err != nil {
92 return nil, err
93 }
94 fields = append(fields, def)
95 }
96 return &FieldQuery{Fields: fields}, nil
97 }
98
99 func (s FieldQueryString) buildMap(v reflect.Value) (*FieldQuery, error) {
100 keys := v.MapKeys()
101 if len(keys) != 1 {
102 return nil, fmt.Errorf("failed to build field query object")
103 }
104 key := keys[0]
105 if key.Type().Kind() != reflect.String {
106 return nil, fmt.Errorf("failed to build field query. invalid object key type")
107 }
108 name := key.String()
109 def, err := s.build(v.MapIndex(key))
110 if err != nil {
111 return nil, err
112 }
113 return &FieldQuery{
114 Name: name,
115 Fields: def.Fields,
116 }, nil
117 }
118
119 type queryKey struct{}
120
121 func FieldQueryFromContext(ctx context.Context) *FieldQuery {
122 query := ctx.Value(queryKey{})
123 if query == nil {
124 return nil
125 }
126 q, ok := query.(*FieldQuery)
127 if !ok {
128 return nil
129 }
130 return q
131 }
132
133 func SetFieldQueryToContext(ctx context.Context, query *FieldQuery) context.Context {
134 return context.WithValue(ctx, queryKey{}, query)
135 }
136
View as plain text