Rusql Alchemy: A Django-Inspired ORM for Rust
Welcome to Rusql Alchemy! This project is a personal challenge to create a simple, intuitive, and powerful ORM for Rust, inspired by the fantastic Django ORM. While it started as a fun side project, it has grown into a capable library that I use for my own applications.
✨ Core Features
- Django-like Model Definitions: Define your database models using simple Rust structs and derive macros.
- Simple & Expressive Query API: Fetch, create, update, and delete records with an intuitive and chainable API.
- Automatic Migrations: Keep your database schema in sync with your models effortlessly.
- Multi-Database Support: Works with PostgreSQL, MySQL, SQLite, and Turso out of the box.
- Asynchronous from the Ground Up: Built with
async/.awaitfor modern, non-blocking applications.
❗️ Runtime Compatibility
This library is built on sqlx and libsql, which are designed to work with the tokio async runtime. All asynchronous operations in rusql-alchemy must be executed within a tokio runtime.
Using this library in other runtimes, such as the one provided by actix-web (#[actix_web::main]), will likely result in runtime panics. Please ensure you are using #[tokio::main] or are manually running a tokio runtime.
🚀 Getting Started
1. Add Rusql Alchemy to Your Project
Depending on the database you want to use, add one of the following to your Cargo.toml:
For PostgreSQL:
[]
= { = "0.5.5", = false, = ["postgres"] }
= "0.8"
= { = "1", = ["full"] }
For MySQL:
[]
= { = "0.5.5", = false, = ["mysql"] }
= "0.8"
= { = "1", = ["full"] }
For SQLite:
[]
= "0.5.5"
= "0.8"
= { = "1", = ["full"] }
For Turso:
[]
= { = "0.5.5", = false, = ["turso"] }
= "1.0"
= { = "1", = ["full"] }
2. Define Your Models
Create your database models using simple Rust structs and the field derive macro. The macro automatically generates the necessary code for database interactions.
When using an auto-incrementing primary key (auto=true), it is recommended to use Option<Integer> for the field type. This allows the model to represent a record that has not yet been inserted into the database (where the ID would be None).
use *;
Note for PostgreSQL users: For auto-incrementing primary keys, it's recommended to use the
Serialtype instead ofIntegerwithauto=true.
3. Connect to Your Database & Run Migrations
Instantiate the Database and run your migrations.
use *;
use Error;
async
NB: For migrations to work correctly, the models must be imported into the binary where
database.migrate()is called. This allows the migration system to discover your models. If your models are in a separate module (e.g.,src/models.rs), ensure you import them:// In your main.rs use *; use Error; // Import your models so they can be discovered for migration. // The `allow(unused_imports)` attribute is useful here. use crate*; // Assuming models are in `src/model` async
CRUD Operations
Create
use *;
use Error;
async
Read
use *;
use Error;
async
Update
use *;
use Error;
async
Delete
use *;
use Error;
async
JOIN Operations
Rusql Alchemy supports INNER JOIN operations, allowing you to query data from multiple tables at once.
First, define the models with a foreign key relationship. Assuming the User model from before, we can define a Profile model:
use *;
Then, you can use the select! macro to perform a join. The join method returns a Vec<T> where T is the type specified in join::<T>.
use *;
use Error;
// Assuming User and Profile models are defined as above
async
A Personal Challenge
This project is, first and foremost, a personal challenge and a learning experience. It's a testament to the power and flexibility of Rust, and I'm proud of how far it has come. I hope you find it useful, and I welcome any feedback or contributions from the community.