sv / kdbgo

kdb+ client driver for Go
MIT License
44 stars 29 forks source link

Unmarshalling dict to struct #25

Open lkramer opened 5 years ago

lkramer commented 5 years ago

Hey, I noticed that the function UnmarshalDict have some behaviour around field names that may be undesirable (certainly is for my usecase).

The main issue is that when it looks up a fieldname it will make the first character uppercase if necessary, but no further changes. That means that if a dict field uses snake case, like this: this_is_a_field the corresponding field in a struct would have to be:

type MyStruct struct {
    This_is_a_field int
}

Which both brake go conventions and is also confusing. For my own purpose I rewrote the function the following way:

func unmarshalResponse(t kdb.Dict) (*OrderResponse, error) {              
    var (
        keys = t.Key.Data.([]string)
        vals = t.Value.Data.([]*kdb.K)                                    
        v    = new(OrderResponse)                                         
    )
    vv := reflect.Indirect(reflect.ValueOf(v))                            
    for i := range keys {
        val := vals[i].Data
        fv := vv.FieldByName(strcase.ToCamel(keys[i]))                    
        if !fv.IsValid() {
            return nil, fmt.Errorf("field does not exist %q", keys[i])    
        }
        if fv.CanSet() && reflect.TypeOf(val).AssignableTo(fv.Type()) {   
            fv.Set(reflect.ValueOf(val))                                  
        }                                                                 
    }
    return v, nil                                                         
}                                                                         

It uses a thirdparty library to convert the name to CamelCase, but that could be done locally, I was just being lazy. (an added benefit with this version is that it will error out if a correct struct field can not be found).

In addition it might be beneficial to support tags as an alternative to strict field naming similar to how the json marshalling works, so it would be possible to do something along these lines.

type MyStruct struct {
    Foo int `kdb:"this_is_a_field"`
}

I'm happy to write up a PR if you think this would be beneficial.

I'm also working on functionality to Marshal structs and maps into Dicts that might be useful as well.

sv commented 5 years ago

Yes, struct field names are better and how it should be done. Never got around to implement it.

Have a look at this branch - https://github.com/sv/kdbgo/tree/v1beta . There are some api changes, but should be much cleaner overall