package encoder
import (
"context"
"fmt"
"reflect"
)
var (
Marshal func (interface {}) ([]byte , error )
Unmarshal func ([]byte , interface {}) error
)
type FieldQuery struct {
Name string
Fields []*FieldQuery
hash string
}
func (q *FieldQuery ) Hash () string {
if q .hash != "" {
return q .hash
}
b , _ := Marshal (q )
q .hash = string (b )
return q .hash
}
func (q *FieldQuery ) MarshalJSON () ([]byte , error ) {
if q .Name != "" {
if len (q .Fields ) > 0 {
return Marshal (map [string ][]*FieldQuery {q .Name : q .Fields })
}
return Marshal (q .Name )
}
return Marshal (q .Fields )
}
func (q *FieldQuery ) QueryString () (FieldQueryString , error ) {
b , err := Marshal (q )
if err != nil {
return "" , err
}
return FieldQueryString (b ), nil
}
type FieldQueryString string
func (s FieldQueryString ) Build () (*FieldQuery , error ) {
var query interface {}
if err := Unmarshal ([]byte (s ), &query ); err != nil {
return nil , err
}
return s .build (reflect .ValueOf (query ))
}
func (s FieldQueryString ) build (v reflect .Value ) (*FieldQuery , error ) {
switch v .Type ().Kind () {
case reflect .String :
return s .buildString (v )
case reflect .Map :
return s .buildMap (v )
case reflect .Slice :
return s .buildSlice (v )
case reflect .Interface :
return s .build (reflect .ValueOf (v .Interface ()))
}
return nil , fmt .Errorf ("failed to build field query" )
}
func (s FieldQueryString ) buildString (v reflect .Value ) (*FieldQuery , error ) {
b := []byte (v .String ())
switch b [0 ] {
case '[' , '{' :
var query interface {}
if err := Unmarshal (b , &query ); err != nil {
return nil , err
}
if str , ok := query .(string ); ok {
return &FieldQuery {Name : str }, nil
}
return s .build (reflect .ValueOf (query ))
}
return &FieldQuery {Name : string (b )}, nil
}
func (s FieldQueryString ) buildSlice (v reflect .Value ) (*FieldQuery , error ) {
fields := make ([]*FieldQuery , 0 , v .Len ())
for i := 0 ; i < v .Len (); i ++ {
def , err := s .build (v .Index (i ))
if err != nil {
return nil , err
}
fields = append (fields , def )
}
return &FieldQuery {Fields : fields }, nil
}
func (s FieldQueryString ) buildMap (v reflect .Value ) (*FieldQuery , error ) {
keys := v .MapKeys ()
if len (keys ) != 1 {
return nil , fmt .Errorf ("failed to build field query object" )
}
key := keys [0 ]
if key .Type ().Kind () != reflect .String {
return nil , fmt .Errorf ("failed to build field query. invalid object key type" )
}
name := key .String ()
def , err := s .build (v .MapIndex (key ))
if err != nil {
return nil , err
}
return &FieldQuery {
Name : name ,
Fields : def .Fields ,
}, nil
}
type queryKey struct {}
func FieldQueryFromContext (ctx context .Context ) *FieldQuery {
query := ctx .Value (queryKey {})
if query == nil {
return nil
}
q , ok := query .(*FieldQuery )
if !ok {
return nil
}
return q
}
func SetFieldQueryToContext (ctx context .Context , query *FieldQuery ) context .Context {
return context .WithValue (ctx , queryKey {}, query )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .