Skip to content

Add ClickhouseClient.queryStream for streaming results in any ClickHouse format - #8544

Open
arrudaricardo wants to merge 2 commits into
Effect-TS:mainfrom
arrudaricardo:feat/clickhouse-query-stream
Open

arrudaricardo wants to merge 2 commits into
Effect-TS:mainfrom
arrudaricardo:feat/clickhouse-query-stream

Conversation

@arrudaricardo

@arrudaricardo arrudaricardo commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Adds ClickhouseClient.queryStream, which streams a sql statement's results in any streamable ClickHouse format.

const rows = client.queryStream(sql<Event>`SELECT * FROM events WHERE day = ${day}`)
const csv = client.queryStream(sql`SELECT * FROM events`, { format: "CSV" })
const progress = client.queryStream(sql`SELECT count() FROM big`, { format: "JSONEachRowWithProgress" })
  • JSON formats emit decoded rows with transformResultNames applied. With JSONEachRowWithProgress, rows arrive alongside progress events, and the row, totals, min, and max payloads are transformed.
  • Raw formats (CSV, TSV, Parquet, …) go through exec and emit the response body untouched as Uint8Array chunks. ResultSet.stream() splits on newline bytes, which would corrupt Parquet.
  • Takes a sql statement, so interpolated values, client.param, and transformQueryNames work the same as for other queries.

Reviewing

Please review commit by commit:

  1. Refactor, no behaviour change. Extracts killQuery and toQueryParams, moves insertQuery onto the connection, and reads ClientMethod, QueryId and ClickhouseSettings with yield* instead of fiber.getRef. Existing tests pass unchanged; one test is added for the query id and settings path.
  2. The feature.

Validation

  • packages/sql/clickhouse unit tests (29), tsc -b, oxlint, dprint.
  • Checked locally against ClickHouse 26.8 in Docker with a throwaway test suite (not included):
    • multi-chunk JSON streaming
    • CSV, TSV and Parquet output
    • classification of failures during streaming, with a slow consumer
    • KILL QUERY sent on interrupt, Stream.take, and consumer failure, and not sent when fully read (checked in system.query_log)
    • the -- comment case
    • the setting precedence
    • the totals/min/max transforms
  • effect-jsdocs --check reports only existing errors in files this PR doesn't touch (ai/DecisionModel.ts, encoding/Base64*.ts).

…e context

Groundwork for streaming queries, with no behaviour change:

- Extract `killQuery` and `toQueryParams`, and move `insertQuery` onto the
  connection so every request path cancels the same way.
- Read `ClientMethod`, `QueryId`, and `ClickhouseSettings` with `yield*`
  instead of `fiber.getRef` / `Fiber.getCurrent()`.
- Describe those references as context references in their JSDoc.
- Reset the client mock between tests and cover that a custom query id and
  settings apply only to the query they are set on.
…use format

`queryStream(sql`...`, { format })` streams a statement's results in any
streamable ClickHouse format. JSON formats emit decoded rows with
`transformResultNames` applied (including the `row`, `totals`, `min`, and
`max` payloads of `JSONEachRowWithProgress` events); raw formats go through
`exec` and emit the response body untouched as `Uint8Array` chunks.

- Failures are classified like regular queries. `JSONEachRowWithProgress`
  enables `http_write_exception_in_output_format` unless it is set in the
  client config or per request, so a failure after streaming has started
  arrives as a final `{exception}` event instead of a trailer that is lost
  when a slow consumer lets the connection reset.
- Unless the response is read to the end or the server rejected the request,
  closing the stream aborts the request and kills the query. This covers
  interruption, early termination such as `Stream.take`, and downstream
  failures; closing the socket alone does not stop a query that is still
  computing.
- Raw formats strip trailing semicolons and start the appended `FORMAT`
  clause on a new line so a trailing `--` comment cannot swallow it.
@changeset-bot

changeset-bot Bot commented Sep 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: eeb0262

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 31 packages
Name Type
@effect/sql-clickhouse Patch
effect Patch
@effect/opentelemetry Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/ai-typesafe Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
arbitrary-combinators.ts 38.53 KB 38.53 KB 0.00 KB (0.00%)
basic.ts 6.88 KB 6.88 KB 0.00 KB (0.00%)
batching.ts 9.97 KB 9.97 KB 0.00 KB (0.00%)
brand.ts 6.57 KB 6.57 KB 0.00 KB (0.00%)
cache.ts 10.73 KB 10.73 KB 0.00 KB (0.00%)
config.ts 21.82 KB 21.82 KB 0.00 KB (0.00%)
differ.ts 20.96 KB 20.96 KB 0.00 KB (0.00%)
http-client.ts 22.11 KB 22.11 KB 0.00 KB (0.00%)
http-router.ts 33.45 KB 33.45 KB 0.00 KB (0.00%)
logger.ts 10.85 KB 10.85 KB 0.00 KB (0.00%)
metric.ts 8.83 KB 8.83 KB 0.00 KB (0.00%)
optic.ts 6.80 KB 6.80 KB 0.00 KB (0.00%)
pubsub.ts 15.00 KB 15.00 KB 0.00 KB (0.00%)
queue.ts 11.87 KB 11.87 KB 0.00 KB (0.00%)
schedule.ts 11.03 KB 11.03 KB 0.00 KB (0.00%)
schema-bigdecimal.ts 13.42 KB 13.42 KB 0.00 KB (0.00%)
schema-binary.ts 39.56 KB 39.56 KB 0.00 KB (0.00%)
schema-class.ts 20.66 KB 20.66 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 31.69 KB 31.69 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 26.88 KB 26.88 KB 0.00 KB (0.00%)
schema-string-transformation.ts 14.14 KB 14.14 KB 0.00 KB (0.00%)
schema-string.ts 11.70 KB 11.70 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.70 KB 15.70 KB 0.00 KB (0.00%)
schema-toArbitrary.ts 38.06 KB 38.06 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 25.12 KB 25.12 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 19.89 KB 19.89 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 20.06 KB 20.06 KB 0.00 KB (0.00%)
schema-toFormatter.ts 20.16 KB 20.16 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 24.64 KB 24.64 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 20.15 KB 20.15 KB 0.00 KB (0.00%)
schema.ts 19.87 KB 19.87 KB 0.00 KB (0.00%)
stm.ts 12.90 KB 12.90 KB 0.00 KB (0.00%)
stream.ts 9.82 KB 9.82 KB 0.00 KB (0.00%)

@arrudaricardo
arrudaricardo marked this pull request as ready for review September 26, 2026 00:52

This branch is waiting to be deployed

1 waiting deployment
fork — eeb0262d Waiting Sep 26, 2026 by arrudaricardo via approval-gate #27850
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