feat: implement task respository
This commit is contained in:
150
internal/db/postgres/task.go
Normal file
150
internal/db/postgres/task.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/models"
|
||||
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/repository"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type pgxRepository struct {
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewTaskRepository(pool *pgxpool.Pool) repository.TaskRepository {
|
||||
return &pgxRepository{
|
||||
db: pool,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *pgxRepository) Save(ctx context.Context, task *models.Task) error {
|
||||
sql := `
|
||||
INSERT INTO public.tasks (text, completed)
|
||||
VALUES ($1, $2)
|
||||
RETURNING id, created_at, updated_at
|
||||
`
|
||||
|
||||
return r.db.QueryRow(ctx, sql, task.Text, task.Completed).Scan(&task.Id, &task.CreatedAt, &task.UpdatedAt)
|
||||
}
|
||||
|
||||
func (r *pgxRepository) GetById(ctx context.Context, id int) (*models.Task, error) {
|
||||
sql := `
|
||||
SELECT id, text, completed, created_at, updated_at
|
||||
FROM public.tasks
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
var task models.Task
|
||||
err := r.db.QueryRow(ctx, sql, id).Scan(
|
||||
&task.Id,
|
||||
&task.Text,
|
||||
&task.Completed,
|
||||
&task.CreatedAt,
|
||||
&task.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unexpected error when retrieving task: %w", err)
|
||||
}
|
||||
|
||||
return &task, nil
|
||||
}
|
||||
|
||||
func (r *pgxRepository) GetAll(ctx context.Context, filters repository.GetAllTaskFilters) ([]models.Task, error) {
|
||||
sql := `SELECT id, text, completed, created_at, updated_at FROM public.tasks WHERE 1 = 1`
|
||||
args := []any{}
|
||||
|
||||
if filters.Completed != nil {
|
||||
args = append(args, *filters.Completed)
|
||||
sql += fmt.Sprintf(" AND completed = $%d", len(args))
|
||||
}
|
||||
|
||||
limit := 1000
|
||||
if filters.Limit > 0 {
|
||||
limit = filters.Limit
|
||||
}
|
||||
args = append(args, limit)
|
||||
sql += fmt.Sprintf(" LIMIT $%d", len(args))
|
||||
|
||||
if filters.Offset > 0 {
|
||||
args = append(args, filters.Offset)
|
||||
sql += fmt.Sprintf(" OFFSET $%d", len(args))
|
||||
}
|
||||
|
||||
rows, err := r.db.Query(ctx, sql, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unexpected error when querying tasks: %w", err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
tasks, err := pgx.CollectRows(rows, pgx.RowToStructByName[models.Task])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unexpected error when collecting tasks: %w", err)
|
||||
}
|
||||
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func (r *pgxRepository) Update(ctx context.Context, id int, input *models.UpdateTaskInput) (*models.Task, error) {
|
||||
sql := "UPDATE public.tasks SET updated_at = CURRENT_TIMESTAMP"
|
||||
args := []any{}
|
||||
|
||||
if input.Text != nil {
|
||||
args = append(args, input.Text)
|
||||
sql += fmt.Sprintf(", text = $%d", len(args))
|
||||
}
|
||||
|
||||
if input.Completed != nil {
|
||||
args = append(args, input.Completed)
|
||||
sql += fmt.Sprintf(", completed = $%d", len(args))
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return r.GetById(ctx, id)
|
||||
}
|
||||
|
||||
args = append(args, id)
|
||||
sql += fmt.Sprintf(" WHERE id = $%d RETURNING id, text, completed, created_at, updated_at", len(args))
|
||||
|
||||
var task models.Task
|
||||
err := r.db.QueryRow(ctx, sql, args...).Scan(
|
||||
&task.Id,
|
||||
&task.Text,
|
||||
&task.Completed,
|
||||
&task.CreatedAt,
|
||||
&task.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, fmt.Errorf("task not found")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("updating task: %w", err)
|
||||
}
|
||||
|
||||
return &task, nil
|
||||
}
|
||||
|
||||
func (r *pgxRepository) Delete(ctx context.Context, id int) error {
|
||||
sql := "DELETE FROM public.tasks WHERE id = $1"
|
||||
|
||||
commandTag, err := r.db.Exec(ctx, sql, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unexpected error when deleting task: %w", err)
|
||||
}
|
||||
|
||||
if commandTag.RowsAffected() == 0 {
|
||||
return fmt.Errorf("No task found with id %d", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -6,10 +6,15 @@ import (
|
||||
)
|
||||
|
||||
type Task struct {
|
||||
Id int `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Completed bool `json:"completed"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
Id int `db:"id" json:"id"`
|
||||
Text string `db:"text" json:"text"`
|
||||
Completed bool `db:"completed" json:"completed"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt *time.Time `db:"updated_at" json:"updated_at"`
|
||||
// UpdatedAt pgtype.Timestamptz `json:"updated_at"` /* evaluar la posibilidad de utilizarlo */
|
||||
}
|
||||
|
||||
type UpdateTaskInput struct {
|
||||
Text *string `json:"text"`
|
||||
Completed *bool `json:"completed"`
|
||||
}
|
||||
|
||||
21
internal/repository/task.go
Normal file
21
internal/repository/task.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/models"
|
||||
)
|
||||
|
||||
type GetAllTaskFilters struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Completed *bool
|
||||
}
|
||||
|
||||
type TaskRepository interface {
|
||||
Save(ctx context.Context, task *models.Task) error
|
||||
GetById(ctx context.Context, id int) (*models.Task, error)
|
||||
GetAll(ctx context.Context, filters GetAllTaskFilters) ([]models.Task, error)
|
||||
Update(ctx context.Context, id int, input *models.UpdateTaskInput) (*models.Task, error)
|
||||
Delete(ctx context.Context, id int) error
|
||||
}
|
||||
Reference in New Issue
Block a user