Quickstart¶
The shortest path from an empty project to a first query. Each step names the page that explains it in depth; this one only gets you running.
Add the crates¶
[dependencies]
turso-orm = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
The engine is part of the crate: there is nothing to install or start. Feature flags are listed on the compatibility page.
Open a database¶
The first decision is where the data lives. Four modes, one line each:
A database that lives as long as the pool and vanishes with it. For tests, prototypes and short-lived agents.
A file next to the binary, created on first open. For desktop tools, services with local state and anything that must survive a restart.
Database is a pool of engine connections, cheap to clone and safe to
share. Entities, queries, transactions and migrations are the same in all
four modes; only this line changes. Tokens, encryption and the other
options are on the compatibility page,
transactions under Transactions.
Describe a table¶
/// The `user` entity.
mod user {
use turso_orm::prelude::*;
/// A row of the `user` table.
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[turso(table_name = "user")]
pub(crate) struct Model {
#[turso(primary_key)]
pub id: i32,
#[turso(unique)]
pub email: String,
pub name: Option<String>,
}
/// The relations of `user`; there are none.
#[derive(Copy, Clone, Debug, DeriveRelation)]
pub(crate) enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
One struct per table, in a module named after it. The derive generates
Entity, Column, PrimaryKey and ActiveModel from it; the empty
Relation enum is where joins will be declared. Attributes and column
types are on the entities page.
Create the table¶
Good enough for a first run and for tests. An application keeps a history of its schema instead; see Migrations.
Write and read¶
// `id` stays `NotSet`, so the database assigns it and `insert` returns
// the stored row with the generated key.
let alice = user::ActiveModel {
email: Set("alice@example.com".into()),
name: Set(Some("Alice".into())),
..Default::default()
}
.insert(&db)
.await?;
println!("inserted {alice:?}");
let found = user::Entity::find()
.filter(user::Column::Email.contains("example"))
.one(&db)
.await?;
println!("found {found:?}");
Set marks the fields to write and insert returns the stored row with
its generated id. find starts a query, filter narrows it with the
generated Column enum, one runs it. Everything the builder can do is
on the queries page, and the
examples on GitHub
show complete programs, including two web APIs.