Derive Macro UpdateTemplate

Source
#[derive(UpdateTemplate)]
{
    // Attributes available to this derive:
    #[table]
    #[tp_update]
    #[tp_update_builder]
    #[debug_slow]
    #[db]
    #[tp_update_builder]
}
Expand description

UpdateTemplate is a derive macro designed to automatically generate record update functions based on sqlx. This macro creates update methods for the struct it is applied to, reducing repetitive code and improving the readability and maintainability of your code. It assumes that the columns in the database correspond to the fields in the struct.

§Attributes

UpdateTemplate accepts the following attributes:

  • table: Specifies the name of the table in the database (mandatory).
  • tp_update: The main configuration for generating the update function, with the following sub-attributes:
    • by: List of columns that will be the update condition, will be the function’s input (mandatory and non-empty).
    • on: List of columns that will be updated. If empty, all columns will be updated.
    • where: Additional WHERE clause with placeholder support (see Placeholder Mapping in SelectTemplate).
    • fn_name: The name of the generated function. If empty, the library will automatically generate a function name.
    • op_lock: The name of the column to apply optimistic locking (optional).
    • returning: Can be set to true for returning the full record, or specify specific columns (e.g., returning = "id, email").
    • debug_slow: Configures debug logs for the executed query:
      • If 0: Only logs the executed query.
      • If > 0: Only logs the query if the execution time exceeds the configured value (in milliseconds).
      • If not configured, no debug logs will be generated.
  • debug_slow: Configures debug logs for the executed query, with priority given to the value in tp_update.
  • db: Specifies the target database type (e.g., #[db("postgres")]).
  • tp_update_builder: Builder pattern configuration for UPDATE operations with custom WHERE conditions.

§Builder Pattern Support

The macro supports fluent builder patterns for query construction with custom WHERE conditions.

§Builder Attributes

  • tp_select_builder: Builder pattern configuration for SELECT operations
  • tp_update_builder: Builder pattern configuration for UPDATE operations
  • tp_delete_builder: Builder pattern configuration for DELETE operations

§Custom Condition Syntax

Custom conditions are defined using the following syntax:

#[tp_select_builder(
    method_name = "SQL_expression_with_placeholders"
)]

§Parameter Types

  • Auto-mapping: :field_name automatically maps to struct field types
  • Explicit types: :param$Type for custom parameter types
  • Multiple parameters: Single condition can accept multiple parameters

§Examples

#[tp_select_builder(
    with_email_domain = "email LIKE :domain$String",
    with_score_range = "score BETWEEN :min$i32 AND :max$i32",
    with_active_status = "active = :active"  // Auto-mapped to bool
)]

§Generated Methods

For each field, the builder generates:

§Field-based Methods

  • Equality: .field_name(value), .field_name_not(value)
  • Comparison: .field_name_gt(value), .field_name_gte(value), .field_name_lt(value), .field_name_lte(value)
  • String operations: .field_name_like(pattern), .field_name_start_with(prefix), .field_name_end_with(suffix)
  • Ordering: .order_by_field_asc(), .order_by_field_desc()

§Builder-specific Methods

§SELECT Builder
  • Query execution: .find_all(), .find_one(), .count(), .find_page(), .stream()
  • SQL generation: .build_sql()
§UPDATE Builder
  • SET clauses: .on_field_name(value) - specify which fields to update
  • WHERE clauses: .by_field_name(value) - specify which records to update
  • Execution: .execute() - returns number of affected rows
§DELETE Builder
  • WHERE clauses: .field_name(value) - specify which records to delete
  • Execution: .execute() - returns number of deleted rows

§Usage Examples

§SELECT Builder

let users = User::builder_select()
    .email("john@example.com")?           // Field-based condition
    .score_gte(&75)?                      // Generated comparison method
    .with_email_domain("%@company.com")?  // Custom condition
    .with_score_range(60, 90)?            // Custom condition with multiple params
    .order_by_score_desc()?               // Generated ORDER BY method
    .find_all(&pool)
    .await?;

§UPDATE Builder

let affected = User::builder_update()
    .on_email("newemail@example.com")?    // SET email = ?
    .on_active(&true)?                    // SET active = ?
    .by_id(&user_id)?                     // WHERE id = ?
    .with_high_score(80)?                 // Custom WHERE condition
    .execute(&pool)
    .await?;

§DELETE Builder

let deleted = User::builder_delete()
    .active(&false)?                      // WHERE active = false
    .with_old_accounts("2023-01-01")?     // Custom WHERE condition
    .execute(&pool)
    .await?;

§Validation

  • Table alias validation: Prevents use of table aliases (e.g., u.field) in custom conditions
  • Column validation: Ensures referenced columns exist in the struct
  • Type safety: Compile-time parameter type checking
  • SQL injection protection: Uses parameterized queries

§Performance Features

  • Compile-time optimization: SQL templates pre-generated at compile time
  • Minimal runtime overhead: Reduced format! calls and string allocations
  • Efficient parameter binding: Direct parameter binding without intermediate formatting

§Document generated by LLMs

§Example

use sqlx_template::UpdateTemplate;
use sqlx::Pool;

#[derive(UpdateTemplate, sqlx::FromRow)]
#[table("users")]
#[db("sqlite")]
#[tp_update(by = "id", op_lock = "version", fn_name = "update_user")]
#[tp_update(by = "id", on = "email, password", fn_name = "update_user_password")]
#[tp_update_builder(
    with_high_score = "score > :threshold$i32"
)]
pub struct User {
    pub id: i32,
    pub email: String,
    pub password: String,
    pub score: i32,
    pub version: i32
}

let user = User {
    id: 1,
    email: "user@example.com".to_string(),
    password: "password".to_string(),
    score: 85,
    version: 1
};

// Traditional update:
User::update_user(&user.version, &user, &pool).await?;

// Builder pattern update:
let affected = User::builder_update()
    .on_email("newemail@example.com")?
    .on_score(&95)?
    .by_id(&user_id)?
    .with_high_score(80)?
    .execute(&pool)
    .await?;

§Note

This macro relies on sqlx, so you need to add sqlx to your [dependencies] in Cargo.toml and properly configure the database connection before using the generated update methods.