import type { DatabaseType, QueryResult } from "@/types/database"; import * as api from "@/lib/backend/api"; import { escapeCsvField, type CsvQuoteMode } from "@/lib/export/csvQuoteMode"; import type { SqlInsertMode } from "@/lib/export/sqlInsertMode"; export type ExportCellValue = string | number | boolean | null; export function formatCsv(columns: string[], rows: ExportCellValue[][], quoteMode: CsvQuoteMode = "all"): string { const header = columns.map((column) => escapeCsvField(column, quoteMode)).join(","); const body = rows.map((row) => row.map((cell) => (cell === null ? "" : escapeCsvField(String(cell), quoteMode))).join(",")).join("\n"); return `${header}\n${body}`; } // Tab-separated values with a header row, mirroring Navicat's "Text File (*.txt)" // export: fields are joined by a tab, NULL becomes empty, and a field is only // wrapped in double quotes (with " doubled) when it contains a tab, newline, // or quote - i.e. the minimum needed to round-trip the value. export function formatTsv(columns: string[], rows: ExportCellValue[][]): string { const esc = (value: ExportCellValue) => { const text = value === null ? "" : String(value); if (text.includes("\t") || text.includes("\n") || text.includes("\r") || text.includes('"')) { return `"${text.replace(/"/g, '""')}"`; } return text; }; const header = columns.map(esc).join("\t"); const body = rows.map((row) => row.map(esc).join("\t")).join("\n"); return `${header}\n${body}`; } export interface FormatSqlInsertOptions { databaseType?: DatabaseType; identifierQuote?: string; schema?: string; tableName?: string; qualifiedTableName?: string; columns: string[]; columnTypes?: Array; spatialColumns?: QueryResult["spatial_columns"]; spatialValues?: QueryResult["spatial_values"]; rows: ExportCellValue[][]; insertMode?: SqlInsertMode; excludeColumns?: string[]; } export function formatSqlInsert({ insertMode = "batch", ...options }: FormatSqlInsertOptions): Promise { return api.buildExportSqlInsert({ ...options, batchSize: insertMode === "single" ? 1 : undefined, }); }