
This commit adds a complete Go implementation of the Todo application. The application uses Gin framework for the web server, GORM for database access, and SQLite for storage. Key features: - Todo CRUD operations with the same API endpoints - Health check endpoint - Database migrations - Tests for models, services, and API handlers - Documentation for the API - Configurable settings
126 lines
2.9 KiB
Go
126 lines
2.9 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/simpletodoapp/go-todo-app/internal/dto"
|
|
"github.com/simpletodoapp/go-todo-app/internal/model"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// TodoService handles todo operations
|
|
type TodoService struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewTodoService creates a new todo service
|
|
func NewTodoService(db *gorm.DB) *TodoService {
|
|
return &TodoService{db: db}
|
|
}
|
|
|
|
// GetTodos retrieves todos with optional filters and pagination
|
|
func (s *TodoService) GetTodos(skip, limit int, completed *bool) ([]model.Todo, error) {
|
|
var todos []model.Todo
|
|
query := s.db
|
|
|
|
// Apply completed filter if provided
|
|
if completed != nil {
|
|
query = query.Where("completed = ?", *completed)
|
|
}
|
|
|
|
// Apply pagination
|
|
result := query.Offset(skip).Limit(limit).Find(&todos)
|
|
if result.Error != nil {
|
|
return nil, fmt.Errorf("error getting todos: %v", result.Error)
|
|
}
|
|
|
|
return todos, nil
|
|
}
|
|
|
|
// GetTodoByID retrieves a specific todo by ID
|
|
func (s *TodoService) GetTodoByID(id uint) (*model.Todo, error) {
|
|
var todo model.Todo
|
|
result := s.db.First(&todo, id)
|
|
|
|
if result.Error != nil {
|
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
|
return nil, nil // Todo not found, but not an error
|
|
}
|
|
return nil, fmt.Errorf("error getting todo: %v", result.Error)
|
|
}
|
|
|
|
return &todo, nil
|
|
}
|
|
|
|
// CreateTodo creates a new todo
|
|
func (s *TodoService) CreateTodo(todoCreate dto.TodoCreate) (*model.Todo, error) {
|
|
todo := model.Todo{
|
|
Title: todoCreate.Title,
|
|
Description: todoCreate.Description,
|
|
Completed: todoCreate.Completed,
|
|
}
|
|
|
|
result := s.db.Create(&todo)
|
|
if result.Error != nil {
|
|
return nil, fmt.Errorf("error creating todo: %v", result.Error)
|
|
}
|
|
|
|
return &todo, nil
|
|
}
|
|
|
|
// UpdateTodo updates an existing todo
|
|
func (s *TodoService) UpdateTodo(id uint, todoUpdate dto.TodoUpdate) (*model.Todo, error) {
|
|
// Get existing todo
|
|
todo, err := s.GetTodoByID(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if todo == nil {
|
|
return nil, nil // Not found
|
|
}
|
|
|
|
// Update fields if provided
|
|
updates := map[string]interface{}{}
|
|
|
|
if todoUpdate.Title != nil {
|
|
updates["title"] = *todoUpdate.Title
|
|
}
|
|
|
|
if todoUpdate.Description != nil {
|
|
updates["description"] = *todoUpdate.Description
|
|
}
|
|
|
|
if todoUpdate.Completed != nil {
|
|
updates["completed"] = *todoUpdate.Completed
|
|
}
|
|
|
|
// Apply updates
|
|
result := s.db.Model(&todo).Updates(updates)
|
|
if result.Error != nil {
|
|
return nil, fmt.Errorf("error updating todo: %v", result.Error)
|
|
}
|
|
|
|
// Refresh the todo from database
|
|
return s.GetTodoByID(id)
|
|
}
|
|
|
|
// DeleteTodo deletes a todo by ID
|
|
func (s *TodoService) DeleteTodo(id uint) (bool, error) {
|
|
// Check if todo exists
|
|
todo, err := s.GetTodoByID(id)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if todo == nil {
|
|
return false, nil // Not found
|
|
}
|
|
|
|
// Delete the todo
|
|
result := s.db.Delete(&model.Todo{}, id)
|
|
if result.Error != nil {
|
|
return false, fmt.Errorf("error deleting todo: %v", result.Error)
|
|
}
|
|
|
|
return true, nil
|
|
} |