SeaORM is a relational ORM to help you build web services in Rust with the familiarity of dynamic languages.
The official docs of SeaORM are on their website.
This guide assumes that you’re using SQLite. Before we start, make sure you have libsqlite3 installed for your system.
The entire code for this guide is in this repo.
In this guide, we’re going to build simple examples of each piece of CRUD operations.
I am using Rust v1.62 and sea-orm
v0.9
cargo new seaorm_demo --lib
cd seaorm_demo
First, let’s add SeaORM and tokio to our dependencies.
File: Cargo.toml
[dependencies]
tokio = { version = "1.20", features = ["macros", "rt-multi-thread"] }
[dependencies.sea-orm]
version = "0.9"
features = [ "sqlx-sqlite", "runtime-tokio-rustls", "macros" ]
default-features = false
cargo install sea-orm-cli
We’ll write a migration file to setup our database and table schema.
sea-orm-cli migrate init
It will generate a module called migration
. Now our project structure should look like this.
.
├── Cargo.lock
├── Cargo.toml
├── migration
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ ├── lib.rs
│ ├── m20220101_000001_create_table.rs
│ └── main.rs
└── src
└── lib.rs
Open the file migration/Cargo.toml
and uncomment the two dependencies for sea-orm-migration
.
File: migration/Cargo.toml
[dependencies.sea-orm-migration]
version = "^0.9.0"
features = [
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
# e.g.
"runtime-tokio-rustls", # `ASYNC_RUNTIME` featrure
"sqlx-sqlite", # `DATABASE_DRIVER` feature
]
Edit the file migration/src/m20220101_000001_create_table.rs
in your
favourite editor and remove the two mentions of todo!()
and save the file.
Set the URL for your database as an environment varibale.
export DATABASE_URL='sqlite://posts.sqlite?mode=rwc'
Next, we’ll run the migration.
sea-orm-cli migrate up
It will compile the migration
module and run your migrations. After this, you
should see a file named posts.sqlite in your directory.
To confirm if we have created the table, run the following command.
$ sqlite3 posts.sqlite ".schema post" ".exit"
CREATE TABLE IF NOT EXISTS "post" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" text NOT NULL, "text" text NOT NULL );
Create a new entity
module.
cargo new entity --lib
Next, generate the entities.
sea-orm-cli generate entity -o entity/src
It will use the database we created earlier by reading the DATABASE_URL
environment variable.
Add the sea-orm
dependency to the entity
module.
File: entity/Cargo.toml
[dependencies]
sea-orm = { version = "0.9" }
The generated entity should look like the following.
File: entity/src/post.rs
Since the module entity
is at the root of our project, let’s convert it into
a library so that we can consume it.
Rename the file entity/src/mod.rs
to entity/src/lib.rs
.
mv entity/src/mod.rs entity/src/lib.rs
Next, we’ll add the entity
and migration
library to the dependencies of the
root project.
File: Cargo.toml
[workspace]
members = [".", "entity", "migration"]
[dependencies]
entity = { path = "entity" }
migration = { path = "migration" }
And now your project structure should look like
.
├── Cargo.lock
├── Cargo.toml
├── entity
│ ├── Cargo.toml
│ └── src
│ ├── lib.rs
│ ├── post.rs
│ └── prelude.rs
├── migration
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── README.md
│ └── src
│ ├── lib.rs
│ ├── m20220101_000001_create_table.rs
│ └── main.rs
├── src
│ └── lib.rs
└── tasks.sqlite
And your entire Cargo.toml
should look like the following.
File: Cargo.tmol
[package]
name = "seaorm_demo"
version = "0.1.0"
edition = "2021"
[workspace]
members = [".", "entity", "migration"]
[dependencies]
entity = { path = "entity" }
migration = { path = "migration" }
tokio = { version = "1.20", features = ["macros", "rt-multi-thread"] }
[dependencies.sea-orm]
version = "0.9"
features = [ "sqlx-sqlite", "runtime-tokio-rustls", "macros" ]
default-features = false
Now we write code for establishing a connection to our database.
File: src/lib.rs
Now let’s write some code to create posts. Create a new file src/bin/create_post.rs
.
File: src/bin/create_post.rs
We can run our new script as follows.
cargo run --bin create_post
It should look like the following.
$ cargo run --bin create_post
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 3.85s
Running `target/debug/create_post`
Post created with ID: 1, TITLE: Amazing title 1
If you wish to create more entries in the database, change the title/text in
create_post.rs
and execute the script again.
I will create one more.
$ cargo run --bin create_post
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 4.08s
Running `target/debug/create_post`
Post created with ID: 2, TITLE: Another title 2
Next, we write the example for reading all the posts in the database.
File: src/bin/read_posts.rs
Just like earlier, you can run this new file as follows.
cargo run --bin read_posts
And this should look like the following.
$ cargo run --bin read_posts
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 4.08s
Running `target/debug/read_posts`
All the posts in db:
ID: 1, TITLE: Amazing title 1
ID: 2, TITLE: Another title 2
Now, let’s say we wanted to perform an UPDATE operation to the title of a post.
File: src/bin/update_post.rs
And we run this script with
cargo run --bin update_post
And it should look like
$ cargo run --bin update
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 2.80s
Running `target/debug/update_post`
Post updated for ID: 1 with TITLE: Updated title
And now for the final operation, the deletion. Create a new file src/bin/delete_post.rs
We will be deleting the post with ID 1
File: src/bin/delete_post.rs
And we will call this script with
cargo run --bin delete_post
And it should look like
$ cargo run --bin delete_post
Compiling seaorm_demo v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 5.42s
Running `target/debug/delete_post`
DeleteResult { rows_affected: 1 }
We can execute script read_post
again to see what posts remain in the database.
$ cargo run --bin read_posts
Finished dev [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/read_posts`
All the posts in db:
ID: 2, TITLE: Another title 2