fix(cabana): dereference nullable pointer scalars in ML host hydration

- hostScalarString walks pointers via reflect; nil at any depth is ""
- string kinds return raw text, byte slices decode, other kinds format the dereferenced value
- Postgres round-trip regression for an mltext field on a *string column
This commit is contained in:
Jakub Zych
2026-10-06 20:35:10 +02:00
parent 8e22e5f25b
commit 90b87d6363
2 changed files with 202 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ package cabana
import (
"context"
"fmt"
"reflect"
"gorm.io/gorm"
)
@@ -217,16 +218,29 @@ func hydrateMLRecord(ctx context.Context, tx *gorm.DB, cc *CompiledController, w
return nil
}
// hostScalarString renders a projected host column as the default-locale text.
// Nullable pointer columns (*string, *int, **string, ...) are dereferenced at
// any depth and a nil pointer becomes the empty string, so neither "<nil>" nor
// a pointer address reaches the admin form. String kinds return their raw text
// (bypassing any String method), byte slices are decoded as text and every
// other kind is formatted from the dereferenced value.
func hostScalarString(v any) string {
if v == nil {
return ""
}
switch t := v.(type) {
case string:
return t
case []byte:
return string(t)
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Pointer {
if rv.IsNil() {
return ""
}
rv = rv.Elem()
}
switch {
case rv.Kind() == reflect.String:
return rv.String()
case rv.Kind() == reflect.Slice && rv.Type().Elem().Kind() == reflect.Uint8:
return string(rv.Bytes())
default:
return fmt.Sprint(t)
return fmt.Sprint(rv.Interface())
}
}