83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import type { OutputColumnMetadata } from "@internal/clickhouse";
|
|
|
|
/**
|
|
* Escape a value for CSV format.
|
|
* - Wraps in quotes if the value contains commas, quotes, or newlines
|
|
* - Escapes quotes by doubling them
|
|
*/
|
|
function escapeCSVValue(value: unknown): string {
|
|
if (value === null || value === undefined) {
|
|
return "";
|
|
}
|
|
|
|
const stringValue = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
|
|
// Check if we need to quote the value
|
|
if (
|
|
stringValue.includes(",") ||
|
|
stringValue.includes('"') ||
|
|
stringValue.includes("\n") ||
|
|
stringValue.includes("\r")
|
|
) {
|
|
// Escape quotes by doubling them and wrap in quotes
|
|
return `"${stringValue.replace(/"/g, '""')}"`;
|
|
}
|
|
|
|
return stringValue;
|
|
}
|
|
|
|
/**
|
|
* Convert query result rows to CSV format.
|
|
*
|
|
* @param rows - Array of row objects from query results
|
|
* @param columns - Column metadata describing the result columns
|
|
* @returns CSV string with header row and data rows
|
|
*/
|
|
export function rowsToCSV(
|
|
rows: Record<string, unknown>[],
|
|
columns: OutputColumnMetadata[]
|
|
): string {
|
|
if (columns.length === 0) {
|
|
return "";
|
|
}
|
|
|
|
const columnNames = columns.map((col) => col.name);
|
|
|
|
// Header row
|
|
const headerRow = columnNames.map(escapeCSVValue).join(",");
|
|
|
|
// Data rows
|
|
const dataRows = rows.map((row) =>
|
|
columnNames.map((name) => escapeCSVValue(row[name])).join(",")
|
|
);
|
|
|
|
return [headerRow, ...dataRows].join("\n");
|
|
}
|
|
|
|
/**
|
|
* Convert query result rows to JSON format.
|
|
*
|
|
* @param rows - Array of row objects from query results
|
|
* @returns Formatted JSON string
|
|
*/
|
|
export function rowsToJSON(rows: Record<string, unknown>[]): string {
|
|
return JSON.stringify(rows, null, 2);
|
|
}
|
|
|
|
/**
|
|
* Trigger a file download in the browser.
|
|
*
|
|
* @param content - The file content as a string
|
|
* @param filename - The name for the downloaded file
|
|
* @param mimeType - The MIME type of the file
|
|
*/
|
|
export function downloadFile(content: string, filename: string, mimeType: string): void {
|
|
const blob = new Blob([content], { type: mimeType });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = filename;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|