From 559f54d22bd60cd8e7a163a032a4c503719ff049 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 02:21:24 -0400 Subject: [PATCH] First pass at databases. --- content/docs/databases.md | 96 ++---------------------------- examples/Cargo.toml | 2 + examples/og_databases/Cargo.toml | 7 +++ examples/og_databases/src/main.rs | 98 +++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 91 deletions(-) create mode 100644 examples/og_databases/Cargo.toml create mode 100644 examples/og_databases/src/main.rs diff --git a/content/docs/databases.md b/content/docs/databases.md index 63218fe..c4dcb11 100644 --- a/content/docs/databases.md +++ b/content/docs/databases.md @@ -16,114 +16,28 @@ Let's create a simple database api that can insert a new user row into a SQLite We must define a sync actor and a connection that this actor will use. The same approach can be used for other databases. -```rust -use actix::prelude::*; - -struct DbExecutor(SqliteConnection); - -impl Actor for DbExecutor { - type Context = SyncContext; -} -``` +{{< include-example example="databases" file="main.rs" section="actor" >}} This is the definition of our actor. Now, we must define the *create user* message and response. -```rust -struct CreateUser { - name: String, -} - -impl Message for CreateUser { - type Result = Result; -} -``` +{{< include-example example="og_databases" file="main.rs" section="message" >}} We can send a `CreateUser` message to the `DbExecutor` actor, and as a result, we will receive a `User` model instance. Next, we must define the handler implementation for this message. -```rust -impl Handler for DbExecutor { - type Result = Result; - - fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result - { - use self::schema::users::dsl::*; - - // Create insertion model - let uuid = format!("{}", uuid::Uuid::new_v4()); - let new_user = models::NewUser { - id: &uuid, - name: &msg.name, - }; - - // normal diesel operations - 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"); - - Ok(items.pop().unwrap()) - } -} -``` +{{< include-example example="og_databases" file="main.rs" section="handler" >}} That's it! Now, we can use the *DbExecutor* actor from any http handler or middleware. All we need is to start *DbExecutor* actors and store the address in a state where http handler can access it. -```rust -/// This is state where we will store *DbExecutor* address. -struct State { - db: Addr, -} - -fn main() { - let sys = actix::System::new("diesel-example"); - - // Start 3 parallel db executors - let addr = SyncArbiter::start(3, || { - DbExecutor(SqliteConnection::establish("test.db").unwrap()) - }); - - // Start http server - HttpServer::new(move || { - App::with_state(State{db: addr.clone()}) - .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(); -} -``` +{{< include-example example="og_databases" file="main.rs" section="main" >}} We will use the address in a request handler. The handle returns a future object; thus, we receive the message response asynchronously. `Route::a()` must be used for async handler registration. - -```rust -/// Async handler -fn index(req: &HttpRequest) -> Box> { - let name = &req.match_info()["name"]; - - // Send message to `DbExecutor` actor - req.state().db.send(CreateUser{name: name.to_owned()}) - .from_err() - .and_then(|res| { - match res { - Ok(user) => Ok(HttpResponse::Ok().json(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()) - } - }) - .responder() -} -``` +{{< include-example example="og_databases" file="main.rs" section="index" >}} > A full example is available in the > [examples directory](https://github.com/actix/examples/tree/master/diesel/). diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8abe786..d83abf1 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -25,4 +25,6 @@ exclude = [ "static-files", "websockets", "http20", + "databases", + "og_databases", ] diff --git a/examples/og_databases/Cargo.toml b/examples/og_databases/Cargo.toml new file mode 100644 index 0000000..1a53463 --- /dev/null +++ b/examples/og_databases/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "og_databases" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] diff --git a/examples/og_databases/src/main.rs b/examples/og_databases/src/main.rs new file mode 100644 index 0000000..c78d064 --- /dev/null +++ b/examples/og_databases/src/main.rs @@ -0,0 +1,98 @@ +// +// use actix::prelude::*; + +// struct DbExecutor(SqliteConnection); + +// impl Actor for DbExecutor { +// type Context = SyncContext; +// } +// + +// +// struct CreateUser { +// name: String, +// } + +// impl Message for CreateUser { +// type Result = Result; +// } +// + +// +// impl Handler for DbExecutor { +// type Result = Result; + +// fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result { +// use self::schema::users::dsl::*; + +// // Create insertion model +// let uuid = format!("{}", uuid::Uuid::new_v4()); +// let new_user = models::NewUser { +// id: &uuid, +// name: &msg.name, +// }; + +// // normal diesel operations +// 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"); + +// Ok(items.pop().unwrap()) +// } +// } +// + +//
+// /// This is state where we will store *DbExecutor* address. +// struct State { +// db: Addr, +// } + +// fn main() { +// let sys = actix::System::new("diesel-example"); + +// // Start 3 parallel db executors +// let addr = SyncArbiter::start(3, || { +// DbExecutor(SqliteConnection::establish("test.db").unwrap()) +// }); + +// // Start http server +// HttpServer::new(move || { +// App::with_state(State { db: addr.clone() }) +// .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(); +// } +//
+ +// +// /// Async handler +// fn index(req: &HttpRequest) -> Box> { +// let name = &req.match_info()["name"]; + +// // Send message to `DbExecutor` actor +// req.state() +// .db +// .send(CreateUser { +// name: name.to_owned(), +// }) +// .from_err() +// .and_then(|res| match res { +// Ok(user) => Ok(HttpResponse::Ok().json(user)), +// Err(_) => Ok(HttpResponse::InternalServerError().into()), +// }) +// .responder() +// } +//