store: activities UNIQUE constraint rebuild for per-user design
Migration 0026 rebuilds the activities table to enforce UNIQUE(user_id, garmin_activity_id) as the composite primary constraint, removing the old global UNIQUE(garmin_activity_id) constraint from migration 0001. This allows the same Garmin activity ID to appear for different users without conflicts, which is essential for the per-user profile design and enables the TestUpsertActivity_SameGarminActivityIDAllowedAcrossDifferentUsers test to pass.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
-- activities.garmin_activity_id's UNIQUE constraint (migration 0001) must become
|
||||
-- per-user (UNIQUE(user_id, garmin_activity_id)) now that the per-user-profile
|
||||
-- design allows multiple users to share the same Garmin activity ID. The old
|
||||
-- constraint alone was intentionally left in place by migration 0022 as a
|
||||
-- belts-and-suspenders safeguard (Garmin IDs are globally unique in practice),
|
||||
-- but it must be removed now to allow Task 6's cross-user test to pass.
|
||||
PRAGMA foreign_keys = OFF;
|
||||
|
||||
CREATE TABLE activities_new (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER REFERENCES users(id),
|
||||
garmin_activity_id INTEGER NOT NULL,
|
||||
event_type_key TEXT NOT NULL,
|
||||
workout_id INTEGER,
|
||||
start_time_utc TEXT NOT NULL,
|
||||
duration_seconds REAL NOT NULL,
|
||||
distance_meters REAL NOT NULL,
|
||||
avg_hr REAL,
|
||||
max_hr REAL,
|
||||
avg_speed_mps REAL,
|
||||
elevation_gain_m REAL,
|
||||
aerobic_training_effect REAL,
|
||||
anaerobic_training_effect REAL,
|
||||
vo2max_value REAL,
|
||||
raw_json TEXT NOT NULL,
|
||||
details_fetched_at TEXT,
|
||||
details_raw_json TEXT,
|
||||
splits_fetched_at TEXT,
|
||||
workout_raw_json TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE(user_id, garmin_activity_id)
|
||||
);
|
||||
|
||||
INSERT INTO activities_new (id, user_id, garmin_activity_id, event_type_key, workout_id, start_time_utc, duration_seconds, distance_meters, avg_hr, max_hr, avg_speed_mps, elevation_gain_m, aerobic_training_effect, anaerobic_training_effect, vo2max_value, raw_json, details_fetched_at, details_raw_json, splits_fetched_at, workout_raw_json, created_at, updated_at)
|
||||
SELECT id, user_id, garmin_activity_id, event_type_key, workout_id, start_time_utc, duration_seconds, distance_meters, avg_hr, max_hr, avg_speed_mps, elevation_gain_m, aerobic_training_effect, anaerobic_training_effect, vo2max_value, raw_json, details_fetched_at, details_raw_json, splits_fetched_at, workout_raw_json, created_at, updated_at
|
||||
FROM activities;
|
||||
|
||||
DROP TABLE activities;
|
||||
|
||||
ALTER TABLE activities_new RENAME TO activities;
|
||||
|
||||
CREATE INDEX idx_activities_start_time ON activities(start_time_utc);
|
||||
CREATE INDEX idx_activities_user_garmin_id ON activities(user_id, garmin_activity_id);
|
||||
|
||||
PRAGMA foreign_keys = ON;
|
||||
Reference in New Issue
Block a user