Explorar o código

Create the session model.

Lee Morgan hai 4 semanas
pai
achega
35dd398084

+ 1 - 0
.gitignore

@@ -3,3 +3,4 @@
 *swo
 .env
 redoc-static.html
+documentation.html

+ 1 - 0
Cargo.lock

@@ -549,6 +549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
 dependencies = [
  "powerfmt",
+ "serde_core",
 ]
 
 [[package]]

+ 1 - 1
Cargo.toml

@@ -10,7 +10,7 @@ dotenvy = "0.15"
 serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 sqlx = { version = "0.8", features = ["postgres", "runtime-tokio", "macros", "uuid", "time"] }
-time = "0.3"
+time = { version = "0.3", features = ["serde"] }
 tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
 uuid = { version = "1", features = ["v4", "serde"] }
 jsonwebtoken = "9"

+ 0 - 0
CLAUDE.md → GROK.md


+ 2 - 0
docs/openapi.yaml

@@ -18,6 +18,8 @@ tags:
 paths:
   /:
     $ref: './paths/index.yaml'
+  /docs:
+    $ref: './paths/docs.yaml'
   /user:
     $ref: './paths/user.yaml'
   /user/login:

+ 12 - 0
docs/paths/docs.yaml

@@ -0,0 +1,12 @@
+get:
+  summary: API documentation
+  operationId: getDocs
+  tags:
+    - General
+  responses:
+    '200':
+      description: ReDoc HTML documentation page.
+      content:
+        text/html:
+          schema:
+            type: string

+ 1 - 0
init.sql

@@ -7,3 +7,4 @@ CREATE DATABASE torus;
 \i migrations/0003_create_exercises.sql
 \i migrations/0004_add_user_to_workouts.sql
 \i migrations/0005_add_position_to_exercises.sql
+\i migrations/0006_create_sessions.sql

+ 5 - 12
instructions.txt

@@ -1,14 +1,7 @@
-Create the following routes:
+Create a model for "sessions".
 
-PUT /workout/{workout_id}
-    This route will allow the user to update the change the name of the workout
-    This route will allow the user to change the name of each exercise and the position/ordering of each exercise
-    Ensure that positions are unique without the workout. So no two exercises within the workout should contain the same value
-    This route will allow the user to delete any exercises
-    This route will allow the user to add new exercises
-    Any error messages should contain a user readable message
-    Ensure logged in user is the owner of the workout
+A session is a when a user does a workout. So it should contain a reference to the original workout. Each session should have a list of exercises that the user completed. This could be cardio, weightlifting, etc. Check the exercise.rs model for information on what that should look like.
 
-DELETE /workout/{workout_id}
-    Ensure logged in user is owner of workout
-    This route simply deletes the workout and all corresponding exercises
+Basically, a session is going to be when a user does a workout and records exactly what/how much/how long they did each exercise. While workout/exercise models are the outline, session is the actual completed/recorded thing done.
+
+Make sure that you create the sql table file and the rust model. 

+ 21 - 0
migrations/0006_create_sessions.sql

@@ -0,0 +1,21 @@
+CREATE TABLE sessions (
+    id         UUID        PRIMARY KEY DEFAULT gen_uuid_v7(),
+    workout    UUID        NOT NULL REFERENCES workouts(id) ON DELETE CASCADE,
+    user_id    UUID        NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE TABLE session_exercises (
+    id               UUID          PRIMARY KEY DEFAULT gen_uuid_v7(),
+    session          UUID          NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
+    exercise         UUID          NOT NULL REFERENCES exercises(id) ON DELETE CASCADE,
+    name             TEXT          NOT NULL,
+    notes            TEXT,
+    exercise_type    exercise_type NOT NULL,
+    position         INTEGER       NOT NULL,
+    sets             INTEGER,
+    reps             INTEGER,
+    weight           DOUBLE PRECISION,
+    duration_seconds INTEGER,
+    distance_meters  DOUBLE PRECISION
+);

+ 1 - 0
src/main.rs

@@ -66,6 +66,7 @@ async fn main() -> std::io::Result<()> {
             .service(routes::workouts::get::get_workout)
             .service(routes::workouts::list::list_workouts)
             .service(routes::workouts::update::update_workout)
+            .service(routes::docs::get::get_docs)
     })
     .bind((host.as_str(), port))?
     .run()

+ 1 - 0
src/models/mod.rs

@@ -1,3 +1,4 @@
 pub mod exercise;
 pub mod user;
 pub mod workout;
+pub mod session;

+ 108 - 0
src/models/session.rs

