11 releases
0.7.10 | Sep 11, 2024 |
---|---|
0.7.9 | Sep 11, 2024 |
0.7.4 | Jun 10, 2024 |
0.1.6 | Jul 17, 2022 |
0.1.3 | May 28, 2022 |
#910 in Database interfaces
16KB
256 lines
Sqlx Models ORM
ActiveRecord pattern for Rust based on SQLx. Write idiomatic DB code (Postgres only).
[dependencies]
sqlx-models-orm = "0.1"
Installation
Read the in-depth tutorial that doubles as a "kitchen sink" test in the examples
These are just some of the time-saving, boilerplate-killing features:
Model
model!{
state: App,
table: humans,
struct Human {
#[sqlx_model_hints(int4, default)]
id: i32,
#[sqlx_model_hints(varchar)]
name: String,
#[sqlx_model_hints(int4)]
age: Option<i32>,
#[sqlx_model_hints(boolean, default)]
is_allowed_unlimited_cats: bool,
#[sqlx_model_hints(boolean)]
likes_dogs_too: bool,
},
has_many {
Cat(human_id),
}
}
Create
let alice = app.human()
.insert(InsertHuman{
name: "Alice".to_string(),
age: Some(19),
likes_dogs_too: true,
})
.save().await?;
assert_eq!(alice.attrs, HumanAttrs{
id: 1,
name: "Alice".to_string(),
age: Some(19),
is_allowed_unlimited_cats: false,
likes_dogs_too: true,
});
Query
let some_humans = app.human()
.select()
.limit(2)
.offset(1)
.likes_dogs_too_eq(false)
.order_by(HumanOrderBy::Name)
.desc(true)
.all().await?;
assert_eq!(some_humans, vec![alice]);
Update
let updated_alice = alice.update().use_struct(UpdateHuman{
name: Some("Alice Alison".to_string()),
age: Some(None),
is_allowed_unlimited_cats: Some(true),
..Default::default()
}).save().await?;
assert_eq!(updated_alice.attrs, HumanAttrs{
id: 1,
name: "Alice Alison".to_string(),
age: None,
is_allowed_unlimited_cats: true,
likes_dogs_too: true,
});
Delete
alice.delete().await?;
Design principles:
- Stateful: You're not supposed to be passing a connection pool around explicitly.
- Your structs, your abstractions: This crate has a proc macro that creates a number of structs for different operations on a single database table. You can add any methods you want to any of these structs. Structs for the same operation in different tables implement a common trait to allow some degree of generalization across operations in these tables.
- Idiomatic rather than performant: This should be easy to learn and use, even if there were performance tradeoffs.
- Fallaback to SQLx: Always make it possible to fall back for custom queries and performance enhancements.
- One table per query. Reinventing SQL for joining tables in the ORM is hard to debug and understand. Favour multiple single-table queries over a single multi-table one. (see previous item).
- Only compile time checked queries. No chance of sql injection, no need for silly tests, at the cost of longer queries.
- Only Postgres for now. Sorry about that :(
Dependencies
~60MB
~1M SLoC