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
|
// 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
|
// product, because the decision being made there is whether the data is good
|
||||||
// enough to publish at all.
|
// 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"`
|
Productdesc string `json:"productdesc,omitempty"`
|
||||||
Productsku string `json:"productsku,omitempty"`
|
Productsku string `json:"productsku,omitempty"`
|
||||||
@@ -331,6 +342,19 @@ type Locationproducts struct {
|
|||||||
Diffpercent float64 `json:"diffpercent,omitempty"`
|
Diffpercent float64 `json:"diffpercent,omitempty"`
|
||||||
Othercost float64 `json:"othercost,omitempty"`
|
Othercost float64 `json:"othercost,omitempty"`
|
||||||
Approve int `json:"approve" gorm:"default:0"`
|
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"`
|
// Productstatus string `json:"productstatus" gorm:"default:available"`
|
||||||
Status string `json:"status" gorm:"default:outofstock"`
|
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