From 1294ec44181edc05fa947fc69c1c22308c0fb8a2 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 24 Jun 2026 12:11:47 +0200 Subject: [PATCH] =?UTF-8?q?feat(go-services):=20inventory-go=20search=20?= =?UTF-8?q?=E2=80=94=20object=5Fclass=5Fname=20(exact,=20gem=20context)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loads the ObjectClass enum map and adds object_class_name via translate_object_class, including the context-aware Gem(11) classification (crystal/mana stone/gem/aetheria by item name, using the original name before the material prefix). The rare aetheria-by-IntValues path is documented as not reproduced (needs original_json). Validated vs Python: 0 mismatches over 600 rows (3 queries incl. a 'crystal' text search that exercises the gem context) for object_class_name, name, material_name, item_set_name, value. Co-Authored-By: Claude Opus 4.8 --- go-services/inventory-go/main.go | 40 +++++++++++++++++++----------- go-services/inventory-go/search.go | 32 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/go-services/inventory-go/main.go b/go-services/inventory-go/main.go index 7a227f80..e5935a54 100644 --- a/go-services/inventory-go/main.go +++ b/go-services/inventory-go/main.go @@ -15,6 +15,7 @@ import ( "net/http" "os" "os/signal" + "strconv" "syscall" "time" @@ -26,6 +27,7 @@ var buildVersion = "dev" type Server struct { pool *pgxpool.Pool attributeSets map[string]string // AttributeSetInfo: set-id -> set name + objectClasses map[int]string // ObjectClass: id -> name log *slog.Logger } @@ -43,13 +45,14 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() - srv := &Server{log: logger, attributeSets: map[string]string{}} + srv := &Server{log: logger, attributeSets: map[string]string{}, objectClasses: map[int]string{}} - if sets, err := loadAttributeSets(enumPath); err != nil { - logger.Warn("could not load enum AttributeSetInfo (set names will be unknown)", "err", err, "path", enumPath) + if sets, classes, err := loadEnums(enumPath); err != nil { + logger.Warn("could not load enum DB (set/class names will be unknown)", "err", err, "path", enumPath) } else { srv.attributeSets = sets - logger.Info("loaded enum AttributeSetInfo", "sets", len(sets)) + srv.objectClasses = classes + logger.Info("loaded enum DB", "sets", len(sets), "object_classes", len(classes)) } if dsn == "" { @@ -159,13 +162,13 @@ func (s *Server) dbErr(w http.ResponseWriter, where string, err error) { writeJSON(w, http.StatusInternalServerError, map[string]any{"detail": "Internal server error"}) } -// loadAttributeSets reads the comprehensive enum DB and extracts AttributeSetInfo -// (set-id -> name), mirroring load_comprehensive_enums (dictionaries first, then -// enums). Only the slice needed for /sets/list is decoded. -func loadAttributeSets(path string) (map[string]string, error) { +// loadEnums reads the comprehensive enum DB and extracts AttributeSetInfo +// (set-id -> name) and ObjectClass (id -> name), mirroring +// load_comprehensive_enums (dictionaries first, then enums). +func loadEnums(path string) (sets map[string]string, classes map[int]string, err error) { b, err := os.ReadFile(path) if err != nil { - return nil, err + return nil, nil, err } var db struct { Dictionaries map[string]struct { @@ -174,17 +177,26 @@ func loadAttributeSets(path string) (map[string]string, error) { Enums map[string]struct { Values map[string]string `json:"values"` } `json:"enums"` + ObjectClasses struct { + Values map[string]string `json:"values"` + } `json:"object_classes"` } if err := json.Unmarshal(b, &db); err != nil { - return nil, err + return nil, nil, err } + sets = map[string]string{} if d, ok := db.Dictionaries["AttributeSetInfo"]; ok && len(d.Values) > 0 { - return d.Values, nil + sets = d.Values + } else if e, ok := db.Enums["AttributeSetInfo"]; ok { + sets = e.Values } - if e, ok := db.Enums["AttributeSetInfo"]; ok { - return e.Values, nil + classes = map[int]string{} + for k, v := range db.ObjectClasses.Values { + if n, err := strconv.Atoi(k); err == nil { + classes[n] = v + } } - return map[string]string{}, nil + return sets, classes, nil } func envOr(key, def string) string { diff --git a/go-services/inventory-go/search.go b/go-services/inventory-go/search.go index 68f5ab8d..847ff782 100644 --- a/go-services/inventory-go/search.go +++ b/go-services/inventory-go/search.go @@ -358,6 +358,12 @@ func (s *Server) enrichRows(rows []map[string]any) []map[string]any { row["last_updated"] = pyISO(t) } + // object_class_name — gem(11) context uses the ORIGINAL item name, so + // compute before the material prefix below (translate_object_class). + if oc := int(toInt64(row["object_class"])); oc != 0 { + row["object_class_name"] = s.translateObjectClass(oc, toStr(row["name"])) + } + // material_name + material prefix on name (material is already a // translated string in the DB; enrich_db_item:2371-2602). if mat := toStr(row["material"]); mat != "" { @@ -383,6 +389,32 @@ func (s *Server) enrichRows(rows []map[string]any) []map[string]any { return out } +// translateObjectClass mirrors translate_object_class: ObjectClass enum lookup, +// with the context-aware Gem(11) classification by item name. The aetheria-by- +// IntValues path (for gem-class items not named crystal/gem/mana stone) is not +// reproduced here (it needs original_json) — a documented rare edge. +func (s *Server) translateObjectClass(oc int, name string) string { + base, ok := s.objectClasses[oc] + if !ok { + return fmt.Sprintf("Unknown_ObjectClass_%d", oc) + } + if base == "Gem" && oc == 11 { + n := strings.ToLower(name) + switch { + case strings.Contains(n, "mana stone"): + return "Mana Stone" + case strings.Contains(n, "crystal"): + return "Crystal" + case strings.Contains(n, "gem"): + return "Gem" + case strings.Contains(n, "aetheria"): + return "Aetheria" + } + return "Gem" + } + return base +} + // translateSetID mirrors translate_equipment_set_id (AttributeSetInfo lookup, // ID-string fallback). func (s *Server) translateSetID(setID string) string {