I'm trying to test around an SQL query wherein one of the arguments is a gosnowflake.Array
(essentially a wrapper to a slice) using the go-sqlmock
package. Normally, something like this requires me to create a value converter, which I have included:
func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) {
casted, ok := v.(*[]T)
if ok {
Expect(*casted).Should(HaveLen(len(opt.Expected)))
for i, c := range *casted {
Expect(c).Should(Equal(opt.Expected[i]))
}
} else {
fmt.Printf("Type: %T\n", v)
return v, nil
}
return "TEST_RESULT", nil
}
Now, this function is called for every argument submitted to the query. I use it to test the correctness of the values in the slice or pass the argument through if it isn't one. The problem I'm having is that, when I create a arrayConverterOption[string]
and give it a gosnowflake.Array(["A", "B", "C"])
as an argument, the type assertion fails because gosnowflake.Array
returns an internal dynamic type, *stringArray
, which is defined as a *[]string
.
So you can see my dilemma here. On the one hand, I can't convert v
because it's an interface{}
and I can't alias v
because the inner type is not *[]string
, but *stringArray
. So then, what should I do here?
I didn't find a way to do this without resulting to reflection. However, with reflction I did manage it:
var casted []T
var ok bool
value := reflect.ValueOf(v)
if value.Kind() == reflect.Pointer {
if inner := value.Elem(); inner.Kind() == reflect.Slice {
r := inner.Convert(reflect.TypeOf([]T{})).Interface()
casted, ok = r.([]T)
}
}
So, this code checks specifically for anything that is a pointer to a slice, which my dynamic type is. Then it uses reflection to convert the inner object to the slice type I was expecting. After that, I call Interface()
on the result to get the interface{}
from the reflected value and then cast it to a []T
. This succeeds. If it doesn't then I'm not working with one of those dynamically typed slices and I can handle the type normally.