refactor: update interface contract and applies some fixes

This commit is contained in:
2025-11-02 17:51:55 -03:00
parent af511203a4
commit 4a28259dc8
4 changed files with 121 additions and 44 deletions

View File

@@ -10,7 +10,7 @@ type baseRepository[T any] struct {
tableName string tableName string
} }
func NewBaseRepository[T any](db *sql.DB, tableName string) Repository[T] { func NewBaseRepository[T any](db *sql.DB, tableName string) *baseRepository[T] {
return &baseRepository[T]{ return &baseRepository[T]{
db: db, db: db,
tableName: tableName, tableName: tableName,
@@ -25,14 +25,34 @@ func (r *baseRepository[T]) GetDB() *sql.DB {
return r.db return r.db
} }
func (r *baseRepository[T]) GetAll() ([]T, error) {
query := r.BuildQuery("SELECT * FROM %s ORDER BY id DESC")
rows, err := r.db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
entities := make([]T, 0)
rowsErr := ScanRows(rows, &entities)
if rowsErr != nil {
return nil, err
}
return entities, nil
}
func (r *baseRepository[T]) GetByID(id int) (*T, error) { func (r *baseRepository[T]) GetByID(id int) (*T, error) {
var entity T var entity T
query := r.BuildQuery("SELECT * FROM %s WHERE id = ?") query := r.BuildQuery("SELECT * FROM %s WHERE id = ?")
err := r.db.QueryRow( row := r.db.QueryRow(
query, query,
id, id,
).Scan(entity) )
err := scanRow(row, &entity)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
@@ -44,33 +64,8 @@ func (r *baseRepository[T]) GetByID(id int) (*T, error) {
return &entity, nil return &entity, nil
} }
func (r *baseRepository[T]) GetAll() ([]T, error) {
query := r.BuildQuery("SELECT * FROM %s ORDER BY id DESC")
rows, err := r.db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
entities := make([]T, 0)
for rows.Next() {
var entity T
if err := rows.Scan(entity); err != nil {
return nil, err
}
entities = append(entities, entity)
}
if err = rows.Err(); err != nil {
return nil, err
}
return entities, nil
}
func (r *baseRepository[T]) Delete(id int) (int64, error) { func (r *baseRepository[T]) Delete(id int) (int64, error) {
query := r.BuildQuery("DELETE %s WHERE id = ? LIMIT 1") query := r.BuildQuery("DELETE FROM %s WHERE id = ?")
res, err := r.db.Exec(query, id) res, err := r.db.Exec(query, id)
if err != nil { if err != nil {
return 0, err return 0, err

View File

@@ -2,6 +2,7 @@ package repository
import ( import (
"database/sql" "database/sql"
"fmt"
"gitea.gabilandia.com/gabdlr/agenda-web-go/internal/models" "gitea.gabilandia.com/gabdlr/agenda-web-go/internal/models"
) )
@@ -10,7 +11,7 @@ type ContactRepository struct {
baseRepository[models.Contact] baseRepository[models.Contact]
} }
func NewContactRepository(db *sql.DB) *ContactRepository { func NewContactRepository(db *sql.DB) Repository[models.Contact] {
return &ContactRepository{ return &ContactRepository{
baseRepository[models.Contact]{ baseRepository[models.Contact]{
db: db, db: db,
@@ -38,20 +39,45 @@ func (r *ContactRepository) Create(contact *models.Contact) (int64, error) {
return id, nil return id, nil
} }
func (r *ContactRepository) Update(contact *models.Contact) (int64, error) { func (r *ContactRepository) Update(contact *models.Contact) error {
query := r.BuildQuery("UPDATE %s SET name = ?, company = ?, phone = ? WHERE id = ?") query := r.BuildQuery("UPDATE %s SET")
result, err := r.db.Exec(query, fieldsToUpdate := make([]string, 0, 4)
contact.Name, contact.Company, contact.Phone, contact.ID, fields := make([]any, 0)
if contact.Name != "" {
fieldsToUpdate = append(fieldsToUpdate, "name")
fields = append(fields, &contact.Name)
}
if contact.Company != "" {
fieldsToUpdate = append(fieldsToUpdate, "company")
fields = append(fields, &contact.Company)
}
if contact.Phone != "" {
fieldsToUpdate = append(fieldsToUpdate, "phone")
fields = append(fields, &contact.Phone)
}
fields = append(fields, &contact.ID)
fieldsToUpdatelen := len(fieldsToUpdate)
for i, field := range fieldsToUpdate {
query += fmt.Sprintf(" %s = ?", field)
if i != fieldsToUpdatelen-1 {
query += ","
}
}
query += " WHERE id = ?"
_, err := r.db.Exec(query,
fields...,
) )
if err != nil { if err != nil {
return 0, err return err
} }
rowsAffected, err := result.RowsAffected() return nil
if err != nil {
return 0, err
}
return rowsAffected, nil
} }

View File

@@ -1,8 +1,9 @@
package repository package repository
type Repository[T any] interface { type Repository[T any] interface {
BuildQuery(s string) string Create(T *T) (int64, error)
GetByID(id int) (*T, error)
GetAll() ([]T, error)
Delete(id int) (int64, error) Delete(id int) (int64, error)
GetAll() ([]T, error)
GetByID(id int) (*T, error)
Update(contact *T) error
} }

View File

@@ -0,0 +1,55 @@
package repository
import (
"database/sql"
"fmt"
"reflect"
)
func scanRow(row *sql.Row, dest any) error {
destValue := reflect.ValueOf(dest).Elem()
fields := make([]any, destValue.NumField())
for i := 0; i < destValue.NumField(); i++ {
fields[i] = destValue.Field(i).Addr().Interface()
}
return row.Scan(fields...)
}
func ScanRows(rows *sql.Rows, destSlice any) error {
sliceValue := reflect.ValueOf(destSlice)
if sliceValue.Kind() != reflect.Pointer || sliceValue.Elem().Kind() != reflect.Slice {
return fmt.Errorf("destSlice must be a pointer to a slice")
}
sliceElem := sliceValue.Elem()
structType := sliceElem.Type().Elem()
for rows.Next() {
newStruct := reflect.New(structType).Elem()
fields := make([]any, newStruct.NumField())
for i := 0; i < newStruct.NumField(); i++ {
fields[i] = newStruct.Field(i).Addr().Interface()
}
if err := rows.Scan(fields...); err != nil {
return err
}
sliceElem.Set(reflect.Append(sliceElem, newStruct))
}
return rows.Err()
}
func GetStructFieldsPtr(object any) []any {
destValue := reflect.ValueOf(object).Elem()
fields := make([]any, destValue.NumField())
for i := 0; i < destValue.NumField(); i++ {
fields[i] = destValue.Field(i).Addr().Interface()
}
return fields
}