feat(inventory-go): POST /admin/backfill-od recompute endpoint

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 08:04:00 +02:00
parent e07a9459cd
commit 3c0a8d9de8
2 changed files with 44 additions and 0 deletions

View file

@ -245,6 +245,49 @@ func (s *Server) handleDeleteItem(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]any{"status": "deleted", "item_id": itemID})
}
// POST /admin/backfill-od — recompute od_rating for all weapon rows from stored
// raw JSON. Internal-only (service is bound to loopback/compose). Idempotent.
func (s *Server) handleBackfillOD(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
rows, err := s.pool.Query(ctx,
`SELECT rd.item_id, rd.original_json FROM item_raw_data rd
JOIN items i ON i.id = rd.item_id
WHERE i.object_class IN (1,9,31)`)
if err != nil {
writeJSON(w, http.StatusInternalServerError, map[string]any{"error": err.Error()})
return
}
type upd struct {
id int
od float64
}
var updates []upd
scanned := 0
for rows.Next() {
var id int
var oj map[string]any
if err := rows.Scan(&id, &oj); err != nil {
rows.Close()
writeJSON(w, http.StatusInternalServerError, map[string]any{"error": err.Error()})
return
}
scanned++
if od, ok := computeOD(oj); ok {
updates = append(updates, upd{id, od})
}
}
rows.Close()
updated := 0
for _, u := range updates {
if _, err := s.pool.Exec(ctx, "UPDATE items SET od_rating=$1 WHERE id=$2", u.od, u.id); err != nil {
writeJSON(w, http.StatusInternalServerError, map[string]any{"error": err.Error(), "updated": updated})
return
}
updated++
}
writeJSON(w, http.StatusOK, map[string]any{"scanned": scanned, "updated": updated})
}
func parseNaiveTime(s string) time.Time {
if s == "" {
return time.Now().UTC()

View file

@ -100,6 +100,7 @@ func main() {
mux.HandleFunc("POST /process-inventory", srv.handleProcessInventory)
mux.HandleFunc("POST /inventory/{character_name}/item", srv.handleUpsertItem)
mux.HandleFunc("DELETE /inventory/{character_name}/item/{item_id}", srv.handleDeleteItem)
mux.HandleFunc("POST /admin/backfill-od", srv.handleBackfillOD)
// Suitbuilder (port of suitbuilder.py router, mounted at /suitbuilder).
mux.HandleFunc("POST /suitbuilder/search", srv.handleSuitSearch)
mux.HandleFunc("GET /suitbuilder/characters", srv.handleSuitCharacters)