diff --git a/options.go b/options.go index f6f2647..eaa0fdb 100644 --- a/options.go +++ b/options.go @@ -164,6 +164,16 @@ func (o *Option[T]) Scan(src any) error { if err != nil { return fmt.Errorf("Option[%T].Scan: failed to convert value from SQL driver: %w", o.value, err) } + + // Convert between string and []byte if needed + dstType := reflect.TypeOf(o.value) + srcType := reflect.TypeOf(av) + if isByteSlice(srcType) && dstType.Kind() == reflect.String { + av = string(av.([]byte)) + } else if srcType.Kind() == reflect.String && isByteSlice(dstType) { + av = []byte(av.(string)) + } + v, ok := av.(T) if !ok { return fmt.Errorf("Option[%T].Scan: failed to convert value %#v to type %T", o.value, av, o.value) @@ -172,6 +182,10 @@ func (o *Option[T]) Scan(src any) error { return nil } +func isByteSlice(t reflect.Type) bool { + return t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 +} + // Equal returns true if the two options are equal. // Equality of the wrapped values is determined by [reflect.DeepEqual]. // diff --git a/options_test.go b/options_test.go index 9821b8e..514f0cb 100644 --- a/options_test.go +++ b/options_test.go @@ -232,6 +232,25 @@ func TestSQLScan(t *testing.T) { t.Fatal(err) } assertEqual(t, opt3, options.New[time.Time](ts)) + + byteString := []byte("hello") + var opt4 options.Option[string] + if err := opt4.Scan(byteString); err != nil { + t.Fatal(err) + } + assertEqual(t, opt4, options.New[string]("hello")) + + var opt5 options.Option[[]byte] + if err := opt5.Scan("hello"); err != nil { + t.Fatal(err) + } + assertDeepEqual(t, opt5, options.New[[]byte]([]byte("hello"))) + + var opt6 options.Option[string] + if err := opt6.Scan(nil); err != nil { + t.Fatal(err) + } + assertEqual(t, opt6, options.None[string]()) } func TestEqual(t *testing.T) {