gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

query.go (2897B)


      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 }