diff --git a/struct_utils/named_values_to_struct.go b/struct_utils/named_values_to_struct.go index 81c58360fad45405036a43ae412fc36d84fd1486..b8f21428d27458b6e07102d5c0be664478ff6b20 100644 --- a/struct_utils/named_values_to_struct.go +++ b/struct_utils/named_values_to_struct.go @@ -1,6 +1,7 @@ package struct_utils import ( + "database/sql" "encoding/csv" "encoding/json" "reflect" @@ -284,19 +285,34 @@ func unmarshalValue(v interface{}, t reflect.Type) (reflect.Value, error) { newValuePtr := reflect.New(t) if reflect.ValueOf(v).Type().AssignableTo(t) { newValuePtr.Elem().Set(reflect.ValueOf(v)) //can assign as is - } else { - //needs conversion - s, ok := v.(string) - if !ok { - jsonValue, _ := json.Marshal(v) - s = string(jsonValue) - } - //is string value, unmarshal as quoted or unquoted JSON value - if err := json.Unmarshal([]byte("\""+s+"\""), newValuePtr.Interface()); err != nil { - if err := json.Unmarshal([]byte(s), newValuePtr.Interface()); err != nil { - return newValuePtr.Elem(), errors.Wrapf(err, "invalid \"%s\"", s) - } + return newValuePtr.Elem(), nil + } + + //needs conversion + s, ok := v.(string) + if !ok { + jsonValue, _ := json.Marshal(v) + s = string(jsonValue) + } + + //now we have string value + if valueScanner, ok := newValuePtr.Interface().(sql.Scanner); ok { + //if has scanner - prefer that over json unmarshal + //because we do not know if json expects quoted/unquoted for this type + //and if we try quoted, it fail, then try unquoted, we have two different + //errors one one of them will be kind of meaning nothing, but which? + //scanner should always take the value as typed, so let's try that first + if err := valueScanner.Scan(s); err == nil { + return newValuePtr.Elem(), nil } } + + //try JSON unmarshal as is else with quotes + if err := json.Unmarshal([]byte(s), newValuePtr.Interface()); err == nil { + return newValuePtr.Elem(), nil + } + if err := json.Unmarshal([]byte("\""+s+"\""), newValuePtr.Interface()); err != nil { + return newValuePtr.Elem(), errors.Wrapf(err, "invalid \"%s\"", s) + } return newValuePtr.Elem(), nil }