diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 742c070..389cba0 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -2,6 +2,7 @@
members = [
"application",
"async-handlers",
+ "databases",
"easy-form-handling",
"either",
"errors",
@@ -23,5 +24,3 @@ members = [
"url-dispatch",
"websockets",
]
-# TODO: update databases
-exclude = ["databases"]
diff --git a/examples/databases/Cargo.toml b/examples/databases/Cargo.toml
index 276e6a2..b17a4aa 100644
--- a/examples/databases/Cargo.toml
+++ b/examples/databases/Cargo.toml
@@ -5,3 +5,6 @@ edition = "2018"
[dependencies]
actix-web = "4"
+diesel = { version = "2", features = ["sqlite", "r2d2"] }
+serde = { version = "1", features = ["derive"] }
+uuid = { version = "1", features = ["v4"] }
diff --git a/examples/databases/src/main.rs b/examples/databases/src/main.rs
index efffd29..55efa1e 100644
--- a/examples/databases/src/main.rs
+++ b/examples/databases/src/main.rs
@@ -1,43 +1,76 @@
+use std::io;
+
+use actix_web::{error, web, App, HttpResponse, HttpServer, Responder};
+use diesel::{prelude::*, r2d2, Insertable, Queryable, SqliteConnection};
+use serde::Serialize;
+
+mod schema {
+ diesel::table! {
+ users {
+ id -> VarChar,
+ name -> VarChar,
+ }
+ }
+}
+
+#[derive(Debug, Serialize, Queryable)]
+struct User {
+ id: String,
+ name: String,
+}
+
//
-fn insert_new_user(db: &SqliteConnection, user: CreateUser) -> Result {
- use self::schema::users::dsl::*;
+#[derive(Debug, Insertable)]
+#[diesel(table_name = self::schema::users)]
+struct NewUser<'a> {
+ id: &'a str,
+ name: &'a str,
+}
+
+fn insert_new_user(
+ conn: &mut SqliteConnection,
+ user_name: String,
+) -> diesel::QueryResult {
+ use crate::schema::users::dsl::*;
// Create insertion model
- let uuid = format!("{}", uuid::Uuid::new_v4());
- let new_user = models::NewUser {
- id: &uuid,
- name: &user.name,
+ let uid = format!("{}", uuid::Uuid::new_v4());
+ let new_user = NewUser {
+ id: &uid,
+ name: &user_name,
};
// normal diesel operations
diesel::insert_into(users)
.values(&new_user)
- .execute(&self.0)
+ .execute(conn)
.expect("Error inserting person");
- let mut items = users
- .filter(id.eq(&uuid))
- .load::(&self.0)
- .expect("Error loading person");
+ let user = users
+ .filter(id.eq(&uid))
+ .first::(conn)
+ .expect("Error loading person that was just inserted");
- Ok(items.pop().unwrap())
+ Ok(user)
}
//
//
-type DbPool = r2d2::Pool>;
+type DbPool = r2d2::Pool>;
#[actix_web::main]
async fn main() -> io::Result<()> {
- // Create connection pool
+ // connect to SQLite DB
+ let manager = r2d2::ConnectionManager::::new("app.db");
let pool = r2d2::Pool::builder()
.build(manager)
- .expect("Failed to create pool.");
+ .expect("database URL should be valid path to SQLite DB file");
- // Start HTTP server
+ // start HTTP server on port 8080
HttpServer::new(move || {
- App::new().app_data(web::Data::new(pool.clone()))
- .resource("/{name}", web::get().to(index))
+ App::new()
+ .app_data(web::Data::new(pool.clone()))
+ .route("/{name}", web::get().to(index))
})
.bind(("127.0.0.1", 8080))?
.run()
@@ -46,18 +79,21 @@ async fn main() -> io::Result<()> {
//
//
-async fn index(pool: web::Data, name: web::Path<(String)>) -> impl Responder {
- let name = name.into_inner();
+async fn index(
+ pool: web::Data,
+ name: web::Path<(String,)>,
+) -> actix_web::Result {
+ let (name,) = name.into_inner();
let user = web::block(move || {
- let conn = pool.get().expect("couldn't get db connection from pool");
- actions::insert_new_user(&conn, &user)
- .await
- .map_err(|e| {
- eprintln!("{}", e);
- HttpResponse::InternalServerError().finish()
- }
- })?;
+ // Obtaining a connection from the pool is also a potentially blocking operation.
+ // So, it should be called within the `web::block` closure, as well.
+ let mut conn = pool.get().expect("couldn't get db connection from pool");
+
+ insert_new_user(&mut conn, name)
+ })
+ .await?
+ .map_err(error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(user))
}