Improve Sum method from utils/reflect.go

This commit is contained in:
TeoV
2019-04-14 11:40:22 +03:00
committed by Dan Christian Bogos
parent a484fc9388
commit 7a971cbb2e
5 changed files with 124 additions and 148 deletions

View File

@@ -129,36 +129,35 @@ func IfaceAsTime(itm interface{}, timezone string) (t time.Time, err error) {
}
func IfaceAsDuration(itm interface{}) (d time.Duration, err error) {
switch itm.(type) {
switch it := itm.(type) {
case time.Duration:
return itm.(time.Duration), nil
return it, nil
case float64: // automatically hitting here also ints
return time.Duration(int64(itm.(float64))), nil
return time.Duration(int64(it)), nil
case int64:
return time.Duration(itm.(int64)), nil
return time.Duration(it), nil
case int:
return time.Duration(itm.(int)), nil
return time.Duration(it), nil
case string:
return ParseDurationWithNanosecs(itm.(string))
default:
err = fmt.Errorf("cannot convert field: %+v to time.Duration", itm)
err = fmt.Errorf("cannot convert field: %+v to time.Duration", it)
}
return
}
func IfaceAsInt64(itm interface{}) (i int64, err error) {
switch itm.(type) {
switch it := itm.(type) {
case int:
return int64(itm.(int)), nil
return int64(it), nil
case time.Duration:
return itm.(time.Duration).Nanoseconds(), nil
return it.Nanoseconds(), nil
case int64:
return itm.(int64), nil
return it, nil
case string:
return strconv.ParseInt(itm.(string), 10, 64)
return strconv.ParseInt(it, 10, 64)
default:
err = fmt.Errorf("cannot convert field: %+v to int", itm)
err = fmt.Errorf("cannot convert field: %+v to int", it)
}
return
}
@@ -352,59 +351,56 @@ func Sum(items ...interface{}) (sum interface{}, err error) {
return nil, ErrNotEnoughParameters
}
// convert the type for first item
valItm := reflect.ValueOf(items[0])
switch valItm.Kind() {
case reflect.Float32:
items[0] = valItm.Float()
valItm = reflect.ValueOf(items[0])
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
items[0] = valItm.Int()
valItm = reflect.ValueOf(items[0])
}
typItem := reflect.TypeOf(items[0])
//populate sum with first item so we can add after
switch items[0].(type) {
case float64:
sum = valItm.Float()
case int64:
sum = valItm.Int()
switch dt := items[0].(type) {
case time.Duration:
tVal := items[0].(time.Duration)
sum = tVal
}
for _, item := range items[1:] {
valOtItm := reflect.ValueOf(item)
// convert to wider type so we can be compatible with StringToInterface function
switch valOtItm.Kind() {
case reflect.Float32:
item = valOtItm.Float()
valOtItm = reflect.ValueOf(item)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
item = valOtItm.Int()
valOtItm = reflect.ValueOf(item)
sum = dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
sum = sum.(time.Duration) + itmVal
}
}
typOItem := reflect.TypeOf(item)
// check if the type for rest items is the same as first
if !typItem.Comparable() ||
!typOItem.Comparable() ||
typItem != typOItem {
return false, errors.New("incomparable")
case time.Time:
sum = dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
sum = sum.(time.Time).Add(itmVal)
}
}
switch items[0].(type) {
case float64:
sum = reflect.ValueOf(sum).Float() + valOtItm.Float()
case int64:
sum = reflect.ValueOf(sum).Int() + valOtItm.Int()
case time.Duration:
tOVal := item.(time.Duration)
sum = sum.(time.Duration) + tOVal
default: // unsupported comparison
err = fmt.Errorf("unsupported comparison type: %v, kind: %v", typItem, typItem.Kind())
break
case float64:
sum = dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsFloat64(item); err != nil {
return nil, err
} else {
sum = sum.(float64) + itmVal
}
}
case int64:
sum = dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
sum = sum.(int64) + itmVal
}
}
case int:
// need explicit conversion for int
if firstItmVal, err := IfaceAsInt64(dt); err != nil {
return nil, err
} else {
sum = firstItmVal
}
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
sum = sum.(int64) + itmVal
}
}
}
return
@@ -417,18 +413,16 @@ func Difference(items ...interface{}) (diff interface{}, err error) {
if len(items) < 2 {
return nil, ErrNotEnoughParameters
}
switch dt := items[0].(type) {
// case time.Duration:
// diff = dt
// for _, item := range items[1:] {
// if itmVal, err := IfaceAsDuration(item); err != nil {
// return nil, err
// } else {
// diff = diff.(time.Duration) - itmVal
// }
// }
case time.Duration:
diff = dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
diff = diff.(time.Duration) - itmVal
}
}
case time.Time:
diff = dt
for _, item := range items[1:] {
@@ -438,7 +432,6 @@ func Difference(items ...interface{}) (diff interface{}, err error) {
diff = diff.(time.Time).Add(-itmVal)
}
}
case float64:
diff = dt
for _, item := range items[1:] {
@@ -448,18 +441,31 @@ func Difference(items ...interface{}) (diff interface{}, err error) {
diff = diff.(float64) - itmVal
}
}
// case int64:
// for _, item := range items[1:] {
// if itmVal, err := IfaceAsInt64(item); err != nil {
// return nil, err
// } else {
// diff = diff.(int64) - itmVal
// }
// }
case int64:
diff = dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
diff = diff.(int64) - itmVal
}
}
case int:
// need explicit conversion for int
if firstItmVal, err := IfaceAsInt64(dt); err != nil {
return nil, err
} else {
diff = firstItmVal
}
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
diff = diff.(int64) - itmVal
}
}
default: // unsupported comparison
return nil, fmt.Errorf("unsupported type")
}
return
}

View File

@@ -466,7 +466,7 @@ func TestSum(t *testing.T) {
if _, err := Sum(1); err == nil || err != ErrNotEnoughParameters {
t.Error(err)
}
if _, err := Sum(1, 1.2, false); err == nil || err.Error() != "incomparable" {
if _, err := Sum(1, 1.2, false); err == nil || err.Error() != "cannot convert field: 1.2 to int" {
t.Error(err)
}
if sum, err := Sum(1.2, 1.2, 1.2, 1.2); err != nil {
@@ -558,14 +558,14 @@ func TestDifference(t *testing.T) {
if _, err := Difference(10); err == nil || err != ErrNotEnoughParameters {
t.Error(err)
}
if _, err := Difference(10, 1.2, false); err == nil || err.Error() != "unsupported type" {
if _, err := Difference(10, 1.2, false); err == nil || err.Error() != "cannot convert field: 1.2 to int" {
t.Error(err)
}
// if diff, err := Difference(12, 1, 2, 3); err != nil {
// t.Error(err)
// } else if diff != int64(6) {
// t.Errorf("Expecting: 6, received: %+v", diff)
// }
if diff, err := Difference(12, 1, 2, 3); err != nil {
t.Error(err)
} else if diff != int64(6) {
t.Errorf("Expecting: 6, received: %+v", diff)
}
if diff, err := Difference(8.0, 4.0, 2.0, -1.0); err != nil {
t.Error(err)
} else if diff != 3.0 {
@@ -577,18 +577,18 @@ func TestDifference(t *testing.T) {
} else if diff != 3.0 {
t.Errorf("Expecting: 3.0, received: %+v", diff)
}
// if diff, err := Difference(10*time.Second, 1*time.Second, 2*time.Second,
// 4*time.Millisecond); err != nil {
// t.Error(err)
// } else if diff != int64(6996000000) {
// t.Errorf("Expecting: 6.996ms, received: %+v", diff)
// }
// if diff, err := Difference(time.Duration(2*time.Second),
// time.Duration(10*time.Millisecond)); err != nil {
// t.Error(err)
// } else if diff != int64(1990000000) {
// t.Errorf("Expecting: 1.99s, received: %+v", diff)
// }
if diff, err := Difference(10*time.Second, 1*time.Second, 2*time.Second,
4*time.Millisecond); err != nil {
t.Error(err)
} else if diff != time.Duration(6*time.Second+996*time.Millisecond) {
t.Errorf("Expecting: 6.996ms, received: %+v", diff)
}
if diff, err := Difference(time.Duration(2*time.Second),
time.Duration(10*time.Millisecond)); err != nil {
t.Error(err)
} else if diff != time.Duration(1*time.Second+990*time.Millisecond) {
t.Errorf("Expecting: 1.99s, received: %+v", diff)
}
if diff, err := Difference(time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
time.Duration(10*time.Second)); err != nil {