fix(#41): expose rawJson in detail response, not just storage
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -84,15 +84,26 @@ func (service *Service) List(ctx context.Context, request ListRequest) (ListResp
|
||||
return ListResponse{Items: items, Total: total, Page: request.Page, PageSize: request.PageSize}, nil
|
||||
}
|
||||
|
||||
func (service *Service) Detail(ctx context.Context, id uint64) (models.SYBProduct, error) {
|
||||
// DetailView exposes RawJSON, which the model deliberately keeps json:"-" so
|
||||
// List (and any other place a bare models.SYBProduct gets serialized) never
|
||||
// leaks the full raw payload by accident. This was caught before it shipped:
|
||||
// the Detail handler used to serialize the bare model directly, which meant
|
||||
// RawJSON — required by #41 ("原始JSON和结构化字段均可在详情查看") — was
|
||||
// silently unreachable through the API despite being stored correctly.
|
||||
type DetailView struct {
|
||||
models.SYBProduct
|
||||
RawJSON string `json:"rawJson"`
|
||||
}
|
||||
|
||||
func (service *Service) Detail(ctx context.Context, id uint64) (DetailView, error) {
|
||||
var record models.SYBProduct
|
||||
if err := service.DB.WithContext(ctx).First(&record, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return models.SYBProduct{}, notFound()
|
||||
return DetailView{}, notFound()
|
||||
}
|
||||
return models.SYBProduct{}, internalError(err)
|
||||
return DetailView{}, internalError(err)
|
||||
}
|
||||
return record, nil
|
||||
return DetailView{SYBProduct: record, RawJSON: record.RawJSON}, nil
|
||||
}
|
||||
|
||||
type ReparseRequest struct {
|
||||
|
||||
@@ -2,7 +2,9 @@ package sybimport_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go-admin/app/goauto/models"
|
||||
@@ -105,3 +107,30 @@ func TestServiceManualCorrectTrimsWhitespace(t *testing.T) {
|
||||
t.Fatalf("expected trimmed values, got %q/%q", record.TargetColor, record.TargetSize)
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test: Detail previously returned the bare model, whose RawJSON
|
||||
// field is json:"-" (to keep List from leaking it). That made the raw
|
||||
// payload silently unreachable through the API despite #41 requiring it in
|
||||
// the detail view. DetailView must carry it under a real JSON key.
|
||||
func TestServiceDetailExposesRawJSON(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), realDetailA())
|
||||
if err != nil {
|
||||
t.Fatalf("apply: %v", err)
|
||||
}
|
||||
service := sybimport.NewService(db)
|
||||
detail, err := service.Detail(context.Background(), applied.SYBProduct.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("detail: %v", err)
|
||||
}
|
||||
if detail.RawJSON == "" || detail.RawJSON == "{}" {
|
||||
t.Fatalf("expected the real raw payload, got %q", detail.RawJSON)
|
||||
}
|
||||
encoded, err := json.Marshal(detail)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(encoded), `"rawJson"`) {
|
||||
t.Fatalf("serialized detail must expose rawJson, got %s", encoded)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user