Skip to content

[codex] add result export formats#36

Merged
tianzhou merged 1 commit into
mainfrom
feat/export-formats
Jun 26, 2026
Merged

[codex] add result export formats#36
tianzhou merged 1 commit into
mainfrom
feat/export-formats

Conversation

@tianzhou

Copy link
Copy Markdown
Contributor

Summary

  • Add a reusable result export serializer with CSV, TSV, JSON, and Markdown output formats.
  • Replace the SQL editor export button with an export menu and include the selected format in audit logging.
  • Add serializer coverage and update SQL editor, audit log, and access-control docs.

Validation

  • pnpm test tests/export.test.ts
  • pnpm exec tsc -p tsconfig.app.json --noEmit
  • pnpm exec eslint src/lib/export-csv.ts tests/export.test.ts
  • git diff --check
  • pnpm build

Note: focused linting that includes QueryResults.tsx is not a clean signal today because that file already has unrelated React compiler / hooks findings on main. The new serializer and tests lint cleanly.

Copilot AI review requested due to automatic review settings June 26, 2026 10:23
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pgconsole Ready Ready Preview, Comment Jun 26, 2026 10:23am

@mintlify

mintlify Bot commented Jun 26, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
pgconsole 🟢 Ready View Preview Jun 26, 2026, 10:26 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a reusable export serializer for query results (CSV/TSV/JSON/Markdown), updates the SQL editor UI from a single “Export to CSV” button to an export menu, and extends documentation and audit logging to reflect the selected export format.

Changes:

  • Added serializeExport() supporting CSV, TSV, JSON, and Markdown, plus EXPORT_FORMATS metadata and a generalized exportRows() download helper.
  • Updated SQL editor results toolbar to an export menu and included the chosen export format in auditExport.
  • Added focused unit tests for the serializer and updated relevant docs (SQL editor, access control, audit log).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/export.test.ts Adds unit coverage for CSV/TSV/JSON/Markdown serialization behavior.
src/lib/export-csv.ts Implements multi-format serialization and export/download plumbing, retaining exportToCsv as a convenience wrapper.
src/components/sql-editor/QueryResults.tsx Replaces the export button with a menu and logs the selected format in audit events.
docs/features/sql-editor.mdx Updates SQL editor documentation to describe multi-format export.
docs/features/database-access-control.mdx Updates the export permission UI description from button to menu.
docs/features/audit-log.mdx Documents the expanded set of possible export formats in audit logs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tianzhou tianzhou marked this pull request as ready for review June 26, 2026 10:44
@tianzhou tianzhou merged commit 5e51d3a into main Jun 26, 2026
6 checks passed
@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown

Greptile Summary

This PR extends the SQL editor's export functionality from CSV-only to a four-format menu (CSV, TSV, JSON, Markdown) by introducing a unified serializeExport function in export-csv.ts, updating the toolbar button to a dropdown menu, threading the selected format through audit logging, and updating the corresponding docs.

  • src/lib/export-csv.ts: Refactored into pure serialization helpers (serializeDelimited, serializeJson, serializeMarkdown) unified under serializeExport, with the original exportToCsv kept as a backward-compatible wrapper. JSON export handles bigint, Date, and undefined values; Markdown export escapes pipes and collapses newlines in cells.
  • src/components/sql-editor/QueryResults.tsx: Export button replaced with a Menu dropdown; handleExport now accepts a format argument and records it in the audit log. The disabled guard and useCallback dependencies are unchanged and correct.
  • tests/export.test.ts: New test file validates CSV formula-injection sanitization, TSV quoting, JSON normalization (bigint → string, undefined → null), and Markdown pipe escaping.

Confidence Score: 4/5

Safe to merge; the change is additive and well-contained with no impact on existing CSV behaviour.

The serialization logic is cleanly separated, the existing exportToCsv wrapper preserves backward compatibility, and the new formats are exercised by dedicated tests. The two notable gaps are that formatMarkdownCell does not strip bare
characters and does not escape Markdown inline-formatting tokens in cell values — both can cause cosmetic rendering issues in Markdown output but do not affect CSV/TSV/JSON or the download mechanism.

src/lib/export-csv.ts — specifically the formatMarkdownCell function and the double EXPORT_FORMATS.find() pattern.

Important Files Changed

