diff --git a/Cargo.lock b/Cargo.lock index ae1526c..694a124 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,6 +539,7 @@ dependencies = [ "byteorder", "diesel_derives", "pq-sys", + "r2d2", ] [[package]] @@ -552,6 +553,16 @@ dependencies = [ "syn", ] +[[package]] +name = "diesel_migrations" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c" +dependencies = [ + "migrations_internals", + "migrations_macros", +] + [[package]] name = "digest" version = "0.9.0" @@ -889,9 +900,11 @@ version = "0.1.0" dependencies = [ "async-std", "diesel", + "diesel_migrations", "env_logger", "log", "rust-embed", + "thiserror", "tide", ] @@ -931,6 +944,16 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -954,6 +977,27 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "migrations_internals" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b4fc84e4af020b837029e017966f86a1c2d5e83e64b589963d5047525995860" +dependencies = [ + "diesel", +] + +[[package]] +name = "migrations_macros" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" +dependencies = [ + "migrations_internals", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1001,6 +1045,29 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1108,6 +1175,17 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + [[package]] name = "rand" version = "0.7.3" @@ -1281,6 +1359,21 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "0.9.0" @@ -1433,6 +1526,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + [[package]] name = "socket2" version = "0.4.4" @@ -1871,3 +1970,46 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/Cargo.toml b/Cargo.toml index a502a92..b6f300e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,12 @@ edition = "2021" [dependencies] log = "0.4" env_logger = "0.9" +thiserror = "1" async-std = "1" tide = "0.16.0" -diesel = { version = "1.4", features = ["postgres"] } +diesel = { version = "1.4", features = ["postgres", "r2d2"] } +diesel_migrations = "1.4" rust-embed = { version = "6.2.0", features = ["interpolate-folder-path"]} diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b8a52dd --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=migrations/"); +} diff --git a/diesel.toml b/diesel.toml index 92267c8..71215db 100644 --- a/diesel.toml +++ b/diesel.toml @@ -2,4 +2,4 @@ # see diesel.rs/guides/configuring-diesel-cli [print_schema] -file = "src/schema.rs" +file = "src/db/schema.rs" diff --git a/src/api.rs b/src/api.rs index 907eec1..747fb56 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,6 +1,16 @@ -pub fn serve() -> tide::Server<()> { - let mut app = tide::new(); +use std::sync::Arc; +use diesel::pg::PgConnection; +use diesel::r2d2::{ConnectionManager, Pool}; + +pub struct State { + _db: Pool>, +} + +pub fn serve(db: Pool>) -> tide::Server> { + let state = Arc::new(State { _db: db }); + + let mut app = tide::with_state(state); app.at("/hello").get(|_| async { Ok("Hello, Jake!") }); app diff --git a/src/db/error.rs b/src/db/error.rs new file mode 100644 index 0000000..4ed0b54 --- /dev/null +++ b/src/db/error.rs @@ -0,0 +1,10 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("database pool failure: {0}")] + Pool(#[from] diesel::r2d2::PoolError), + + #[error("database migration failed: {0}")] + Migration(#[from] diesel::migration::RunMigrationsError), +} diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 0000000..629f804 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1,24 @@ +use log::info; + +mod error; +pub mod schema; + +use crate::embedded_migrations; +pub use error::Error; + +use std::env; + +use diesel::pg::PgConnection; +use diesel::r2d2::{ConnectionManager, Pool}; + +pub(super) fn new() -> Result>, Error> { + let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + + let pool = Pool::new(ConnectionManager::new(database_url))?; + + info!("starting db migrations..."); + embedded_migrations::run(&pool.get()?)?; + info!("db migrations complete"); + + Ok(pool) +} diff --git a/src/schema.rs b/src/db/schema.rs similarity index 100% rename from src/schema.rs rename to src/db/schema.rs diff --git a/src/main.rs b/src/main.rs index 3c3da6e..8df6fed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod api; +mod db; mod react; use api::serve as serve_api; @@ -7,13 +8,23 @@ use react::serve as serve_react; use async_std::task; use std::io; +#[macro_use] +extern crate diesel; + +// embed diesel migrations +#[macro_use] +extern crate diesel_migrations; + +embed_migrations!(); + fn main() -> Result<(), io::Error> { let env = env_logger::Env::new().filter_or("LOG", "info"); env_logger::init_from_env(env); - let mut app = tide::new(); + let db = db::new().unwrap(); - app.at("/_api").nest(serve_api()); + let mut app = tide::new(); + app.at("/_api").nest(serve_api(db)); app.at("/").nest(serve_react()); task::block_on(app.listen("127.0.0.1:8080"))