const { getRedisClient } = require("./client") const { ensureMinDealTtl } = require("./dealCache.service") function createRedisClient() { return getRedisClient() } const DEAL_VOTE_HASH_PREFIX = "data:deals:votes:" async function updateDealVoteInRedis({ dealId, userId, voteType, score }) { if (!dealId || !userId) return const redis = createRedisClient() try { const key = `data:deals:${dealId}` const voteKey = `${DEAL_VOTE_HASH_PREFIX}${dealId}` const raw = await redis.call("JSON.GET", key) if (!raw) return { updated: false, delta: 0, score: null } const deal = JSON.parse(raw) const currentScore = Number.isFinite(deal?.score) ? Number(deal.score) : 0 const maxNotifiedMilestone = Number.isFinite(deal?.maxNotifiedMilestone) ? Number(deal.maxNotifiedMilestone) : 0 const dealUserId = Number(deal?.userId) const rawVotes = deal?.votes ?? [] let votes = [] votes = Array.isArray(rawVotes) ? rawVotes : [] const normalizedUserId = Number(userId) const normalizedVoteType = Number(voteType) const idx = votes.findIndex((vote) => Number(vote.userId) === normalizedUserId) const oldVote = idx >= 0 ? Number(votes[idx]?.voteType ?? 0) : 0 if (idx >= 0) { votes[idx] = { userId: normalizedUserId, voteType: normalizedVoteType } } else { votes.push({ userId: normalizedUserId, voteType: normalizedVoteType }) } await redis.call("JSON.SET", key, "$.votes", JSON.stringify(votes)) const delta = normalizedVoteType - oldVote const nextScore = score !== undefined && score !== null ? Number(score) : currentScore + delta await redis.call("JSON.SET", key, "$.score", nextScore) await redis.hset(voteKey, String(normalizedUserId), String(normalizedVoteType)) const dealTtl = await redis.ttl(key) if (Number.isFinite(dealTtl) && dealTtl > 0) { await redis.expire(voteKey, dealTtl) } await ensureMinDealTtl(dealId, { minSeconds: 15 * 60 }) return { updated: true, delta, score: nextScore, maxNotifiedMilestone, dealUserId } } finally {} } async function getDealVoteFromRedis(dealId, userId) { const id = Number(dealId) const uid = Number(userId) if (!Number.isInteger(id) || !Number.isInteger(uid)) return 0 const redis = createRedisClient() try { const voteKey = `${DEAL_VOTE_HASH_PREFIX}${id}` const raw = await redis.hget(voteKey, String(uid)) const value = raw == null ? 0 : Number(raw) return Number.isFinite(value) ? value : 0 } finally {} } async function getMyVotesForDeals(dealIds = [], userId) { const uid = Number(userId) if (!Number.isInteger(uid)) return new Map() const ids = (Array.isArray(dealIds) ? dealIds : []) .map((id) => Number(id)) .filter((id) => Number.isInteger(id) && id > 0) if (!ids.length) return new Map() const redis = createRedisClient() try { const pipeline = redis.pipeline() ids.forEach((id) => { pipeline.hget(`${DEAL_VOTE_HASH_PREFIX}${id}`, String(uid)) }) const results = await pipeline.exec() const map = new Map() results.forEach(([, raw], idx) => { const value = raw == null ? 0 : Number(raw) map.set(ids[idx], Number.isFinite(value) ? value : 0) }) return map } finally {} } module.exports = { updateDealVoteInRedis, getDealVoteFromRedis, getMyVotesForDeals, }