Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial code creation. working on creating review schema and model setup and handler functions #21

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions backend/internal/models/review.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package models

import "time"

type Review struct {
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
UserID string `json:"user_id"`
MediaType string `json:"media_type"`
MediaID string `json:"media_id"`
Rating string `json:"rating"`
Desc *string `json:"desc,omitempty"`
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
104 changes: 104 additions & 0 deletions backend/internal/service/handler/review.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package handler

import (
"fmt"
"platnm/internal/storage"
"strconv"

"github.com/gofiber/fiber/v2"
)

type ReviewHandler struct {
reviewRepository storage.ReviewRepository
}

func NewReviewHandler(reviewRepository storage.ReviewRepository) *ReviewHandler {
return &ReviewHandler{
reviewRepository,
}
}

func (h *ReviewHandler) GetReviews(c *fiber.Ctx) error {
review, err := h.reviewRepository.GetReviews(c.Context())
if err != nil {
return err
}

return c.Status(fiber.StatusOK).JSON(review)
}

func (h *ReviewHandler) GetReviewById(c *fiber.Ctx, mediaType string) error {
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
id := c.Params("id")
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
offsetstr := c.Query("offset", "0")
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
limitstr := c.Query("limit", "10")
//limitParam := r.URL.Query().Get("limit")
//offsetParam := r.URL.Query().Get("offset")
//review, err := h.reviewRepository.GetReviewsByID(id, mediaType, c.Context())

var offset int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe move offset limit stuff to helper func to clean up handler func. or create utils package with this functionality since we may need in the future

if offsetstr == "" {
offset = 0 // Default to 0 if no offset is provided
} else {
var err error
offset, err = strconv.Atoi(offsetstr)
if err != nil || offset < 0 {
offset = 0 // Ensure offset is non-negative
}
}

// Check if limitstr is empty, then default to 10
var limit int
if limitstr == "" {
limit = 10 // Default to 10 if no limit is provided
} else {
var err error
limit, err = strconv.Atoi(limitstr)
if err != nil || limit <= 0 {
limit = 10 // Ensure limit is positive
}
}

print("running?")

// Fetch the review based on ID and media type
review, err := h.reviewRepository.GetReviewsByID(c.Context(), id, mediaType)
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
// If error, log it and return 500
fmt.Println(err.Error(), "from transactions err ")
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Unable to retrieve reviews",
})
}

// If no review is found, return a 404 status
if len(review) == 0 {
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"message": "No reviews found",
})
}

// Calculate average rating
var avgRating float64
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
for _, r := range review {
rating, err := strconv.ParseFloat(r.Rating, 64)
if err != nil {
avgRating += rating
}

}
if len(review) > 0 {
avgRating /= float64(len(review))
}

var end = offset*limit - 1
var start = end - limit
var paginatedReview = review[start:end]

// Return the reviews and average rating
response := fiber.Map{
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
"avgRating": avgRating,
"reviews": paginatedReview,
}

return c.Status(fiber.StatusOK).JSON(response)
}
12 changes: 12 additions & 0 deletions backend/internal/service/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ func setupRoutes(app *fiber.App, conn *pgxpool.Pool) {
r.Get("/", userHandler.GetUsers)
r.Get("/:id", userHandler.GetUserById)
})

reviewHandler := handler.NewReviewHandler(repository.Review)
app.Route("/reviews", func(r fiber.Router) {
r.Get("/album", reviewHandler.GetReviews)
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
r.Get("/album/:albumID", func(c *fiber.Ctx) error {
return reviewHandler.GetReviewById(c, "album")
})
r.Get("/track", reviewHandler.GetReviews)
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
r.Get("/track/:trackID", func(c *fiber.Ctx) error {
return reviewHandler.GetReviewById(c, "track")
})
})
}

