// sql console — run ad-hoc queries against archive or intelligence db // depends on: app.js async function runSql() { const sql = document.getElementById("sql-input").value.trim(); if (!sql) return; const database = document.getElementById("sql-db").value; const errEl = document.getElementById("sql-error"); const resultsEl = document.getElementById("sql-results"); const elapsedEl = document.getElementById("sql-elapsed"); errEl.style.display = "none"; resultsEl.innerHTML = ""; elapsedEl.textContent = ""; try { const data = await fetch("/admin/api/sql", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sql, database }), }).then(r => r.json()); if (data.error) { errEl.textContent = data.error; errEl.style.display = ""; return; } elapsedEl.textContent = `${data.elapsed}ms`; const blocks = []; for (const r of (data.results || [])) { if (r.error) { blocks.push(`
${escapeHtml(r.sql.slice(0, 120))}${escapeHtml(r.error)}
`); } else if (r.rows && r.rows.length > 0) { const cols = Object.keys(r.rows[0]); blocks.push(`
${cols.map(c => ``).join("")}${r.rows.map(row => `${cols.map(c => ``).join("")}` ).join("")}
${escapeHtml(c)}
${row[c] == null ? 'NULL' : escapeHtml(row[c])}
${r.rows.length} row${r.rows.length !== 1 ? "s" : ""}
`); } else if (r.rows) { blocks.push(`
No rows returned.
`); } else { blocks.push(`
${r.changes} row${r.changes !== 1 ? "s" : ""} affected.
`); } } resultsEl.innerHTML = blocks.join(""); } catch (e) { errEl.textContent = e.message; errEl.style.display = ""; } } document.addEventListener("DOMContentLoaded", () => { document.getElementById("sql-run-btn").onclick = runSql; document.getElementById("sql-input").addEventListener("keydown", e => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) runSql(); }); });