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 }