Overview of types
There is a hierarchy of types that can be used to build queries.
- [TableRow], [i64], [f64], [bool],
&[u8],&str: These are the base types for building expressions. They all implement [IntoExpr] and are [Copy]. Note that [TableRow] is special because it refers to a table row that is guaranteed to exist. - [Expr] is the type that all [IntoExpr] values can be converted into. It has a lot of methods to combine expressions into more complicated expressions. Most importantly, it implements [std::ops::Deref], if the expression is a table expression. This can be used to get access to the columns of the table, which can themselves be table expressions. Note that combinators like [optional] and [aggregate] also have [Expr] as return type.
(), [Expr] and(Expr, Expr)implement [IntoSelect] These types can be used as the return type of a query. They specify exactly which values should be returned for each row in the result set.- [struct@Select] is the type that all [IntoSelect] value can be converted into. It has the [Select::map] method which allows changing the type that is returned from the query.
How to provide [IntoSelect]
Making a selection of values to return for each row in the result set is the final step when building queries. [rust_query] has many different methods of selecting.
- First, you can specify the columns that you want directly.
into_vec(&user.name)orinto_vec((&user.name, some_other_expr))Note that this method only supports tuples of size 2 (which can be nested). If you want to have more expressions, then you probably want to use one of the other methods. - Derive [derive@Select], super useful when some of the values are aggregates.
- Derive [derive@FromExpr], choose this method if you just want (a subset of) existing columns.
- Finally, you can implement [trait@IntoSelect] manually, for maximum flexibility.
How to work with optional rows
A single optional row is quite common as the result of using unique constraint.
For example you might create a Expr<Option<User>> with something like User.name(name).
- [trait@FromExpr] is automatically implemented for
Option<T>if it is implemented forT, so you can do something likeOption::<UserInfo>::from_expr(User.name(name)). - [Transaction::lazy] also works with optional rows, so you can write
txn.lazy(User.name(name)). - For more complicated queries you have to use [args::Optional::then_select].
FAQ
-
Q: How do I get a full row from the database?
A: The [Lazy] type is most convenient if you want to use the row columns immediately. For other use cases, please take a look at the other options.
-
Q: How do I retrieve some columns + the [TableRow] of a row?
A: The [Lazy] type has a [Lazy::table_row] method to get the [TableRow].
-
Q: Why is [TableRow] (and many other types)
!Send?A: This prevents moving the [TableRow] between transactions. Moving a [TableRow] between transactions would make it possible for the refered row to already be deleted in the new transaction.
What it looks like
Define a schema using the syntax of a module with structs:
#
use schema;
Initialize a database:
let database = migrator
.expect
// migrations go here
.finish
.expect;
Perform a transaction!
database.transaction_mut_ok;
Insert in the database:
// Lets make a new user 'mike',
let mike = User ;
let mike_id = txn.insert_ok;
// and also insert a dog picture for 'mike'.
let dog_picture = Image ;
let _picture_id = txn.insert_ok;
Query from the database:
// Now we want to get all pictures for 'mike'.
let mike_pictures = txn.query;
println!; // This should print `["dog"]`.
Roadmap
This project is under development and there are some things missing. Below is a checklist of planned features and implemented features. (Implemented features have a checkmark, planned features do not).
Schema:
- Basic types (integer, real, text, blob, null)
- Basic foreign keys
- (Multi column) unique constraints
- Check constraints
- Overlapping foreign keys
Statements:
- Multi row query + single row query (and optional query)
- Single row insert, update and delete
Expressions:
- Some basic math, boolean and string operations
- Aggregate combinator
- Optional combinator
- Everything else
Advanced operations:
- Window
- Limit