query!() { /* proc-macro */ }Expand description
Type-safe SQL macro that builds and executes a query with compile-time checks.
Validates table/column names, binds arguments, and executes immediately, returns awaitable anyhow::Result.
Notes:
- For INSERT/UPDATE/DELETE without
RETURNING, the output is driver-specific (generally the number of rows affected). - Input syntax highlighting is applied in IDE’s, but on documentation page it is not.
§Syntax
query!(<Driver> conn, SQL)<Driver>is optional, if omitted the driver is inferred fromconn.connis generally a connection or transaction implementingEasyExecutor, implemented for mutable versions of both, also implemented for Sqlx Executor types.
Example:
let value = 42;
let result =
query!(<Sqlite> &mut conn, SELECT OutputType From TableType where column = {value}).await?;- SQL keywords are case-insensitive.
{value}inserts an external Rust value as a bound argument.- See below for more info about the accepted SQL.
§Query forms
§SELECT
SELECT OutputType FROM TableType ... returns OutputType, a single row implementing Output.
The Output trait also covers Vec<T> and Option<T> for multiple or optional rows.
let id = 1;
let one: ExprTestData = query!(&mut conn,
SELECT ExprTestData FROM ExprTestTable WHERE ExprTestTable.id = {id}
)
.await?;
let many: Vec<ExprTestData> = query!(&mut conn,
SELECT Vec<ExprTestData> FROM ExprTestTable WHERE ExprTestTable.int_field > 0
)
.await?;
let maybe: Option<ExprTestData> = query!(&mut conn,
SELECT Option<ExprTestData> FROM ExprTestTable WHERE ExprTestTable.id < {id+1}
)
.await?;Use Table.column or OutputType.column for column references. With the
use_output_columns feature, bare column names are validated against the output type instead of the Table type.
let min_val = 10;
let results: Vec<ExprTestData> = query!(&mut conn,
SELECT Vec<ExprTestData> FROM ExprTestTable
WHERE ExprTestTable.int_field > {min_val} AND ExprTestData.bool_field = true
ORDER BY int_field DESC
)
.await?;Accepted Clauses: WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, DISTINCT
§INSERT
INSERT INTO TableType VALUES {data} inserts one value or a collection. {data} must implement Insert.
let data = ExprTestData {
int_field: 42,
str_field: "ready".to_string(),
bool_field: true,
nullable_field: None,
};
query!(&mut conn, INSERT INTO ExprTestTable VALUES {data}).await?;Use RETURNING OutputType to return inserted data, OutputType needs to implement Output.
let data = ExprTestData {
int_field: 7,
str_field: "added".to_string(),
bool_field: false,
nullable_field: None,
};
let inserted: ExprTestData = query!(&mut conn,
INSERT INTO ExprTestTable VALUES {data} RETURNING ExprTestData
)
.await?;§UPDATE
UPDATE TableType SET {update} uses a struct implementing Update, or
SET field = value for inline updates.
let id = 1;
let updated = ExprTestData {
int_field: 5,
str_field: "updated".to_string(),
bool_field: false,
nullable_field: None,
};
query!(&mut conn,
UPDATE ExprTestTable SET {updated} WHERE id = {id}
)
.await?;let id = 1;
query!(&mut conn,
UPDATE ExprTestTable SET str_field = "inline", bool_field = false WHERE ExprTestTable.id = {id}
)
.await?;Use RETURNING OutputType to return rows, OutputType needs to implement Output.
let bool_value = false;
let updated: Vec<ExprTestData> = query!(&mut conn,
UPDATE ExprTestTable SET bool_field = {bool_value}
WHERE ExprTestTable.id > 1
RETURNING Vec<ExprTestData>
)
.await?;Accepted Clauses: WHERE, RETURNING
§DELETE
DELETE FROM TableType ... removes rows.
query!(&mut conn, DELETE FROM ExprTestTable WHERE ExprTestTable.id = 1).await?;Use RETURNING OutputType to return rows, OutputType needs to implement Output
let removed: Option<ExprTestData> = query!(&mut conn,
DELETE FROM ExprTestTable WHERE ExprTestTable.id = 1 RETURNING Option<ExprTestData>
)
.await?;Accepted Clauses: WHERE, RETURNING
§EXISTS
EXISTS TableType WHERE ... returns bool.
let exists: bool = query!(&mut conn,
EXISTS ExprTestTable WHERE str_field IS NOT NULL And str_field = "exists"
)
.await?;Accepted Clauses: WHERE, GROUP BY, HAVING, ORDER BY, LIMIT
§Table joins
Use table_join! to define joins, then reference joined columns with
JoinedTable.column.
table_join!(ExprWithRelated | ExprTestTable INNER JOIN RelatedTestTable ON ExprTestTable.id = RelatedTestTable.parent_id);
#[derive(Output)]
#[sql(table = ExprWithRelated)]
struct ExprRelatedOutput {
#[sql(field = ExprTestTable.int_field)]
int_field: i32,
#[sql(field = RelatedTestTable.data)]
data: String,
}
let parent_id = 1;
let rows: Vec<ExprRelatedOutput> = query!(&mut conn,
SELECT Vec<ExprRelatedOutput> FROM ExprWithRelated
WHERE RelatedTestTable.parent_id = {parent_id}
)
.await?;§SQL functions
Built-in functions (like COUNT, SUM, LOWER) are available, and custom ones can be
registered with custom_sql_function!.
let rows: Vec<ExprTestData> = query!(&mut conn,
SELECT Vec<ExprTestData> FROM ExprTestTable WHERE LOWER(str_field) = "hello"
)
.await?;custom_sql_function!(Len; "LENGTH"; 1);
let rows: Vec<ExprTestData> = query!(&mut conn,
SELECT Vec<ExprTestData> FROM ExprTestTable
WHERE Len(str_field) > 3
)
.await?;§IN {vec} parameter binding
IN {vec} expands placeholders at runtime. The value must implement IntoIterator and
len() (e.g., Vec<T>, &[T]). Use IN {&vec} if you need to reuse the collection.
let ids = vec![10, 30, 50];
let results: Vec<ExprTestData> = query!(&mut conn,
SELECT Vec<ExprTestData> FROM ExprTestTable
WHERE ExprTestTable.int_field IN {ids}
)
.await?;§Generic connection
*conn syntax might be needed when using &mut EasyExecutor<D> as connection
let rows: Vec<ExprTestData> =
query!(*conn, SELECT Vec<ExprTestData> FROM ExprTestTable).await?;