Skip to content

feat(cli): fold substreams-sink-sql into the substreams CLI#830

Draft
GabrielCartier wants to merge 9 commits into
developfrom
feature/sink-sql-cli
Draft

feat(cli): fold substreams-sink-sql into the substreams CLI#830
GabrielCartier wants to merge 9 commits into
developfrom
feature/sink-sql-cli

Conversation

@GabrielCartier

@GabrielCartier GabrielCartier commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

substreams-sink-sql binary now lives in the CLI:

  • substreams sink database-changes {run,setup,create-user,generate-csv,inject-csv,tools} (alias db-changes) — DatabaseChanges mode (db_out + schema.sql)
  • substreams sink from-proto — relational-mappings mode (any proto output)

Two top-level commands because the two modes share almost no code (db_changes/ vs db_proto/), incompatible cursor storage.

Why

One CLI for sinks (follows noop/webhook/protojson precedent). "sql" name dropped — says nothing distinguishing, both modes target SQL DBs.

Changes vs standalone binary

  • DSN: positional arg → --dsn flag / SUBSTREAMS_SINK_DSN env, all subcommands
  • Metrics: house --prometheus-addr flag, custom --metrics-listen-addr gone
  • Bug fixes: dbt interval slept ns not seconds, zip-slip in dbt config extraction, tools cursor delete <hash> deleted ALL cursors (shadowing)
  • Deprecated alias flags dropped (--flush-interval, --on-module-hash-mistmatch typo)

Notes

  • Integration tests (Docker, postgres+clickhouse) run on ubuntu CI leg via SF_SINK_SQL_INTEGRATION_TESTS
  • Follow-ups: mode B cursor unification, from-proto double manifest read, standalone repo deprecation + MIGRATION.md
  • Naming to confirm before merge

Ported from substreams-sink-sql as-is: historical proto packages
(bare `schema`, `sf.substreams.sink.sql.service.v1`) kept for
compat with published .spkg files, hence the buf lint ignores.
Deprecated sf.substreams.sink.sql.v1 duplicate not ported; its
type URL stays accepted at the sink-config layer.
Verbatim port from github.com/streamingfast/substreams-sink-sql
under sink/sql/: db_changes (DatabaseChanges mode), db_proto
(relational from-proto mode), bytes, proto, services, and the
integration test harness.

- imports rewritten to in-repo pb/sf/substreams/sink/sql protos;
  the dead vendored options.pb.go copy was dropped
- integration tests (Docker) gated behind
  SF_SINK_SQL_INTEGRATION_TESTS, CI runners lack Docker
- testcontainers bumped to v0.43: wait.ForSQL now takes
  network.Port instead of nat.Port in helpers_test.go
Fold the substreams-sink-sql binary into the substreams CLI:
- sink sql {run,setup,create-user,generate-csv,inject-csv,tools}
  drives the DatabaseChanges mode
- sink from-proto drives the relational-mappings mode

Deliberate changes from the standalone binary:
- DSN is now --dsn (or SUBSTREAMS_SINK_SQL_DSN) instead of a
  positional arg, consistent across every subcommand
- metrics/pprof listeners are opt-in flags, no hardcoded :6060
- pgx v4 -> v5 for the inject-csv COPY path
- 'tools cursor delete <hash>' deleted all cursors in the
  standalone binary due to variable shadowing; now deletes only
  the given hash as documented
- dbt run interval slept nanoseconds instead of seconds
- reject dbt config zip entries escaping the extraction dir; the
  zip comes from untrusted .spkg files
- drop dead err param from FileDescriptorForOutputType
- port FROM_PROTO.md and point the clickhouse_table_options error
  at its real anchor (old link 404'd)
'sql' says nothing distinguishing: both sink modes target SQL
databases. New name matches the mode's proto (DatabaseChanges) and
the db_out module convention; 'db-changes' kept as alias. Review
fixes bundled:

- DSN env fallback renamed to SUBSTREAMS_SINK_DSN (shared with
  from-proto)
- pprof/delay flags honored by every subcommand, after cheap
  validation so a bad DSN fails before the delay sleep
- metrics via the standard --prometheus-addr sink flag; custom
  --metrics-listen-addr dropped
- block range arg: shared helper, errors on non-range input
  instead of silently ignoring, supports :stop and start 0
- generate-csv: final-blocks-only forced in config, flag removed
  from surface instead of silently overridden
- from-proto: dead endpoint-resolution block removed (extra
  manifest read), sink-service run only when a sink config exists
- create-user retry via derr.RetryContext (ctx-aware)
- load .substreams.env before streaming, like other sink commands
- deprecated flag aliases from the standalone binary dropped
  (--on-module-hash-mistmatch typo, --flush-interval)
- SF_SINK_SQL_INTEGRATION_TESTS set on the ubuntu leg only; macos
  runners have no Docker
- buf lint exemptions for the sink/sql protos narrowed from blanket
  ignore to the specific historical-naming rules
Examples still showed the standalone binary's positional DSN and a
DSN env var the command never reads; copy-pasting them failed with
'no DSN provided'. Also update a stale 'sink sql' panic message.
Transitive dep of the sink/sql port (via wk8/go-ordered-map);
Docker Scout blocks the image build on the HIGH out-of-bounds
read fixed in 1.1.2.
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