Introduce db connection pool. Derive Clone for State

This commit is contained in:
Magnus Hoff 2017-09-05 14:55:10 +02:00
parent 5a859e5c33
commit 60a87d1898
5 changed files with 87 additions and 23 deletions

38
Cargo.lock generated
View file

@ -14,6 +14,8 @@ dependencies = [
"num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2-diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -37,6 +39,11 @@ name = "ansi_term"
version = "0.9.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "antidote"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.2" version = "0.2.2"
@ -451,6 +458,25 @@ name = "quote"
version = "0.3.15" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "r2d2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "r2d2-diesel"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"diesel 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.3.16" version = "0.3.16"
@ -504,6 +530,14 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "scheduled-thread-pool"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "scoped-tls" name = "scoped-tls"
version = "0.1.0" version = "0.1.0"
@ -791,6 +825,7 @@ dependencies = [
[metadata] [metadata]
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
"checksum bart 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f9d52a5c46e2abe28ae1c2ecdaa320c01e424c29a56acb7a6222141c78bae7" "checksum bart 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f9d52a5c46e2abe28ae1c2ecdaa320c01e424c29a56acb7a6222141c78bae7"
"checksum bart_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "39fdc9035ac29aeb14993e2cdae217de7ccc9f9960eae0c5a12d541ca11c6af1" "checksum bart_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "39fdc9035ac29aeb14993e2cdae217de7ccc9f9960eae0c5a12d541ca11c6af1"
@ -843,6 +878,8 @@ dependencies = [
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum pulldown-cmark 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4c7c04a8bb38f80717527edea39c82378c2ef13ecdbc914cbd90653a2e24afdf" "checksum pulldown-cmark 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4c7c04a8bb38f80717527edea39c82378c2ef13ecdbc914cbd90653a2e24afdf"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c665a538b218e1620093be6643b375d3321837bfc1b30aa18757b7c6546d2ca"
"checksum r2d2-diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6b921696a6c45991296d21b52ed973b9fb56f6c47524fda1f99458c2d6c0478"
"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf"
"checksum redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "8312fba776a49cf390b7b62f3135f9b294d8617f7a7592cfd0ac2492b658cd7b" "checksum redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "8312fba776a49cf390b7b62f3135f9b294d8617f7a7592cfd0ac2492b658cd7b"
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
@ -850,6 +887,7 @@ dependencies = [
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d9fbe48ead32343b76f544c85953bf260ed39219a8bbbb62cd85f6a00f9644f"
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9"

View file

@ -12,6 +12,8 @@ tokio-service = "0.1"
serde_derive = "1.0.0" serde_derive = "1.0.0"
serde = "1.0.0" serde = "1.0.0"
serde_urlencoded = "0.5.0" serde_urlencoded = "0.5.0"
r2d2 = "0.7"
r2d2-diesel = "0.16"
regex = "0.2" regex = "0.2"
lazy_static = "0.2" lazy_static = "0.2"
chrono = "0.4" chrono = "0.4"

View file

@ -1,23 +1,33 @@
use diesel::Connection;
use diesel::sqlite::SqliteConnection; use diesel::sqlite::SqliteConnection;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::expression::sql_literal::sql; use diesel::expression::sql_literal::sql;
use diesel::types::*; use diesel::types::*;
use r2d2::{Config, CustomizeConnection, Pool};
use r2d2_diesel::{self, ConnectionManager};
embed_migrations!(); embed_migrations!();
pub fn connect_database(connection_string: &str, run_migrations: bool) -> SqliteConnection { #[derive(Debug)]
let connection = SqliteConnection::establish(connection_string) struct SqliteInitializer;
.expect(&format!("Error connecting to database at {}", connection_string));
// Integer is a dummy placeholder. Compiling fails when passing (). impl CustomizeConnection<SqliteConnection, r2d2_diesel::Error> for SqliteInitializer {
fn on_acquire(&self, conn: &mut SqliteConnection) -> Result<(), r2d2_diesel::Error> {
sql::<(Integer)>("PRAGMA foreign_keys = ON") sql::<(Integer)>("PRAGMA foreign_keys = ON")
.execute(&connection) .execute(conn)
.expect("Should be able to enable foreign_keys"); .and(Ok(()))
.map_err(|x| r2d2_diesel::Error::QueryError(x))
if run_migrations {
embedded_migrations::run(&connection).unwrap();
} }
}
connection
pub fn create_pool(connection_string: String) -> Result<Pool<ConnectionManager<SqliteConnection>>, Box<::std::error::Error>> {
let config = Config::builder()
.connection_customizer(Box::new(SqliteInitializer {}))
.build();
let manager = ConnectionManager::<SqliteConnection>::new(connection_string);
let pool = Pool::new(config, manager)?;
embedded_migrations::run(&*pool.get()?)?;
Ok(pool)
} }

View file

@ -2,13 +2,16 @@
#[macro_use] extern crate diesel; #[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen; #[macro_use] extern crate diesel_codegen;
#[macro_use] extern crate lazy_static; #[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde_derive;
extern crate bart;
extern crate chrono; extern crate chrono;
extern crate clap; extern crate clap;
extern crate futures; extern crate futures;
extern crate hyper; extern crate hyper;
extern crate pulldown_cmark; extern crate pulldown_cmark;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate serde_urlencoded;
use std::net::SocketAddr; use std::net::SocketAddr;
@ -48,14 +51,14 @@ fn core_main() -> Result<(), Box<std::error::Error>> {
.map(|p| p.parse().expect("Guaranteed by validator")) .map(|p| p.parse().expect("Guaranteed by validator"))
.unwrap_or(8080); .unwrap_or(8080);
// Connect to the database and run migrations up front: let db_pool = db::create_pool(db_file)?;
db::connect_database(&db_file, true); let state = state::State::new(db_pool);
let server = let server =
hyper::server::Http::new() hyper::server::Http::new()
.bind( .bind(
&SocketAddr::new(bind_host, bind_port), &SocketAddr::new(bind_host, bind_port),
move || Ok(site::Site::new(state::State::new(db::connect_database(&db_file, false)))) move || Ok(site::Site::new(state.clone()))
)?; )?;
println!("Listening on http://{}", server.local_addr().unwrap()); println!("Listening on http://{}", server.local_addr().unwrap());

View file

@ -3,19 +3,30 @@ use std;
use chrono; use chrono;
use diesel::sqlite::SqliteConnection; use diesel::sqlite::SqliteConnection;
use diesel::prelude::*; use diesel::prelude::*;
use r2d2::Pool;
use r2d2_diesel::ConnectionManager;
use models; use models;
#[derive(Clone)]
pub struct State { pub struct State {
db_connection: SqliteConnection connection_pool: Pool<ConnectionManager<SqliteConnection>>
} }
#[derive(Deserialize)]
pub struct UpdateArticle {
base_revision: i32,
body: String,
}
pub type Error = Box<std::error::Error + Send + Sync>;
impl State { impl State {
pub fn new(db_connection: SqliteConnection) -> State { pub fn new(connection_pool: Pool<ConnectionManager<SqliteConnection>>) -> State {
State { db_connection } State { connection_pool }
} }
pub fn get_article_revision_by_slug(&self, slug: &str) -> Result<Option<models::ArticleRevision>, Box<std::error::Error + Send + Sync>> { pub fn get_article_revision_by_slug(&self, slug: &str) -> Result<Option<models::ArticleRevision>, Error> {
Ok(Some(models::ArticleRevision { Ok(Some(models::ArticleRevision {
article_id: 0, article_id: 0,
revision: 0, revision: 0,
@ -25,14 +36,14 @@ impl State {
})) }))
} }
pub fn get_article_revision_by_id(&self, article_id: i32) -> Result<Option<models::ArticleRevision>, Box<std::error::Error + Send + Sync>> { pub fn get_article_revision_by_id(&self, article_id: i32) -> Result<Option<models::ArticleRevision>, Error> {
use schema::article_revisions; use schema::article_revisions;
Ok(article_revisions::table Ok(article_revisions::table
.filter(article_revisions::article_id.eq(article_id)) .filter(article_revisions::article_id.eq(article_id))
.order(article_revisions::revision.desc()) .order(article_revisions::revision.desc())
.limit(1) .limit(1)
.load::<models::ArticleRevision>(&self.db_connection)? .load::<models::ArticleRevision>(&*self.connection_pool.get()?)?
.pop()) .pop())
} }
} }