updates
This commit is contained in:
22
server/internal/repository/category_repository.go
Normal file
22
server/internal/repository/category_repository.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go-server/internal/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CategoryRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewCategoryRepository(db *gorm.DB) *CategoryRepository {
|
||||
return &CategoryRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) GetAll(ctx context.Context) ([]models.Category, error) {
|
||||
var categories []models.Category
|
||||
err := r.db.WithContext(ctx).Find(&categories).Error
|
||||
return categories, err
|
||||
}
|
||||
187
server/internal/repository/daily_overview_repository.go
Normal file
187
server/internal/repository/daily_overview_repository.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go-server/internal/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DailyOverviewRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewDailyOverviewRepository(db *gorm.DB) *DailyOverviewRepository {
|
||||
return &DailyOverviewRepository{db: db}
|
||||
}
|
||||
|
||||
// NutrientTotal represents the aggregated total for a nutrient across all supplements
|
||||
type NutrientTotal struct {
|
||||
NutrientID models.ULID `json:"nutrientId" db:"nutrient_id"`
|
||||
NutrientName string `json:"nutrientName" db:"nutrient_name"`
|
||||
Description string `json:"description" db:"description"`
|
||||
TotalAmount string `json:"totalAmount" db:"total_amount"`
|
||||
Unit string `json:"unit" db:"unit"`
|
||||
Categories []string `json:"categories" db:"categories"`
|
||||
}
|
||||
|
||||
// SupplementNutrientDetails represents detailed breakdown by supplement
|
||||
type SupplementNutrientDetails struct {
|
||||
SupplementID models.ULID `json:"supplementId" db:"supplement_id"`
|
||||
SupplementName string `json:"supplementName" db:"supplement_name"`
|
||||
NutrientID models.ULID `json:"nutrientId" db:"nutrient_id"`
|
||||
NutrientName string `json:"nutrientName" db:"nutrient_name"`
|
||||
Amount string `json:"amount" db:"amount"`
|
||||
Unit string `json:"unit" db:"unit"`
|
||||
ServingSize string `json:"servingSize" db:"serving_size"`
|
||||
ReferenceIntake string `json:"referenceIntake" db:"reference_intake"`
|
||||
}
|
||||
|
||||
// GetNutrientTotals returns aggregated nutrient totals across all supplements
|
||||
// This is perfect for a daily overview where you want to see total intake
|
||||
func (r *DailyOverviewRepository) GetNutrientTotals(ctx context.Context) ([]NutrientTotal, error) {
|
||||
var results []NutrientTotal
|
||||
|
||||
query := `
|
||||
SELECT
|
||||
n.id as nutrient_id,
|
||||
n.name as nutrient_name,
|
||||
n.description,
|
||||
sn.per_serving_reference_intake,
|
||||
-- For now, we'll concatenate amounts (later we can parse and sum numeric values)
|
||||
STRING_AGG(sn.per_serving, ' + ') as total_amount,
|
||||
-- Extract unit from first entry (assumption: same nutrient has same unit)
|
||||
SPLIT_PART(MIN(sn.per_serving), ' ', 2) as unit,
|
||||
-- Get all categories for this nutrient
|
||||
ARRAY_AGG(DISTINCT c.name) as categories
|
||||
FROM nutrients n
|
||||
LEFT JOIN supplement_nutrients sn ON n.id = sn.nutrient_id
|
||||
LEFT JOIN supplements s ON sn.supplement_id = s.id
|
||||
LEFT JOIN nutrient_categories nc ON n.id = nc.nutrient_id
|
||||
LEFT JOIN categories c ON nc.category_id = c.id
|
||||
WHERE sn.id IS NOT NULL -- Only nutrients that are in supplements
|
||||
GROUP BY n.id, n.name, n.description, sn.per_serving_reference_intake
|
||||
ORDER BY n.name
|
||||
`
|
||||
|
||||
err := r.db.WithContext(ctx).Raw(query).Scan(&results).Error
|
||||
return results, err
|
||||
}
|
||||
|
||||
// GetSupplementBreakdown returns detailed breakdown of nutrients by supplement
|
||||
func (r *DailyOverviewRepository) GetSupplementBreakdown(ctx context.Context) ([]SupplementNutrientDetails, error) {
|
||||
var results []SupplementNutrientDetails
|
||||
|
||||
query := `
|
||||
SELECT
|
||||
s.id as supplement_id,
|
||||
s.name as supplement_name,
|
||||
n.id as nutrient_id,
|
||||
n.name as nutrient_name,
|
||||
sn.per_serving as amount,
|
||||
SPLIT_PART(sn.per_serving, ' ', 2) as unit,
|
||||
sn.serving_size,
|
||||
sn.per_serving_reference_intake as reference_intake
|
||||
FROM supplements s
|
||||
JOIN supplement_nutrients sn ON s.id = sn.supplement_id
|
||||
JOIN nutrients n ON sn.nutrient_id = n.id
|
||||
ORDER BY s.name, n.name
|
||||
`
|
||||
|
||||
err := r.db.WithContext(ctx).Raw(query).Scan(&results).Error
|
||||
return results, err
|
||||
}
|
||||
|
||||
// GetNutrientsByCategory returns nutrients grouped by category with totals
|
||||
func (r *DailyOverviewRepository) GetNutrientsByCategory(ctx context.Context) (map[string][]NutrientTotal, error) {
|
||||
var results []struct {
|
||||
CategoryName string `db:"category_name"`
|
||||
CategoryID models.ULID `db:"category_id"`
|
||||
NutrientID models.ULID `db:"nutrient_id"`
|
||||
NutrientName string `db:"nutrient_name"`
|
||||
Description string `db:"description"`
|
||||
TotalAmount string `db:"total_amount"`
|
||||
Unit string `db:"unit"`
|
||||
}
|
||||
|
||||
query := `
|
||||
SELECT
|
||||
c.name as category_name,
|
||||
c.id as category_id,
|
||||
n.id as nutrient_id,
|
||||
n.name as nutrient_name,
|
||||
n.description,
|
||||
STRING_AGG(sn.per_serving, ' + ') as total_amount,
|
||||
SPLIT_PART(MIN(sn.per_serving), ' ', 2) as unit
|
||||
FROM categories c
|
||||
JOIN nutrient_categories nc ON c.id = nc.category_id
|
||||
JOIN nutrients n ON nc.nutrient_id = n.id
|
||||
LEFT JOIN supplement_nutrients sn ON n.id = sn.nutrient_id
|
||||
WHERE sn.id IS NOT NULL
|
||||
GROUP BY c.name, n.id, n.name, n.description, c.id
|
||||
ORDER BY c.name, n.name
|
||||
`
|
||||
|
||||
err := r.db.WithContext(ctx).Raw(query).Scan(&results).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Group by category
|
||||
categoryMap := make(map[string][]NutrientTotal)
|
||||
for _, result := range results {
|
||||
nutrient := NutrientTotal{
|
||||
NutrientID: result.NutrientID,
|
||||
NutrientName: result.NutrientName,
|
||||
Description: result.Description,
|
||||
TotalAmount: result.TotalAmount,
|
||||
Unit: result.Unit,
|
||||
Categories: []string{result.CategoryID.String()},
|
||||
}
|
||||
categoryMap[result.CategoryName] = append(categoryMap[result.CategoryName], nutrient)
|
||||
}
|
||||
|
||||
return categoryMap, nil
|
||||
}
|
||||
|
||||
// ExecuteRawQuery allows executing arbitrary SQL queries and scanning into any struct
|
||||
// This gives you full flexibility for custom queries
|
||||
func (r *DailyOverviewRepository) ExecuteRawQuery(ctx context.Context, query string, dest interface{}, args ...interface{}) error {
|
||||
return r.db.WithContext(ctx).Raw(query, args...).Scan(dest).Error
|
||||
}
|
||||
|
||||
// ExecuteRawQueryWithResult executes a raw query and returns the result as a map
|
||||
// Useful for dynamic queries where you don't know the structure ahead of time
|
||||
func (r *DailyOverviewRepository) ExecuteRawQueryWithResult(ctx context.Context, query string, args ...interface{}) ([]map[string]interface{}, error) {
|
||||
rows, err := r.db.WithContext(ctx).Raw(query, args...).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results []map[string]interface{}
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, len(columns))
|
||||
valuePtrs := make([]interface{}, len(columns))
|
||||
for i := range columns {
|
||||
valuePtrs[i] = &values[i]
|
||||
}
|
||||
|
||||
if err := rows.Scan(valuePtrs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]interface{})
|
||||
for i, col := range columns {
|
||||
result[col] = values[i]
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
28
server/internal/repository/nutrient_repository.go
Normal file
28
server/internal/repository/nutrient_repository.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go-server/internal/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type NutrientRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewNutrientRepository(db *gorm.DB) *NutrientRepository {
|
||||
return &NutrientRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *NutrientRepository) GetAll(ctx context.Context) ([]*models.Nutrient, error) {
|
||||
var nutrients []*models.Nutrient
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Categories").
|
||||
Find(&nutrients).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nutrients, nil
|
||||
}
|
||||
57
server/internal/repository/supplement_repository.go
Normal file
57
server/internal/repository/supplement_repository.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go-server/internal/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SupplementRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewSupplementRepository(db *gorm.DB) *SupplementRepository {
|
||||
return &SupplementRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *SupplementRepository) GetAll(ctx context.Context) ([]*models.Supplement, error) {
|
||||
var supplements []*models.Supplement
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Nutrients").
|
||||
Preload("SupplementNutrients").
|
||||
Find(&supplements).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return supplements, nil
|
||||
}
|
||||
|
||||
func (r *SupplementRepository) GetById(ctx context.Context, id string) (*models.Supplement, error) {
|
||||
var supplement *models.Supplement
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Nutrients").
|
||||
Preload("SupplementNutrients").
|
||||
First(&supplement, "id = ?", id).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return supplement, nil
|
||||
}
|
||||
|
||||
func (r *SupplementRepository) GetDailySupplementsOverview(ctx context.Context) ([]*models.SupplementNutrientOverview, error) {
|
||||
var supplementNutrientOverview []*models.SupplementNutrientOverview
|
||||
err := r.db.WithContext(ctx).
|
||||
Table("supplements").
|
||||
Select("supplements.id as supplement_id, supplements.name as supplement_name, supplements.description as supplement_description, supplement_nutrients.serving_size as serving_size, supplement_nutrients.per_serving as per_serving, supplement_nutrients.per_serving_reference_intake as per_serving_reference_intake, nutrients.id as nutrient_id, nutrients.name as nutrient_name, nutrients.description as nutrient_description").
|
||||
Joins("INNER JOIN supplement_nutrients ON supplements.id = supplement_nutrients.supplement_id").
|
||||
Joins("JOIN nutrients ON supplement_nutrients.nutrient_id = nutrients.id").
|
||||
Find(&supplementNutrientOverview).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return supplementNutrientOverview, nil
|
||||
}
|
||||
247
server/internal/repository/todo_repository.go
Normal file
247
server/internal/repository/todo_repository.go
Normal file
@@ -0,0 +1,247 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go-server/internal/models"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TodoRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewTodoRepository(db *gorm.DB) *TodoRepository {
|
||||
return &TodoRepository{db: db}
|
||||
}
|
||||
|
||||
// CreateTodo creates a new todo for a user
|
||||
func (r *TodoRepository) CreateTodo(ctx context.Context, todo *models.Todo) error {
|
||||
return r.db.WithContext(ctx).Create(todo).Error
|
||||
}
|
||||
|
||||
// GetTodosByUserID gets all active todos for a user
|
||||
func (r *TodoRepository) GetTodosByUserID(ctx context.Context, userID models.ULID) ([]models.Todo, error) {
|
||||
var todos []models.Todo
|
||||
err := r.db.WithContext(ctx).
|
||||
Where("user_id = ? AND is_active = ?", userID, true).
|
||||
Order("created_at ASC").
|
||||
Find(&todos).Error
|
||||
return todos, err
|
||||
}
|
||||
|
||||
// GetTodoByID gets a todo by ID and user ID (for security)
|
||||
func (r *TodoRepository) GetTodoByID(ctx context.Context, todoID, userID models.ULID) (*models.Todo, error) {
|
||||
var todo models.Todo
|
||||
err := r.db.WithContext(ctx).
|
||||
Where("id = ? AND user_id = ?", todoID, userID).
|
||||
First(&todo).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &todo, nil
|
||||
}
|
||||
|
||||
// UpdateTodo updates a todo
|
||||
func (r *TodoRepository) UpdateTodo(ctx context.Context, todo *models.Todo) error {
|
||||
return r.db.WithContext(ctx).Save(todo).Error
|
||||
}
|
||||
|
||||
// DeleteTodo soft deletes a todo (sets is_active to false)
|
||||
func (r *TodoRepository) DeleteTodo(ctx context.Context, todoID, userID models.ULID) error {
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&models.Todo{}).
|
||||
Where("id = ? AND user_id = ?", todoID, userID).
|
||||
Update("is_active", false).Error
|
||||
}
|
||||
|
||||
// CompleteTodo creates a completion record for a todo
|
||||
func (r *TodoRepository) CompleteTodo(ctx context.Context, completion *models.TodoCompletion) error {
|
||||
return r.db.WithContext(ctx).Create(completion).Error
|
||||
}
|
||||
|
||||
// GetTodayCompletions gets all completions for today for a user
|
||||
func (r *TodoRepository) GetTodayCompletions(ctx context.Context, userID models.ULID) ([]models.TodoCompletion, error) {
|
||||
now := time.Now()
|
||||
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
endOfDay := startOfDay.Add(24 * time.Hour)
|
||||
|
||||
var completions []models.TodoCompletion
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Todo").
|
||||
Where("user_id = ? AND completed_at >= ? AND completed_at < ?", userID, startOfDay, endOfDay).
|
||||
Order("completed_at DESC").
|
||||
Find(&completions).Error
|
||||
return completions, err
|
||||
}
|
||||
|
||||
// GetCompletionsByDateRange gets completions for a date range
|
||||
func (r *TodoRepository) GetCompletionsByDateRange(ctx context.Context, userID models.ULID, startDate, endDate time.Time) ([]models.TodoCompletion, error) {
|
||||
var completions []models.TodoCompletion
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Todo").
|
||||
Where("user_id = ? AND completed_at >= ? AND completed_at < ?", userID, startDate, endDate).
|
||||
Order("completed_at DESC").
|
||||
Find(&completions).Error
|
||||
return completions, err
|
||||
}
|
||||
|
||||
// GetTodoWithStats gets todos with completion statistics using raw SQL for better performance
|
||||
func (r *TodoRepository) GetTodosWithStats(ctx context.Context, userID models.ULID) ([]models.TodoWithStats, error) {
|
||||
var results []models.TodoWithStats
|
||||
|
||||
query := `
|
||||
WITH todo_stats AS (
|
||||
SELECT
|
||||
t.id,
|
||||
t.user_id,
|
||||
t.title,
|
||||
t.description,
|
||||
t.color,
|
||||
t.is_active,
|
||||
t.created_at,
|
||||
t.updated_at,
|
||||
COUNT(tc.id) as total_completions,
|
||||
MAX(tc.completed_at) as last_completed_at,
|
||||
CASE
|
||||
WHEN MAX(tc.completed_at) >= CURRENT_DATE
|
||||
THEN true
|
||||
ELSE false
|
||||
END as completed_today
|
||||
FROM todos t
|
||||
LEFT JOIN todo_completions tc ON t.id = tc.todo_id
|
||||
WHERE t.user_id = ? AND t.is_active = true
|
||||
GROUP BY t.id, t.user_id, t.title, t.description, t.color, t.is_active, t.created_at, t.updated_at
|
||||
),
|
||||
streak_calc AS (
|
||||
SELECT
|
||||
ts.*,
|
||||
COALESCE(
|
||||
(SELECT COUNT(*)
|
||||
FROM generate_series(
|
||||
CURRENT_DATE - INTERVAL '365 days',
|
||||
CURRENT_DATE,
|
||||
INTERVAL '1 day'
|
||||
) AS date_series(date)
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM todo_completions tc2
|
||||
WHERE tc2.todo_id = ts.id
|
||||
AND DATE(tc2.completed_at) = date_series.date
|
||||
)
|
||||
AND date_series.date <= CURRENT_DATE
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM generate_series(
|
||||
date_series.date + INTERVAL '1 day',
|
||||
CURRENT_DATE,
|
||||
INTERVAL '1 day'
|
||||
) AS gap_check(gap_date)
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM todo_completions tc3
|
||||
WHERE tc3.todo_id = ts.id
|
||||
AND DATE(tc3.completed_at) = gap_check.gap_date
|
||||
)
|
||||
)
|
||||
), 0
|
||||
) as current_streak
|
||||
FROM todo_stats ts
|
||||
)
|
||||
SELECT
|
||||
sc.*,
|
||||
COALESCE(
|
||||
(SELECT MAX(streak_length)
|
||||
FROM (
|
||||
SELECT COUNT(*) as streak_length
|
||||
FROM (
|
||||
SELECT
|
||||
DATE(tc.completed_at) as completion_date,
|
||||
ROW_NUMBER() OVER (ORDER BY DATE(tc.completed_at)) as rn,
|
||||
DATE(tc.completed_at) - INTERVAL '1 day' * ROW_NUMBER() OVER (ORDER BY DATE(tc.completed_at)) as streak_group
|
||||
FROM todo_completions tc
|
||||
WHERE tc.todo_id = sc.id
|
||||
) grouped
|
||||
GROUP BY streak_group
|
||||
) streaks), 0
|
||||
) as longest_streak
|
||||
FROM streak_calc sc
|
||||
ORDER BY sc.created_at ASC
|
||||
`
|
||||
|
||||
rows, err := r.db.WithContext(ctx).Raw(query, userID).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var result models.TodoWithStats
|
||||
var lastCompletedAt *time.Time
|
||||
|
||||
err := rows.Scan(
|
||||
&result.ID,
|
||||
&result.UserID,
|
||||
&result.Title,
|
||||
&result.Description,
|
||||
&result.Color,
|
||||
&result.IsActive,
|
||||
&result.CreatedAt,
|
||||
&result.UpdatedAt,
|
||||
&result.TotalCompletions,
|
||||
&lastCompletedAt,
|
||||
&result.CompletedToday,
|
||||
&result.CurrentStreak,
|
||||
&result.LongestStreak,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.LastCompletedAt = lastCompletedAt
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// CheckTodoCompletedToday checks if a todo was completed today
|
||||
func (r *TodoRepository) CheckTodoCompletedToday(ctx context.Context, todoID, userID models.ULID) (bool, error) {
|
||||
now := time.Now()
|
||||
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
endOfDay := startOfDay.Add(24 * time.Hour)
|
||||
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).
|
||||
Model(&models.TodoCompletion{}).
|
||||
Where("todo_id = ? AND user_id = ? AND completed_at >= ? AND completed_at < ?",
|
||||
todoID, userID, startOfDay, endOfDay).
|
||||
Count(&count).Error
|
||||
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// GetActivityLog gets activity log with pagination
|
||||
func (r *TodoRepository) GetActivityLog(ctx context.Context, userID models.ULID, limit, offset int) ([]models.TodoCompletion, error) {
|
||||
var completions []models.TodoCompletion
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Todo").
|
||||
Where("user_id = ?", userID).
|
||||
Order("completed_at DESC").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&completions).Error
|
||||
return completions, err
|
||||
}
|
||||
|
||||
// GetActivityLogByDate gets activity log for a specific date
|
||||
func (r *TodoRepository) GetActivityLogByDate(ctx context.Context, userID models.ULID, date time.Time) ([]models.TodoCompletion, error) {
|
||||
startOfDay := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
|
||||
endOfDay := startOfDay.Add(24 * time.Hour)
|
||||
|
||||
var completions []models.TodoCompletion
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Todo").
|
||||
Where("user_id = ? AND completed_at >= ? AND completed_at < ?", userID, startOfDay, endOfDay).
|
||||
Order("completed_at DESC").
|
||||
Find(&completions).Error
|
||||
return completions, err
|
||||
}
|
||||
51
server/internal/repository/user_repository.go
Normal file
51
server/internal/repository/user_repository.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go-server/internal/models"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewUserRepository(db *gorm.DB) *UserRepository {
|
||||
return &UserRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *UserRepository) Create(ctx context.Context, user *models.User) error {
|
||||
return r.db.WithContext(ctx).Create(user).Error
|
||||
}
|
||||
|
||||
func (r *UserRepository) GetByID(ctx context.Context, id uuid.UUID) (*models.User, error) {
|
||||
var user models.User
|
||||
if err := r.db.WithContext(ctx).First(&user, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) Update(ctx context.Context, user *models.User) error {
|
||||
return r.db.WithContext(ctx).Save(user).Error
|
||||
}
|
||||
|
||||
func (r *UserRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return r.db.WithContext(ctx).Delete(&models.User{}, id).Error
|
||||
}
|
||||
|
||||
func (r *UserRepository) GetAll(ctx context.Context) ([]*models.User, error) {
|
||||
var users []*models.User
|
||||
err := r.db.WithContext(ctx).Find(&users).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
Reference in New Issue
Block a user