Raw SQL and Macro Interpolation
Relevant source files
The following files were used as context for generating this wiki page:
SeaQuery provides a powerful "escape hatch" for developers who need to write custom SQL while still benefiting from the library's dynamic parameter binding and database-specific formatting. This system is primarily exposed through the raw_query! and raw_sql! macros, as well as the underlying RawSqlQueryBuilder and inject_parameters utility.
Sources: README.md:129-130, src/lib.rs:556-560
The raw_query! Macro
The raw_query! macro, introduced in version 1.0, allows for the construction of complex SQL queries using a familiar string-based syntax enhanced with Rust variable interpolation. It supports named parameters, nested field access, and automatic expansion of arrays and tuples. This macro essentially bridges the gap between raw SQL strings and SeaQuery's internal Values management, ensuring that parameters are correctly sequenced for different database backends (e.g., $1, $2 for Postgres vs ?, ? for MySQL).
Sources: README.md:130-136, sea-query-derive/src/lib.rs:43-49
Key Interpolation Features
The macro supports several advanced interpolation patterns:
- Direct Variable Access:
{variable_name} - Nested Field Access:
{struct.field} - Array Expansion:
{..vector}expands a collection into a comma-separated list of placeholders. - Tuple Expansion:
{..(values.0:1),}handles vector-of-tuples for bulk operations like multi-row inserts.
Sources: README.md:136-174, src/lib.rs:172-210
| Feature | Syntax | Description |
|---|---|---|
| Named Parameter | {a} | Binds the Rust variable a to a SQL placeholder. |
| Array Expansion | {..d} | Expands a vector d into ($n, $n+1, ...). |
| Nested Access | {c.id} | Accesses the id field of struct c. |
| Tuple Expansion | {..(v.0:1),} | Expands tuples within a list for bulk inserts. |
Sources: README.md:136-174
Raw SQL Construction Logic
The underlying architecture for handling raw SQL fragments is managed by the RawSqlQueryBuilder. This component tracks the state of the SQL string, including the current parameter index and the specific placeholder syntax required by the target database backend.
Raw SQL Build Process
The following diagram illustrates how the RawSqlQueryBuilder processes fragments and parameters to generate a final SQL string:
The builder ensures that even when mixing raw fragments and dynamic parameters, the resulting SQL adheres to the backend's specific requirements (e.g., Postgres requires numbered placeholders like $1, while MySQL uses ?).
Sources: src/raw_sql.rs:7-54
Tuple Parameter Groups
For bulk operations, RawSqlQueryBuilder provides push_tuple_parameter_groups. This method takes a length and a tuple arity, generating the necessary parenthesized placeholder groups. For example, a length of 2 and arity of 2 would produce (?, ?), (?, ?).
Sources: src/raw_sql.rs:41-50
Parameter Injection Utility
SeaQuery provides an inject_parameters function in the prepare module. This utility is used to take a SQL string containing placeholders and a slice of Value objects, then produce a final SQL string with the parameters safely injected.
This process is technically critical because it respects operator precedence and database-specific escaping rules (e.g., Postgres E-strings for escaping single quotes).
Sources: src/prepare.rs:101-136
Backend-Specific Placeholders
Different backends require different SQL formatting. The RawSqlQueryBuilder and the raw_query! macro utilize the placeholder() method from the QueryBuilder trait to determine the correct syntax.
| Backend | Placeholder | Numbered | Example |
|---|---|---|---|
| MySQL | ? | No | WHERE id = ? |
| Postgres | $ | Yes | WHERE id = $1 |
| SQLite | ? | No | WHERE id = ? |
Sources: src/backend/query_builder.rs:10-13, src/raw_sql.rs:15-23, src/prepare.rs:163-186
Summary
The Raw SQL and Macro Interpolation system in SeaQuery provides a bridge between low-level SQL control and high-level safety. By using the raw_query! macro, developers can write SQL that looks natural while the library handles the complex task of parameter sequencing, tuple expansion, and backend-specific placeholder generation. This ensures that custom queries remain portable and secure against injection vulnerabilities.
Sources: README.md:129-140, src/raw_sql.rs:73-100