Filename Overview
src/lib/export-csv.ts Refactors CSV export into a multi-format serializer. Minor edge cases: standalone \r not handled in formatMarkdownCell, and Markdown special chars in cell values are unescaped.
src/components/sql-editor/QueryResults.tsx Replaces Export CSV button with a Menu dropdown. Disabled guard, audit logging, and useCallback dependencies are correct. Minor: EXPORT_FORMATS.find() is called twice per export.
tests/export.test.ts New tests covering CSV, TSV, JSON, and Markdown serialization. Good coverage; null-in-JSON and standalone \r corner cases are untested.
docs/features/sql-editor.mdx Updates export description to multi-format and fixes missing trailing newline.
docs/features/audit-log.mdx Updates format field docs to list all four supported export formats.
docs/features/database-access-control.mdx Minor wording update: Export button → Export menu to match new UI.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant Menu as Export Menu
    participant Handler as handleExport
    participant Serializer as serializeExport
    participant Browser as Browser Download
    participant Audit as auditExport

    User->>Menu: Click Download button
    Menu-->>User: Show format options (CSV / TSV / JSON / Markdown)
    User->>Menu: Select format
    Menu->>Handler: handleExport(format)
    Handler->>Handler: Build filename with extension
    Handler->>Serializer: exportRows(columns, rows, filename, format)
    Serializer->>Serializer: serializeExport to format-specific serializer
    Serializer->>Browser: downloadText(content, filename, mimeType)
    Handler->>Audit: auditExport with format
    Audit-->>Handler: fire-and-forget
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant Menu as Export Menu
    participant Handler as handleExport
    participant Serializer as serializeExport
    participant Browser as Browser Download
    participant Audit as auditExport

    User->>Menu: Click Download button
    Menu-->>User: Show format options (CSV / TSV / JSON / Markdown)
    User->>Menu: Select format
    Menu->>Handler: handleExport(format)
    Handler->>Handler: Build filename with extension
    Handler->>Serializer: exportRows(columns, rows, filename, format)
    Serializer->>Serializer: serializeExport to format-specific serializer
    Serializer->>Browser: downloadText(content, filename, mimeType)
    Handler->>Audit: auditExport with format
    Audit-->>Handler: fire-and-forget
Loading

Reviews (1): Last reviewed commit: "feat: add result export formats" | Re-trigger Greptile

Comment thread src/lib/export-csv.ts
Comment on lines +58 to +64
function formatMarkdownCell(value: unknown): string {
if (value === null) return 'null'
if (value === undefined) return ''
return String(value)
.replace(/\|/g, '\\|')
.replace(/\r?\n/g, ' ')
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Standalone \r not sanitized in Markdown cells

formatMarkdownCell replaces \r?\n (CRLF or LF) with a space, but a bare carriage return (\r) without a following newline is left unchanged. Some Markdown renderers treat a bare \r as a line break, which can corrupt the table row. Consider broadening the replacement to /\r?\n|\r/g.

Comment thread src/lib/export-csv.ts
Comment on lines +58 to +64
function formatMarkdownCell(value: unknown): string {
if (value === null) return 'null'
if (value === undefined) return ''
return String(value)
.replace(/\|/g, '\\|')
.replace(/\r?\n/g, ' ')
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Markdown inline formatting characters are not escaped in cell values

formatMarkdownCell only escapes pipe characters. Cell values containing Markdown formatting tokens — *, _, `, [, ], or \ — will be interpreted as inline Markdown rather than literal text. For example, a DB value of **status** exports as bold text. If the intent is a plain-text data dump, escaping these characters would prevent unintended formatting.

Comment thread src/lib/export-csv.ts
Comment on lines +111 to +121
export function exportRows(
columns: Array<Pick<ColumnMetadata, 'name'>>,
rows: Record<string, unknown>[],
filename: string,
format: ExportFormat
) {
const exportFormat = EXPORT_FORMATS.find((item) => item.value === format)
if (!exportFormat) return

downloadText(serializeExport(columns, rows, format), filename, exportFormat.mimeType)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 EXPORT_FORMATS.find() is called twice per export

handleExport calls EXPORT_FORMATS.find() to get the file extension, then exportRows calls it again for the MIME type. Since ExportFormat is a discriminated union and always a known value at call sites, the second lookup is redundant. Consider passing the metadata object directly into exportRows to make the contract explicit.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread src/lib/export-csv.ts
Comment on lines +61 to +63
return String(value)
.replace(/\|/g, '\\|')
.replace(/\r?\n/g, ' ')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The regex replaces and but leaves bare unchanged, which some Markdown renderers treat as a line break inside the table cell.

Suggested change
return String(value)
.replace(/\|/g, '\\|')
.replace(/\r?\n/g, ' ')
return String(value)
.replace(/\|/g, '\\|')
.replace(/\r?\n|\r/g, ' ')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants