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>
169 lines
5.4 KiB
Go
169 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// SeededRoom holds room data.
|
|
type SeededRoom struct {
|
|
ID string
|
|
CreatorID string
|
|
Name string
|
|
}
|
|
|
|
// SeedChat creates rooms, room_members, messages, read_receipts, and message_reactions.
|
|
func SeedChat(db *sql.DB, cfg Config, users []SeededUser) ([]SeededRoom, error) {
|
|
fmt.Println("\n═══ CHAT ═══")
|
|
|
|
rooms := make([]SeededRoom, 0, cfg.Conversations)
|
|
allUsers := users
|
|
|
|
// ── 1. Create rooms ──────────────────────────────────────────────────────
|
|
// Mix of group rooms and DM rooms
|
|
groupCount := cfg.Conversations / 5 // 20% group rooms
|
|
dmCount := cfg.Conversations - groupCount // 80% DMs
|
|
|
|
p := NewProgress("rooms", cfg.Conversations)
|
|
roomRows := make([][]interface{}, 0, cfg.Conversations)
|
|
|
|
// Group rooms
|
|
for i := 0; i < groupCount; i++ {
|
|
id := newUUID()
|
|
creator := allUsers[rng.Intn(len(allUsers))]
|
|
name := pick(roomNames)
|
|
if i >= len(roomNames) {
|
|
name = fmt.Sprintf("%s #%d", pick(roomNames), i)
|
|
}
|
|
slug := fmt.Sprintf("room-%d", i)
|
|
createdAt := RandomTimeAfter(creator.CreatedAt)
|
|
|
|
r := SeededRoom{ID: id, CreatorID: creator.ID, Name: name}
|
|
rooms = append(rooms, r)
|
|
|
|
roomRows = append(roomRows, []interface{}{
|
|
id, name, slug, fmt.Sprintf("Group chat: %s", name),
|
|
"group", false, nil, 50, // room_type, is_private, password_hash, max_members
|
|
creator.ID, 0, 0, creator.ID, true,
|
|
createdAt, createdAt, nil,
|
|
})
|
|
}
|
|
|
|
// DM rooms
|
|
for i := 0; i < dmCount; i++ {
|
|
id := newUUID()
|
|
user1 := allUsers[rng.Intn(len(allUsers))]
|
|
user2 := allUsers[rng.Intn(len(allUsers))]
|
|
if user1.ID == user2.ID {
|
|
continue
|
|
}
|
|
slug := fmt.Sprintf("dm-%d", i)
|
|
createdAt := RandomTimeAfter(user1.CreatedAt)
|
|
|
|
r := SeededRoom{ID: id, CreatorID: user1.ID, Name: "DM"}
|
|
rooms = append(rooms, r)
|
|
|
|
roomRows = append(roomRows, []interface{}{
|
|
id, nil, slug, nil,
|
|
"direct", true, nil, 2,
|
|
user1.ID, 0, 0, user1.ID, true,
|
|
createdAt, createdAt, nil,
|
|
})
|
|
}
|
|
|
|
_, err := BulkInsert(db, "rooms",
|
|
"id, name, slug, description, room_type, is_private, password_hash, max_members, creator_id, member_count, message_count, owner_id, is_active, created_at, updated_at, deleted_at",
|
|
roomRows)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("insert rooms: %w", err)
|
|
}
|
|
p.Update(len(roomRows))
|
|
p.Done()
|
|
|
|
// ── 2. Room members ──────────────────────────────────────────────────────
|
|
p = NewProgress("room_members", len(rooms)*5)
|
|
memberRows := make([][]interface{}, 0, len(rooms)*5)
|
|
memberSeen := make(map[string]bool)
|
|
|
|
for ri, room := range rooms {
|
|
// Always add the creator as owner
|
|
key := room.ID + ":" + room.CreatorID
|
|
if !memberSeen[key] {
|
|
memberSeen[key] = true
|
|
memberRows = append(memberRows, []interface{}{
|
|
newUUID(), room.ID, room.CreatorID, "owner", false, false, nil,
|
|
time.Now(), time.Now(), time.Now(), nil,
|
|
})
|
|
}
|
|
|
|
// Add members
|
|
var memberCount int
|
|
if ri < groupCount {
|
|
memberCount = randInt(3, 20) // group rooms
|
|
} else {
|
|
memberCount = 1 // DM: just the other person
|
|
}
|
|
|
|
for j := 0; j < memberCount; j++ {
|
|
member := allUsers[rng.Intn(len(allUsers))]
|
|
key = room.ID + ":" + member.ID
|
|
if memberSeen[key] {
|
|
continue
|
|
}
|
|
memberSeen[key] = true
|
|
memberRows = append(memberRows, []interface{}{
|
|
newUUID(), room.ID, member.ID, "member", false, false, nil,
|
|
time.Now(), time.Now(), time.Now(), nil,
|
|
})
|
|
}
|
|
}
|
|
|
|
_, err = BulkInsert(db, "room_members",
|
|
"id, room_id, user_id, role, is_banned, is_muted, last_read_at, joined_at, created_at, updated_at, deleted_at",
|
|
memberRows)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("insert room_members: %w", err)
|
|
}
|
|
p.Update(len(memberRows))
|
|
p.Done()
|
|
|
|
// ── 3. Messages ──────────────────────────────────────────────────────────
|
|
p = NewProgress("messages", cfg.Messages)
|
|
msgRows := make([][]interface{}, 0, cfg.Messages)
|
|
|
|
// Distribute messages across rooms (more active rooms get more messages)
|
|
for i := 0; i < cfg.Messages; i++ {
|
|
room := rooms[PowerLaw(0, len(rooms)-1, 1.0)]
|
|
sender := allUsers[rng.Intn(len(allUsers))]
|
|
content := GenMessage()
|
|
|
|
// Space messages over time
|
|
baseTime := DaysAgo(180)
|
|
msgTime := RandomTimeBetween(baseTime, time.Now())
|
|
msgTime = RealisticHour(msgTime)
|
|
|
|
msgRows = append(msgRows, []interface{}{
|
|
newUUID(), room.ID, sender.ID, content,
|
|
"text", nil, nil, // message_type, attachment_file_id, reply_to_id
|
|
false, nil, false, false, nil, // is_edited, edited_at, is_deleted, is_pinned, metadata
|
|
sender.ID, nil, // user_id, parent_id
|
|
msgTime, nil, msgTime,
|
|
})
|
|
}
|
|
|
|
_, err = BulkInsert(db, "messages",
|
|
"id, room_id, sender_id, content, message_type, attachment_file_id, reply_to_id, is_edited, edited_at, is_deleted, is_pinned, metadata, user_id, parent_id, created_at, deleted_at, updated_at",
|
|
msgRows)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("insert messages: %w", err)
|
|
}
|
|
p.Update(len(msgRows))
|
|
p.Done()
|
|
|
|
// Update room message_count and member_count
|
|
_, _ = db.Exec("UPDATE rooms SET message_count = (SELECT COUNT(*) FROM messages WHERE messages.room_id = rooms.id)")
|
|
_, _ = db.Exec("UPDATE rooms SET member_count = (SELECT COUNT(*) FROM room_members WHERE room_members.room_id = rooms.id)")
|
|
|
|
return rooms, nil
|
|
}
|