aboutsummaryrefslogtreecommitdiff
path: root/ride
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-27 19:07:33 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-27 19:07:33 +0200
commit4a61f3eb3103aa512bef1b0d82295403bc4bc977 (patch)
tree73eb78c50518f129d5e6aaa86153a1b4c4637bf5 /ride
parentd7b93325d4f70eeab369fa8a3c4cce9f0c4e0081 (diff)
Swap ride read path from GPX to FIT for performance
Always use FIT for detail, official climb creation and backtest; keep GPX fallback for legacy rides pending backfill. FIT is 10-20x smaller and parses without XML.
Diffstat (limited to 'ride')
-rw-r--r--ride/store.go12
-rw-r--r--ride/store_test.go12
2 files changed, 22 insertions, 2 deletions
diff --git a/ride/store.go b/ride/store.go
index f6de535..9429acf 100644
--- a/ride/store.go
+++ b/ride/store.go
@@ -56,7 +56,17 @@ func Save(db *sql.DB, r StoredRide) error {
var cotacolAlgorithmVersion any
var movingTimeS any
var movingTimeAlgorithmVersion any
- if r.GPXPath != "" {
+ if r.FitPath != "" {
+ parsed, err := ParseFile(FITRideParser{}, r.FitPath)
+ if err != nil {
+ return fmt.Errorf("compute ride values for %q: %w", r.ExternalID, err)
+ }
+ cotacolScore = climb.Cotacol(parsed.Distances, parsed.Elevations)
+ cotacolAlgorithmVersion = climb.CotacolAlgorithmVersion
+ movingTimeS = int64(MovingTime(parsed) / time.Second)
+ movingTimeAlgorithmVersion = MovingTimeAlgorithmVersion
+ } else if r.GPXPath != "" {
+ // Legacy fallback for rides created before FIT (e.g. tests).
parsed, err := ParseFile(GPXRideParser{}, r.GPXPath)
if err != nil {
return fmt.Errorf("compute ride values for %q: %w", r.ExternalID, err)
diff --git a/ride/store_test.go b/ride/store_test.go
index 1ee3c69..1fca056 100644
--- a/ride/store_test.go
+++ b/ride/store_test.go
@@ -20,11 +20,20 @@ func newTestDB(t *testing.T) *sql.DB {
func sampleRide(t *testing.T) StoredRide {
t.Helper()
- gpxPath := filepath.Join(t.TempDir(), "ride.gpx")
+ dir := t.TempDir()
+ gpxPath := filepath.Join(dir, "ride.gpx")
require.NoError(t, os.WriteFile(gpxPath, []byte(testGPX), 0o600))
+ fitPath := filepath.Join(dir, "ride.fit")
+ parsed, err := ParseFile(GPXRideParser{}, gpxPath)
+ require.NoError(t, err)
+ f, err := os.Create(fitPath)
+ require.NoError(t, err)
+ require.NoError(t, EncodeFIT(parsed, f))
+ require.NoError(t, f.Close())
return StoredRide{
ExternalID: "strava:1234",
GPXPath: gpxPath,
+ FitPath: fitPath,
Name: "Morning Ride",
Type: "Ride",
StartDate: time.Date(2026, 8, 1, 7, 30, 0, 0, time.UTC),
@@ -112,6 +121,7 @@ func TestSaveAllowsRideWithoutGPX(t *testing.T) {
indoor := sampleRide(t)
indoor.ExternalID = "strava:14701658670"
indoor.GPXPath = ""
+ indoor.FitPath = ""
require.NoError(t, Save(db, indoor))