From 77c373c12679026ab7ee7f179e03f2f96edc8f6e Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Fri, 10 Apr 2026 19:15:35 +0200 Subject: [PATCH] Correct Null Key Suppression --- internal/topdata/convert.go | 11 +++++++++++ internal/topdata/convert_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/internal/topdata/convert.go b/internal/topdata/convert.go index bb2e01d..95c52be 100644 --- a/internal/topdata/convert.go +++ b/internal/topdata/convert.go @@ -453,6 +453,17 @@ func convertedRowKeyCandidates(row map[string]any, preferred []string) []string fields := preferred if len(fields) == 0 { fields = []string{"LABEL", "Label", "Name"} + } else { + for _, field := range fields { + value, ok := row[field] + if !ok { + return nil + } + text := strings.TrimSpace(format2DAValue(value)) + if text == "" || text == nullValue { + return nil + } + } } values := make([]string, 0, len(fields)) seen := map[string]struct{}{} diff --git a/internal/topdata/convert_test.go b/internal/topdata/convert_test.go index 9ce0a17..9befb4e 100644 --- a/internal/topdata/convert_test.go +++ b/internal/topdata/convert_test.go @@ -177,6 +177,31 @@ func TestRunConvertCommand2DAToJSONInfersOutputDatasetKeysFromConfig(t *testing. } } +func TestConvert2DAToJSONSkipsConfiguredKeysWhenAnyKeyFieldIsNull(t *testing.T) { + result, err := convert2DAToJSON(parsed2DA{ + Columns: []string{"LABEL", "RESREF", "STRREF"}, + Rows: []map[string]any{ + {"id": 309, "LABEL": "Unused", "RESREF": "unused", "STRREF": 1}, + {"id": 310, "LABEL": nullValue, "RESREF": "unused", "STRREF": 2}, + }, + }, "topdata/data/soundset/base.json", convertOptions{ + Namespace: "soundset", + KeyFields: []string{"RESREF", "LABEL"}, + CollisionMode: "error", + }) + if err != nil { + t.Fatalf("convert2DAToJSON failed: %v", err) + } + + rows := result["rows"].([]map[string]any) + if got := rows[0]["key"]; got != "soundset:unused" { + t.Fatalf("expected first row key to use the primary configured key field, got %#v", got) + } + if _, ok := rows[1]["key"]; ok { + t.Fatalf("expected second row to remain unkeyed when one configured key field is null, got %#v", rows[1]["key"]) + } +} + func TestRunConvertCommandFailsOnUnkeyedRows(t *testing.T) { root := testProjectRoot(t) writeFile(t, filepath.Join(root, "nwn-tool.json"), `{