Skip to content

Commit c6b7343

Browse files
Jing-yilinclaude
andcommitted
fix: execute deduplication SQL independently to guarantee execution
Previous fix still had the deduplication inside the IF EXISTS (table) block. If table exists, the deduplication would run, but it was still part of a DO block which could fail silently. Split into TWO separate Exec calls: 1. DO block for column additions (snapshot_date, backers_count) 2. Standalone DELETE for deduplication (runs EVERY time) Also moved SET NOT NULL inside the IF NOT EXISTS block where it belongs (only needed when first adding the column). This ensures deduplication always runs before AutoMigrate creates the unique index, regardless of database state. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 9f08cf2 commit c6b7343

1 file changed

Lines changed: 14 additions & 11 deletions

File tree

backend/internal/db/db.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ func Init(cfg *config.Config) error {
160160
) THEN
161161
ALTER TABLE campaign_snapshots ADD COLUMN snapshot_date date;
162162
UPDATE campaign_snapshots SET snapshot_date = DATE(snapshot_at);
163+
ALTER TABLE campaign_snapshots ALTER COLUMN snapshot_date SET NOT NULL;
163164
END IF;
164165
165166
-- Add backers_count if missing (added alongside snapshot_date).
@@ -169,21 +170,23 @@ func Init(cfg *config.Config) error {
169170
) THEN
170171
ALTER TABLE campaign_snapshots ADD COLUMN backers_count int DEFAULT 0;
171172
END IF;
172-
173-
-- Set NOT NULL now that all rows have a value.
174-
ALTER TABLE campaign_snapshots ALTER COLUMN snapshot_date SET NOT NULL;
175173
END IF;
176-
177-
-- Deduplicate: keep only the latest snapshot per (campaign_pid, snapshot_date).
178-
-- Run this EVERY time (not just when column is missing) to handle legacy duplicate data.
179-
DELETE FROM campaign_snapshots a USING campaign_snapshots b
180-
WHERE a.campaign_pid = b.campaign_pid
181-
AND a.snapshot_date = b.snapshot_date
182-
AND a.snapshot_at < b.snapshot_at;
183174
END
184175
$$;
185176
`).Error; err != nil {
186-
return fmt.Errorf("pre-migrate campaign_snapshots: %w", err)
177+
return fmt.Errorf("pre-migrate campaign_snapshots columns: %w", err)
178+
}
179+
180+
// Deduplicate snapshots: keep only the latest per (campaign_pid, snapshot_date).
181+
// Run this EVERY time to handle legacy duplicate data from buggy upsert logic.
182+
// Must run BEFORE AutoMigrate attempts to create the unique index.
183+
if err := DB.Exec(`
184+
DELETE FROM campaign_snapshots a USING campaign_snapshots b
185+
WHERE a.campaign_pid = b.campaign_pid
186+
AND a.snapshot_date = b.snapshot_date
187+
AND a.snapshot_at < b.snapshot_at
188+
`).Error; err != nil {
189+
return fmt.Errorf("deduplicate campaign_snapshots: %w", err)
187190
}
188191

189192
// NOW run AutoMigrate after all column renames are complete

0 commit comments

Comments
 (0)