diff --git a/examples/diesel/.env b/examples/diesel/.env new file mode 100644 index 000000000..1fbc5af72 --- /dev/null +++ b/examples/diesel/.env @@ -0,0 +1 @@ +DATABASE_URL=file:test.db diff --git a/examples/diesel/Cargo.toml b/examples/diesel/Cargo.toml new file mode 100644 index 000000000..40e78e307 --- /dev/null +++ b/examples/diesel/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "diesel-example" +version = "0.1.0" +authors = ["Nikolay Kim "] + +[dependencies] +env_logger = "0.4" +actix = "^0.3.1" +actix-web = { git = "https://github.com/actix/actix-web.git" } + +futures = "0.1" +uuid = { version = "0.5", features = ["serde", "v4"] } +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" + +diesel = { version = "1.0.0-beta1", features = ["sqlite"] } +dotenv = "0.10" diff --git a/examples/diesel/README.md b/examples/diesel/README.md new file mode 100644 index 000000000..129c4fbe3 --- /dev/null +++ b/examples/diesel/README.md @@ -0,0 +1,15 @@ +Diesel's `Getting Started` guide using SQLite for Actix web + +## Usage + +install `diesel_cli` + +``` +cargo install diesel_cli --no-default-features --features sqlite +``` + + +``` +$ echo "DATABASE_URL=file:test.db" > .env +$ diesel migration run +``` diff --git a/examples/diesel/migrations/20170124012402_create_users/down.sql b/examples/diesel/migrations/20170124012402_create_users/down.sql new file mode 100644 index 000000000..9951735c4 --- /dev/null +++ b/examples/diesel/migrations/20170124012402_create_users/down.sql @@ -0,0 +1 @@ +DROP TABLE users diff --git a/examples/diesel/migrations/20170124012402_create_users/up.sql b/examples/diesel/migrations/20170124012402_create_users/up.sql new file mode 100644 index 000000000..d88d44fb7 --- /dev/null +++ b/examples/diesel/migrations/20170124012402_create_users/up.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR NOT NULL +) diff --git a/examples/diesel/src/main.rs b/examples/diesel/src/main.rs new file mode 100644 index 000000000..331c5f800 --- /dev/null +++ b/examples/diesel/src/main.rs @@ -0,0 +1,114 @@ +//! Actix web diesel example +//! +//! Diesel does not support tokio, so we have to run it in separate threads. +//! Actix supports sync actors by default, so we going to create sync actor that will +//! use diesel. Technically sync actors are worker style actors, multiple of them +//! can run in parallele and process messages from same queue. +extern crate serde; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate diesel; +extern crate uuid; +extern crate futures; +extern crate actix; +extern crate actix_web; +extern crate env_logger; + +use actix::prelude::*; +use actix_web::*; +use futures::future::{Future, ok}; +use diesel::Connection; +use diesel::sqlite::SqliteConnection; +use diesel::prelude::*; + +mod models; +mod schema; + + +struct State { + db: SyncAddress, +} + +fn index(req: HttpRequest) -> Box> { + let name = &req.match_info()["name"]; + + Box::new( + req.state().db.call_fut(CreatePerson{name: name.to_owned()}) + .and_then(|res| { + match res { + Ok(person) => ok(httpcodes::HTTPOk.build().json(person).unwrap()), + Err(_) => ok(httpcodes::HTTPInternalServerError.response()) + } + }) + .map_err(|e| error::ErrorInternalServerError(e).into())) +} + +/// This is db executor actor. We are going to run 3 of them in parallele. +struct DbExecutor(SqliteConnection); + +/// This is only message that this actor can handle, but it is easy to extend number of +/// messages. +struct CreatePerson { + name: String, +} + +impl ResponseType for CreatePerson { + type Item = models::User; + type Error = Error; +} + +impl Actor for DbExecutor { + type Context = SyncContext; +} + +impl Handler for DbExecutor { + fn handle(&mut self, msg: CreatePerson, _: &mut Self::Context) + -> Response + { + use self::schema::users::dsl::*; + + let uuid = format!("{}", uuid::Uuid::new_v4()); + let new_user = models::NewUser { + id: &uuid, + name: &msg.name, + }; + + diesel::insert_into(users) + .values(&new_user) + .execute(&self.0) + .expect("Error inserting person"); + + let mut items = users + .filter(id.eq(&uuid)) + .load::(&self.0) + .expect("Error loading person"); + + Self::reply(items.pop().unwrap()) + } +} + + +fn main() { + ::std::env::set_var("RUST_LOG", "actix_web=info"); + let _ = env_logger::init(); + let sys = actix::System::new("diesel-example"); + + // Start db executor actors + let addr = SyncArbiter::start(3, || { + DbExecutor(SqliteConnection::establish("test.db").unwrap()) + }); + + // Start http server + HttpServer::new(move || { + Application::with_state(State{db: addr.clone()}) + // enable logger + .middleware(middlewares::Logger::default()) + .resource("/{name}", |r| r.method(Method::GET).a(index))}) + .bind("127.0.0.1:8080").unwrap() + .start().unwrap(); + + println!("Started http server: 127.0.0.1:8080"); + let _ = sys.run(); +} diff --git a/examples/diesel/src/models.rs b/examples/diesel/src/models.rs new file mode 100644 index 000000000..315d59f13 --- /dev/null +++ b/examples/diesel/src/models.rs @@ -0,0 +1,14 @@ +use super::schema::users; + +#[derive(Serialize, Queryable)] +pub struct User { + pub id: String, + pub name: String, +} + +#[derive(Insertable)] +#[table_name = "users"] +pub struct NewUser<'a> { + pub id: &'a str, + pub name: &'a str, +} diff --git a/examples/diesel/src/schema.rs b/examples/diesel/src/schema.rs new file mode 100644 index 000000000..51aa40b89 --- /dev/null +++ b/examples/diesel/src/schema.rs @@ -0,0 +1,6 @@ +table! { + users (id) { + id -> Text, + name -> Text, + } +} diff --git a/examples/diesel/test.db b/examples/diesel/test.db new file mode 100644 index 000000000..3afa1579e Binary files /dev/null and b/examples/diesel/test.db differ