Summary
There is no method that combines FromRow struct-mapping with
ToSqlParam parameter binding in a single call. Today you can have one or
the other, but not both — so a parameterized query whose results you want as a
struct requires dropping to the raw Row API and mapping by hand.
Current state
Struct-mapping methods take a plain &str (no params):
fetch_one_as<T: FromRow>(&self, query: &str) — connection.rs:742 / async_connection.rs:359
fetch_all_as<T: FromRow>(&self, query: &str) — connection.rs:775 / async_connection.rs:375
stream_as<T: FromRow>(&self, query: &str) — connection.rs:840 / async_connection.rs:435
Parameter-binding methods return raw rows (no FromRow):
query_params(&self, query, params: &[&dyn ToSqlParam]) → Rowset — connection.rs:1036 / async_connection.rs:574
command_params(...) → affected-row count — connection.rs:1089 / async_connection.rs:608
So SELECT * FROM users WHERE org_id = $1 → Vec<User> isn't expressible in
one call. The workaround is query_params(...) then a manual
RowAccessor/row.get() loop — which defeats the ergonomics FromRow exists
to provide, and is exactly the pattern users reach for now that #65 broadened
ToSqlParam coverage (Numeric/Interval/JSON).
Proposed work
Add parameterized *_as variants mirroring the existing trio, on both the sync
Connection and the async AsyncConnection:
fetch_one_as_params<T: FromRow>(&self, query: &str, params: &[&dyn ToSqlParam]) -> Result<T>
fetch_all_as_params<T: FromRow>(&self, query: &str, params: &[&dyn ToSqlParam]) -> Result<Vec<T>>
stream_as_params<T: FromRow>(&self, query: &str, params: &[&dyn ToSqlParam]) -> Result<impl Iterator<Item = Result<T>>>
(async: Stream)
Implementation should be small: reuse the existing extended-query path
(prepare_typed + binary bind from query_params) to get the Rowset, then
feed each row through RowAccessor + T::from_row exactly as the current
*_as methods already do. The two halves already exist; this is plumbing them
together, not new protocol work.
Naming is open (_as_params vs _params_as vs an options struct) — pick what
reads best against the existing query_params / fetch_*_as names.
Acceptance criteria
Context
Surfaced while reviewing FromRow coverage after #65. The mapping layer
(FromRow + #[derive(FromRow)]) and the binding layer (ToSqlParam) are
both complete individually; this is the missing intersection.
Summary
There is no method that combines
FromRowstruct-mapping withToSqlParamparameter binding in a single call. Today you can have one orthe other, but not both — so a parameterized query whose results you want as a
struct requires dropping to the raw
RowAPI and mapping by hand.Current state
Struct-mapping methods take a plain
&str(no params):fetch_one_as<T: FromRow>(&self, query: &str)—connection.rs:742/async_connection.rs:359fetch_all_as<T: FromRow>(&self, query: &str)—connection.rs:775/async_connection.rs:375stream_as<T: FromRow>(&self, query: &str)—connection.rs:840/async_connection.rs:435Parameter-binding methods return raw rows (no
FromRow):query_params(&self, query, params: &[&dyn ToSqlParam])→Rowset—connection.rs:1036/async_connection.rs:574command_params(...)→ affected-row count —connection.rs:1089/async_connection.rs:608So
SELECT * FROM users WHERE org_id = $1→Vec<User>isn't expressible inone call. The workaround is
query_params(...)then a manualRowAccessor/row.get()loop — which defeats the ergonomicsFromRowexiststo provide, and is exactly the pattern users reach for now that #65 broadened
ToSqlParamcoverage (Numeric/Interval/JSON).Proposed work
Add parameterized
*_asvariants mirroring the existing trio, on both the syncConnectionand the asyncAsyncConnection:fetch_one_as_params<T: FromRow>(&self, query: &str, params: &[&dyn ToSqlParam]) -> Result<T>fetch_all_as_params<T: FromRow>(&self, query: &str, params: &[&dyn ToSqlParam]) -> Result<Vec<T>>stream_as_params<T: FromRow>(&self, query: &str, params: &[&dyn ToSqlParam]) -> Result<impl Iterator<Item = Result<T>>>(async:
Stream)Implementation should be small: reuse the existing extended-query path
(
prepare_typed+ binary bind fromquery_params) to get theRowset, thenfeed each row through
RowAccessor+T::from_rowexactly as the current*_asmethods already do. The two halves already exist; this is plumbing themtogether, not new protocol work.
Naming is open (
_as_paramsvs_params_asvs an options struct) — pick whatreads best against the existing
query_params/fetch_*_asnames.Acceptance criteria
ToSqlParamvalue,mapped into a
#[derive(FromRow)]struct, asserting the values.FromRowandToSqlParammodule docscross-reference the new methods.
Context
Surfaced while reviewing FromRow coverage after #65. The mapping layer
(
FromRow+#[derive(FromRow)]) and the binding layer (ToSqlParam) areboth complete individually; this is the missing intersection.