//! The embedded store's migration runner. //! //! //! //! # Why this is a quasi crate //! //! The admission test in `CONTRIBUTING.md` asks which two implementations a //! boundary has. When goingson and Balanced Breakfast moved to rusqlite they //! each hand-wrote a runner, and a third would have been written by the first //! app the scaffolder generated. Two copies existing is the evidence; the //! crate is what stops the third. //! //! It is a quasi crate rather than a makeover one on the audience rule: a //! migration runner tied to our ledger conventions is something you take once //! you are on the stack, not something another developer picks up on its own. //! There are good standalone migration crates and this is not competing with //! them. //! //! # The two halves //! //! They share no dependency, and that is the point rather than tidiness. //! //! - [`runtime`](crate::migrate) reads the ledger and applies what is missing. //! An app links it. //! - [`build`](crate::embed) turns a directory of `.sql` files into a table //! compiled into the binary. An app's `build.rs` links it, with //! `default-features = false`, so a build script does not pull //! `libsqlite3-sys` into a second compile for the host. //! //! ```toml //! [dependencies] //! quasi-store = { path = "../../../quasi/crates/quasi-store" } //! //! [build-dependencies] //! quasi-store = { path = "../../../quasi/crates/quasi-store", default-features = false, features = ["build"] } //! ``` //! //! # Using it //! //! `build.rs`, once. Not compiled as a doctest: the two halves are separate //! features and a doctest gets one set of them, so an example naming both would //! have to turn on the driver this half exists to avoid. //! //! ```ignore //! fn main() { //! quasi_store::embed::from_dir("../../migrations").expect("migrations"); //! } //! ``` //! //! Then the crate, once: //! //! ```ignore //! quasi_store::migrations!(); //! //! let mut conn = rusqlite::Connection::open("app.db")?; //! quasi_store::Migrator::new(MIGRATIONS).run(&mut conn)?; //! ``` //! //! # What it does not do //! //! Connections, pools, queries, or anything resembling a query layer. quasi //! owns which driver is configured and how migrations run, and queries stay //! written against `rusqlite` directly — the same line the README draws around //! `sqlx`, for the same reason. There is no Postgres half here and there should //! not be one: `sqlx` ships its own migrator and it is one of the reasons to //! use `sqlx`. #[cfg(feature = "build")] pub mod embed; #[cfg(feature = "runtime")] pub mod migrate; #[cfg(feature = "runtime")] pub use crate::migrate::{MigrateError, Migration, Migrator}; /// Include the table [`embed::from_dir`] generated. /// /// A macro rather than a documented `include!` line, so the path the build /// script writes to is named in one place. Expands to a /// `static MIGRATIONS: &[Migration]`. #[cfg(feature = "runtime")] #[macro_export] macro_rules! migrations { () => { include!(concat!(env!("OUT_DIR"), "/quasi_migrations.rs")); }; }