store: scope kind assignments, laps, and samples via activity ownership
None of these three tables gained their own user_id column -- they're always accessed through a specific activity, so ownership is checked via a join/subquery against activities.user_id instead.
This commit is contained in:
@@ -2,6 +2,7 @@ package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@@ -15,9 +16,19 @@ type Sample struct {
|
||||
ElevationM *float64
|
||||
}
|
||||
|
||||
// ReplaceActivitySamples deletes any existing samples for activityID and
|
||||
// bulk-inserts the given set, so re-syncing an activity's details is idempotent.
|
||||
func (db *DB) ReplaceActivitySamples(ctx context.Context, activityID int64, samples []Sample) error {
|
||||
// ReplaceActivitySamples deletes any existing samples for activityID (owned
|
||||
// by userID) and bulk-inserts the given set, so re-syncing an activity's
|
||||
// details is idempotent.
|
||||
func (db *DB) ReplaceActivitySamples(ctx context.Context, userID, activityID int64, samples []Sample) error {
|
||||
var exists int
|
||||
err := db.QueryRowContext(ctx, `SELECT 1 FROM activities WHERE id = ? AND user_id = ?`, activityID, userID).Scan(&exists)
|
||||
if err == sql.ErrNoRows {
|
||||
return fmt.Errorf("replace activity samples: activity %d not found for user %d", activityID, userID)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("replace activity samples for activity %d (user %d): %w", activityID, userID, err)
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin replace samples tx: %w", err)
|
||||
@@ -44,13 +55,18 @@ func (db *DB) ReplaceActivitySamples(ctx context.Context, activityID int64, samp
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// SamplesForActivity returns all samples for an activity, ordered by elapsed_seconds.
|
||||
func (db *DB) SamplesForActivity(ctx context.Context, activityID int64) ([]Sample, error) {
|
||||
// SamplesForActivity returns all samples for an activity owned by userID,
|
||||
// ordered by elapsed_seconds.
|
||||
func (db *DB) SamplesForActivity(ctx context.Context, userID, activityID int64) ([]Sample, error) {
|
||||
rows, err := db.QueryContext(ctx, `
|
||||
SELECT elapsed_seconds, timestamp_ms, heart_rate, speed_mps, distance_m, elevation_m
|
||||
FROM activity_samples WHERE activity_id = ? ORDER BY elapsed_seconds`, activityID)
|
||||
SELECT activity_samples.elapsed_seconds, activity_samples.timestamp_ms, activity_samples.heart_rate,
|
||||
activity_samples.speed_mps, activity_samples.distance_m, activity_samples.elevation_m
|
||||
FROM activity_samples
|
||||
JOIN activities ON activities.id = activity_samples.activity_id
|
||||
WHERE activity_samples.activity_id = ? AND activities.user_id = ?
|
||||
ORDER BY activity_samples.elapsed_seconds`, activityID, userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("samples for activity %d: %w", activityID, err)
|
||||
return nil, fmt.Errorf("samples for activity %d (user %d): %w", activityID, userID, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user