From cb9cfec119c54f687df1696dac4332a550266b87 Mon Sep 17 00:00:00 2001 From: Daniel Svitan Date: Sun, 5 Oct 2025 19:44:31 +0200 Subject: [PATCH] :hammer: Refactors into packages models and dtos --- src/api/tracker.rs | 68 +++++++++++++++++++++++++++++------- src/{dtos.rs => dtos/hit.rs} | 18 +--------- src/dtos/mod.rs | 2 ++ src/dtos/tracker.rs | 17 +++++++++ src/main.rs | 17 +++------ src/models.rs | 36 ------------------- src/models/hit.rs | 15 ++++++++ src/models/mod.rs | 17 +++++++++ src/models/tracker.rs | 18 ++++++++++ 9 files changed, 130 insertions(+), 78 deletions(-) rename src/{dtos.rs => dtos/hit.rs} (60%) create mode 100644 src/dtos/mod.rs create mode 100644 src/dtos/tracker.rs delete mode 100644 src/models.rs create mode 100644 src/models/hit.rs create mode 100644 src/models/mod.rs create mode 100644 src/models/tracker.rs diff --git a/src/api/tracker.rs b/src/api/tracker.rs index 2d6cc4f..5698ea7 100644 --- a/src/api/tracker.rs +++ b/src/api/tracker.rs @@ -1,29 +1,73 @@ -use crate::dtos::TrackerDTO; -use crate::models::{AppState, Tracker}; -use crate::schema::trackers::dsl::trackers; -use diesel::{QueryDsl, RunQueryDsl, SelectableHelper}; +use crate::dtos::tracker::TrackerDTO; +use crate::models::AppState; +use crate::models::tracker::{NewTracker, Tracker}; +use crate::schema::trackers; +use chrono::Utc; +use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl, SelectableHelper}; use rocket::State; +use rocket::http::Status; use rocket::serde::json::Json; +use uuid::Uuid; #[get("/?&")] pub fn index( offset: Option, limit: Option, - data: &State, -) -> Json> { - let mut db = data.db.lock().unwrap(); + state: &State, +) -> Result>, Status> { + let mut db = state.db.lock().unwrap(); let offset = offset.unwrap_or(0); let limit = limit.unwrap_or(10); - println!("hey"); - let results = trackers + let results = trackers::dsl::trackers .offset(offset) .limit(limit) .select(Tracker::as_select()) .load(&mut *db) - .expect("Error loading trackers"); + .ok(); - println!("hi"); - Json(results.iter().map(TrackerDTO::from).collect()) + match results { + Some(results) => Ok(Json(results.iter().map(TrackerDTO::from).collect())), + None => Err(Status::InternalServerError), + } +} + +#[get("/")] +pub fn get(id: String, state: &State) -> Result, Status> { + let mut db = state.db.lock().unwrap(); + + let id = match Uuid::parse_str(id.as_str()).ok() { + Some(id) => id, + None => return Err(Status::NotFound), + }; + + let result = trackers::dsl::trackers + .filter(trackers::id.eq(id)) + .first::(&mut *db) + .ok(); + + match result { + Some(tracker) => Ok(Json(TrackerDTO::from(&tracker))), + None => Err(Status::NotFound), + } +} + +#[post("/")] +pub fn create(state: &State) -> Result, Status> { + let mut db = state.db.lock().unwrap(); + + let new = NewTracker { + created_at: Utc::now().naive_utc(), + }; + let result = diesel::insert_into(trackers::table) + .values(&new) + .returning(Tracker::as_returning()) + .get_result(&mut *db) + .ok(); + + match result { + Some(tracker) => Ok(Json(TrackerDTO::from(&tracker))), + None => Err(Status::InternalServerError), + } } diff --git a/src/dtos.rs b/src/dtos/hit.rs similarity index 60% rename from src/dtos.rs rename to src/dtos/hit.rs index 43e3c02..0020073 100644 --- a/src/dtos.rs +++ b/src/dtos/hit.rs @@ -1,22 +1,6 @@ -use chrono::{DateTime, Utc}; -use crate::models::{Hit, Tracker}; +use crate::models::hit::Hit; use serde::Serialize; -#[derive(Serialize)] -pub struct TrackerDTO { - pub id: String, - pub created_at: String, -} - -impl TrackerDTO { - pub fn from(tracker: &Tracker) -> TrackerDTO { - TrackerDTO { - id: tracker.id.to_string(), - created_at: tracker.created_at.to_string(), - } - } -} - #[derive(Serialize)] pub struct HitDTO { pub id: String, diff --git a/src/dtos/mod.rs b/src/dtos/mod.rs new file mode 100644 index 0000000..15ef570 --- /dev/null +++ b/src/dtos/mod.rs @@ -0,0 +1,2 @@ +pub mod hit; +pub mod tracker; diff --git a/src/dtos/tracker.rs b/src/dtos/tracker.rs new file mode 100644 index 0000000..4867db9 --- /dev/null +++ b/src/dtos/tracker.rs @@ -0,0 +1,17 @@ +use crate::models::tracker::Tracker; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize)] +pub struct TrackerDTO { + pub id: String, + pub created_at: String, +} + +impl TrackerDTO { + pub fn from(tracker: &Tracker) -> TrackerDTO { + TrackerDTO { + id: tracker.id.to_string(), + created_at: tracker.created_at.to_string(), + } + } +} diff --git a/src/main.rs b/src/main.rs index a72880b..a69b185 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,10 @@ mod api; +mod dtos; mod models; mod schema; -mod dtos; use crate::api::tracker; -use crate::models::Hit; -use crate::schema::hits::dsl::*; -use diesel::{Connection, PgConnection, QueryDsl, RunQueryDsl, SelectableHelper}; +use diesel::{Connection, PgConnection}; use std::env; #[macro_use] @@ -22,19 +20,12 @@ fn rocket() -> _ { dotenv::dotenv().ok(); let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - let mut db = PgConnection::establish(&database_url) + let db = PgConnection::establish(&database_url) .expect(&format!("Error connecting to {}", database_url)); - let results = hits - .limit(5) - .select(Hit::as_select()) - .load(&mut db) - .expect("Error loading hits"); - println!("results: {}", results.len()); - let app_data = models::AppState::new(db); rocket::build() .manage(app_data) .mount("/", routes![index]) - .mount("/tracker", routes![tracker::index]) + .mount("/tracker", routes![tracker::index, tracker::get, tracker::create]) } diff --git a/src/models.rs b/src/models.rs deleted file mode 100644 index cd99ede..0000000 --- a/src/models.rs +++ /dev/null @@ -1,36 +0,0 @@ -use chrono::NaiveDateTime; -use diesel::{PgConnection, Queryable, Selectable}; -use std::sync::{Arc, Mutex}; -use uuid::Uuid; - -#[derive(Queryable, Selectable, Clone)] -#[diesel(table_name = crate::schema::trackers)] -#[diesel(check_for_backend(diesel::pg::Pg))] -pub struct Tracker { - pub id: Uuid, - pub created_at: NaiveDateTime, -} - -#[derive(Queryable, Selectable, Clone)] -#[diesel(table_name = crate::schema::hits)] -#[diesel(check_for_backend(diesel::pg::Pg))] -pub struct Hit { - pub id: Uuid, - pub tracker_id: Uuid, - pub ip: String, - pub agent: Option, - pub language: Option, - pub created_at: NaiveDateTime, -} - -pub struct AppState { - pub db: Arc>, -} - -impl AppState { - pub fn new(db: PgConnection) -> Self { - AppState { - db: Arc::new(Mutex::new(db)), - } - } -} diff --git a/src/models/hit.rs b/src/models/hit.rs new file mode 100644 index 0000000..efd1faa --- /dev/null +++ b/src/models/hit.rs @@ -0,0 +1,15 @@ +use chrono::NaiveDateTime; +use diesel::{Queryable, Selectable}; +use uuid::Uuid; + +#[derive(Queryable, Selectable, Clone)] +#[diesel(table_name = crate::schema::hits)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct Hit { + pub id: Uuid, + pub tracker_id: Uuid, + pub ip: String, + pub agent: Option, + pub language: Option, + pub created_at: NaiveDateTime, +} diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..52619f6 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1,17 @@ +use diesel::PgConnection; +use std::sync::{Arc, Mutex}; + +pub mod hit; +pub mod tracker; + +pub struct AppState { + pub db: Arc>, +} + +impl AppState { + pub fn new(db: PgConnection) -> Self { + AppState { + db: Arc::new(Mutex::new(db)), + } + } +} diff --git a/src/models/tracker.rs b/src/models/tracker.rs new file mode 100644 index 0000000..00aa087 --- /dev/null +++ b/src/models/tracker.rs @@ -0,0 +1,18 @@ +use chrono::NaiveDateTime; +use diesel::{Insertable, Queryable, Selectable}; +use uuid::Uuid; + +#[derive(Queryable, Selectable, Clone)] +#[diesel(table_name = crate::schema::trackers)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct Tracker { + pub id: Uuid, + pub created_at: NaiveDateTime, +} + +#[derive(Insertable)] +#[diesel(table_name = crate::schema::trackers)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct NewTracker { + pub created_at: NaiveDateTime, +}