|
@@ -3,9 +3,11 @@ extern crate dotenv;
|
|
|
#[macro_use]
|
|
|
extern crate async_trait;
|
|
|
|
|
|
-mod models;
|
|
|
+mod common_handlers;
|
|
|
+mod models_common;
|
|
|
+mod models_bb8;
|
|
|
mod database_bb8;
|
|
|
-mod common;
|
|
|
+mod utils;
|
|
|
|
|
|
use dotenv::dotenv;
|
|
|
use std::net::{Ipv4Addr, SocketAddr};
|
|
@@ -24,10 +26,13 @@ use tower_http::set_header::SetResponseHeaderLayer;
|
|
|
use hyper::Body;
|
|
|
use rand::rngs::SmallRng;
|
|
|
use rand::{SeedableRng};
|
|
|
-use yarte::TemplateTrait;
|
|
|
+use tokio_pg_mapper::FromTokioPostgresRow;
|
|
|
+use yarte::Template;
|
|
|
|
|
|
-use models::{World, Fortune};
|
|
|
-use crate::common::{FortunesTemplate, internal_error, json, Params, parse_params, plaintext, random_number, Utf8Html};
|
|
|
+use models_bb8::{World, Fortune};
|
|
|
+use common_handlers::{json, plaintext};
|
|
|
+use utils::{Params, parse_params, random_number};
|
|
|
+use crate::utils::Utf8Html;
|
|
|
|
|
|
async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
|
|
|
let mut rng = SmallRng::from_entropy();
|
|
@@ -39,18 +44,10 @@ async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
|
|
|
(StatusCode::OK, Json(world))
|
|
|
}
|
|
|
|
|
|
-async fn prepare_fetch_world_by_id_statement(conn: &Connection) -> Statement {
|
|
|
- conn.prepare("SELECT id, randomnumber FROM World WHERE id = $1").await.unwrap()
|
|
|
-}
|
|
|
-
|
|
|
async fn fetch_world_by_id_using_statement(conn: &Connection, number: i32, select: &Statement) -> World {
|
|
|
let row: Row = conn.query_one(select, &[&number]).await.unwrap();
|
|
|
|
|
|
- let id: i32 = row.get(0);
|
|
|
- let random_num: i32 = row.get(1);
|
|
|
-
|
|
|
- let world: World = World { id, random_number: random_num };
|
|
|
- world
|
|
|
+ World::from_row(row).unwrap()
|
|
|
}
|
|
|
|
|
|
async fn queries(DatabaseConnection(conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
|
|
@@ -72,52 +69,71 @@ async fn queries(DatabaseConnection(conn): DatabaseConnection, Query(params): Qu
|
|
|
|
|
|
(StatusCode::OK, Json(results))
|
|
|
}
|
|
|
-//
|
|
|
-// async fn fortunes(DatabaseConnection(mut conn): DatabaseConnection) -> impl IntoResponse {
|
|
|
-// let mut fortunes: Vec<Fortune> = sqlx::query_as("SELECT * FROM Fortune").fetch_all(&mut conn).await
|
|
|
-// .ok().expect("Could not load Fortunes");
|
|
|
-//
|
|
|
-// fortunes.push(Fortune {
|
|
|
-// id: 0,
|
|
|
-// message: "Additional fortune added at request time.".to_string(),
|
|
|
-// });
|
|
|
-//
|
|
|
-// fortunes.sort_by(|a, b| a.message.cmp(&b.message));
|
|
|
-//
|
|
|
-// Utf8Html(
|
|
|
-// FortunesTemplate {
|
|
|
-// fortunes: &fortunes,
|
|
|
-// }
|
|
|
-// .call()
|
|
|
-// .expect("error rendering template"),
|
|
|
-// )
|
|
|
-// }
|
|
|
-//
|
|
|
-// async fn updates(DatabaseConnection(mut conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
|
|
|
-// let q = parse_params(params);
|
|
|
-//
|
|
|
-// let mut rng = SmallRng::from_entropy();
|
|
|
-//
|
|
|
-// let mut results = Vec::with_capacity(q as usize);
|
|
|
-//
|
|
|
-// for _ in 0..q {
|
|
|
-// let query_id = random_number(&mut rng);
|
|
|
-// let mut result :World = sqlx::query_as("SELECT * FROM World WHERE id = $1").bind(query_id)
|
|
|
-// .fetch_one(&mut conn).await.ok().expect("error loading world");
|
|
|
-//
|
|
|
-// result.random_number = random_number(&mut rng);
|
|
|
-// results.push(result);
|
|
|
-// }
|
|
|
-//
|
|
|
-// for w in &results {
|
|
|
-// sqlx::query("UPDATE World SET randomnumber = $1 WHERE id = $2")
|
|
|
-// .bind(w.random_number).bind(w.id)
|
|
|
-// .execute(&mut conn)
|
|
|
-// .await.ok().expect("could not update world");
|
|
|
-// }
|
|
|
-//
|
|
|
-// (StatusCode::OK, Json(results))
|
|
|
-// }
|
|
|
+
|
|
|
+async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
|
|
|
+ let select = prepare_fetch_all_fortunes_statement(&conn).await;
|
|
|
+
|
|
|
+ let rows: Vec<Row> = conn.query(&select, &[]).await.unwrap();
|
|
|
+
|
|
|
+ let mut fortunes: Vec<Fortune> = Vec::with_capacity(rows.capacity());;
|
|
|
+
|
|
|
+ for row in rows {
|
|
|
+ fortunes.push(Fortune::from_row(row).unwrap());
|
|
|
+ }
|
|
|
+
|
|
|
+ fortunes.push(Fortune {
|
|
|
+ id: 0,
|
|
|
+ message: "Additional fortune added at request time.".to_string(),
|
|
|
+ });
|
|
|
+
|
|
|
+ fortunes.sort_by(|a, b| a.message.cmp(&b.message));
|
|
|
+
|
|
|
+ Utf8Html(
|
|
|
+ FortunesTemplate {
|
|
|
+ fortunes: &fortunes,
|
|
|
+ }
|
|
|
+ .call()
|
|
|
+ .expect("error rendering template"),
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+async fn updates(DatabaseConnection(conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
|
|
|
+ let q = parse_params(params);
|
|
|
+
|
|
|
+ let mut rng = SmallRng::from_entropy();
|
|
|
+
|
|
|
+ let mut results = Vec::with_capacity(q as usize);
|
|
|
+
|
|
|
+ let select = prepare_fetch_world_by_id_statement(&conn).await;
|
|
|
+
|
|
|
+ for _ in 0..q {
|
|
|
+ let query_id = random_number(&mut rng);
|
|
|
+ let mut result :World = fetch_world_by_id_using_statement(&conn, query_id, &select).await;
|
|
|
+
|
|
|
+ result.randomnumber = random_number(&mut rng);
|
|
|
+ results.push(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ let update = prepare_update_world_by_id_statement(&conn).await;
|
|
|
+
|
|
|
+ for w in &results {
|
|
|
+ conn.execute(&update, &[&w.randomnumber, &w.id]).await.unwrap();
|
|
|
+ }
|
|
|
+
|
|
|
+ (StatusCode::OK, Json(results))
|
|
|
+}
|
|
|
+
|
|
|
+async fn prepare_fetch_all_fortunes_statement(conn: &Connection) -> Statement {
|
|
|
+ conn.prepare("SELECT * FROM Fortune").await.unwrap()
|
|
|
+}
|
|
|
+
|
|
|
+async fn prepare_fetch_world_by_id_statement(conn: &Connection) -> Statement {
|
|
|
+ conn.prepare("SELECT id, randomnumber FROM World WHERE id = $1").await.unwrap()
|
|
|
+}
|
|
|
+
|
|
|
+async fn prepare_update_world_by_id_statement(conn: &Connection) -> Statement {
|
|
|
+ conn.prepare("UPDATE World SET randomnumber = $1 WHERE id = $2").await.unwrap()
|
|
|
+}
|
|
|
|
|
|
#[tokio::main]
|
|
|
async fn main() {
|
|
@@ -134,10 +150,10 @@ async fn main() {
|
|
|
let router = Router::new()
|
|
|
.route("/plaintext", get(plaintext))
|
|
|
.route("/json", get(json))
|
|
|
- // .route("/fortunes", get(fortunes))
|
|
|
+ .route("/fortunes", get(fortunes))
|
|
|
.route("/db", get(db))
|
|
|
.route("/queries", get(queries))
|
|
|
- // .route("/updates", get(updates))
|
|
|
+ .route("/updates", get(updates))
|
|
|
.layer(AddExtensionLayer::new(pool))
|
|
|
.layer(SetResponseHeaderLayer::<_, Body>::if_not_present(header::SERVER, HeaderValue::from_static("Axum")));
|
|
|
|
|
@@ -147,3 +163,8 @@ async fn main() {
|
|
|
.unwrap();
|
|
|
}
|
|
|
|
|
|
+#[derive(Template)]
|
|
|
+#[template(path = "fortunes.html.hbs")]
|
|
|
+pub struct FortunesTemplate<'a> {
|
|
|
+ pub fortunes: &'a Vec<Fortune>,
|
|
|
+}
|