Use connection pool in todo example.

This commit is contained in:
Sergio Benitez 2017-02-02 17:38:36 -08:00
parent 7f9ced7db3
commit a15002877d
3 changed files with 32 additions and 30 deletions

View File

@ -9,8 +9,10 @@ rocket_codegen = { path = "../../codegen" }
serde = "0.9" serde = "0.9"
serde_json = "0.9" serde_json = "0.9"
serde_derive = "0.9" serde_derive = "0.9"
r2d2 = "0.7"
diesel = { version = "0.10", features = ["sqlite"] } diesel = { version = "0.10", features = ["sqlite"] }
diesel_codegen = { version = "0.10", features = ["sqlite"] } diesel_codegen = { version = "0.10", features = ["sqlite"] }
r2d2-diesel = { version = "0.10", features = ["sqlite"] }
[dependencies.rocket_contrib] [dependencies.rocket_contrib]
path = "../../contrib" path = "../../contrib"

View File

@ -7,34 +7,38 @@ extern crate serde_json;
#[macro_use] extern crate diesel_codegen; #[macro_use] extern crate diesel_codegen;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
extern crate rocket_contrib; extern crate rocket_contrib;
extern crate r2d2;
extern crate r2d2_diesel;
mod static_files; mod static_files;
mod task; mod task;
mod db;
use rocket::request::{Form, FlashMessage}; use rocket::request::{Form, FlashMessage};
use rocket::response::{Flash, Redirect}; use rocket::response::{Flash, Redirect};
use rocket_contrib::Template; use rocket_contrib::Template;
use task::Task; use task::Task;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct Context<'a, 'b>{ msg: Option<(&'a str, &'b str)>, tasks: Vec<Task> } struct Context<'a, 'b>{ msg: Option<(&'a str, &'b str)>, tasks: Vec<Task> }
impl<'a, 'b> Context<'a, 'b> { impl<'a, 'b> Context<'a, 'b> {
pub fn err(msg: &'a str) -> Context<'static, 'a> { pub fn err(conn: &db::Conn, msg: &'a str) -> Context<'static, 'a> {
Context{msg: Some(("error", msg)), tasks: Task::all()} Context{msg: Some(("error", msg)), tasks: Task::all(conn)}
} }
pub fn raw(msg: Option<(&'a str, &'b str)>) -> Context<'a, 'b> { pub fn raw(conn: &db::Conn, msg: Option<(&'a str, &'b str)>) -> Context<'a, 'b> {
Context{msg: msg, tasks: Task::all()} Context{msg: msg, tasks: Task::all(conn)}
} }
} }
#[post("/", data = "<todo_form>")] #[post("/", data = "<todo_form>")]
fn new(todo_form: Form<Task>) -> Flash<Redirect> { fn new(todo_form: Form<Task>, conn: db::Conn) -> Flash<Redirect> {
let todo = todo_form.into_inner(); let todo = todo_form.into_inner();
if todo.description.is_empty() { if todo.description.is_empty() {
Flash::error(Redirect::to("/"), "Description cannot be empty.") Flash::error(Redirect::to("/"), "Description cannot be empty.")
} else if todo.insert() { } else if todo.insert(&conn) {
Flash::success(Redirect::to("/"), "Todo successfully added.") Flash::success(Redirect::to("/"), "Todo successfully added.")
} else { } else {
Flash::error(Redirect::to("/"), "Whoops! The server failed.") Flash::error(Redirect::to("/"), "Whoops! The server failed.")
@ -42,33 +46,34 @@ fn new(todo_form: Form<Task>) -> Flash<Redirect> {
} }
#[put("/<id>")] #[put("/<id>")]
fn toggle(id: i32) -> Result<Redirect, Template> { fn toggle(id: i32, conn: db::Conn) -> Result<Redirect, Template> {
if Task::toggle_with_id(id) { if Task::toggle_with_id(id, &conn) {
Ok(Redirect::to("/")) Ok(Redirect::to("/"))
} else { } else {
Err(Template::render("index", &Context::err("Couldn't toggle task."))) Err(Template::render("index", &Context::err(&conn, "Couldn't toggle task.")))
} }
} }
#[delete("/<id>")] #[delete("/<id>")]
fn delete(id: i32) -> Result<Flash<Redirect>, Template> { fn delete(id: i32, conn: db::Conn) -> Result<Flash<Redirect>, Template> {
if Task::delete_with_id(id) { if Task::delete_with_id(id, &conn) {
Ok(Flash::success(Redirect::to("/"), "Todo was deleted.")) Ok(Flash::success(Redirect::to("/"), "Todo was deleted."))
} else { } else {
Err(Template::render("index", &Context::err("Couldn't delete task."))) Err(Template::render("index", &Context::err(&conn, "Couldn't delete task.")))
} }
} }
#[get("/")] #[get("/")]
fn index(msg: Option<FlashMessage>) -> Template { fn index(msg: Option<FlashMessage>, conn: db::Conn) -> Template {
Template::render("index", &match msg { Template::render("index", &match msg {
Some(ref msg) => Context::raw(Some((msg.name(), msg.msg()))), Some(ref msg) => Context::raw(&conn, Some((msg.name(), msg.msg()))),
None => Context::raw(None), None => Context::raw(&conn, None),
}) })
} }
fn main() { fn main() {
rocket::ignite() rocket::ignite()
.manage(db::init_pool())
.mount("/", routes![index, static_files::all]) .mount("/", routes![index, static_files::all])
.mount("/todo/", routes![new, toggle, delete]) .mount("/todo/", routes![new, toggle, delete])
.launch(); .launch();

View File

@ -1,19 +1,14 @@
use diesel; use diesel;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::sqlite::SqliteConnection; use diesel::sqlite::SqliteConnection;
use self::schema::tasks; use self::schema::tasks;
use self::schema::tasks::dsl::{tasks as all_tasks, completed as task_completed}; use self::schema::tasks::dsl::{tasks as all_tasks, completed as task_completed};
const DATABASE_FILE: &'static str = env!("DATABASE_URL");
mod schema { mod schema {
infer_schema!("env:DATABASE_URL"); infer_schema!("env:DATABASE_URL");
} }
fn db() -> SqliteConnection {
SqliteConnection::establish(DATABASE_FILE).expect("Failed to connect to db.")
}
#[table_name = "tasks"] #[table_name = "tasks"]
#[derive(Serialize, Queryable, Insertable, FromForm, Debug, Clone)] #[derive(Serialize, Queryable, Insertable, FromForm, Debug, Clone)]
pub struct Task { pub struct Task {
@ -23,27 +18,27 @@ pub struct Task {
} }
impl Task { impl Task {
pub fn all() -> Vec<Task> { pub fn all(conn: &SqliteConnection) -> Vec<Task> {
all_tasks.order(tasks::id.desc()).load::<Task>(&db()).unwrap() all_tasks.order(tasks::id.desc()).load::<Task>(conn).unwrap()
} }
pub fn insert(&self) -> bool { pub fn insert(&self, conn: &SqliteConnection) -> bool {
diesel::insert(self).into(tasks::table).execute(&db()).is_ok() diesel::insert(self).into(tasks::table).execute(conn).is_ok()
} }
pub fn toggle_with_id(id: i32) -> bool { pub fn toggle_with_id(id: i32, conn: &SqliteConnection) -> bool {
let task = all_tasks.find(id).get_result::<Task>(&db()); let task = all_tasks.find(id).get_result::<Task>(conn);
if task.is_err() { if task.is_err() {
return false; return false;
} }
let new_status = !task.unwrap().completed.unwrap(); let new_status = !task.unwrap().completed.unwrap();
let updated_task = diesel::update(all_tasks.find(id)); let updated_task = diesel::update(all_tasks.find(id));
updated_task.set(task_completed.eq(new_status)).execute(&db()).is_ok() updated_task.set(task_completed.eq(new_status)).execute(conn).is_ok()
} }
pub fn delete_with_id(id: i32) -> bool { pub fn delete_with_id(id: i32, conn: &SqliteConnection) -> bool {
diesel::delete(all_tasks.find(id)).execute(&db()).is_ok() diesel::delete(all_tasks.find(id)).execute(conn).is_ok()
} }
} }