fix room owner list scan columns

This commit is contained in:
zhx 2026-07-04 22:23:59 +08:00
parent e5cd2a5ce7
commit b666a5ad99
2 changed files with 134 additions and 2 deletions

View File

@ -559,6 +559,13 @@ const roomListSelectColumns = `
heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms
FROM room_list_entries` FROM room_list_entries`
// owner 定向列表复用公共列表扫描器,但不参与公共发现页置顶排序;这里补零值列保持 scan 契约稳定。
const roomListOwnerSelectColumns = `
SELECT app_code, room_id, room_short_id, visible_region_id, owner_country_code, owner_user_id, title, cover_url, mode, status, locked,
heat, online_count, seat_count, occupied_seat_count, sort_score, created_at_ms, updated_at_ms,
0 AS is_pinned, 0 AS pin_list_rank, 0 AS pin_weight, 0 AS pinned_until_ms
FROM room_list_entries`
const roomUserFeedSelectColumns = ` const roomUserFeedSelectColumns = `
SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_country_code, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked, SELECT r.app_code, r.room_id, r.room_short_id, r.visible_region_id, r.owner_country_code, r.owner_user_id, r.title, r.cover_url, r.mode, r.status, r.locked,
r.heat, r.online_count, r.seat_count, r.occupied_seat_count, r.sort_score, r.created_at_ms, f.updated_at_ms r.heat, r.online_count, r.seat_count, r.occupied_seat_count, r.sort_score, r.created_at_ms, f.updated_at_ms
@ -700,7 +707,7 @@ func buildRoomListByOwnersQuerySQL(query roomservice.RoomListQuery) (string, []a
args = append(args, query.CursorCreatedAtMS, query.CursorCreatedAtMS, query.CursorRoomID) args = append(args, query.CursorCreatedAtMS, query.CursorCreatedAtMS, query.CursorRoomID)
} }
args = append(args, query.Limit) args = append(args, query.Limit)
return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY created_at_ms DESC, room_id ASC\n\tLIMIT ?", args return roomListOwnerSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY created_at_ms DESC, room_id ASC\n\tLIMIT ?", args
} }
if query.CursorRoomID != "" { if query.CursorRoomID != "" {
@ -708,7 +715,7 @@ func buildRoomListByOwnersQuerySQL(query roomservice.RoomListQuery) (string, []a
args = append(args, query.CursorSortScore, query.CursorSortScore, query.CursorRoomID) args = append(args, query.CursorSortScore, query.CursorSortScore, query.CursorRoomID)
} }
args = append(args, query.Limit) args = append(args, query.Limit)
return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY sort_score DESC, room_id ASC\n\tLIMIT ?", args return roomListOwnerSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY sort_score DESC, room_id ASC\n\tLIMIT ?", args
} }
func normalizeRoomListSQLCountryCode(countryCode string) string { func normalizeRoomListSQLCountryCode(countryCode string) string {

View File

@ -0,0 +1,125 @@
package mysql
import (
"context"
"strings"
"testing"
"github.com/DATA-DOG/go-sqlmock"
"hyapp/pkg/appcode"
roomservice "hyapp/services/room-service/internal/room/service"
)
func TestListRoomListEntriesByOwnersScansPinPlaceholders(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock: %v", err)
}
defer db.Close()
repository := &Repository{db: db}
rows := sqlmock.NewRows([]string{
"app_code",
"room_id",
"room_short_id",
"visible_region_id",
"owner_country_code",
"owner_user_id",
"title",
"cover_url",
"mode",
"status",
"locked",
"heat",
"online_count",
"seat_count",
"occupied_seat_count",
"sort_score",
"created_at_ms",
"updated_at_ms",
"is_pinned",
"pin_list_rank",
"pin_weight",
"pinned_until_ms",
}).AddRow(
appcode.Default,
"room-agency-owner",
"10001",
int64(7101),
"US",
int64(6201),
"Agency Host",
"",
"voice",
"active",
false,
int64(0),
int64(1),
int64(8),
int64(1),
int64(99),
int64(1700000000000),
int64(1700000001000),
int64(0),
int64(0),
int64(0),
int64(0),
)
mock.ExpectQuery(`(?s)SELECT .*0 AS is_pinned.*0 AS pin_list_rank.*0 AS pin_weight.*0 AS pinned_until_ms.*FROM room_list_entries.*owner_user_id IN \(\?,\?\).*ORDER BY created_at_ms DESC, room_id ASC`).
WithArgs(appcode.Default, "active", int64(6201), int64(6202), 11).
WillReturnRows(rows)
entries, err := repository.ListRoomListEntries(context.Background(), roomservice.RoomListQuery{
AppCode: appcode.Default,
Tab: "new",
OwnerUserIDs: []int64{6201, 6202},
Limit: 11,
})
if err != nil {
t.Fatalf("owner list query should scan placeholder pin columns: %v", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("sql expectations: %v", err)
}
if len(entries) != 1 || entries[0].RoomID != "room-agency-owner" {
t.Fatalf("unexpected owner list entries: %+v", entries)
}
if entries[0].IsPinned || entries[0].PinListRank != 0 || entries[0].PinWeight != 0 || entries[0].PinnedUntilMS != 0 {
t.Fatalf("owner list pin placeholders must scan as zero values: %+v", entries[0])
}
}
func TestBuildRoomListByOwnersQuerySQLKeepsHotCursorOrdering(t *testing.T) {
sqlText, args := buildRoomListByOwnersQuerySQL(roomservice.RoomListQuery{
AppCode: appcode.Default,
Tab: "hot",
OwnerUserIDs: []int64{6201, 6202},
CursorSortScore: 900,
CursorRoomID: "room-cursor",
Limit: 21,
})
for _, fragment := range []string{
"0 AS is_pinned",
"0 AS pin_list_rank",
"0 AS pin_weight",
"0 AS pinned_until_ms",
"owner_user_id IN (?,?)",
"(sort_score < ? OR (sort_score = ? AND room_id > ?))",
"ORDER BY sort_score DESC, room_id ASC",
} {
if !strings.Contains(sqlText, fragment) {
t.Fatalf("owner hot SQL missing %q in:\n%s", fragment, sqlText)
}
}
wantArgs := []any{appcode.Default, "active", int64(6201), int64(6202), int64(900), int64(900), "room-cursor", 21}
if len(args) != len(wantArgs) {
t.Fatalf("owner hot args length mismatch: got=%v want=%v", args, wantArgs)
}
for i := range args {
if args[i] != wantArgs[i] {
t.Fatalf("owner hot args[%d] mismatch: got=%v want=%v; all=%v", i, args[i], wantArgs[i], args)
}
}
}