Skip to main content

Introducing SeaORM

· 5 min read
Chris Tsang
SeaQL Team

We are pleased to introduce SeaORM 0.2.2 to the Rust community today. It's our pleasure to have received feedback and contributions from awesome people to SeaQuery and SeaORM since 0.1.0.

Rust is a wonderful language that can be used to build anything. One of the FAQs is "Are We Web Yet?", and if Rocket (or your favourite web framework) is Rust's Rail, then SeaORM is precisely Rust's ActiveRecord.

SeaORM is an async ORM built from the ground up, designed to play well with the async ecosystem, whether it's actix, async-std, tokio or any web framework built on top.

Let's have a quick tour of SeaORM.

Async#

Here is how you'd execute multiple queries in parallel:

// execute multiple queries in parallellet cakes_and_fruits: (Vec<cake::Model>, Vec<fruit::Model>) =    futures::try_join!(Cake::find().all(&db), Fruit::find().all(&db))?;

Dynamic#

You can use SeaQuery to build complex queries without 'fighting the ORM':

// build subquery with easelet cakes_with_filling: Vec<cake::Model> = cake::Entity::find()    .filter(        Condition::any().add(            cake::Column::Id.in_subquery(                Query::select()                    .column(cake_filling::Column::CakeId)                    .from(cake_filling::Entity)                    .to_owned(),            ),        ),    )    .all(&db)    .await?;

More on SeaQuery

Testable#

To write unit tests, you can use our mock interface:

// Setup mock connectionlet db = MockDatabase::new(DbBackend::Postgres)    .append_query_results(vec![        vec![            cake::Model {                id: 1,                name: "New York Cheese".to_owned(),            },        ],    ])    .into_connection();
// Perform your application logicassert_eq!(    cake::Entity::find().one(&db).await?,    Some(cake::Model {        id: 1,        name: "New York Cheese".to_owned(),    }));
// Compare it against the expected transaction logassert_eq!(    db.into_transaction_log(),    vec![        Transaction::from_sql_and_values(            DbBackend::Postgres,            r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,            vec![1u64.into()]        ),    ]);

More on testing

Service Oriented#

Here is an example Rocket handler with pagination:

#[get("/?<page>&<posts_per_page>")]async fn list(    conn: Connection<Db>,    page: Option<usize>,    per_page: Option<usize>,) -> Template {    // Set page number and items per page    let page = page.unwrap_or(1);    let per_page = per_page.unwrap_or(10);
    // Setup paginator    let paginator = Post::find()        .order_by_asc(post::Column::Id)        .paginate(&conn, per_page);    let num_pages = paginator.num_pages().await.unwrap();
    // Fetch paginated posts    let posts = paginator        .fetch_page(page - 1)        .await        .expect("could not retrieve posts");
    Template::render(        "index",        context! {            page: page,            per_page: per_page,            posts: posts,            num_pages: num_pages,        },    )}

Full Rocket example

We are building more examples for other web frameworks too.

People#

SeaQL is a community driven project. We welcome you to participate, contribute and together build for Rust's future.

Core Members#

Chris Tsang
Billy Chan

Contributors#

As a courtesy, here is the list of SeaQL's early contributors (in alphabetic order):

Ari Seyhun
Ayomide Bamidele
Ben Armstead
Bobby Ng
Daniel Lyne
Hirtol
Jonas Rinner
Marco Napetti
Markus Merklinger
Muhannad
nitnelave
Raphaël Duchaîne
Rémi Kalbe
Sam Samai