Defining Models
Models define the structure of your entities. Define them once in Rust, and they work everywhere—native servers, browser clients, and mobile apps.
Basic Model Definition
Use the #[derive(Model)] macro to define a model:
#[derive(Model, Debug, Serialize, Deserialize)]
pub struct Album {
#[active_type(YrsString)]
pub name: String,
pub artist: String,
pub year: i32,
}
This single definition generates:
| Generated Type | Purpose |
|---|---|
Album | The model struct for creating new entities |
AlbumView | Read-only view of an entity’s current state |
AlbumMut | Mutable handle for updating entities in a transaction |
Field Types
Basic Types
#[derive(Model, Debug, Serialize, Deserialize)]
pub struct Task {
pub title: String,
pub completed: bool,
pub priority: i32,
}
Supported types include:
Stringbool- Integers:
i8,i16,i32,i64,u8,u16,u32,u64 f32,f64
CRDT Types
Use #[active_type(...)] to specify a CRDT backend for a field. The first supported CRDT type is YrsString for collaborative text:
#[derive(Model, Debug, Serialize, Deserialize)]
pub struct Document {
#[active_type(YrsString)]
pub content: String,
pub title: String,
}
Entity References
Use Ref<T> to create typed references between entities:
#[derive(Model, Debug, Serialize, Deserialize, Clone)]
pub struct Artist {
pub name: String,
}
#[derive(Model, Debug, Serialize, Deserialize, Clone)]
pub struct Song {
pub title: String,
pub artist: Ref<Artist>,
}
References enable graph-style navigation between related entities.
JSON Fields
Use Json for schemaless, dynamic data:
#[derive(Model, Debug, Serialize, Deserialize, Clone)]
pub struct Track {
pub name: String,
pub metadata: Json,
}
JSON fields support nested path queries like metadata.genre = 'rock'.
Creating Entities
Use a transaction to create new entities:
let trx = ctx.begin();
let album = trx.create(&Album {
name: "Parade".into(),
artist: "Prince".into(),
year: 1986,
}).await?;
let album_id = album.id();
trx.commit().await?;
Reading Entities
Access data through the View type:
let view: AlbumView = ctx.get(album_id).await?;
println!("Album: {} by {} ({})", view.name()?, view.artist()?, view.year()?);
Generated TypeScript
When you build your WASM bindings, TypeScript types are generated automatically:
// Generated from your Rust model
interface AlbumView {
id: EntityId;
name: string;
artist: string;
year: number;
}
// Static methods on the model class
class Album {
static query(ctx: Context, query: string): AlbumLiveQuery;
static create(trx: Transaction, data: AlbumData): Promise<AlbumView>;
}
Next Steps
- Querying Data - How to query and filter entities
- Query Syntax - Full AnkQL syntax reference