MetricReader is text-IO-first today: delimited rows in, validated metrics out. For metrics that already live in a DB or in Parquet/Arrow, going through a TSV intermediary is awkward. DuckDB queries any of CSV/Parquet/Arrow/JSON/SQLite/Postgres/S3-hosted files and yields rows as dicts — exactly the shape Metric.model_validate wants.
Proposal: add a MetricReader.from_sql(metric_class, query, *, connection) classmethod (DuckDB connection or relation) that runs the query, iterates rows as dict[str, Any], and validates each through the supplied Metric subclass.
Open questions:
- Scope: DuckDB-only (cleanest row→dict story) vs a generic DB-API 2.0 cursor adapter (column-name resolution becomes the caller's problem).
- Dependency shape: optional extra (
fgmetric[duckdb]), matching the remote-files pattern.
- Name:
from_sql, from_duckdb, from_query?
- Headerless mode +
fieldnames doesn't apply here — SQL columns are already named. Worth calling out that the SQL path is header-only by construction.
MetricReaderis text-IO-first today: delimited rows in, validated metrics out. For metrics that already live in a DB or in Parquet/Arrow, going through a TSV intermediary is awkward. DuckDB queries any of CSV/Parquet/Arrow/JSON/SQLite/Postgres/S3-hosted files and yields rows as dicts — exactly the shapeMetric.model_validatewants.Proposal: add a
MetricReader.from_sql(metric_class, query, *, connection)classmethod (DuckDB connection or relation) that runs the query, iterates rows asdict[str, Any], and validates each through the supplied Metric subclass.Open questions:
fgmetric[duckdb]), matching the remote-files pattern.from_sql,from_duckdb,from_query?fieldnamesdoesn't apply here — SQL columns are already named. Worth calling out that the SQL path is header-only by construction.