pub struct RawQuery<D> { /* private fields */ }Expand description
A whole statement, written by hand.
The builder’s counterpart to raw: that one is a
fragment an expression accepts, this one is a statement nothing built
it. It is an ordinary Query, so the execution layer’s verbs apply
unchanged — fetch_all::<T>() maps hand-written SQL onto a struct exactly
as it maps a built statement — and it is an Expression, so it nests as
a sub-select in a built statement like any other query.
Construct one from the dialect it is written in: psql::raw_query(…),
mysql::raw_query(…), sqlite::raw_query(…) — or, when the SQL is a
literal, through that dialect’s sql! (feature macros), which writes the
values at the holes they bind to and is the form to reach for first. This
one is what sql! expands to, and what SQL arriving at run time — from a
file, a migration runner — has to use, since a macro can only read a
literal.
Placeholders are ?, on every dialect, and are rewritten into that
dialect’s own syntax as the statement renders — $1 on PostgreSQL, ?1 on
SQLite, ? on MySQL. Write \? for a literal question mark. The rule is
template’s, for the same reason: a hand-written
statement should not have to be respelled to move between engines, and a
value still never reaches the SQL text. A ? count that disagrees with the
bound arguments is an error from build, not a silently
misbound statement.
keelson does not parse what you hand it. Everything the builder guarantees — that the SQL is grammatical for the engine, that identifiers are quoted — is yours here; what you keep is the binding, the placeholder rewriting, the row mapping, the transaction, and the tracing span.
§Why this is untyped, and stays untyped
The row type is whatever you name in fetch_all::<T>(), and nothing checks
it against the schema. That is the escape hatch’s job description, not a
gap waiting to be filled.
The rejected alternative: a proc macro that types the row and the
parameters at the call site, by running keelson-gen’s own inference against
a committed schema snapshot at compile time. It would work — the analysis
is already a library, and the snapshot would need no database at build
time, which is more than sqlx’s query! manages. It was rejected because
it adds no guarantee keelson does not already offer: the same analysis,
against the same schema, producing the same types, is Layer 4
(keelson-gen’s .sql files). The only difference is where the SQL lives.
Paying a build-time SQL parser (libpg_query, in C, for PostgreSQL), a new
artifact to keep fresh, and a second answer to “typed hand-written SQL”
buys locality and nothing else.
So the line is: typed SQL goes in a .sql file (Layer 4) or comes from
a generated model (Layer 3), and both are typed because they were derived
from the schema. Untyped SQL is this, and its counterpart for
fragments. Wanting the compiler to reject a malformed query outright is a
real want, and diesel is the library that serves it.
Implementations§
Source§impl<D> RawQuery<D>
impl<D> RawQuery<D>
Sourcepub fn new(dialect: D, sql: impl Into<Cow<'static, str>>) -> RawQuery<D>
pub fn new(dialect: D, sql: impl Into<Cow<'static, str>>) -> RawQuery<D>
The statement, in dialect’s SQL. Dialect crates wrap this as
raw_query, which is how a caller should reach it.
Sourcepub fn bind_all<V>(self, values: impl IntoIterator<Item = V>) -> RawQuery<D>where
V: ToValue,
pub fn bind_all<V>(self, values: impl IntoIterator<Item = V>) -> RawQuery<D>where
V: ToValue,
Bind every value in values, in order — one ? each.
Sourcepub fn bind_expr(self, expression: impl IntoExpr) -> RawQuery<D>
pub fn bind_expr(self, expression: impl IntoExpr) -> RawQuery<D>
Splice an expression into the next ? instead of binding a value.
This is what makes WHERE id IN (?) work: the expression consumes as
many placeholder positions as it binds arguments, and the counter keeps
going from there. A quoted identifier, a sub-query and a built
statement all go in this way.
Sourcepub fn kind(self, query_type: QueryType) -> RawQuery<D>
pub fn kind(self, query_type: QueryType) -> RawQuery<D>
Declare which statement this is.
It feeds the tracing span and nothing else — the execution layer never
polices it against the SQL. The default is
QueryType::Unknown, which is the honest answer for text keelson has
not read: guessing from the leading keyword would be wrong for
WITH … INSERT, and keelson does not guess.