104 lines
2.9 KiB
JavaScript
104 lines
2.9 KiB
JavaScript
const prisma = require("./client")
|
|
|
|
function normalizeIds(ids = []) {
|
|
return Array.from(
|
|
new Set(
|
|
(Array.isArray(ids) ? ids : [])
|
|
.map((id) => Number(id))
|
|
.filter((id) => Number.isInteger(id) && id > 0)
|
|
)
|
|
)
|
|
}
|
|
|
|
async function ensureTotalsForDealIds(dealIds = []) {
|
|
const ids = normalizeIds(dealIds)
|
|
if (!ids.length) return 0
|
|
const existing = await prisma.deal.findMany({
|
|
where: { id: { in: ids } },
|
|
select: { id: true },
|
|
})
|
|
const existingIds = new Set(existing.map((d) => d.id))
|
|
if (!existingIds.size) return 0
|
|
const data = ids.filter((id) => existingIds.has(id)).map((dealId) => ({ dealId }))
|
|
const result = await prisma.dealAnalyticsTotal.createMany({
|
|
data,
|
|
skipDuplicates: true,
|
|
})
|
|
return result?.count ?? 0
|
|
}
|
|
|
|
async function getTotalsByDealIds(dealIds = []) {
|
|
const ids = normalizeIds(dealIds)
|
|
if (!ids.length) return []
|
|
return prisma.dealAnalyticsTotal.findMany({
|
|
where: { dealId: { in: ids } },
|
|
select: {
|
|
dealId: true,
|
|
impressions: true,
|
|
views: true,
|
|
clicks: true,
|
|
},
|
|
})
|
|
}
|
|
|
|
function aggregateEventIncrements(events = []) {
|
|
const byDeal = new Map()
|
|
for (const event of events) {
|
|
const dealId = Number(event.dealId)
|
|
if (!Number.isInteger(dealId) || dealId <= 0) continue
|
|
const type = String(event.type || "").toUpperCase()
|
|
const entry = byDeal.get(dealId) || { dealId, impressions: 0, views: 0, clicks: 0 }
|
|
if (type === "IMPRESSION") entry.impressions += 1
|
|
else if (type === "VIEW") entry.views += 1
|
|
else if (type === "CLICK") entry.clicks += 1
|
|
byDeal.set(dealId, entry)
|
|
}
|
|
return Array.from(byDeal.values())
|
|
}
|
|
|
|
async function applyDealEventBatch(events = []) {
|
|
const filtered = (Array.isArray(events) ? events : []).filter(
|
|
(e) => e && e.dealId && (e.userId || e.ip)
|
|
)
|
|
if (!filtered.length) return { inserted: 0, increments: [] }
|
|
|
|
const data = filtered.map((event) => ({
|
|
dealId: Number(event.dealId),
|
|
type: String(event.type || "IMPRESSION").toUpperCase(),
|
|
userId: event.userId ? Number(event.userId) : null,
|
|
ip: event.ip ? String(event.ip) : null,
|
|
createdAt: event.createdAt ? new Date(event.createdAt) : new Date(),
|
|
}))
|
|
|
|
const increments = aggregateEventIncrements(data)
|
|
|
|
await prisma.$transaction(async (tx) => {
|
|
await tx.dealEvent.createMany({ data })
|
|
|
|
for (const inc of increments) {
|
|
await tx.dealAnalyticsTotal.upsert({
|
|
where: { dealId: inc.dealId },
|
|
create: {
|
|
dealId: inc.dealId,
|
|
impressions: inc.impressions,
|
|
views: inc.views,
|
|
clicks: inc.clicks,
|
|
},
|
|
update: {
|
|
impressions: { increment: inc.impressions },
|
|
views: { increment: inc.views },
|
|
clicks: { increment: inc.clicks },
|
|
},
|
|
})
|
|
}
|
|
})
|
|
|
|
return { inserted: data.length, increments }
|
|
}
|
|
|
|
module.exports = {
|
|
ensureTotalsForDealIds,
|
|
getTotalsByDealIds,
|
|
applyDealEventBatch,
|
|
}
|