feat: script export — multi-statement follow-up to streaming Export (#99)#104
Merged
Conversation
) Export on a multi-statement script now opens a directory picker and runs each statement sequentially into its own file (row-returning) or logs it for effect, sharing one ClickHouse session across the script. A live log pane (metadata only, never the exported rows) shows status/file/bytes/ elapsed per statement; Cancel stops the active statement and skips the rest while keeping completed files. Closes #99 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EfEGDNjwJcudck7Dzm82Pu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Follow-up to #87. The editor's Export button only handled a single query — running Export on a multi-statement script silently no-oped/blocked. This adds a dedicated script-export flow:
exportEntry()dispatches by statement count: one statement keeps Export button: stream full query result to disk as TSV (File System Access API, uncapped, bypasses the grid) #87's single-fileexportDirectpath; more than one opensexportScriptEntry.showDirectoryPicker, requested before any auth/config await — transient activation) is skipped entirely when the script has no row-returning statements.exportScriptruns statements sequentially in one shared ClickHouse HTTP session (sessionParamsFor), soSET/CREATE TEMPORARY TABLEstate carries across statements. Row-returning statements stream uncapped to their own file (NNN-slug.ext, via the new purescriptExportNamehelper); non-row statements run for effect and log OK/error with no file.tab.result.scriptExport— metadata only, never the exported rows, so a multi-million-row script export stays flat in memory. A newresults.jsbranch (buildToolbar+renderScriptExportGrid) renders it live:#/Statement/Type/Status/File/Bytes/Time, ticked every 200ms.KILL QUERY, marks the rest Skipped, and keeps already-completed files. Stop-on-first-failure, no retry — a partially-written file shouldn't be silently re-attempted.ch.exportQuery(from Export button: stream full query result to disk as TSV (File System Access API, uncapped, bypasses the grid) #87) already forwardedparams, sosession_idrides alongsidequery_idwith no net.js change beyond a regression test.Two re-entrancy/leak bugs found and fixed during self-review before this PR:
exportScriptEntrynow flipsapp.state.exportingbefore its own directory-picker/auth await (mirroringexportDirect, closing a double-click race); the live-rendersetIntervalnow starts insideexportScript'stryso a throw can't leak it.Manually verified end-to-end in a real Chromium browser (real editor, real button clicks, injected fetch/picker seams) — single-statement still uses the save-file picker, a 3-statement script opens the directory picker and produces exactly the expected per-statement file/log output, and Cancel mid-export correctly marks Cancelled/Skipped while keeping the completed file.
Closes #99
Checklist
npm testpasses (the per-file coverage gate is non-negotiable)npm run buildsucceeds (single-filedist/sql.html)src/core/, network insrc/net/(injected fetch), DOM insrc/ui/CHANGELOG.md([Unreleased]) updated🤖 Generated with Claude Code
https://claude.ai/code/session_01EfEGDNjwJcudck7Dzm82Pu