Move migration code to lib.rs
This commit is contained in:
parent
f37b4aa81c
commit
b432f0ac37
2 changed files with 34 additions and 34 deletions
32
src/lib.rs
32
src/lib.rs
|
|
@ -12,7 +12,7 @@
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
pub mod tokio;
|
pub mod tokio;
|
||||||
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::{Connection, Transaction};
|
||||||
|
|
||||||
/// An action that can be performed on a [`Connection`].
|
/// An action that can be performed on a [`Connection`].
|
||||||
///
|
///
|
||||||
|
|
@ -25,3 +25,33 @@ pub trait Action {
|
||||||
type Result;
|
type Result;
|
||||||
fn run(self, conn: &mut Connection) -> rusqlite::Result<Self::Result>;
|
fn run(self, conn: &mut Connection) -> rusqlite::Result<Self::Result>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single database migration.
|
||||||
|
///
|
||||||
|
/// It receives a [`Transaction`] to perform database operations in, its index
|
||||||
|
/// in the migration array and the size of the migration array. The latter two
|
||||||
|
/// might be useful for logging.
|
||||||
|
///
|
||||||
|
/// The transaction spans all migrations currently being performed. If any
|
||||||
|
/// single migration fails, all migrations are rolled back and the database is
|
||||||
|
/// unchanged.
|
||||||
|
///
|
||||||
|
/// The migration does not need to update the `user_version` or commit the
|
||||||
|
/// transaction.
|
||||||
|
pub type Migration = fn(&mut Transaction<'_>, usize, usize) -> rusqlite::Result<()>;
|
||||||
|
|
||||||
|
fn migrate(conn: &mut Connection, migrations: &[Migration]) -> rusqlite::Result<()> {
|
||||||
|
let mut tx = conn.transaction()?;
|
||||||
|
|
||||||
|
let user_version: usize =
|
||||||
|
tx.query_row("SELECT * FROM pragma_user_version", [], |r| r.get(0))?;
|
||||||
|
|
||||||
|
let total = migrations.len();
|
||||||
|
assert!(user_version <= total, "malformed database schema");
|
||||||
|
for (i, migration) in migrations.iter().enumerate().skip(user_version) {
|
||||||
|
migration(&mut tx, i, total)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.pragma_update(None, "user_version", total)?;
|
||||||
|
tx.commit()
|
||||||
|
}
|
||||||
|
|
|
||||||
36
src/tokio.rs
36
src/tokio.rs
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
use std::{any::Any, result, thread};
|
use std::{any::Any, result, thread};
|
||||||
|
|
||||||
use rusqlite::{Connection, Transaction};
|
use rusqlite::Connection;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
|
||||||
use crate::Action;
|
use crate::{Action, Migration};
|
||||||
|
|
||||||
/// Wrapper trait around [`Action`] that turns `Box<Self>` into a `Self` and the
|
/// Wrapper trait around [`Action`] that turns `Box<Self>` into a `Self` and the
|
||||||
/// action's return type into `Box<dyn Any + Send>`.
|
/// action's return type into `Box<dyn Any + Send>`.
|
||||||
|
|
@ -48,36 +48,6 @@ pub enum Error {
|
||||||
|
|
||||||
pub type Result<R> = result::Result<R, Error>;
|
pub type Result<R> = result::Result<R, Error>;
|
||||||
|
|
||||||
/// A single database migration.
|
|
||||||
///
|
|
||||||
/// It receives a [`Transaction`] to perform database operations in, its index
|
|
||||||
/// in the migration array and the size of the migration array. The latter two
|
|
||||||
/// might be useful for logging.
|
|
||||||
///
|
|
||||||
/// The transaction spans all migrations currently being performed. If any
|
|
||||||
/// single migration fails, all migrations are rolled back and the database is
|
|
||||||
/// unchanged.
|
|
||||||
///
|
|
||||||
/// The migration does not need to update the `user_version` or commit the
|
|
||||||
/// transaction.
|
|
||||||
pub type Migration = fn(&mut Transaction<'_>, usize, usize) -> rusqlite::Result<()>;
|
|
||||||
|
|
||||||
fn migrate(conn: &mut Connection, migrations: &[Migration]) -> rusqlite::Result<()> {
|
|
||||||
let mut tx = conn.transaction()?;
|
|
||||||
|
|
||||||
let user_version: usize =
|
|
||||||
tx.query_row("SELECT * FROM pragma_user_version", [], |r| r.get(0))?;
|
|
||||||
|
|
||||||
let total = migrations.len();
|
|
||||||
assert!(user_version <= total, "malformed database schema");
|
|
||||||
for (i, migration) in migrations.iter().enumerate().skip(user_version) {
|
|
||||||
migration(&mut tx, i, total)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.pragma_update(None, "user_version", total)?;
|
|
||||||
tx.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(mut conn: Connection, mut rx: mpsc::UnboundedReceiver<Command>) {
|
fn run(mut conn: Connection, mut rx: mpsc::UnboundedReceiver<Command>) {
|
||||||
while let Some(command) = rx.blocking_recv() {
|
while let Some(command) = rx.blocking_recv() {
|
||||||
match command {
|
match command {
|
||||||
|
|
@ -132,7 +102,7 @@ impl TokioVault {
|
||||||
migrations: &[Migration],
|
migrations: &[Migration],
|
||||||
prepare: impl FnOnce(&mut Connection) -> rusqlite::Result<()>,
|
prepare: impl FnOnce(&mut Connection) -> rusqlite::Result<()>,
|
||||||
) -> rusqlite::Result<Self> {
|
) -> rusqlite::Result<Self> {
|
||||||
migrate(&mut conn, migrations)?;
|
crate::migrate(&mut conn, migrations)?;
|
||||||
prepare(&mut conn)?;
|
prepare(&mut conn)?;
|
||||||
|
|
||||||
let (tx, rx) = mpsc::unbounded_channel();
|
let (tx, rx) = mpsc::unbounded_channel();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue