From 62f05060c054433482ed42466c5dc368e254adfe Mon Sep 17 00:00:00 2001 From: projectmoon Date: Wed, 30 Dec 2020 16:14:04 +0000 Subject: [PATCH] Move migrations to refinery + barrel, enable 'offline' sqlx query checking --- .env | 3 +- .gitignore | 1 + Cargo.lock | 93 ++++++++++ Cargo.toml | 13 +- migrations/.gitkeep | 0 .../2020-12-02-213704_characters/down.sql | 1 - .../2020-12-02-213704_characters/up.sql | 9 - migrations/2020-12-04-202734_users/down.sql | 1 - migrations/2020-12-04-202734_users/up.sql | 5 - sqlx-data.json | 165 ++++++++++++++++++ src/db.rs | 13 +- src/main.rs | 5 +- src/migrate.rs | 6 + src/migrator.rs | 21 +++ src/migrator/migrations/V1__users.rs | 15 ++ src/migrator/migrations/V2__characters.rs | 20 +++ src/migrator/migrations/mod.rs | 2 + 17 files changed, 353 insertions(+), 20 deletions(-) delete mode 100644 migrations/.gitkeep delete mode 100644 migrations/2020-12-02-213704_characters/down.sql delete mode 100644 migrations/2020-12-02-213704_characters/up.sql delete mode 100644 migrations/2020-12-04-202734_users/down.sql delete mode 100644 migrations/2020-12-04-202734_users/up.sql create mode 100644 sqlx-data.json create mode 100644 src/migrate.rs create mode 100644 src/migrator.rs create mode 100644 src/migrator/migrations/V1__users.rs create mode 100644 src/migrator/migrations/V2__characters.rs create mode 100644 src/migrator/migrations/mod.rs diff --git a/.env b/.env index 34b8b52..b157e9d 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -DATABASE_URL="sqlite://./tenebrous.sqlite" +DATABASE_URL="sqlite://tenebrous.sqlite" +SQLX_OFFLINE="true" diff --git a/.gitignore b/.gitignore index 75a61e2..9b8c154 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target todo.org *.sqlite +*.sqlite.* diff --git a/Cargo.lock b/Cargo.lock index 43ff2c2..e53a577 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "barrel" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d67c978b1322c8031145b1f6c236fc371292f52c565bc96018b2971afcbffe1" + [[package]] name = "base-x" version = "0.2.8" @@ -508,6 +514,9 @@ name = "either" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +dependencies = [ + "serde", +] [[package]] name = "erased-serde" @@ -524,6 +533,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "figment" version = "0.9.4" @@ -1711,6 +1732,50 @@ dependencies = [ "syn", ] +[[package]] +name = "refinery" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "432021bd2eb60a8851757fdd145907be1a96c70961da167a3fb362001f2f397c" +dependencies = [ + "refinery-core", + "refinery-macros", +] + +[[package]] +name = "refinery-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8c973af7988f84595fe204529bf04b129fcb33c77a928fdc049980beb24c5b" +dependencies = [ + "async-trait", + "cfg-if 0.1.10", + "chrono", + "lazy_static", + "log", + "regex", + "rusqlite", + "serde", + "siphasher", + "thiserror", + "toml", + "url", + "walkdir", +] + +[[package]] +name = "refinery-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f397c4dfbcf0b298e8b10e5702d69852829636ee121215c42efe421dd16126e1" +dependencies = [ + "proc-macro2", + "quote", + "refinery-core", + "regex", + "syn", +] + [[package]] name = "regex" version = "1.4.2" @@ -1818,6 +1883,21 @@ dependencies = [ "version_check", ] +[[package]] +name = "rusqlite" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38ee71cbab2c827ec0ac24e76f82eca723cee92c509a65f67dee393c25112" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "memchr", + "smallvec", +] + [[package]] name = "rust-argon2" version = "0.8.3" @@ -1954,6 +2034,7 @@ version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" dependencies = [ + "indexmap", "itoa", "ryu", "serde", @@ -1999,6 +2080,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" + [[package]] name = "slab" version = "0.4.2" @@ -2084,6 +2171,7 @@ dependencies = [ "once_cell", "parking_lot", "percent-encoding", + "serde", "sha2", "smallvec", "sqlformat", @@ -2105,9 +2193,12 @@ dependencies = [ "either", "futures", "heck", + "hex", "lazy_static", "proc-macro2", "quote", + "serde", + "serde_json", "sha2", "sqlx-core", "sqlx-rt", @@ -2269,12 +2360,14 @@ dependencies = [ name = "tenebrous-sheets" version = "0.1.0" dependencies = [ + "barrel", "erased-serde", "futures", "log", "prost", "prost-build", "rand", + "refinery", "rocket", "rocket_contrib", "rust-argon2", diff --git a/Cargo.toml b/Cargo.toml index c60e66e..6d41500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,15 @@ version = "0.1.0" authors = ["jeff "] edition = "2018" build = "build.rs" +default-run = "tenebrous" + +[[bin]] +name = "migrate" +path = "src/migrate.rs" + +[[bin]] +name = "tenebrous" +path = "src/main.rs" [build-dependencies] prost-build = "0.6" @@ -20,7 +29,9 @@ log = "0.4" rand = "0.7" futures = "0.3" strum = { version = "0.20", features = ["derive"] } -sqlx = { version = "0.4.2", features = [ "sqlite", "runtime-tokio-native-tls" ] } +sqlx = { version = "0.4.2", features = [ "offline", "sqlite", "runtime-tokio-native-tls" ] } +refinery = { version = "0.3", features = ["rusqlite"]} +barrel = { version = "0.6", features = ["sqlite3"] } [dependencies.rocket] git = "https://github.com/SergioBenitez/Rocket" diff --git a/migrations/.gitkeep b/migrations/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/migrations/2020-12-02-213704_characters/down.sql b/migrations/2020-12-02-213704_characters/down.sql deleted file mode 100644 index 75784eb..0000000 --- a/migrations/2020-12-02-213704_characters/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE characters; diff --git a/migrations/2020-12-02-213704_characters/up.sql b/migrations/2020-12-02-213704_characters/up.sql deleted file mode 100644 index 383481c..0000000 --- a/migrations/2020-12-02-213704_characters/up.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE characters( - id INTEGER NOT NULL PRIMARY KEY, - user_id INTEGER NOT NULL, - viewable BOOLEAN NOT NULL, - character_name TEXT NOT NULL, - data_type TEXT CHECK(data_type IN ('chronicles_of_darkness_v1', 'changeling_v1')) NOT NULL, - data_version INTEGER NOT NULL, - data BLOB NOT NULL -); diff --git a/migrations/2020-12-04-202734_users/down.sql b/migrations/2020-12-04-202734_users/down.sql deleted file mode 100644 index cc1f647..0000000 --- a/migrations/2020-12-04-202734_users/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE users; diff --git a/migrations/2020-12-04-202734_users/up.sql b/migrations/2020-12-04-202734_users/up.sql deleted file mode 100644 index 109d18a..0000000 --- a/migrations/2020-12-04-202734_users/up.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE users ( - id INTEGER NOT NULL PRIMARY KEY, - username TEXT NOT NULL, - password TEXT NOT NULL -); diff --git a/sqlx-data.json b/sqlx-data.json new file mode 100644 index 0000000..77a08eb --- /dev/null +++ b/sqlx-data.json @@ -0,0 +1,165 @@ +{ + "db": "SQLite", + "492e1e087edc6eff4004033227e3f3510f1165c3ec7626e89b695c760bc113d2": { + "query": "SELECT id as \"id: _\",\n user_id as \"user_id: _\",\n data_type as \"data_type: _\",\n data_version as \"data_version: _\",\n viewable, character_name\n FROM characters WHERE user_id = ?", + "describe": { + "columns": [ + { + "name": "id: _", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "user_id: _", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "data_type: _", + "ordinal": 2, + "type_info": "Null" + }, + { + "name": "data_version: _", + "ordinal": 3, + "type_info": "Int64" + }, + { + "name": "viewable", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "character_name", + "ordinal": 5, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false, + false, + false + ] + } + }, + "7a55ee917cf1ec732b10b2844dd5a3d0089c177b0eb183932fd73e20387a1610": { + "query": "SELECT id as \"id: _\", username, password FROM users WHERE username = ?", + "describe": { + "columns": [ + { + "name": "id: _", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 2, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + } + }, + "d7d1fc9ceff3b7659c8f04fd5b574104d1866cb1ea67d9534b6f3f4064699fb6": { + "query": "SELECT id as \"id: _\", username, password FROM users WHERE id = ?", + "describe": { + "columns": [ + { + "name": "id: _", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 2, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + } + }, + "e3c4b224ce8ce70a4d7709af7abe82a6f53bff834460fa7d32bb0b6daea94565": { + "query": "SELECT id as \"id: _\",\n user_id as \"user_id: _\",\n viewable, character_name, data,\n data_type as \"data_type: _\",\n data_version as \"data_version: _\"\n FROM characters WHERE id = ?", + "describe": { + "columns": [ + { + "name": "id: _", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "user_id: _", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "viewable", + "ordinal": 2, + "type_info": "Bool" + }, + { + "name": "character_name", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "data", + "ordinal": 4, + "type_info": "Blob" + }, + { + "name": "data_type: _", + "ordinal": 5, + "type_info": "Null" + }, + { + "name": "data_version: _", + "ordinal": 6, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ] + } + } +} \ No newline at end of file diff --git a/src/db.rs b/src/db.rs index 752d144..31e5bba 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,10 +1,21 @@ use crate::models::characters::{Character, NewCharacter, StrippedCharacter}; use crate::models::users::{NewUser, User}; -use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; +use sqlx::sqlite::{SqliteConnectOptions, SqlitePool, SqlitePoolOptions}; +use sqlx::ConnectOptions; +use std::str::FromStr; pub type TenebrousDbConn<'a> = rocket::State<'a, SqlitePool>; pub(crate) async fn create_pool() -> Result { + //Create database if missing. + let conn = SqliteConnectOptions::from_str("sqlite://tenebrous.sqlite")? + .create_if_missing(true) + .connect() + .await?; + + drop(conn); + + //Return actual conncetion pool. SqlitePoolOptions::new() .max_connections(5) .connect("tenebrous.sqlite") diff --git a/src/main.rs b/src/main.rs index a94618e..8ef23fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,11 +15,14 @@ use rocket_contrib::templates::Template; pub mod catchers; pub mod db; pub mod errors; +pub mod migrator; pub mod models; pub mod routes; #[rocket::main] -async fn main() -> Result<(), crate::errors::Error> { +async fn main() -> Result<(), Box> { + migrator::migrate().await?; + let root_routes: Vec = { routes::root::routes() .into_iter() diff --git a/src/migrate.rs b/src/migrate.rs new file mode 100644 index 0000000..c7d9f7b --- /dev/null +++ b/src/migrate.rs @@ -0,0 +1,6 @@ +pub mod migrator; + +#[rocket::main] +async fn main() -> Result<(), Box> { + crate::migrator::migrate().await +} diff --git a/src/migrator.rs b/src/migrator.rs new file mode 100644 index 0000000..4b1f9d3 --- /dev/null +++ b/src/migrator.rs @@ -0,0 +1,21 @@ +use refinery::config::{Config, ConfigDbType}; +use sqlx::sqlite::SqliteConnectOptions; +use sqlx::ConnectOptions; +use std::str::FromStr; + +pub mod migrations; + +pub(crate) async fn migrate() -> Result<(), Box> { + //Create database if missing. + let conn = SqliteConnectOptions::from_str("sqlite://tenebrous.sqlite")? + .create_if_missing(true) + .connect() + .await?; + + drop(conn); + + let mut conn = Config::new(ConfigDbType::Sqlite).set_db_path("tenebrous.sqlite"); + println!("Running migrations"); + migrations::runner().run(&mut conn)?; + Ok(()) +} diff --git a/src/migrator/migrations/V1__users.rs b/src/migrator/migrations/V1__users.rs new file mode 100644 index 0000000..107afc4 --- /dev/null +++ b/src/migrator/migrations/V1__users.rs @@ -0,0 +1,15 @@ +use barrel::backend::Sqlite; +use barrel::{types, Migration}; + +pub fn migration() -> String { + let mut m = Migration::new(); + println!("Applying: {}", file!()); + + m.create_table("users", |t| { + t.add_column("id", types::primary()); + t.add_column("username", types::text()); + t.add_column("password", types::text()); + }); + + m.make::() +} diff --git a/src/migrator/migrations/V2__characters.rs b/src/migrator/migrations/V2__characters.rs new file mode 100644 index 0000000..a4aeb87 --- /dev/null +++ b/src/migrator/migrations/V2__characters.rs @@ -0,0 +1,20 @@ +use barrel::backend::Sqlite; +use barrel::{types, Migration}; + +pub fn migration() -> String { + let mut m = Migration::new(); + println!("Applying: {}", file!()); + + m.create_table("characters", move |t| { + let db_enum = r#"CHECK(data_type IN ('chronicles_of_darkness_v1', 'changeling_v1'))"#; + t.add_column("id", types::primary()); + t.add_column("user_id", types::integer()); + t.add_column("viewable", types::boolean()); + t.add_column("character_name", types::text()); + t.add_column("data_type", types::custom(db_enum)); + t.add_column("data_version", types::integer()); + t.add_column("data", types::custom("BLOB")); + }); + + m.make::() +} diff --git a/src/migrator/migrations/mod.rs b/src/migrator/migrations/mod.rs new file mode 100644 index 0000000..b237433 --- /dev/null +++ b/src/migrator/migrations/mod.rs @@ -0,0 +1,2 @@ +use refinery::include_migration_mods; +include_migration_mods!("src/migrator/migrations");