Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

60 linesCodeBlameRaw
1//! The work database as the migrations make it, for tests: SQLite (which
2//! D1 is), with foreign keys on as D1 has them, each migration in a
3//! transaction of its own as D1 applies it.
4
5use rusqlite::Connection;
6
7/// The migrations, in order: each file's name and SQL.
8pub(crate) fn migrations() -> Vec<(String, String)> {
9 let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("migrations");
10 let mut names: Vec<String> = std::fs::read_dir(&dir)
11 .unwrap()
12 .map(|entry| entry.unwrap().file_name().into_string().unwrap())
13 .filter(|name| name.ends_with(".sql"))
14 .collect();
15 names.sort();
16 names.into_iter().map(|name| (name.clone(), std::fs::read_to_string(dir.join(&name)).unwrap())).collect()
17}
18
19/// Applies one migration as D1 does: in one transaction.
20pub(crate) fn apply(db: &Connection, name: &str, sql: &str) {
21 db.execute_batch(&format!("BEGIN;\n{sql}\nCOMMIT;")).unwrap_or_else(|error| panic!("{name}: {error}"));
22}
23
24/// A database at `path` with every migration applied.
25pub(crate) fn database_at(path: impl AsRef<std::path::Path>) -> Connection {
26 let db = Connection::open(path).unwrap();
27 db.execute_batch("PRAGMA foreign_keys = ON;").unwrap();
28 for (name, sql) in migrations() {
29 apply(&db, &name, &sql);
30 }
31 db
32}
33
34/// An in-memory database with every migration applied.
35pub(crate) fn database() -> Connection {
36 database_at(":memory:")
37}
38
39/// An in-memory database with the migrations before `name` applied, for
40/// filling with what that migration then moves.
41pub(crate) fn database_before(name: &str) -> Connection {
42 let db = Connection::open_in_memory().unwrap();
43 db.execute_batch("PRAGMA foreign_keys = ON;").unwrap();
44 for (file, sql) in migrations() {
45 if file.as_str() >= name {
46 break;
47 }
48 apply(&db, &file, &sql);
49 }
50 db
51}
52
53/// Applies the migrations from `name` on.
54pub(crate) fn migrate_from(db: &Connection, name: &str) {
55 for (file, sql) in migrations() {
56 if file.as_str() >= name {
57 apply(db, &file, &sql);
58 }
59 }
60}