diff --git a/data.db b/data.db index e7f5f66f7..662df3d20 100644 Binary files a/data.db and b/data.db differ diff --git a/web_server/src/extensions.rs b/web_server/src/extensions.rs new file mode 100644 index 000000000..7b2858072 --- /dev/null +++ b/web_server/src/extensions.rs @@ -0,0 +1,23 @@ +use std::{slice::Iter, str::FromStr}; + +pub trait PairExt { + fn next_field(&mut self) -> T + where + T: FromStr, + ::Err: std::fmt::Debug; +} + +impl PairExt for Iter<'_, (&str, Option<&str>)> { + fn next_field(&mut self) -> T + where + T: FromStr, + ::Err: std::fmt::Debug, + { + self.next() + .expect("should exist") + .1 + .expect("should be not null") + .parse() + .expect("Should parse") + } +} diff --git a/web_server/src/main.rs b/web_server/src/main.rs index 9dc6b03ce..c167df6cb 100644 --- a/web_server/src/main.rs +++ b/web_server/src/main.rs @@ -1,13 +1,14 @@ +mod extensions; mod structs; + use axum::{ extract::State, http::StatusCode, - response::IntoResponse, routing::{get, post}, Json, Router, }; -use serde::{Deserialize, Serialize}; -use std::{net::SocketAddr, sync::Arc}; +use extensions::PairExt; +use std::{net::SocketAddr, slice::Iter, sync::Arc}; use structs::User; struct AppState { @@ -17,7 +18,7 @@ struct AppState { #[tokio::main] async fn main() { let shared_state = Arc::new(AppState { - conn: sqlite::Connection::open_with_full_mutex("../../data.db").expect("file should exist"), + conn: sqlite::Connection::open_with_full_mutex("../data.db").expect("file should exist"), }); tracing_subscriber::fmt::init(); @@ -27,7 +28,9 @@ async fn main() { .route("/", get(root)) // `POST /users` goes to `create_user` .route("/users", post(create_user)) - .with_state(shared_state); + .with_state(shared_state.clone()) + .route("/users", get(get_users)) + .with_state(shared_state.clone()); // run our app with hyper // `axum::Server` is a re-export of `hyper::Server` @@ -44,6 +47,37 @@ async fn root() -> &'static str { "Hello, World!" } +async fn get_users(State(state): State>) -> (StatusCode, Json>) { + let query = "SELECT * FROM users;"; + let mut users = Vec::new(); + let result = state.conn.iterate(query, |pairs| { + let mut pairs = pairs.into_iter(); + + let user = User { + id: Some( + pairs.next_field(), + // .expect("should exist") + // .1 + // .expect("should be not null") + // .parse() + // .expect("Should parse"), + ), + name: pairs.next_field(), + about: pairs.next_field(), + github: pairs.next_field(), + email: pairs.next_field(), + }; + users.push(user); + true + }); + + if let Err(e) = result { + println!("{}", e); + return (StatusCode::INTERNAL_SERVER_ERROR, Json(users)); + }; + (StatusCode::OK, Json(users)) +} + async fn create_user( // this argument tells axum to parse the request body // as JSON into a `CreateUser` type @@ -63,10 +97,15 @@ async fn create_user( .. } = payload; - let cmd = format!(r#"INSERT INTO users VALUES ("{name}", "{about}", "{github}", "{email}"))"#); + let cmd = format!( + r#"INSERT INTO users(name, about, github_link, email) VALUES ("{name}", "{about}", "{github}", "{email}")"# + ); match state.conn.execute(cmd) { Ok(_) => StatusCode::CREATED, // TODO: replace with better status code - Err(_) => StatusCode::IM_A_TEAPOT, + Err(err) => { + println!("{}", err); + StatusCode::INTERNAL_SERVER_ERROR + } } }