Files
go-garth/internal/stats/base.go
sstent 2fdfbea34e feat(refactor): Implement 1A.1 Package Structure Refactoring
This commit implements the package structure refactoring as outlined in phase1.md (Task 1A.1).

Key changes include:
- Reorganized packages into `pkg/garmin` for public API and `internal/` for internal implementations.
- Updated all import paths to reflect the new structure.
- Consolidated types and client logic into their respective new packages.
- Updated `cmd/garth/main.go` to use the new public API.
- Fixed various compilation and test issues encountered during the refactoring process.
- Converted `internal/api/client/auth_test.go` to a functional test.

This establishes a solid foundation for future enhancements and improves maintainability.
2025-09-18 13:13:39 -07:00

102 lines
2.3 KiB
Go

package stats
import (
"encoding/json"
"fmt"
"strings"
"time"
"garmin-connect/internal/api/client"
"garmin-connect/internal/utils"
)
type Stats interface {
List(end time.Time, period int, client *client.Client) ([]interface{}, error)
}
type BaseStats struct {
Path string
PageSize int
}
func (b *BaseStats) List(end time.Time, period int, client *client.Client) ([]interface{}, error) {
endDate := utils.FormatEndDate(end)
var allData []interface{}
var errs []error
for period > 0 {
pageSize := b.PageSize
if period < pageSize {
pageSize = period
}
page, err := b.fetchPage(endDate, pageSize, client)
if err != nil {
errs = append(errs, err)
// Continue to next page even if current fails
} else {
allData = append(page, allData...)
}
// Move to previous page
endDate = endDate.AddDate(0, 0, -pageSize)
period -= pageSize
}
// Return partial data with aggregated errors
var finalErr error
if len(errs) > 0 {
finalErr = fmt.Errorf("partial failure: %v", errs)
}
return allData, finalErr
}
func (b *BaseStats) fetchPage(end time.Time, period int, client *client.Client) ([]interface{}, error) {
var start time.Time
var path string
if strings.Contains(b.Path, "daily") {
start = end.AddDate(0, 0, -(period - 1))
path = strings.Replace(b.Path, "{start}", start.Format("2006-01-02"), 1)
path = strings.Replace(path, "{end}", end.Format("2006-01-02"), 1)
} else {
path = strings.Replace(b.Path, "{end}", end.Format("2006-01-02"), 1)
path = strings.Replace(path, "{period}", fmt.Sprintf("%d", period), 1)
}
data, err := client.ConnectAPI(path, "GET", nil, nil)
if err != nil {
return nil, err
}
if len(data) == 0 {
return []interface{}{}, nil
}
var responseSlice []map[string]interface{}
if err := json.Unmarshal(data, &responseSlice); err != nil {
return nil, err
}
if len(responseSlice) == 0 {
return []interface{}{}, nil
}
var results []interface{}
for _, itemMap := range responseSlice {
// Handle nested "values" structure
if values, exists := itemMap["values"]; exists {
valuesMap := values.(map[string]interface{})
for k, v := range valuesMap {
itemMap[k] = v
}
delete(itemMap, "values")
}
snakeItem := utils.CamelToSnakeDict(itemMap)
results = append(results, snakeItem)
}
return results, nil
}