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