api for health score toggle test reverse
This commit is contained in:
@@ -214,7 +214,18 @@ type Products struct {
|
||||
// The PLATFORM console ignores this: Nearle staff see every score on every
|
||||
// product, because the decision being made there is whether the data is good
|
||||
// enough to publish at all.
|
||||
Showhealthscore bool `json:"showhealthscore" gorm:"column:showhealthscore;default:true"`
|
||||
//
|
||||
// NO `default` IN THE GORM TAG, and that is not an oversight. GORM skips a
|
||||
// zero-value field whose tag names a default, so `false` was never written:
|
||||
// the INSERT omitted the column, the database default of true applied, and a
|
||||
// product imported with the score switched off came back switched on. It
|
||||
// shipped that way and was found by importing one and reading it back.
|
||||
//
|
||||
// The DEFAULT lives on the column instead, set by the migration in main.go.
|
||||
// That still covers what it is for — rows that predate the column, and any
|
||||
// INSERT that genuinely omits it — without teaching GORM to drop a
|
||||
// deliberate false on the way past.
|
||||
Showhealthscore bool `json:"showhealthscore" gorm:"column:showhealthscore"`
|
||||
|
||||
Productdesc string `json:"productdesc,omitempty"`
|
||||
Productsku string `json:"productsku,omitempty"`
|
||||
@@ -331,6 +342,19 @@ type Locationproducts struct {
|
||||
Diffpercent float64 `json:"diffpercent,omitempty"`
|
||||
Othercost float64 `json:"othercost,omitempty"`
|
||||
Approve int `json:"approve" gorm:"default:0"`
|
||||
// Whether this product's health score is shown to shoppers.
|
||||
//
|
||||
// It has to be HERE and not only on Products, because this is the struct the
|
||||
// admin catalogue reads. Without it the console received no value at all,
|
||||
// the drawer's switch rendered "on" for every product including the ones
|
||||
// that were off, and a product already hidden showed no panel and so no way
|
||||
// to turn it back on. The column was being written correctly the whole time
|
||||
// and simply never read back — which also made every "it did not save"
|
||||
// reading taken from this endpoint meaningless.
|
||||
//
|
||||
// No `omitempty`: a false has to survive the trip, and omitempty would drop
|
||||
// exactly the value this field exists to carry.
|
||||
Showhealthscore bool `json:"showhealthscore"`
|
||||
// Productstatus string `json:"productstatus" gorm:"default:available"`
|
||||
Status string `json:"status" gorm:"default:outofstock"`
|
||||
|
||||
|
||||
64
models/showHealthScoreTag_test.go
Normal file
64
models/showHealthScoreTag_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/*
|
||||
`showhealthscore` must not carry a GORM default.
|
||||
|
||||
GORM skips a zero-value field whose tag names a default — the documented
|
||||
behaviour is that a `false`, `0` or `""` is left out of the INSERT so the
|
||||
database default applies. For a boolean whose whole purpose is being set to
|
||||
false, that means the one value anybody would set it to is the one that cannot
|
||||
be written.
|
||||
|
||||
It shipped that way. A product imported with the health score switched off came
|
||||
back switched on, and it took importing one and reading it back to find out,
|
||||
because every layer above reported success: the console sent `false`, the
|
||||
request carried `false`, the handler read `false`, GORM dropped it, and the
|
||||
column default wrote `true`.
|
||||
|
||||
The DEFAULT belongs on the column, set by the migration in main.go. That covers
|
||||
rows predating the column and any INSERT that genuinely omits it, without
|
||||
teaching the ORM to discard a deliberate false on the way past.
|
||||
*/
|
||||
func TestShowHealthScoreCarriesNoGormDefault(t *testing.T) {
|
||||
field, ok := reflect.TypeFor[Products]().FieldByName("Showhealthscore")
|
||||
if !ok {
|
||||
t.Fatal("Products.Showhealthscore has moved or been renamed")
|
||||
}
|
||||
|
||||
tag := field.Tag.Get("gorm")
|
||||
if strings.Contains(strings.ToLower(tag), "default") {
|
||||
t.Fatalf(
|
||||
"gorm tag %q names a default. GORM then skips this field when it is false, "+
|
||||
"so a product whose health score is switched off is written as switched on. "+
|
||||
"The column default is set by the migration in main.go instead.",
|
||||
tag,
|
||||
)
|
||||
}
|
||||
|
||||
// The column still has to be named, since the Go field is one word and the
|
||||
// column is too but GORM's default naming would make it `show_health_score`.
|
||||
if !strings.Contains(tag, "column:showhealthscore") {
|
||||
t.Errorf("gorm tag %q no longer names the column", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowHealthScoreIsAPlainBoolOnTheWire(t *testing.T) {
|
||||
// Not a pointer, and not `omitempty`. Every product says what it is: the
|
||||
// console reads it to set the switch, and an absent key would be
|
||||
// indistinguishable from false on a screen that has to show one or the
|
||||
// other.
|
||||
field, _ := reflect.TypeFor[Products]().FieldByName("Showhealthscore")
|
||||
|
||||
if field.Type.Kind() != reflect.Bool {
|
||||
t.Errorf("Showhealthscore is %s, want bool", field.Type.Kind())
|
||||
}
|
||||
if tag := field.Tag.Get("json"); tag != "showhealthscore" {
|
||||
t.Errorf("json tag is %q — an omitempty here would hide every `false`", tag)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user