diff --git a/processor/luahelper-test.lua b/processor/luahelper-test.lua index f51f970..f52bca2 100644 --- a/processor/luahelper-test.lua +++ b/processor/luahelper-test.lua @@ -520,4 +520,57 @@ phoenix_brigade 30 0.1 shielding_basic battle_physicist_basic reinforced_battery assert(rows2.Headers[1] == rows.Headers[1], "First header should match") end) +-- Test metatable: row[1] and row.foobar return same value +test("metatable row[1] equals row.header", function() + local csv = "Id Name Value\n1 Test 100" + local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true }) + if err then error("fromCSV error: " .. err) end + assert(rows[1][1] == rows[1].Id, "row[1] should equal row.Id") + assert(rows[1][2] == rows[1].Name, "row[2] should equal row.Name") + assert(rows[1][3] == rows[1].Value, "row[3] should equal row.Value") + assert(rows[1].Id == "1", "row.Id should be '1'") + assert(rows[1][1] == "1", "row[1] should be '1'") +end) + +-- Test metatable: setting via header name updates numeric index +test("metatable set via header name", function() + local csv = "Id Name Value\n1 Test 100" + local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true }) + if err then error("fromCSV error: " .. err) end + rows[1].Id = "999" + assert(rows[1][1] == "999", "Setting row.Id should update row[1]") + assert(rows[1].Id == "999", "row.Id should be '999'") +end) + +-- Test metatable: error on unknown header assignment +test("metatable error on unknown header", function() + local csv = "Id Name Value\n1 Test 100" + local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true }) + if err then error("fromCSV error: " .. err) end + local ok, errMsg = pcall(function() + rows[1].UnknownHeader = "test" + end) + assert(ok == false, "Should error on unknown header") + assert(string.find(errMsg, "unknown header"), "Error should mention unknown header") +end) + +-- Test metatable: numeric indices still work +test("metatable numeric indices work", function() + local csv = "Id Name Value\n1 Test 100" + local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true }) + if err then error("fromCSV error: " .. err) end + rows[1][1] = "999" + assert(rows[1].Id == "999", "Setting row[1] should update row.Id") + assert(rows[1][1] == "999", "row[1] should be '999'") +end) + +-- Test metatable: numeric keys work normally +test("metatable numeric keys work", function() + local csv = "Id Name Value\n1 Test 100" + local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true }) + if err then error("fromCSV error: " .. err) end + rows[1][100] = "hundred" + assert(rows[1][100] == "hundred", "Numeric keys should work") +end) + print("\nAll tests completed!") diff --git a/processor/luahelper.lua b/processor/luahelper.lua index 1e2f260..8288938 100644 --- a/processor/luahelper.lua +++ b/processor/luahelper.lua @@ -209,17 +209,45 @@ function fromCSV(csv, options) if hasheader and #allRows > 0 then local headers = allRows[1] + local headerMap = {} + for j = 1, #headers do + if headers[j] ~= nil and headers[j] ~= "" then + local headerName = trim(headers[j]) + headerMap[headerName] = j + end + end + + local header_mt = { + headers = headerMap, + __index = function(t, key) + local mt = getmetatable(t) + if type(key) == "string" and mt.headers and mt.headers[key] then + return rawget(t, mt.headers[key]) + end + return rawget(t, key) + end, + __newindex = function(t, key, value) + local mt = getmetatable(t) + if type(key) == "string" and mt.headers then + if mt.headers[key] then + rawset(t, mt.headers[key], value) + else + error("unknown header: " .. tostring(key)) + end + else + rawset(t, key, value) + end + end + } + local rows = {} for ii = 2, #allRows do local row = {} local dataRow = allRows[ii] for j = 1, #dataRow do row[j] = dataRow[j] - if headers[j] ~= nil and headers[j] ~= "" then - local headerName = trim(headers[j]) - row[headerName] = dataRow[j] - end end + setmetatable(row, header_mt) table.insert(rows, row) end rows.Headers = headers