mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-05-01 17:24:57 +00:00
236 lines
6.5 KiB
Lua
236 lines
6.5 KiB
Lua
-- Export utilities for data tables
|
|
-- Provides CSV and JSON export functionality
|
|
|
|
---@class Export
|
|
local M = {}
|
|
|
|
---@class ExportOptions
|
|
---@field includeHeaders boolean Include column headers in export
|
|
---@field columns string[]|nil Specific columns to export (nil = all)
|
|
---@field delimiter string CSV delimiter (default: ",")
|
|
---@field lineEnding string Line ending (default: "\n")
|
|
|
|
---Escape a value for CSV
|
|
---@param value any Value to escape
|
|
---@return string Escaped CSV string
|
|
function M.escapeCsv(value)
|
|
if value == nil then
|
|
return ""
|
|
end
|
|
|
|
local str = tostring(value)
|
|
|
|
-- Check if escaping is needed
|
|
if string.find(str, '[,"\r\n]') then
|
|
-- Escape double quotes by doubling them
|
|
str = string.gsub(str, '"', '""')
|
|
-- Wrap in double quotes
|
|
str = '"' .. str .. '"'
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
---Get column values from row data
|
|
---@param row table Row data object
|
|
---@param columns table[] Column definitions
|
|
---@param columnIds string[]|nil Specific column IDs (nil = all)
|
|
---@return string[] Array of values
|
|
function M.getRowValues(row, columns, columnIds)
|
|
local values = {}
|
|
|
|
if columnIds then
|
|
-- Specific columns only
|
|
for _, id in ipairs(columnIds) do
|
|
table.insert(values, row[id])
|
|
end
|
|
else
|
|
-- All columns
|
|
for _, col in ipairs(columns) do
|
|
if col.type ~= "actions" then
|
|
table.insert(values, row[col.id])
|
|
end
|
|
end
|
|
end
|
|
|
|
return values
|
|
end
|
|
|
|
---Get column labels for headers
|
|
---@param columns table[] Column definitions
|
|
---@param columnIds string[]|nil Specific column IDs (nil = all)
|
|
---@return string[] Array of labels
|
|
function M.getColumnLabels(columns, columnIds)
|
|
local labels = {}
|
|
|
|
if columnIds then
|
|
-- Specific columns only
|
|
for _, id in ipairs(columnIds) do
|
|
for _, col in ipairs(columns) do
|
|
if col.id == id then
|
|
table.insert(labels, col.label or col.id)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
else
|
|
-- All columns (except actions)
|
|
for _, col in ipairs(columns) do
|
|
if col.type ~= "actions" then
|
|
table.insert(labels, col.label or col.id)
|
|
end
|
|
end
|
|
end
|
|
|
|
return labels
|
|
end
|
|
|
|
---Export data to CSV format
|
|
---@param data table[] Array of row data objects
|
|
---@param columns table[] Column definitions
|
|
---@param options? ExportOptions Export options
|
|
---@return string CSV formatted string
|
|
function M.exportToCsv(data, columns, options)
|
|
options = options or {}
|
|
local includeHeaders = options.includeHeaders ~= false
|
|
local columnIds = options.columns
|
|
local delimiter = options.delimiter or ","
|
|
local lineEnding = options.lineEnding or "\n"
|
|
|
|
local lines = {}
|
|
|
|
-- Add header row
|
|
if includeHeaders then
|
|
local headers = M.getColumnLabels(columns, columnIds)
|
|
local escapedHeaders = {}
|
|
for _, h in ipairs(headers) do
|
|
table.insert(escapedHeaders, M.escapeCsv(h))
|
|
end
|
|
table.insert(lines, table.concat(escapedHeaders, delimiter))
|
|
end
|
|
|
|
-- Add data rows
|
|
for _, row in ipairs(data) do
|
|
local values = M.getRowValues(row, columns, columnIds)
|
|
local escapedValues = {}
|
|
for _, v in ipairs(values) do
|
|
table.insert(escapedValues, M.escapeCsv(v))
|
|
end
|
|
table.insert(lines, table.concat(escapedValues, delimiter))
|
|
end
|
|
|
|
return table.concat(lines, lineEnding)
|
|
end
|
|
|
|
---Serialize a value to JSON
|
|
---@param value any Value to serialize
|
|
---@return string JSON string
|
|
function M.jsonEncode(value)
|
|
local t = type(value)
|
|
|
|
if value == nil then
|
|
return "null"
|
|
elseif t == "boolean" then
|
|
return value and "true" or "false"
|
|
elseif t == "number" then
|
|
return tostring(value)
|
|
elseif t == "string" then
|
|
-- Escape special characters
|
|
local escaped = value
|
|
escaped = string.gsub(escaped, '\\', '\\\\')
|
|
escaped = string.gsub(escaped, '"', '\\"')
|
|
escaped = string.gsub(escaped, '\n', '\\n')
|
|
escaped = string.gsub(escaped, '\r', '\\r')
|
|
escaped = string.gsub(escaped, '\t', '\\t')
|
|
return '"' .. escaped .. '"'
|
|
elseif t == "table" then
|
|
-- Check if array or object
|
|
local isArray = true
|
|
local maxIndex = 0
|
|
for k, _ in pairs(value) do
|
|
if type(k) ~= "number" or k < 1 or k ~= math.floor(k) then
|
|
isArray = false
|
|
break
|
|
end
|
|
if k > maxIndex then maxIndex = k end
|
|
end
|
|
isArray = isArray and maxIndex == #value
|
|
|
|
if isArray then
|
|
local items = {}
|
|
for _, v in ipairs(value) do
|
|
table.insert(items, M.jsonEncode(v))
|
|
end
|
|
return "[" .. table.concat(items, ",") .. "]"
|
|
else
|
|
local items = {}
|
|
for k, v in pairs(value) do
|
|
table.insert(items, M.jsonEncode(tostring(k)) .. ":" .. M.jsonEncode(v))
|
|
end
|
|
return "{" .. table.concat(items, ",") .. "}"
|
|
end
|
|
end
|
|
|
|
return "null"
|
|
end
|
|
|
|
---Export data to JSON format
|
|
---@param data table[] Array of row data objects
|
|
---@param columns? table[] Column definitions (optional, for column filtering)
|
|
---@param columnIds? string[] Specific columns to export (nil = all)
|
|
---@return string JSON formatted string
|
|
function M.exportToJson(data, columns, columnIds)
|
|
local result
|
|
|
|
if columns and columnIds then
|
|
-- Export only specified columns
|
|
result = {}
|
|
for _, row in ipairs(data) do
|
|
local filtered = {}
|
|
for _, id in ipairs(columnIds) do
|
|
filtered[id] = row[id]
|
|
end
|
|
table.insert(result, filtered)
|
|
end
|
|
else
|
|
result = data
|
|
end
|
|
|
|
return M.jsonEncode(result)
|
|
end
|
|
|
|
---Create a download-ready export object
|
|
---@param content string Export content
|
|
---@param filename string Suggested filename
|
|
---@param mimeType string MIME type
|
|
---@return table Export object with content, filename, mimeType
|
|
function M.createExport(content, filename, mimeType)
|
|
return {
|
|
content = content,
|
|
filename = filename,
|
|
mimeType = mimeType
|
|
}
|
|
end
|
|
|
|
---Export to CSV with download metadata
|
|
---@param data table[] Array of row data objects
|
|
---@param columns table[] Column definitions
|
|
---@param filename? string Suggested filename (default: "export.csv")
|
|
---@param options? ExportOptions Export options
|
|
---@return table Export object
|
|
function M.downloadCsv(data, columns, filename, options)
|
|
local csv = M.exportToCsv(data, columns, options)
|
|
return M.createExport(csv, filename or "export.csv", "text/csv")
|
|
end
|
|
|
|
---Export to JSON with download metadata
|
|
---@param data table[] Array of row data objects
|
|
---@param filename? string Suggested filename (default: "export.json")
|
|
---@return table Export object
|
|
function M.downloadJson(data, filename)
|
|
local json = M.exportToJson(data)
|
|
return M.createExport(json, filename or "export.json", "application/json")
|
|
end
|
|
|
|
return M
|