fix(open-api): schedules 的缓存/Redis 分支补齐 voteCount,消除分支间字段不一致
上一步只给数据库分支补了 voteCount,但实测该接口通常命中缓存分支, 导致 voteCount 依然缺失。抽出 buildVoteCountMap() 供三条分支共用, 保证无论缓存命中与否,输出结构一致。
This commit is contained in:
@@ -21,6 +21,32 @@ import {
|
||||
type VisibilitySettingsLike
|
||||
} from '~~/server/utils/schedule-visibility'
|
||||
|
||||
/**
|
||||
* 批量统计歌曲票数。
|
||||
*
|
||||
* 该接口有缓存分支和数据库分支两条路径,此前字段互不一致
|
||||
* (序列号只在缓存分支有、票数只在数据库分支有)。统一由本函数提供票数,
|
||||
* 保证把缓存开关、Redis 开关怎么组合,输出结构都一致。
|
||||
*/
|
||||
async function buildVoteCountMap(songIds: number[]): Promise<Map<number, number>> {
|
||||
const map = new Map<number, number>()
|
||||
if (songIds.length === 0) return map
|
||||
|
||||
const rows = await db
|
||||
.select({
|
||||
songId: votes.songId,
|
||||
count: sql`count(*)`
|
||||
})
|
||||
.from(votes)
|
||||
.where(inArray(votes.songId, songIds))
|
||||
.groupBy(votes.songId)
|
||||
|
||||
rows.forEach((row) => {
|
||||
map.set(row.songId, Number(row.count))
|
||||
})
|
||||
return map
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const query = getQuery(event)
|
||||
@@ -85,6 +111,10 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
filteredSchedules = applyVisibilityFilter(filteredSchedules)
|
||||
|
||||
const voteCounts = await buildVoteCountMap(
|
||||
filteredSchedules.map((s: any) => s.song?.id).filter(Boolean)
|
||||
)
|
||||
|
||||
// 转换为开放API格式
|
||||
const result = {
|
||||
success: true,
|
||||
@@ -101,7 +131,8 @@ export default defineEventHandler(async (event) => {
|
||||
semester: schedule.song.semester,
|
||||
cover: schedule.song.cover,
|
||||
musicPlatform: schedule.song.musicPlatform,
|
||||
musicId: schedule.song.musicId
|
||||
musicId: schedule.song.musicId,
|
||||
voteCount: voteCounts.get(schedule.song.id) || 0
|
||||
},
|
||||
playTime: schedule.playTime
|
||||
? {
|
||||
@@ -141,6 +172,11 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
if (redisData) {
|
||||
const filteredRedisData = applyVisibilityFilter(redisData)
|
||||
|
||||
const voteCounts = await buildVoteCountMap(
|
||||
filteredRedisData.map((s: any) => s.song?.id).filter(Boolean)
|
||||
)
|
||||
|
||||
// 转换为开放API格式
|
||||
const result = {
|
||||
success: true,
|
||||
@@ -157,7 +193,8 @@ export default defineEventHandler(async (event) => {
|
||||
semester: schedule.song.semester,
|
||||
cover: schedule.song.cover,
|
||||
musicPlatform: schedule.song.musicPlatform,
|
||||
musicId: schedule.song.musicId
|
||||
musicId: schedule.song.musicId,
|
||||
voteCount: voteCounts.get(schedule.song.id) || 0
|
||||
},
|
||||
playTime: schedule.playTime
|
||||
? {
|
||||
@@ -322,24 +359,7 @@ export default defineEventHandler(async (event) => {
|
||||
})
|
||||
}
|
||||
|
||||
// 统计每首歌的票数。
|
||||
// 该接口的缓存分支(本文件上方)会返回 voteCount,数据库分支此前漏了,
|
||||
// 导致两条分支字段不一致,这里补齐。
|
||||
const voteCountsMap = new Map<number, number>()
|
||||
if (songIds.length > 0) {
|
||||
const voteCountsData = await db
|
||||
.select({
|
||||
songId: votes.songId,
|
||||
count: sql`count(*)`
|
||||
})
|
||||
.from(votes)
|
||||
.where(inArray(votes.songId, songIds))
|
||||
.groupBy(votes.songId)
|
||||
|
||||
voteCountsData.forEach((row) => {
|
||||
voteCountsMap.set(row.songId, Number(row.count))
|
||||
})
|
||||
}
|
||||
const voteCountsMap = await buildVoteCountMap(songIds)
|
||||
|
||||
// 格式化数据
|
||||
const formattedSchedules = schedulesData.map((schedule) => {
|
||||
|
||||
Reference in New Issue
Block a user