const { query } = require('../../utils/db') const COLS = 'id, post_id, status, ' + 'towncrier_status, towncrier_attempts, towncrier_last_error, towncrier_next_attempt_at, ' + 'discord_status, discord_attempts, discord_last_error, discord_next_attempt_at, ' + 'created_at, updated_at' // Whitelist so a `leg` value can be interpolated into a column name safely — it // never comes from raw user input, but keep the guard explicit. const LEGS = ['towncrier', 'discord'] function assertLeg(leg) { if (!LEGS.includes(leg)) throw new Error(`unknown announce leg: ${leg}`) } async function create(postId) { const res = await query('INSERT INTO announce_jobs (post_id) VALUES (?)', [postId]) return res.insertId } async function findById(id) { const rows = await query(`SELECT ${COLS} FROM announce_jobs WHERE id = ? LIMIT 1`, [id]) return rows[0] || null } async function findByPostId(postId) { const rows = await query( `SELECT ${COLS} FROM announce_jobs WHERE post_id = ? ORDER BY id DESC LIMIT 1`, [postId], ) return rows[0] || null } // Jobs with at least one leg that is due now: pending and either never scheduled // (next_attempt_at IS NULL — a fresh enqueue) or past its backoff time. async function findDue(now = new Date(), limit = 25) { return query( `SELECT ${COLS} FROM announce_jobs WHERE (towncrier_status = 'pending' AND (towncrier_next_attempt_at IS NULL OR towncrier_next_attempt_at <= ?)) OR (discord_status = 'pending' AND (discord_next_attempt_at IS NULL OR discord_next_attempt_at <= ?)) ORDER BY id ASC LIMIT ?`, [now, now, limit], ) } // Update one leg's columns. `fields` uses leg-agnostic keys (status, attempts, // lastError, nextAttemptAt); we map them onto the leg-prefixed columns. async function updateLeg(id, leg, { status, attempts, lastError, nextAttemptAt }) { assertLeg(leg) await query( `UPDATE announce_jobs SET ${leg}_status = ?, ${leg}_attempts = ?, ${leg}_last_error = ?, ${leg}_next_attempt_at = ? WHERE id = ?`, [status, attempts, lastError ?? null, nextAttemptAt ?? null, id], ) } async function setStatus(id, status) { await query('UPDATE announce_jobs SET status = ? WHERE id = ?', [status, id]) } module.exports = { LEGS, create, findById, findByPostId, findDue, updateLeg, setStatus }