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 }