fix(10.1): CR-01 answer a value that does not fit its column with a 422

lagoon.Fill now returns a *lagoon.FillTypeError naming the key when a
requested value cannot be stored in its column (a fraction, exponent or
overflow for an integer field, or a value of the wrong type). The admin
save path maps it to a validation_failed 422 on that field instead of a
500 CapabilityError; genuine capability failures keep the 500.
This commit is contained in:
Jakub Zych
2026-09-29 09:44:14 +02:00
parent 74e30c9878
commit e60e69745e
6 changed files with 152 additions and 4 deletions

View File

@@ -3,6 +3,7 @@ package lagoon
import (
"bytes"
"encoding/json"
"errors"
"log/slog"
"strings"
"testing"
@@ -193,3 +194,38 @@ func TestFillJSONNumber(t *testing.T) {
}
}
}
// TestFillTypeErrorNamesTheKey proves a value that does not fit its column
// comes back as a *FillTypeError carrying the requested key, so a caller can
// answer it as a validation failure on that field, while a bad model stays a
// plain error.
func TestFillTypeErrorNamesTheKey(t *testing.T) {
type numbers struct {
Year int `gorm:"column:year"`
Count uint8 `gorm:"column:count"`
Title string `gorm:"column:title"`
Price float64 `gorm:"column:price"`
}
allowed := []string{"year", "count", "title", "price"}
cases := map[string]any{
"year": json.Number("1977.5"),
"count": json.Number("1e21"),
"title": true,
"price": "cheap",
}
for key, value := range cases {
var row numbers
err := Fill(&row, allowed, map[string]any{key: value}, true)
var typed *FillTypeError
if !errors.As(err, &typed) || typed.Key != key || typed.Err == nil {
t.Fatalf("%s = %v: err = %#v, want *FillTypeError for %s", key, value, err, key)
}
if !strings.Contains(err.Error(), "lagoon: fill "+key+": ") {
t.Fatalf("%s: message = %q", key, err.Error())
}
}
var typed *FillTypeError
if err := Fill(numbers{}, allowed, map[string]any{"year": 1}, true); err == nil || errors.As(err, &typed) {
t.Fatalf("non-pointer model: err = %v, want a plain error", err)
}
}