Move migrations to refinery + barrel, enable 'offline' sqlx query checking

This commit is contained in:
projectmoon 2020-12-30 16:14:04 +00:00
parent e148b45edd
commit 62f05060c0
17 changed files with 353 additions and 20 deletions

3
.env
View File

@ -1 +1,2 @@
DATABASE_URL="sqlite://./tenebrous.sqlite" DATABASE_URL="sqlite://tenebrous.sqlite"
SQLX_OFFLINE="true"

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
todo.org todo.org
*.sqlite *.sqlite
*.sqlite.*

93
Cargo.lock generated
View File

@ -144,6 +144,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "barrel"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d67c978b1322c8031145b1f6c236fc371292f52c565bc96018b2971afcbffe1"
[[package]] [[package]]
name = "base-x" name = "base-x"
version = "0.2.8" version = "0.2.8"
@ -508,6 +514,9 @@ name = "either"
version = "1.6.1" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "erased-serde" name = "erased-serde"
@ -524,6 +533,18 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 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]] [[package]]
name = "figment" name = "figment"
version = "0.9.4" version = "0.9.4"
@ -1711,6 +1732,50 @@ dependencies = [
"syn", "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]] [[package]]
name = "regex" name = "regex"
version = "1.4.2" version = "1.4.2"
@ -1818,6 +1883,21 @@ dependencies = [
"version_check", "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]] [[package]]
name = "rust-argon2" name = "rust-argon2"
version = "0.8.3" version = "0.8.3"
@ -1954,6 +2034,7 @@ version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
dependencies = [ dependencies = [
"indexmap",
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",
@ -1999,6 +2080,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "siphasher"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.2" version = "0.4.2"
@ -2084,6 +2171,7 @@ dependencies = [
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"percent-encoding", "percent-encoding",
"serde",
"sha2", "sha2",
"smallvec", "smallvec",
"sqlformat", "sqlformat",
@ -2105,9 +2193,12 @@ dependencies = [
"either", "either",
"futures", "futures",
"heck", "heck",
"hex",
"lazy_static", "lazy_static",
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde",
"serde_json",
"sha2", "sha2",
"sqlx-core", "sqlx-core",
"sqlx-rt", "sqlx-rt",
@ -2269,12 +2360,14 @@ dependencies = [
name = "tenebrous-sheets" name = "tenebrous-sheets"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"barrel",
"erased-serde", "erased-serde",
"futures", "futures",
"log", "log",
"prost", "prost",
"prost-build", "prost-build",
"rand", "rand",
"refinery",
"rocket", "rocket",
"rocket_contrib", "rocket_contrib",
"rust-argon2", "rust-argon2",

View File

@ -4,6 +4,15 @@ version = "0.1.0"
authors = ["jeff <jeff@agnos.is>"] authors = ["jeff <jeff@agnos.is>"]
edition = "2018" edition = "2018"
build = "build.rs" build = "build.rs"
default-run = "tenebrous"
[[bin]]
name = "migrate"
path = "src/migrate.rs"
[[bin]]
name = "tenebrous"
path = "src/main.rs"
[build-dependencies] [build-dependencies]
prost-build = "0.6" prost-build = "0.6"
@ -20,7 +29,9 @@ log = "0.4"
rand = "0.7" rand = "0.7"
futures = "0.3" futures = "0.3"
strum = { version = "0.20", features = ["derive"] } 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] [dependencies.rocket]
git = "https://github.com/SergioBenitez/Rocket" git = "https://github.com/SergioBenitez/Rocket"

View File

View File

@ -1 +0,0 @@
DROP TABLE characters;

View File

@ -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
);

View File

@ -1 +0,0 @@
DROP TABLE users;

View File

@ -1,5 +0,0 @@
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
password TEXT NOT NULL
);

165
sqlx-data.json Normal file
View File

@ -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
]
}
}
}

View File

@ -1,10 +1,21 @@
use crate::models::characters::{Character, NewCharacter, StrippedCharacter}; use crate::models::characters::{Character, NewCharacter, StrippedCharacter};
use crate::models::users::{NewUser, User}; 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 type TenebrousDbConn<'a> = rocket::State<'a, SqlitePool>;
pub(crate) async fn create_pool() -> Result<SqlitePool, crate::errors::Error> { pub(crate) async fn create_pool() -> Result<SqlitePool, crate::errors::Error> {
//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() SqlitePoolOptions::new()
.max_connections(5) .max_connections(5)
.connect("tenebrous.sqlite") .connect("tenebrous.sqlite")

View File

@ -15,11 +15,14 @@ use rocket_contrib::templates::Template;
pub mod catchers; pub mod catchers;
pub mod db; pub mod db;
pub mod errors; pub mod errors;
pub mod migrator;
pub mod models; pub mod models;
pub mod routes; pub mod routes;
#[rocket::main] #[rocket::main]
async fn main() -> Result<(), crate::errors::Error> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
migrator::migrate().await?;
let root_routes: Vec<rocket::Route> = { let root_routes: Vec<rocket::Route> = {
routes::root::routes() routes::root::routes()
.into_iter() .into_iter()

6
src/migrate.rs Normal file
View File

@ -0,0 +1,6 @@
pub mod migrator;
#[rocket::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
crate::migrator::migrate().await
}

21
src/migrator.rs Normal file
View File

@ -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<dyn std::error::Error>> {
//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(())
}

View File

@ -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::<Sqlite>()
}

View File

@ -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::<Sqlite>()
}

View File

@ -0,0 +1,2 @@
use refinery::include_migration_mods;
include_migration_mods!("src/migrator/migrations");