# src/dsl — Subsystem Rules
Typed query builder DSL. Entry points: `db::select()`, `db::insert_into()`, `db::update()`, `db::delete_from()`.
## Invariants
- Every builder method that returns `Self` **must** have `#[must_use]`.
- `to_sql_pg()`, `to_sql_mysql()`, `to_sql_sqlite()` must stay in sync. Adding a new clause → update all three renderers in the same commit.
- SQL rendering is pure (no I/O). Executor methods (`fetch_all`, `execute`, `stream`) are in the `#[cfg(feature = "postgres")]` impl block.
## Adding a new `Expr` variant
1. Add the variant to `expr.rs::Expr` enum.
2. Add render arm in `Expr::to_sql_pg` and `Expr::to_sql_qmark`.
3. Add a `to_literal_sql` arm (used by `.inspect()` debug output).
4. If the variant introduces a new `SqlValue` variant → also update `condition.rs`, `sqlx/pg.rs`, `sqlx/sqlite.rs`, `sqlx/mysql.rs`.
## Adding a new `Condition` variant
Same steps as `Expr` plus update `core/query.rs` builder method and all three `Condition::to_sql` branches.
## Column constants
Generated by `#[derive(Table)]` as `SCREAMING_SNAKE_CASE` via `heck::ToShoutySnakeCase`. Do not hand-write column constants.
## Lifetime trap (stream)
`SelectBuilder::stream()` cannot return a `&str` reference to a locally-rendered SQL string. Workaround: move the `String` into `futures::stream::once(async move { ... })` so the future owns it.