veza/veza-backend-api/cmd/tools/seed/seed_playlists.go
senke 2eff5a9b10 refactor(backend): split seed tool into domain-specific modules
Extract monolithic seed main.go into separate files per domain:
users, tracks, playlists, chat, analytics, marketplace, social,
content, live, moderation, notifications, and misc. Add config,
fake data helpers, and utility modules. Update Makefile targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 23:35:07 +01:00

133 lines
4.2 KiB
Go

package main
import (
"database/sql"
"fmt"
"time"
)
// SeededPlaylist holds playlist data.
type SeededPlaylist struct {
ID string
UserID string
Name string
}
// SeedPlaylists creates playlists and populates playlist_tracks, playlist_follows.
func SeedPlaylists(db *sql.DB, cfg Config, users []SeededUser, tracks []SeededTrack) ([]SeededPlaylist, error) {
fmt.Println("\n═══ PLAYLISTS ═══")
allUsers := users
playlists := make([]SeededPlaylist, 0, cfg.Playlists)
// ── 1. Create playlists ──────────────────────────────────────────────────
p := NewProgress("playlists", cfg.Playlists)
playlistRows := make([][]interface{}, 0, cfg.Playlists)
for i := 0; i < cfg.Playlists; i++ {
id := newUUID()
user := allUsers[rng.Intn(len(allUsers))]
name := GenPlaylistName(i)
desc := fmt.Sprintf("Curated by %s", user.DisplayName)
createdAt := RandomTimeAfter(user.CreatedAt)
visibility := "public"
isPublic := true
if randChance(15) {
visibility = "private"
isPublic = false
}
isCollab := randChance(10)
pl := SeededPlaylist{ID: id, UserID: user.ID, Name: name}
playlists = append(playlists, pl)
playlistRows = append(playlistRows, []interface{}{
id, user.ID, name, desc, nil, // cover_url
visibility, isCollab, 0, 0, 0, // track_count, duration_seconds, follower_count
name, isPublic,
createdAt, createdAt, nil,
})
}
_, err := BulkInsert(db, "playlists",
"id, user_id, name, description, cover_url, visibility, is_collaborative, track_count, duration_seconds, follower_count, title, is_public, created_at, updated_at, deleted_at",
playlistRows)
if err != nil {
return nil, fmt.Errorf("insert playlists: %w", err)
}
p.Update(cfg.Playlists)
p.Done()
// ── 2. Populate playlist_tracks ──────────────────────────────────────────
if len(tracks) == 0 {
return playlists, nil
}
p = NewProgress("playlist_tracks", cfg.Playlists)
ptRows := make([][]interface{}, 0, cfg.Playlists*15)
seen := make(map[string]bool) // prevent duplicate (playlist_id, track_id)
for _, pl := range playlists {
trackCount := randInt(cfg.PlaylistMinTracks, cfg.PlaylistMaxTracks)
if trackCount > len(tracks) {
trackCount = len(tracks)
}
selectedTracks := pickN(tracks, trackCount)
for pos, t := range selectedTracks {
key := pl.ID + ":" + t.ID
if seen[key] {
continue
}
seen[key] = true
ptRows = append(ptRows, []interface{}{
newUUID(), pl.ID, t.ID, pos, pl.UserID, time.Now(),
})
}
}
_, err = BulkInsert(db, "playlist_tracks",
"id, playlist_id, track_id, position, added_by, added_at",
ptRows)
if err != nil {
return nil, fmt.Errorf("insert playlist_tracks: %w", err)
}
p.Update(len(ptRows))
p.Done()
// ── 3. Update track_count on playlists ───────────────────────────────────
_, _ = db.Exec("UPDATE playlists SET track_count = (SELECT COUNT(*) FROM playlist_tracks WHERE playlist_tracks.playlist_id = playlists.id)")
// ── 4. Playlist follows ──────────────────────────────────────────────────
followCount := len(playlists) * 3 // ~3 follows per playlist on average
p = NewProgress("playlist_follows", followCount)
pfRows := make([][]interface{}, 0, followCount)
pfSeen := make(map[string]bool)
for i := 0; i < followCount; i++ {
pl := playlists[rng.Intn(len(playlists))]
user := allUsers[rng.Intn(len(allUsers))]
if user.ID == pl.UserID {
continue // Don't follow own playlist
}
key := pl.ID + ":" + user.ID
if pfSeen[key] {
continue
}
pfSeen[key] = true
pfRows = append(pfRows, []interface{}{
newUUID(), pl.ID, user.ID, time.Now(), time.Now(), nil,
})
}
_, err = BulkInsert(db, "playlist_follows",
"id, playlist_id, user_id, created_at, updated_at, deleted_at",
pfRows)
if err != nil {
return nil, fmt.Errorf("insert playlist_follows: %w", err)
}
p.Update(len(pfRows))
p.Done()
return playlists, nil
}