ormlite
ormlite is an ORM in Rust for developers that love SQL. Let's see it in action:
use *;
use SqliteConnection;
async
You might like ormlite because:
- It auto-generates migrations from Rust structs. To my knowledge, it is the only Rust ORM with this capability.
- The join API (in alpha) has far fewer moving pieces than any other Rust ORM. It only relies on the table
structs themselves, and does not rely on relation traits (SeaORM) or modules (Diesel). - There's little to no query builder syntax to learn. The query builder basically joins together &str fragments of raw SQL. It strikes the right level of abstraction between composability, and having near-zero learning curve for anyone who already knows SQL.
Quickstart
Installation
Install with cargo:
# For postgres
cargo add ormlite --features postgres
# For sqlite
cargo add ormlite --features sqlite
Or update your Cargo.toml:
[]
# For postgres
= { = "..", = ["postgres"] }
# For sqlite
= { = "..", = ["sqlite"] }
Other databases and runtimes are supported, but are less tested. Please submit an issue if you encounter any.
Environment Setup
You need DATABASE_URL in your environment. We recommend a tool like just, which
can pull in a .env file, but for simplicity, here we'll use shell directly.
Migrations
If you are querying a static database and don't need migrations, skip this section. If you want migrations, keep reading.
First, install ormlite-cli. Currently, the CLI only supports Postgres. While ormlite-cli is separate from sqlx-cli, they are 100% compatible with each other.
sqlx-cli does not support auto-generating migrations or snapshots (to rollback in development without writing down migrations), but it is less bleeding edge and supports more database types.
Next, create the database and the migrations table. init creates a _sqlx_migrations table that tracks your migrations.
# Create the database if it doesn't exist. For postgres, that's:
# createdb <dbname>
Let's see migrations in action. Create a Rust struct with #[derive(Model)], which the CLI tool detects to auto-generate migrations:
# src/models.rs
use ormlite::model::*;
#[derive(Model, Debug)]
pub struct Person {
pub id: i32,
pub name: String,
pub age: i32,
}
Next, auto-generate the migration.
This creates a plain SQL file in migrations/. Let's review it before we execute it:
Once you're satisfied reviewing it, you can execute it:
By default, up also creates a snapshot, so you can rollback using ormlite down if need be. There's also an option to generate paired up/down migrations instead of only up migrations.
That's the end of setup. Let's now look at how to run queries.
Insert & Update
The insert and update syntax at the top of the README is most effective for UUID primary key tables.
use *;
use Uuid;
async
This syntax has two possible issues. First, id is not Option, so it must be set,
causing problems for autoincrement id fields. Second, the struct cannot track which fields are modified, so the update
method must update all columns.
Insertion Struct
To work around the autoincrement issue, you can use an insertion struct, shown here, or a builder, shown below.
use Json;
use Value;
async
If the derived struct doesn't meet your needs, you can manually define a struct that only contains the fields you want,
specifying table = "<table>" to route the struct to the same database table.
Insert Builder & Update Builder
You can also use builder syntax for insertion or to update only certain fields.
async
Upsert
You can handle insertion on conflict using OnConflict (docs).
use ;
async
Select Query
You can use Model::select to build a SQL query using Rust logic.
Note: Postgres's approach of using numbered dollar sign placeholders quickly breaks down when building queries. Instead, even with Postgres, use
?for parameters, andormlitewill replace the?placeholders with$placeholders when it constructs the final query.
async
Raw Query
You can fall back to raw queries if the ORM methods don't work for you. You can include handwritten strings, or if
you want a lower-level query builder, you can use sql,
the underlying engine that powers ormlite's query builder & migration auto-generation.
async
async
Table Customization
Attributes are defined in these structs.
This example shows them in action:
Joins
Join support is alpha stage. Right now, ormlite only support many-to-one relations (e.g. Person belongs to Organization).
Support for many-to-many and one-to-many is planned. If you use this functionality, please report any bugs you encounter.
async
Features & Data Types
Uuid, Chrono, & Time
If you want Uuid or DateTime, combined with serde, you need to depend directly on uuid, time or chrono,
and add the serde feature to each of them.
# Cargo.toml
[dependencies]
uuid = { version = "...", features = ["serde"] }
chrono = { version = "...", features = ["serde"] }
time = { version = "...", features = ["serde"] }
use *;
use ;
use Uuid;
use ;
Json/Jsonb Columns
You can either use ormlite::types::Json for JSON or JSONB fields, or you can use the json attribute.
For unstructured data, use serde_json::Value as the inner type. Use a struct with Deserialize + Serialize as the
generic for structured data.
use *;
use Json;
use Value;
Logging
You can log queries using sqlx's logger: RUST_LOG=sqlx=info
Roadmap
- Insert, update, delete directly on model instances
- Builder for partial update and insertions
- User can create insert models that ignore default values
- Select query builder
- Build the derive macro
- Get() function for fetching a single entity.
- Ability to specify the name of a table and name of primary column
- Automatically generate insert models
- Automatically generate migrations
- Eliminate need for FromRow macro
- Many to one joins
- created_at should naturally default to now()
- id: i32 should default to identity by default
- Autogenerate indexes for migrations
- Many to many joins
- One to many joins
- Make sure features are wired up correctly to support mysql and different runtimes & SSL libraries.
- Macro option to auto adjust columns like updated_at
- Upsert functionality
- Bulk insertions
- Query builder for bulk update
- Handle on conflict clauses for bulk update
- Benchmarks against raw sql, sqlx, ormx, seaorm, sqlite3-sys, pg, diesel
- Support for patch records, i.e. update with static fields.
- Consider a blocking interface, perhaps for sqlite/Rusqlite only.
Contributing
Open source thrives on contributions, and ormlite is a community project. We welcome you to file bugs, feature
requests, requests for better docs, pull requests, and more!