98 lines
3.3 KiB
JavaScript
98 lines
3.3 KiB
JavaScript
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,
|
|
}
|