Implement the Repository Pattern by defining an interface for data operations and a concrete struct that uses database/sql to execute queries.
// Define the interface
//go:generate mockgen -source=repository.go -destination=mock_repository.go -package=mocks
type UserRepository interface {
GetByID(ctx context.Context, id int) (*User, error)
Save(ctx context.Context, user *User) error
}
// Define the concrete implementation
type userRepository struct {
db *sql.DB
}
func NewUserRepository(db *sql.DB) UserRepository {
return &userRepository{db: db}
}
func (r *userRepository) GetByID(ctx context.Context, id int) (*User, error) {
var user User
err := r.db.QueryRowContext(ctx, "SELECT id, name, email FROM users WHERE id = $1", id).
Scan(&user.ID, &user.Name, &user.Email)
if err == sql.ErrNoRows {
return nil, nil
}
return &user, err
}
func (r *userRepository) Save(ctx context.Context, user *User) error {
_, err := r.db.ExecContext(ctx, "INSERT INTO users (name, email) VALUES ($1, $2)", user.Name, user.Email)
return err
}