Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions cmd/add_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import "github.com/spf13/cobra"

var addTaskCmd = &cobra.Command{
Use: "add <name_of_task>",
Short: "Create a new task",
Long: `Create a new task with shared name`,
Short: "Create new task",
Long: `Create new task with shared name`,
Run: func(cmd *cobra.Command, args []string) {
taskName := args[0]
task, err := service.Task.Create(taskName)
Expand Down
4 changes: 2 additions & 2 deletions cmd/delete_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

var deleteTaskCmd = &cobra.Command{
Use: "delete <id_of_task>",
Short: "Delete the task",
Long: `Delete the task by shared id`,
Short: "Delete task",
Long: `Delete task by shared id`,
Run: func(cmd *cobra.Command, args []string) {
taskID, err := uuid.Parse(args[0])
if err != nil {
Expand Down
44 changes: 44 additions & 0 deletions cmd/get_by_id_task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cmd

import (
"reflect"

"github.com/google/uuid"
"github.com/spf13/cobra"
)

var getTaskByIdCmd = &cobra.Command{
Use: "get-task-by-id <task_id>",
Short: "Get task by id",
Long: `Get the task by shared id`,
Run: func(cmd *cobra.Command, args []string) {
taskID, err := uuid.Parse(args[0])
if err != nil {
cmd.Printf("Failed to parse id string to uuid: %v\n", err)
return
}

task, err := service.Task.GetByID(taskID)
if err != nil {
cmd.Printf("Failed to get task by id: %v\n", err)
return
}

cmd.Printf("Got task by id: %v\n\n", taskID)

taskValue := reflect.ValueOf(task)
taskType := reflect.TypeOf(task)

if taskType.Kind() == reflect.Ptr {
taskType = taskType.Elem()
taskValue = taskValue.Elem()
}

for i := 0; i < taskType.NumField(); i++ {
fieldInfo := taskType.Field(i)
fieldValue := taskValue.Field(i)

cmd.Printf("%s: %v\n", fieldInfo.Name, fieldValue.Interface())
}
},
}
36 changes: 36 additions & 0 deletions cmd/get_list_task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmd

import (
"reflect"

"github.com/spf13/cobra"
)

var getListTaskCmd = &cobra.Command{
Use: "get-list",
Short: "Get list of tasks",
Long: `Get list of tasks in descending order by created_at`,
Run: func(cmd *cobra.Command, args []string) {
tasks, err := service.Task.GetList()
if err != nil {
cmd.Printf("Failed to get all tasks: %v\n", err)
return
}

cmd.Print("Got list of tasks: \n")

for index, task := range *tasks {
cmd.Printf("\nTask #%d\n", index+1)

taskValue := reflect.ValueOf(task)
taskType := reflect.TypeOf(task)

for i := 0; i < taskType.NumField(); i++ {
fieldInfo := taskType.Field(i)
fieldValue := taskValue.Field(i)

cmd.Printf("%s: %v\n", fieldInfo.Name, fieldValue.Interface())
}
}
},
}
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ func init() {
rootCmd.AddCommand(addTaskCmd)
rootCmd.AddCommand(updateTaskCmd)
rootCmd.AddCommand(deleteTaskCmd)
rootCmd.AddCommand(getTaskByIdCmd)
rootCmd.AddCommand(getListTaskCmd)
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
4 changes: 2 additions & 2 deletions cmd/update_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

var updateTaskCmd = &cobra.Command{
Use: "update <id_of_task> <name_of_task>",
Short: "Update the task",
Long: `Update the task by shared id`,
Short: "Update task",
Long: `Update task by shared id`,
Run: func(cmd *cobra.Command, args []string) {
taskID, err := uuid.Parse(args[0])
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion internal/database/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import (
"github.com/sirupsen/logrus"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)

func ConnectPostgres(cfg *configs.DBConfig) (*gorm.DB, error) {
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%s sslmode=%s",
cfg.Host, cfg.Username, cfg.Password, cfg.DBName, cfg.Port, cfg.SSLMode,
)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
return nil, fmt.Errorf("failed to connect to DB: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions internal/repositories/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Task interface {
Create(task *models.Task) error
Update(task *models.Task) error
GetByID(id uuid.UUID) (*models.Task, error)
GetList() (*[]models.Task, error)
Delete(id uuid.UUID) (uuid.UUID, error)
}

Expand Down
8 changes: 8 additions & 0 deletions internal/repositories/task_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ func (r *TaskRepository) GetByID(id uuid.UUID) (*models.Task, error) {
return &task, nil
}

func (r *TaskRepository) GetList() (*[]models.Task, error) {
var tasks []models.Task
if err := r.db.Order("created_at desc").Find(&tasks).Error; err != nil {
return nil, err
}
return &tasks, nil
}

func (r *TaskRepository) Delete(id uuid.UUID) error {
if err := r.db.Delete(&models.Task{}, "id = ?", id).Error; err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions internal/services/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Task interface {
Create(name string) (*models.Task, error)
Update(name string) (*models.Task, error)
GetByID(id uuid.UUID) (*models.Task, error)
GetList() (*[]models.Task, error)
Delete(id uuid.UUID) (uuid.UUID, error)
}

Expand Down
4 changes: 4 additions & 0 deletions internal/services/task_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func (service *TaskService) GetByID(id uuid.UUID) (*models.Task, error) {
return service.repository.GetByID(id)
}

func (service *TaskService) GetList() (*[]models.Task, error) {
return service.repository.GetList()
}

func (service *TaskService) Delete(id uuid.UUID) (uuid.UUID, error) {
if err := service.repository.Delete(id); err != nil {
return uuid.Nil, err
Expand Down
65 changes: 65 additions & 0 deletions test/services/task_service/task_get_by_id_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package task_service

import (
"CLI-todo/internal/models"
"CLI-todo/test"
"testing"
"time"

"github.com/DATA-DOG/go-sqlmock"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)

func TestTaskService_GetByID(t *testing.T) {
existingTask := &models.Task{
ID: uuid.New(),
Name: "Task Name",
CreatedAt: time.Now().Add(-48 * time.Hour),
UpdatedAt: time.Now().Add(-48 * time.Hour),
DeletedAt: nil,
}

tests := []struct {
name string
taskID uuid.UUID
wantError bool
}{
{
name: "Valid parameters for get task by id",
taskID: existingTask.ID,
wantError: false,
},
{
name: "Valid parameters when task doesn't exist",
taskID: uuid.New(),
wantError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, mock, service := test.CreateMockService(t)

if !tt.wantError {
mock.ExpectQuery(`SELECT \* FROM \"tasks\".*`).
WithArgs(tt.taskID, sqlmock.AnyArg()).
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "created_at", "updated_at", "deleted_at"}).
AddRow(tt.taskID, existingTask.Name, existingTask.CreatedAt, existingTask.UpdatedAt, existingTask.DeletedAt))
}

task, err := service.Task.GetByID(tt.taskID)

if tt.wantError {
assert.Error(t, err)
return
}

if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

assert.Equal(t, tt.taskID.String(), task.ID.String())
})
}
}
75 changes: 75 additions & 0 deletions test/services/task_service/task_get_list_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package task_service

import (
"CLI-todo/internal/models"
"CLI-todo/test"
"testing"
"time"

"github.com/DATA-DOG/go-sqlmock"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)

func TestTaskService_GetList(t *testing.T) {
existingTasks := []models.Task{
{
ID: uuid.New(),
Name: "Task Name1",
CreatedAt: time.Now().Add(-48 * time.Hour),
UpdatedAt: time.Now().Add(-48 * time.Hour),
DeletedAt: nil,
},
{
ID: uuid.New(),
Name: "Task Name2",
CreatedAt: time.Now().Add(-48 * time.Hour),
UpdatedAt: time.Now().Add(-48 * time.Hour),
DeletedAt: nil,
},
}

tests := []struct {
name string
tasks []models.Task
wantError bool
}{
{
name: "Valid parameters for get list of tasks",
tasks: existingTasks,
wantError: false,
},
{
name: "Valid parameters for get list of tasks, but tasks do not exist",
tasks: []models.Task{},
wantError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, mock, service := test.CreateMockService(t)

if !tt.wantError {
rowBuilder := sqlmock.NewRows([]string{"id", "name", "created_at", "updated_at", "deleted_at"})
for _, task := range tt.tasks {
rowBuilder = rowBuilder.AddRow(task.ID, task.Name, task.CreatedAt, task.UpdatedAt, task.DeletedAt)
}
mock.ExpectQuery(`SELECT \* FROM \"tasks\".*`).WillReturnRows(rowBuilder)
}

tasks, err := service.Task.GetList()

if tt.wantError {
assert.Error(t, err)
return
}

if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

assert.Equal(t, tt.tasks, *tasks)
})
}
}