Ormer
Home
Quick Start
GitHub
  • 简体中文
  • English
Home
Quick Start
GitHub
  • 简体中文
  • English
  • Introduction to Ormer
  • Quick Start
  • Model Definition
  • Database Connection
  • Data Operations
  • Query Builder
  • Advanced Queries
  • Transaction Management
  • Connection Pool

Model Definition

Basic Definition

use ormer::Model;

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    name: String,
    email: Option<String>,
}

Attributes

  • #[table = "table_name"] - Specifies the table name
  • #[primary] - Primary key (supports composite primary keys)
  • #[primary(auto)] - Auto-increment primary key (only for single primary key or the first field of composite primary key)
  • #[unique] - Unique constraint (supports group parameter for composite unique)
  • #[index] - Index
  • #[foreign(Type)] - Foreign key relationship
  • #[data_type(i64)] - Database type override (e.g., Rust i32 field mapped to BIGINT in database)
  • #[hypertable(Duration::from_secs(86400))] - TimescaleDB hypertable chunk interval
  • #[compress] - PostgreSQL column-level compression (generates COMPRESSION pglz)

Field Attributes

Unique Constraint

Single Column Unique

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    
    #[unique]
    email: String,
}

Composite Unique

#[derive(Debug, Model)]
#[table = "user_roles"]
struct UserRole {
    #[primary(auto)]
    id: i32,
    
    #[unique(group = 1)]
    user_id: i32,
    
    #[unique(group = 1)]
    role_id: i32,
}

Indexes

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    
    #[index]
    age: i32,
    
    #[index]
    created_at: String,
}

Nullable Fields

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    name: String,
    
    email: Option<String>,
    phone: Option<String>,
}

Supported Types

Rust TypeSQL Type (SQLite)SQL Type (PostgreSQL)SQL Type (MySQL)SQL Type (MSSQL)
i32INTEGERINTEGERINTINT
i64INTEGERBIGINTBIGINTBIGINT
f64REALDOUBLEDOUBLEFLOAT
StringTEXTTEXTTEXTNVARCHAR(255)
boolINTEGER (0/1)BOOLEANBOOLEANBIT
Vec<u8>BLOBBYTEABLOBVARBINARY(MAX)

All basic types can be wrapped with Option<T> for nullable fields.

Enum Types

use ormer::{Model, ModelEnum};

#[derive(Debug, Clone, ModelEnum, PartialEq)]
enum UserStatus {
    Active,
    Inactive,
    Banned,
}

#[derive(Debug, Model)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    status: UserStatus,
    name: String,
}

Supports Option<EnumType> for nullable enum fields.

Complete Example

use ormer::Model;

#[derive(Debug, Model, Clone)]
#[table = "products"]
struct Product {
    #[primary(auto)]
    id: i32,
    
    #[unique]
    sku: String,
    name: String,
    price: f64,
    
    #[index]
    category_id: i32,
    stock: i32,
    
    description: Option<String>,
    is_active: bool,
}

Foreign Key Relationships

#[derive(Debug, Model)]
#[table = "posts"]
struct Post {
    #[primary(auto)]
    id: i32,
    
    #[foreign(User)]
    user_id: i32,
    
    title: String,
    content: String,
}

Composite Primary Keys

Add #[primary] to multiple fields to define a composite primary key:

#[derive(Debug, Model)]
#[table = "user_roles"]
struct UserRole {
    #[primary]
    user_id: i32,
    #[primary]
    role_id: i32,
    assigned_at: String,
}

Only the first primary key field can use auto:

#[primary(auto)]
id: i32,
#[primary]
product_id: i32,

Use primary_key_columns() to get the list of primary key column names.

Table Operations

Creating Tables

db.create_table::<User>().execute().await?;

Validating Tables

db.validate_table::<User>().await?;

Dropping Tables

db.drop_table::<User>().execute().await?;

Model Wrappers

// Base model
#[derive(Debug, Model, Clone)]
#[table = "users"]
struct User {
    #[primary(auto)]
    id: i32,
    name: String,
    age: i32,
    email: Option<String>,
}

// Wrapper - different table name
#[derive(Debug, Model)]
#[table = "archive_users"]
struct ArchiveUser(User);

#[derive(Debug, Model)]
#[table = "temp_users"]
struct TempUser(User);

Usage Example

db.create_table::<User>().execute().await?;
db.create_table::<ArchiveUser>().execute().await?;

db.insert(&User {
    id: 0,
    name: "Alice".to_string(),
    age: 25,
    email: Some("alice@example.com".to_string()),
}).await?;

let archive_user = ArchiveUser(User {
    id: 0,
    name: "Bob".to_string(),
    age: 30,
    email: Some("bob@example.com".to_string()),
});
db.insert(&archive_user).execute().await?;

let archived: Vec<ArchiveUser> = db
    .select::<ArchiveUser>()
    .collect::<Vec<_>>()
    .await?;

for au in &archived {
    println!("User: {}", au.inner().name);
}
Last Updated: 6/4/26, 12:14 AM
Contributors: fawdlstty
Prev
Quick Start
Next
Database Connection