sqlmodel 0.4.3

SQL databases in Rust, designed to be intuitive and type-safe
# Chapter 1: Models & Field Attributes

In **SQLModel Rust**, database models are plain Rust `struct` definitions decorated with `#[derive(Model)]`. The procedural derive macro inspects field types and attributes at compile time, generating table metadata, column converters, primary key accessors, and relationship hooks without any runtime reflection.

---

## Defining a Basic Model

To declare a model, derive `Model` and specify the table name using the `#[sqlmodel(table = "...")]` container attribute:

```rust
use sqlmodel::prelude::*;

#[derive(Model, Debug, Clone, PartialEq)]
#[sqlmodel(table = "heroes")]
pub struct Hero {
    #[sqlmodel(primary_key, auto_increment)]
    pub id: Option<i64>,

    #[sqlmodel(index = "heroes_name_idx")]
    pub name: String,

    pub secret_name: String,

    #[sqlmodel(default = "18")]
    pub age: i32,

    #[sqlmodel(nullable)]
    pub team_id: Option<i64>,
}

# fn main() {
assert_eq!(Hero::TABLE_NAME, "heroes");
assert_eq!(Hero::PRIMARY_KEY, &["id"]);
assert_eq!(Hero::fields().len(), 5);
# }
```

When `table` is specified without an explicit string (e.g. `#[sqlmodel(table)]`), the table name defaults to the snake_case name of the struct.

---

## Primary Keys & Sequences

SQLModel Rust supports single-column and composite primary keys:

### Single Primary Key
A primary key is designated with `#[sqlmodel(primary_key)]`. If the primary key is generated by an auto-incrementing database sequence (such as PostgreSQL's `GENERATED ALWAYS AS IDENTITY`, MySQL's `AUTO_INCREMENT`, or SQLite's `ROWID`), mark the field as `Option<T>` with `auto_increment`:

```rust
use sqlmodel::prelude::*;

#[derive(Model, Debug, Clone)]
#[sqlmodel(table = "accounts")]
pub struct Account {
    #[sqlmodel(primary_key, auto_increment)]
    pub id: Option<i64>,
    pub username: String,
}
```

### Composite Primary Key
To declare a composite primary key, place `#[sqlmodel(primary_key)]` on multiple fields:

```rust
use sqlmodel::prelude::*;

#[derive(Model, Debug, Clone)]
#[sqlmodel(table = "user_organization_roles")]
pub struct UserOrgRole {
    #[sqlmodel(primary_key)]
    pub user_id: i64,

    #[sqlmodel(primary_key)]
    pub org_id: i64,

    pub role: String,
}

# fn main() {
assert_eq!(UserOrgRole::PRIMARY_KEY, &["user_id", "org_id"]);
# }
```

---

## Field Attributes Cheat Sheet

SQLModel provides fine-grained control over column DDL and ORM behavior via field attributes:

| Attribute | Description | Example |
|-----------|-------------|---------|
| `primary_key` | Marks the column as primary key | `#[sqlmodel(primary_key)]` |
| `auto_increment` | Generates engine-specific identity column DDL | `#[sqlmodel(auto_increment)]` |
| `unique` | Generates a `UNIQUE` constraint | `#[sqlmodel(unique)]` |
| `nullable` | Explicitly permits `NULL` values (default for `Option<T>`) | `#[sqlmodel(nullable)]` |
| `column = "..."` | Renames the SQL column name | `#[sqlmodel(column = "email_address")]` |
| `column_comment = "..."` | Adds a comment to the column definition | `#[sqlmodel(column_comment = "User contact email")]` |
| `column_constraints = "..."` | Inlines custom raw SQL check constraints | `#[sqlmodel(column_constraints = "CHECK(score >= 0)")]` |
| `default = "..."` | Emits a `DEFAULT` clause in DDL | `#[sqlmodel(default = "0")]` |
| `index` | Emits a secondary index | `#[sqlmodel(index)]` or `#[sqlmodel(index = "idx_name")]` |
| `sql_type = "..."` | Overrides the SQL type emitted in DDL | `#[sqlmodel(sql_type = "VARCHAR(255)")]` |
| `foreign_key = "..."` | Declares a foreign key constraint | `#[sqlmodel(foreign_key = "teams.id")]` |
| `on_delete = "..."` | Sets foreign key delete action | `#[sqlmodel(on_delete = "CASCADE")]` |
| `on_update = "..."` | Sets foreign key update action | `#[sqlmodel(on_update = "CASCADE")]` |
| `skip` | Completely ignores field for database operations | `#[sqlmodel(skip)]` |
| `skip_insert` | Excludes column from generated `INSERT` statements | `#[sqlmodel(skip_insert)]` |
| `skip_update` | Excludes column from generated `UPDATE` statements | `#[sqlmodel(skip_update)]` |

---

## Supported Column Types

The following Rust standard types map to SQL types out of the box:

- **Integers**: `i8`, `i16`, `i32`, `i64`, `isize`, `u8`, `u16`, `u32`, `u64`, `usize`
- **Floating Point**: `f32`, `f64`
- **Boolean**: `bool`
- **Strings**: `String`, `&str`
- **Binary Data**: `Vec<u8>`
- **JSON**: `serde_json::Value` (requires `serde_json`)
- **Nullable variants**: Any type wrapped in `Option<T>`

### Optional Extended Types
When enabling optional features on `sqlmodel`, additional domain types become first-class model fields:
- `chrono` feature: `chrono::DateTime<Utc>`, `chrono::NaiveDateTime`, `chrono::NaiveDate`, `chrono::NaiveTime`
- `uuid` feature: `uuid::Uuid`
- `decimal` feature: `rust_decimal::Decimal`

Compile-time diagnostics (`#[diagnostic::on_unimplemented]`) will guide you to enable the corresponding feature flag if you use these types without enabling their respective cargo features.

---

## Timestamps & Soft Deletes

SQLModel Rust includes built-in conventions for common entity metadata patterns:

```rust
use sqlmodel::prelude::*;

#[derive(Model, Debug, Clone)]
#[sqlmodel(table = "articles")]
pub struct Article {
    #[sqlmodel(primary_key, auto_increment)]
    pub id: Option<i64>,

    pub title: String,
    pub content: String,

    #[sqlmodel(default = "CURRENT_TIMESTAMP")]
    pub created_at: String,

    #[sqlmodel(default = "CURRENT_TIMESTAMP")]
    pub updated_at: String,

    #[sqlmodel(nullable)]
    pub deleted_at: Option<String>,
}
```

---

## Differences from Python SQLModel

- **Compile-time Metadata**: Python SQLModel relies on runtime metaclasses and inspection of `__annotations__`. In Rust, `#[derive(Model)]` generates zero-cost struct metadata and conversion functions at compile time.
- **Type-safe Nullability**: Rather than relying on `Optional[T] = Field(default=None)`, Rust uses native `Option<T>`. Non-optional fields statically guarantee `NOT NULL` constraints.
- **Explicit Column Overrides**: Python's `sa_column_args` and `sa_column_kwargs` dictionaries are replaced with strongly-typed attribute parameters such as `#[sqlmodel(column = "...", sql_type = "...")]`.
- **Validation**: While Python models inherit from Pydantic `BaseModel` and run validators on assignment, Rust models separate pure persistence (`Model`) from validation (`#[derive(Validate)]`), maximizing runtime performance.