| Crates.io | usual |
| lib.rs | usual |
| version | 0.1.2 |
| created_at | 2021-08-11 23:14:17.084214+00 |
| updated_at | 2022-04-07 18:26:54.690464+00 |
| description | An experimental, extremely light, 'NORM' wrapper. |
| homepage | https://github.com/trezm/usual |
| repository | https://github.com/trezm/usual |
| max_upload_size | |
| id | 434986 |
| size | 40,562 |
Usual is a simple wrapper for querying, and deserializing SQL queries in a (relatively) type safe way. Queries are still written in plain SQL, so you, the developer get all of the power (and responsibility) of not having a DSL.
Usual revolves around models. Models let you query the data you want, and only the data you want. Simply add a derive for UsualModel.
use usual::{base::Model, base::TryGetRow, query, UsualModel};
derive(UsualModel)
struct Post {
id: i64,
title: String,
content: String,
}
This gives you access to deserialize like a boss (this example uses tokio-postgres):
let _ = client
.execute(
query!("INSERT INTO posts (title, content) VALUES ($1, $2)").as_str(),
&[
&format!("title {}", Utc::now().timestamp_millis()),
&"this is some content",
],
)
.await?;
let rows = client
.query(query!("SELECT {Post} FROM posts").as_str(), &[])
.await?
.iter()
.map(Post::from_row)
.collect::<Vec<_>>();
The only special, usual-specific, language here is {Post}. This means "all of the fields in the Post model."
Often, you don't want to query every field on a table, we have that too with the partial macro.
let partial_rows = client
.query(
query!("SELECT {Post::title,created_at} FROM posts").as_str(),
&[],
)
.await?
.iter()
.map(partial!(Post, title as String, created_at as Time))
.collect::<Vec<_>>();
let post = partial_rows.get(0).unwrap();
// This is fine, because we grabbed the title row
println!("title: {}", post.title);
// This is a compile-time error, because we haven't fetched that row from the table.
println!("content: {}", post.content);
The syntax is simple, it's just ModelName::field,field,field.
Aliasing is supported via a query of the form:
query!("SELECT {TestModel::some_string as t} FROM test_model as t")
This query selects a field from the test_model table, which we've aliased as t in the query.
Fetching from multiple tables is also possible, simply add more {}:
query!("SELECT {TestModel as t}, {TestModel2 as t2} FROM test_model as t JOIN test_model as t2 on t.id = t2.id")
This will let you do a single query and hydrate multiple types of objects from the resulting rows.
Including values not stored in SQL can be achieved by using the #[unusual] attribute. In order to be unusual, a field must implement Default, as when the struct is created this is what will be called for that field.
use usual::{base::Model, base::TryGetRow, query, UsualModel};
struct SomethingElse {}
derive(UsualModel)
struct Post {
id: i64,
title: String,
content: String,
#[unusual]
non_sql: Option<SomethingElse>
}