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  }