1
0
Fork 0

Add diesel and example page

This commit is contained in:
Florian RICHER (MrDev023) 2022-03-21 22:37:03 +01:00
parent 1197fe687b
commit d20ca7cfa9
20 changed files with 453 additions and 14 deletions

1
.env Normal file
View file

@ -0,0 +1 @@
DATABASE_URL=db/dev.db

2
.gitignore vendored
View file

@ -1 +1,3 @@
/target
thirdparty
db/*.db

180
Cargo.lock generated
View file

@ -24,6 +24,13 @@ name = "actix-example"
version = "0.1.0"
dependencies = [
"actix-web",
"diesel",
"dotenv",
"env_logger",
"log",
"serde",
"serde_json",
"uuid",
"yew",
]
@ -236,6 +243,17 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -305,6 +323,12 @@ version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.1.0"
@ -403,6 +427,29 @@ dependencies = [
"syn",
]
[[package]]
name = "diesel"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d"
dependencies = [
"byteorder",
"diesel_derives",
"libsqlite3-sys",
"r2d2",
]
[[package]]
name = "diesel_derives"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.10.3"
@ -413,6 +460,12 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "encoding_rs"
version = "0.8.30"
@ -422,6 +475,19 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "firestorm"
version = "0.5.0"
@ -794,6 +860,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "idna"
version = "0.2.3"
@ -815,6 +887,15 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "itoa"
version = "1.0.1"
@ -857,6 +938,16 @@ version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]]
name = "libsqlite3-sys"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]]
name = "local-channel"
version = "0.1.2"
@ -978,6 +1069,17 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.5",
]
[[package]]
name = "parking_lot"
version = "0.12.0"
@ -985,7 +1087,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
dependencies = [
"lock_api",
"parking_lot_core",
"parking_lot_core 0.9.1",
]
[[package]]
name = "parking_lot_core"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
@ -1045,6 +1161,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
@ -1103,6 +1225,17 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r2d2"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f"
dependencies = [
"log",
"parking_lot 0.11.2",
"scheduled-thread-pool",
]
[[package]]
name = "rand"
version = "0.8.5"
@ -1174,6 +1307,15 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "scheduled-thread-pool"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7"
dependencies = [
"parking_lot 0.11.2",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -1294,6 +1436,15 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.30"
@ -1358,7 +1509,7 @@ dependencies = [
"memchr",
"mio",
"once_cell",
"parking_lot",
"parking_lot 0.12.0",
"pin-project-lite",
"signal-hook-registry",
"socket2",
@ -1459,6 +1610,22 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
"serde",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
@ -1571,6 +1738,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

View file

@ -8,3 +8,10 @@ edition = "2021"
[dependencies]
actix-web = "4"
yew = { git = "https://github.com/yewstack/yew/", features = ["ssr"] }
diesel = { version = "1.4.8", features = ["sqlite", "r2d2"] }
dotenv = "0.15"
env_logger = "0.9.0"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "0.8", features = ["serde", "v4"] }

61
README.md Normal file
View file

@ -0,0 +1,61 @@
# Actix web + Diesel + Yew SSR
Basic complete web application with rust.
## Usage
### Install SQLite
```sh
# on OpenSUSE
sudo zypper install sqlite3-devel libsqlite3-0 sqlite3
# on Ubuntu
sudo apt-get install libsqlite3-dev sqlite3
# on Fedora
sudo dnf install libsqlite3x-devel sqlite3x
# on macOS (using homebrew)
brew install sqlite3
```
### Initialize SQLite Database
```sh
# UNIX
cargo install diesel_cli --no-default-features --features sqlite
# IF NOT WORK USE THIS
cargo install diesel_cli --no-default-features --features sqlite-bundled
echo "DATABASE_URL=db/test.db" > .env
diesel migration run
```
There will now be a database file at `./test.db`.
### Running Server
```sh
cargo run
# Started http server: 127.0.0.1:8080
```
### Explore The SQLite DB
```sh
sqlite3 test.db
```
```
sqlite> .tables
sqlite> SELECT * FROM users;
```
## Using Other Databases
You can find a complete example of Diesel + PostgreSQL at: [https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix)

0
db/.gitkeep Normal file
View file

5
diesel.toml Normal file
View file

@ -0,0 +1,5 @@
# For documentation on how to configure this file,
# see diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/schema.rs"

0
migrations/.gitkeep Normal file
View file

View file

@ -0,0 +1 @@
DROP TABLE users;

View file

@ -0,0 +1,4 @@
CREATE TABLE users (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL
);

View file

@ -1,5 +1,4 @@
use actix_web::{get, Responder, web, HttpResponse};
use actix_web::{get, web, HttpResponse, Responder};
use yew::ServerRenderer;
use crate::views::components::hello::{Hello, HelloProps};
@ -7,8 +6,6 @@ use crate::views::components::hello::{Hello, HelloProps};
#[get("/{name}")]
async fn index(name: web::Path<String>) -> impl Responder {
let name = name.into_inner();
let renderer = ServerRenderer::<Hello>::with_props(HelloProps {
name
});
let renderer = ServerRenderer::<Hello>::with_props(HelloProps { name });
HttpResponse::Ok().body(renderer.render().await)
}
}

View file

@ -1 +1,2 @@
pub mod hello_controller;
pub mod hello_controller;
pub mod users_controller;

View file

@ -0,0 +1,44 @@
use actix_web::{get, web, Error, HttpResponse};
use yew::ServerRenderer;
use crate::{
models::user::{NewUser, User},
views::components::{
user::{UserComponent, UserComponentProps},
users::{UsersComponent, UsersComponentProps}
},
DbPool,
};
#[get("")]
async fn index(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
let users = web::block(move || {
let conn = pool.get()?;
User::all(&conn)
})
.await?
.map_err(actix_web::error::ErrorInternalServerError)?;
let renderer =
ServerRenderer::<UsersComponent>::with_props(UsersComponentProps { users: users.clone() });
Ok(HttpResponse::Ok().body(renderer.render().await))
}
#[get("")]
async fn create(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
let user = User::new(NewUser {
name: "John".to_string(),
});
let u = user.clone();
web::block(move || {
let conn = pool.get()?;
u.insert(&conn)
})
.await?
.map_err(actix_web::error::ErrorInternalServerError)?;
let renderer =
ServerRenderer::<UserComponent>::with_props(UserComponentProps { user: user.clone() });
Ok(HttpResponse::Ok().body(renderer.render().await))
}

View file

@ -1,12 +1,38 @@
#[macro_use]
extern crate diesel; // Required for schema.rs
pub(self) mod controllers;
pub(self) mod models;
pub(self) mod schema;
pub(self) mod views;
use actix_web::{App, HttpServer, web};
pub(self) type DbPool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
use actix_web::{middleware, web, App, HttpServer};
use diesel::{
r2d2::{self, ConnectionManager},
SqliteConnection,
};
#[actix_web::main]
async fn main() -> std::io::Result<()>{
HttpServer::new(|| {
App::new().service(web::scope("/hello").service(controllers::hello_controller::index))
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
// set up database connection pool
let conn_spec = std::env::var("DATABASE_URL").expect("DATABASE_URL");
let manager = ConnectionManager::<SqliteConnection>::new(conn_spec);
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(pool.clone()))
.wrap(middleware::Logger::default())
.service(web::scope("/hello").service(controllers::hello_controller::index))
.service(web::scope("/users").service(controllers::users_controller::index))
.service(web::scope("/user").service(controllers::users_controller::create))
})
.bind(("127.0.0.1", 8000))?
.run()

3
src/models/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub(self) type DbError = Box<dyn std::error::Error + Send + Sync>;
pub mod user;

64
src/models/user.rs Normal file
View file

@ -0,0 +1,64 @@
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::schema::users;
use super::DbError;
#[derive(Debug, Clone, Serialize, Deserialize, Queryable, Insertable, AsChangeset, PartialEq)]
pub struct User {
pub id: String,
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewUser {
pub name: String,
}
impl User {
pub fn new(new_user: NewUser) -> Self {
Self {
id: Uuid::new_v4().to_string(),
name: new_user.name,
}
}
pub fn all(conn: &SqliteConnection) -> Result<Vec<Self>, DbError> {
users::table.load::<Self>(conn).map_err(Into::into)
}
pub fn find_by_id(conn: &SqliteConnection, id: String) -> Result<Self, DbError> {
users::table
.filter(users::id.eq(id))
.first::<Self>(conn)
.map_err(Into::into)
}
pub fn insert(&self, conn: &SqliteConnection) -> Result<(), DbError> {
use crate::schema::users::dsl::*;
diesel::insert_into(users).values(self).execute(conn)?;
Ok(())
}
pub fn update(&self, conn: &SqliteConnection) -> Result<(), DbError> {
use crate::schema::users::dsl::*;
diesel::update(users.find(self.id.clone()))
.set(self)
.execute(conn)?;
Ok(())
}
pub fn delete(&self, conn: &SqliteConnection) -> Result<(), DbError> {
use crate::schema::users::dsl::*;
diesel::delete(users.filter(id.eq(self.id.clone()))).execute(conn)?;
Ok(())
}
}

6
src/schema.rs Normal file
View file

@ -0,0 +1,6 @@
table! {
users (id) {
id -> Text,
name -> Text,
}
}

View file

@ -1 +1,3 @@
pub mod hello;
pub mod hello;
pub mod user;
pub mod users;

View file

@ -0,0 +1,18 @@
use yew::prelude::*;
use crate::models::user::User;
#[derive(Properties, PartialEq)]
pub struct UserComponentProps {
pub user: User,
}
#[function_component]
pub fn UserComponent(props: &UserComponentProps) -> Html {
html! {
<div>
<p>{ props.user.clone().id } </p>
<p>{ props.user.clone().name } </p>
</div>
}
}

View file

@ -0,0 +1,21 @@
use yew::prelude::*;
use crate::models::user::User;
use crate::views::components::user::UserComponent;
#[derive(Properties, PartialEq)]
pub struct UsersComponentProps {
pub users: Vec<User>,
}
#[function_component]
pub fn UsersComponent(props: &UsersComponentProps) -> Html {
let users = props.users.clone().iter().map(|user| html! {
<UserComponent user={user.clone()} />
}).collect::<Html>();
html! {
<div>
{ users }
</div>
}
}