Skip to content
Snippets Groups Projects

Use Scan() method before json.Unmarshal for param values

Merged Pieter van Staden requested to merge 18-use-scan-for-param-values into main
1 file
+ 28
12
Compare changes
  • Side-by-side
  • Inline
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
}
Loading