Expand description
§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.- 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, aggregate(...)))
Note that the 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 Select, super useful when some of the values are aggregates.
- Derive FromExpr, choose this method if you just want (a subset of) existing columns.
- Use
YourTableName!(columns, that, you, want)
to do the same as the FromExpr derive. This last option is especially useful for migrations. Note that you have to import both the table name and the specialMacroRoot
type that is defined as part of the migration::schema macro. - Finally, you can implement 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::unique_name(name)
.
FromExpr is automatically implemented for Option<T>
if it is implemented for T
, so
you can do something like Option::<User!(name, score)>::from_expr(User::unique_name(name))
.
For more complicated queries you have to use the optional combinator.
§FAQ
-
Q: How do I get a full row from the database?
A: There is no special syntax to get all columns of a row, but you can use the facilities for getting multiple columns.
-
Q: How do I retrieve some columns + the TableRow of a row?
A: With something like this:
q.into_vec((&user, User!(name, score)::from_expr(&user)))
. -
Q: Why is TableRow
!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 rust_query::migration::schema;
#[schema(MySchema)]
pub mod vN {
// Structs are database tables
pub struct User {
// This table has one column with String (sqlite TEXT) type.
pub name: String,
}
pub struct Image {
pub description: String,
// This column has a foreign key constraint to the User table
pub uploaded_by: User,
}
}
Initialize a database:
let database = Database::migrator(Config::open("my_database.sqlite"))
.expect("database version is before supported versions")
// migrations go here
.finish()
.expect("database version is after supported versions");
Perform a transaction!
database.transaction_mut(|mut txn| {
do_stuff_with_database(&mut txn);
// After we are done we commit the changes!
txn.commit();
});
Insert in the database:
// Lets make a new user 'mike',
let mike = User { name: "mike" };
let mike_id = txn.insert_ok(mike);
// and also insert a dog picture for 'mike'.
let dog_picture = Image {
description: "dog",
uploaded_by: mike_id,
};
let _picture_id = txn.insert_ok(dog_picture);
Query from the database:
// Now we want to get all pictures for 'mike'.
let mike_pictures = txn.query(|rows| {
// Initially there is one empty row.
// Lets join the pictures table.
let picture = rows.join(Image);
// Now lets filter for pictures from mike,
rows.filter(picture.uploaded_by.eq(mike_id));
// and finally turn the rows into a vec.
rows.into_vec(&picture.description)
});
println!("{mike_pictures:?}"); // 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
Modules§
Structs§
- Database
- Database is a proof that the database has been configured.
- Expr
- This is an expression that can be used in queries.
- Select
- Select is used to define what to query from the database for each row.
- Table
Row - Row reference that can be used in any query in the same transaction.
- Transaction
- Transaction can be used to query and update the database.
- Transaction
Weak - This is the weak version of Transaction.
- Unix
Epoch - Use this a value in a query to get the current datetime as a number of miliseconds.
- Update
- Defines a column update.
Traits§
- From
Expr - Trait for values that can be retrieved from the database using one expression.
- Into
Expr - Trait for all values that can be used as expressions in queries.
- Into
Select - This trait is implemented by everything that can be retrieved from the database.
- Table
- This trait is implemented for all table types as generated by the crate::migration::schema macro.
Functions§
- aggregate
- Perform an aggregate that returns a single result for each of the current rows.
- optional
- This is a combinator function that allows constructing single row optional queries.