Skip to content

feat(exec): add streaming, pagination, and serialization for query execution#360

Open
joewiz wants to merge 5 commits intoeXist-db:mainfrom
joewiz:feature/exec-streaming
Open

feat(exec): add streaming, pagination, and serialization for query execution#360
joewiz wants to merge 5 commits intoeXist-db:mainfrom
joewiz:feature/exec-streaming

Conversation

@joewiz
Copy link
Copy Markdown
Member

@joewiz joewiz commented Mar 22, 2026

Summary

Overhauls the exec command with three new execution capabilities and rich serialization control.

Execution modes

  • Cursor-based pagination (new default) — uses lsp:eval/lsp:fetch via REST API; interactive TTY sessions prompt between pages, piped output fetches all pages automatically. Falls back to XML-RPC if the lsp module is unavailable.
  • WebSocket streaming (--stream) — connects to /exist/ws/eval, prints results as they arrive, Ctrl+C sends cancel.
  • XML-RPC (fallback) — used when --bind variables are provided or cursor API is unavailable.

New flags

Flag Description
--stream / -s Stream results via WebSocket
--timing / -t Show execution timing breakdown
--page-size <n> Results per page in cursor mode (default: 20)
--output / -o Output format: text (default) or json
--method Serialization method: xml, json, text, html, adaptive
--indent / --no-indent Enable or suppress indented output
--highlight Wrap full-text matches in highlight elements

Sample commands

# Default: paginated output (cursor-based, 20 results/page)
xst exec "for $i in 1 to 100 return $i"

# Explicit page size
xst exec --page-size 50 "for $i in 1 to 1000 return $i"

# Stream all results via WebSocket
xst exec --stream "for $i in 1 to 100000 return $i"

# Show timing breakdown
xst exec --timing "1 + 1"
# 2
# Parse: 1ms | Compile: 2ms | Eval: 0ms | Total: 3ms

# JSON output format (collects all pages)
xst exec --output json "map { 'key': 'value' }"

# Serialization: JSON method
xst exec --method json "map { 'key': 'value' }"

# Serialization: XML without indentation
xst exec --method xml --no-indent "doc('/db/data.xml')"

# Serialization: raw text values
xst exec --method text "string-join(1 to 5, ',')"

# Serialization: full-text highlights
xst exec --highlight "collection('/db/shakespeare')//SPEECH[ft:query(., 'love')]"

# Compact output (no indent)
xst exec --no-indent "for $i in 1 to 5 return <item>{$i}</item>"

# Stream with timing
xst exec --stream --timing "for $i in 1 to 10 return $i"

# Variable bindings (uses XML-RPC fallback)
xst exec -b '{"a":1}' '$a+$a'

Dependencies

Requires the server-side WebSocket eval endpoint from eXist-db/exist#6145 for --stream to function. Cursor-based pagination requires the lsp XQuery module; falls back to XML-RPC automatically if unavailable. --timing without --stream works against any existing eXist-db instance.

Note: CI is expected to fail until eXist-db/exist#6145 is merged into develop.

Test plan

  • xst exec "1+1" — uses cursor API, falls back to XML-RPC
  • xst exec --timing "1+1" — prints result + timing to stderr
  • xst exec --stream "for $i in 1 to 10 return $i" — streams items via WebSocket
  • xst exec --stream --timing "1+1" — streams + shows granular timing
  • xst exec --page-size 50 "for $i in 1 to 1000 return $i" — paginated output with custom page size
  • xst exec --output json "map { 'key': 'value' }" — JSON-formatted output
  • xst exec --method text 'string-join(("a","b","c"), ",")' — text serialization
  • xst exec --no-indent "<root><child/></root>" — suppressed indentation
  • xst exec -b '{"a":1}' '$a+$a' — variable bindings use XML-RPC path
  • Ctrl+C during --stream — sends cancel, prints summary
  • Piped output (xst exec --page-size 5 "..." | cat) fetches all pages without prompting

🤖 Generated with Claude Code

@joewiz joewiz requested a review from a team as a code owner March 22, 2026 14:59
joewiz and others added 2 commits March 22, 2026 11:26
Add streaming query execution via WebSocket to the existing exec command.
--stream connects to the /exist/ws/eval endpoint and prints results as
they arrive, with Ctrl+C cancellation support. --timing reports execution
timing in both HTTP and streaming modes.

Depends on the server-side WebSocket eval endpoint (eXist-db/exist#6145).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests argument parsing for new flags, WebSocket URL construction,
auth header encoding, and --timing integration over HTTP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@joewiz joewiz force-pushed the feature/exec-streaming branch from 59bdf2d to c574b1b Compare March 22, 2026 15:27
joewiz and others added 2 commits March 22, 2026 14:52
Use lsp:eval/lsp:fetch via REST API for paginated query results as the
default execution mode (falls back to XML-RPC if unavailable). Interactive
TTY sessions show a page prompt; piped output fetches all pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verifies that piped (non-TTY) output fetches all pages without
showing interactive pagination prompts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@joewiz joewiz changed the title feat(exec): add --stream and --timing flags feat(exec): add streaming, pagination, and timing for query execution Mar 22, 2026
Pass serialization options to lsp:fetch (cursor mode) and to the
WebSocket eval message (streaming mode). Supports xml, json, text,
html, and adaptive methods; indent yes/no; and full-text highlight.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@joewiz joewiz changed the title feat(exec): add streaming, pagination, and timing for query execution feat(exec): add streaming, pagination, and serialization for query execution Mar 22, 2026
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.

1 participant