func setupApp() *fiber.App {
Expand Down
103 changes: 103 additions & 0 deletions backend/internal/storage/postgres/schema/review.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package user

import (
"context"
"platnm/internal/models"

"time"

"github.com/jackc/pgx/v5/pgxpool"
)

type ReviewRepository struct {
db *pgxpool.Pool
}

func (r *ReviewRepository) GetReviews(ctx context.Context) ([]*models.Review, error) {
rows, err := r.db.Query(context.Background(), "SELECT user_id, media_id, media_type, desc, rating, CreatedAt, UpdatedAt FROM review")
if err != nil {
print(err.Error(), "from transactions err ")
return []*models.Review{}, err
}
defer rows.Close()

var reviews []*models.Review
for rows.Next() {
var review models.Review
var userID, mediaID, mediaType, desc, rating *string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont think u need these temp vals. can just bind straight to fields of review struct

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya see this from the pgx docs

var CreatedAt, UpdatedAt *time.Time

if err := rows.Scan(&userID, &mediaID, &mediaType, &desc, &rating, &UpdatedAt, &CreatedAt); err != nil {
print(err.Error(), "from transactions err ")
return reviews, err
}

review.UserID = *userID
review.MediaID = *mediaID
review.MediaType = *mediaType
review.Desc = desc
review.Rating = *rating
review.UpdatedAt = *UpdatedAt
review.CreatedAt = *CreatedAt

reviews = append(reviews, &review)
}

if err := rows.Err(); err != nil {
print(err.Error(), "from transactions err ")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont need log here. we added central error handling so if u just return error, fiber will catch it and log it

return []*models.Review{}, err
}

return reviews, nil
}

func (r *ReviewRepository) GetReviewsByID(ctx context.Context, id string, mediaType string) ([]*models.Review, error) {

rows, err := r.db.Query(ctx, "SELECT * FROM review WHERE media_id = $1 and Media_type = $2", id, mediaType)
print(rows)
if err != nil {
print(err.Error(), "from transactions err ")
return []*models.Review{}, err
}
defer rows.Close()

var reviews []*models.Review

for rows.Next() {
print("1")
var review models.Review
print("2")
var mediaType, desc, userID, mediaID, rating *string
var createdAt, updatedAt *time.Time
print("3")
if err := rows.Scan(&userID, &mediaID, &mediaType, &rating, &desc, &createdAt, &updatedAt); err != nil {
print(err.Error(), "from transactions err ")
return reviews, err
}
print("4")
review.UserID = *userID
review.MediaID = *mediaID
review.MediaType = *mediaType
review.Desc = desc
review.Rating = *rating
review.CreatedAt = *createdAt
review.UpdatedAt = *updatedAt
print("5")
reviews = append(reviews, &review)
}

print("second")
adescoteaux1 marked this conversation as resolved.
Show resolved Hide resolved
if err := rows.Err(); err != nil {
print(err.Error(), "this from transactions err ")
return []*models.Review{}, err
}

return reviews, nil

}

func NewReviewRepository(db *pgxpool.Pool) *ReviewRepository {
return &ReviewRepository{
db: db,
}
}
4 changes: 3 additions & 1 deletion backend/internal/storage/postgres/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"platnm/internal/storage"
review "platnm/internal/storage/postgres/schema"
user "platnm/internal/storage/postgres/schema"

"github.com/jackc/pgx/v5"
Expand Down Expand Up @@ -40,6 +41,7 @@ func ConnectDatabase(host, user, password, dbname, port string) *pgxpool.Pool {

func NewRepository(db *pgxpool.Pool) *storage.Repository {
return &storage.Repository{
User: user.NewUserRepository(db),
User: user.NewUserRepository(db),
Review: review.NewReviewRepository(db),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the same import here for the NewReviewRepository(db). Honestly might be better to change user into something more universal.

}
}
8 changes: 7 additions & 1 deletion backend/internal/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ type UserRepository interface {
GetUserByID(id string, ctx context.Context) (*models.User, error)
}

type ReviewRepository interface {
GetReviews(ctx context.Context) ([]*models.Review, error)
GetReviewsByID(ctx context.Context, id string, mediaType string) ([]*models.Review, error)
}

// Repository storage of all repositories.
type Repository struct {
User UserRepository
User UserRepository
Review ReviewRepository
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ CREATE TABLE IF NOT EXISTS "public"."users" (
"push_notification_enabled" boolean DEFAULT false
);

CREATE TABLE review (
user_id VARCHAR(255) NOT NULL,
media_type VARCHAR(50) NOT NULL,
media_id VARCHAR(255) NOT NULL,
rating VARCHAR(10) NOT NULL,
description TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, media_id, media_type) -- Assuming a composite key
);

ALTER TABLE "public"."users" OWNER TO "postgres";

ALTER TABLE ONLY "public"."users"
Expand Down
9 changes: 8 additions & 1 deletion backend/internal/supabase/seed.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,11 @@ VALUES
('user2', 'Jane', 'Doe', '[email protected]', '987-654-3210', NULL),
('user3', 'Bob', 'Johnson', '[email protected]', NULL, NULL, NULL),
('user4', 'Emily', 'Garcia', '[email protected]', '555-1212', NULL)
;
;

INSERT INTO review (user_id, media_type, media_id, rating, description, created_at, updated_at)
VALUES
('user123', 'album', 'album123', '1', 'Great album, enjoyed every track!', '2023-09-19 14:45:00', '2023-09-19 14:45:00'),
('user456', 'track', 'track789', '1', 'Not my taste, but decent production.', '2023-09-19 15:00:00', '2023-09-19 15:00:00'),
('user789', 'album', 'album456', '2', 'Absolutely fantastic! Best album of the year.', '2023-09-20 08:30:00', '2023-09-20 08:30:00'),
('user101', 'track', 'track654', '2', NULL, '2023-09-20 09:45:00', '2023-09-20 09:45:00');
Loading