package repositories import ( "context" "database/sql" "errors" "thamanyah/discovery/internal/models" "github.com/lib/pq" ) type VideoRepository struct { SQLDB *sql.DB } var VideoRepo VideoRepository // SaveVideo records an announced video, replacing what the catalogue already // held for that id. // // The upsert is what makes the consumer safe to retry: the catalogue topic // delivers at-least-once, so the same announcement can arrive twice, and a // plain INSERT would fail the second time on the primary key. Re-announcing a // video is also how it is corrected — a later announcement wins, which is why // every column is overwritten rather than merged. func (svc VideoRepository) SaveVideo(ctx context.Context, v models.Video) error { _, err := svc.SQLDB.ExecContext(ctx, ` INSERT INTO videos (id, title, playback_url, categories) VALUES ($1, $2, $3, $4) ON CONFLICT (id) DO UPDATE SET title = EXCLUDED.title, playback_url = EXCLUDED.playback_url, categories = EXCLUDED.categories, updated_at = now() `, v.ID, v.Title, v.PlaybackURL, pq.Array(v.Categories)) return err } // GetVideoByID reads the catalogue's copy of one video. It returns // ErrVideoNotFound when the catalogue has not heard about it — which, for a // video cms has only just made ready, is a matter of timing rather than a // mistake. func (svc VideoRepository) GetVideoByID(ctx context.Context, id string) (models.Video, error) { var v models.Video err := svc.SQLDB.QueryRowContext(ctx, ` SELECT id, title, playback_url, categories, created_at, updated_at FROM videos WHERE id = $1 `, id).Scan(&v.ID, &v.Title, &v.PlaybackURL, pq.Array(&v.Categories), &v.CreatedAt, &v.UpdatedAt) if errors.Is(err, sql.ErrNoRows) { return models.Video{}, ErrVideoNotFound } if err != nil { return models.Video{}, err } return v, nil }