Why
dbfy today is "write YAML, run one-shot queries from the CLI". A
REPL closes the demo experience: download binary, dbfy repl,
exploratory queries land in 30 seconds. The pitch becomes "psql, but
for REST + logs + Excel + LDAP + Postgres + …".
Every comparable project has one — psql, duckdb, sqlite3,
clickhouse-client. Without it, dbfy feels less mature than it
actually is.
Sketch
$ dbfy repl --config examples/showcase/configs/all.yaml
dbfy v0.5.0 — connected to 3 sources, 5 tables.
Type \? for help, \q to quit.
dbfy> \d
source table rows (est)
───────────── ───────────── ──────────
github repos ~10
fleet_logs jsonl ~50000
syslog events ~5000
dbfy> SELECT count(*) FROM github.repos
;
count(*)
────────
10
(1 row, 312 ms)
dbfy> \timing on
dbfy> \explain SELECT count(*) FROM fleet_logs.jsonl WHERE level = 'ERROR';
[plan + per-source pushdown summary]
dbfy> \q
$
Meta-commands (psql-style \ prefix)
| Command |
Behaviour |
\d |
List tables (qualified name + estimated row count) |
\d <table> |
Schema for that table — typed columns, pushdown capabilities |
\explain <sql> |
Logical plan + per-source pushdown summary (already implemented in Engine::explain) |
\timing on|off |
Show ms per query |
\format table|csv|json|tsv |
Output formatter |
\source <file.sql> |
Run a SQL script |
\reload |
Re-read the YAML config from disk (live config reload, picks up new sources without restart) |
\? |
Help |
\q |
Quit (also Ctrl-D) |
Implementation
rustyline crate — canonical Rust readline replacement. Handles
line editing, history, multi-line, terminal capabilities.
- History file at
${XDG_STATE_HOME:-~/.local/state}/dbfy/history with
the standard 1000-line cap.
- Multi-line input: prompt becomes
dbfy*> (asterisk) when the
current input doesn't end in ; — matches psql convention.
- Tab completion wired to:
- keywords (
SELECT, FROM, WHERE, …)
- registered table names from
engine.registered_tables()
- column names from
arrow_schema per table after the user types
<table>. or after SELECT when DataFusion can resolve the FROM
clause
- Pretty-print: reuse the
--format=table printer from
dbfy query so REPL and one-shot output match byte-for-byte.
New file: crates/dbfy-cli/src/repl.rs. New CLI subcommand:
dbfy repl --config <path>.
Effort
| Step |
Effort |
| Loop + rustyline + history + multi-line |
0.5 d |
Meta-commands \d \q \? \timing \format \source |
0.3 d |
| Tab completion from registered schemas |
0.5 d |
\explain + \reload (live YAML reload) |
0.4 d |
4 integration tests with expectrl (script-driven) |
0.3 d |
| Total |
~2 d |
Bonus per language binding
- Python:
dbfy.repl(engine) launches the same loop inside an
IPython kernel — useful in Jupyter. ~0.3 d on top.
- Node: a wrapper that spawns the dbfy binary in REPL mode. ~0.2 d.
These can ship as v0.5.1 patches; not gating the v0.5 milestone.
Acceptance for v1
dbfy repl --config x.yaml opens an interactive prompt
- Multi-line SQL works (input not terminated until
;)
- All meta-commands above work and are documented in
\?
- Tab completion produces ≥ table names; column names is a
stretch goal
- History persists across sessions
- Ctrl-C cancels the current query (not the REPL); Ctrl-D quits
- Showcase demo: an asciicast linked from the README that walks
through 5 queries against the examples/showcase/ config
Targeted milestone: v0.5.
Why
dbfy today is "write YAML, run one-shot queries from the CLI". A
REPL closes the demo experience: download binary,
dbfy repl,exploratory queries land in 30 seconds. The pitch becomes "psql, but
for REST + logs + Excel + LDAP + Postgres + …".
Every comparable project has one —
psql,duckdb,sqlite3,clickhouse-client. Without it, dbfy feels less mature than itactually is.
Sketch
Meta-commands (psql-style
\prefix)\d\d <table>\explain <sql>Engine::explain)\timing on|off\format table|csv|json|tsv\source <file.sql>\reload\?\qImplementation
rustylinecrate — canonical Rust readline replacement. Handlesline editing, history, multi-line, terminal capabilities.
${XDG_STATE_HOME:-~/.local/state}/dbfy/historywiththe standard 1000-line cap.
dbfy*>(asterisk) when thecurrent input doesn't end in
;— matches psql convention.SELECT,FROM,WHERE, …)engine.registered_tables()arrow_schemaper table after the user types<table>.or afterSELECTwhen DataFusion can resolve the FROMclause
--format=tableprinter fromdbfy queryso REPL and one-shot output match byte-for-byte.New file:
crates/dbfy-cli/src/repl.rs. New CLI subcommand:dbfy repl --config <path>.Effort
\d \q \? \timing \format \source\explain+\reload(live YAML reload)expectrl(script-driven)Bonus per language binding
dbfy.repl(engine)launches the same loop inside anIPython kernel — useful in Jupyter. ~0.3 d on top.
These can ship as v0.5.1 patches; not gating the v0.5 milestone.
Acceptance for v1
dbfy repl --config x.yamlopens an interactive prompt;)\?stretch goal
through 5 queries against the
examples/showcase/configTargeted milestone: v0.5.