github.com/night-codes/go-json@v0.9.15/internal/encoder/query.go (about) 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 }