@@ -0,0 +1,108 @@
+use serde::Serialize;
+use sqlx::{PgPool, Postgres};
+use time::OffsetDateTime;
+use uuid::Uuid;
+
+use super::exercise::ExerciseType;
+
+#[derive(sqlx::FromRow, Serialize)]
+pub struct Session {
+    pub id: Uuid,
+    pub workout: Uuid,
+    pub user_id: Uuid,
+    #[serde(with = "time::serde::iso8601")]
+    pub created_at: OffsetDateTime,
+}
+
+impl Session {
+    pub async fn create<'c, E>(executor: E, workout_id: Uuid, user_id: Uuid) -> Result<Session, sqlx::Error>
+    where
+        E: sqlx::Executor<'c, Database = Postgres>,
+    {
+        sqlx::query_as::<_, Session>(
+            "INSERT INTO sessions (workout, user_id) VALUES ($1, $2) RETURNING *",
+        )
+        .bind(workout_id)
+        .bind(user_id)
+        .fetch_one(executor)
+        .await
+    }
+
+    pub async fn find_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Session>, sqlx::Error> {
+        sqlx::query_as::<_, Session>("SELECT * FROM sessions WHERE id = $1")
+            .bind(id)
+            .fetch_optional(pool)
+            .await
+    }
+
+    pub async fn find_by_user(pool: &PgPool, user_id: Uuid) -> Result<Vec<Session>, sqlx::Error> {
+        sqlx::query_as::<_, Session>(
+            "SELECT * FROM sessions WHERE user_id = $1 ORDER BY created_at DESC",
+        )
+        .bind(user_id)
+        .fetch_all(pool)
+        .await
+    }
+}
+
+#[derive(sqlx::FromRow, Serialize, Clone)]
+pub struct SessionExercise {
+    pub id: Uuid,
+    pub session: Uuid,
+    pub exercise: Uuid,
+    pub name: String,
+    pub notes: Option<String>,
+    pub exercise_type: ExerciseType,
+    pub position: i32,
+    pub sets: Option<i32>,
+    pub reps: Option<i32>,
+    pub weight: Option<f64>,
+    pub duration_seconds: Option<i32>,
+    pub distance_meters: Option<f64>,
+}
+
+impl SessionExercise {
+    pub async fn find_by_session(pool: &PgPool, session_id: Uuid) -> Result<Vec<SessionExercise>, sqlx::Error> {
+        sqlx::query_as::<_, SessionExercise>("SELECT * FROM session_exercises WHERE session = $1 ORDER BY position")
+            .bind(session_id)
+            .fetch_all(pool)
+            .await
+    }
+
+    pub async fn create<'c, E>(
+        executor: E,
+        session_id: Uuid,
+        exercise_id: Uuid,
+        name: &str,
+        notes: Option<&str>,
+        exercise_type: ExerciseType,
+        position: i32,
+        sets: Option<i32>,
+        reps: Option<i32>,
+        weight: Option<f64>,
+        duration_seconds: Option<i32>,
+        distance_meters: Option<f64>,
+    ) -> Result<SessionExercise, sqlx::Error>
+    where
+        E: sqlx::Executor<'c, Database = Postgres>,
+    {
+        sqlx::query_as::<_, SessionExercise>(
+            r#"INSERT INTO session_exercises
+            (session, exercise, name, notes, exercise_type, position, sets, reps, weight, duration_seconds, distance_meters)
+            VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *"#,
+        )
+        .bind(session_id)
+        .bind(exercise_id)
+        .bind(name)
+        .bind(notes)
+        .bind(exercise_type)
+        .bind(position)
+        .bind(sets)
+        .bind(reps)
+        .bind(weight)
+        .bind(duration_seconds)
+        .bind(distance_meters)
+        .fetch_one(executor)
+        .await
+    }
+}

+ 10 - 0
src/routes/docs/get.rs

@@ -0,0 +1,10 @@
+use actix_web::{get, HttpResponse, Responder};
+
+static REDOC_HTML: &str = include_str!("../../../docs/redoc-static.html");
+
+#[get("/docs")]
+pub async fn get_docs() -> impl Responder {
+    HttpResponse::Ok()
+        .content_type("text/html; charset=utf-8")
+        .body(REDOC_HTML)
+}

+ 1 - 0
src/routes/docs/mod.rs

@@ -0,0 +1 @@
+pub mod get;

+ 1 - 0
src/routes/mod.rs

@@ -1,2 +1,3 @@
+pub mod docs;
 pub mod users;
 pub mod workouts;