#[schema]
Expand description
Use this macro to define your schema.
§Supported data types:
i64
(sqliteinteger
)f64
(sqlitereal
)String
(sqlitetext
)- Any table in the same schema (sqlite
integer
with foreign key constraint) Option<T>
whereT
is not anOption
(sqlite nullable)
Booleans are not supported in schemas yet.
§Unique constraints
For example:
#[rust_query::migration::schema]
#[version(0..=0)]
enum Schema {
User {
#[unique_email]
email: String,
#[unique_username]
username: String,
}
}
This will create a single schema with a single table called user
and two columns.
The table will also have two unique contraints.
§Multiple versions
The macro uses enum syntax, but it generates multiple modules of types.
Note that the schema version range is 0..=0
so there is only a version 0.
The generated code will have a structure like this:
mod v0 {
struct User(..);
// a bunch of other stuff
}
§Adding tables
At some point you might want to add a new table.
#[rust_query::migration::schema]
#[version(0..=1)]
enum Schema {
User {
#[unique_email]
email: String,
#[unique_username]
username: String,
},
#[version(1..)] // <-- note that `Game`` has a version range
Game {
name: String,
size: i64,
}
}
We now have two schema versions which generates two modules v0
and v1
.
They look something like this:
mod v0 {
struct User(..);
// a bunch of other stuff
}
mod v1 {
struct User(..);
struct Game(..);
// a bunch of other stuff
}
§Changing columns
Changing columns is very similar to adding and removing structs.
use rust_query::migration::{schema, Prepare, Alter};
use rust_query::{Dummy, ThreadToken, Database};
#[schema]
#[version(0..=1)]
enum Schema {
User {
#[unique_email]
email: String,
#[unique_username]
username: String,
#[version(1..)] // <-- here
score: i64,
},
}
// In this case it is required to provide a value for each row that already exists.
// This is done with the `v1::update::UserMigration`:
pub fn migrate(t: &mut ThreadToken) -> Database<v1::Schema> {
let m = Prepare::open_in_memory(); // we use an in memory database for this test
let m = m.create_db_empty().expect("database version is before supported versions");
let m = m.migrate(t, |db| v1::update::Schema {
user: Box::new(|user|
Alter::new(v1::update::UserMigration {
score: user.email().map_dummy(|x| x.len() as i64) // use the email length as the new score
})
),
});
m.finish(t).expect("database version is after supported versions")
}
The migrate
function first creates an empty database if it does not exists.
Then it migrates the database if necessary, where it initializes every user score to the length of their email.
§Other features
You can delete columns and tables by specifying the version range end.
#[version(..3)]
You can make a multi column unique constraint by specifying it before the table.
#[unique(user, game)]
UserGameStats {
user: User,
game: Game,
score: i64,
}