feat: add SQL console endpoint for local MariaDB queries
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
generateServerConfig,
|
||||
seedDatabase,
|
||||
} from "../services/server.service.js";
|
||||
import { getDockerClient } from "../services/docker.service.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -67,4 +68,73 @@ router.post("/seed-db", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/sql", async (req, res) => {
|
||||
const { query, allowWrite } = req.body;
|
||||
if (!query) return res.status(400).json({ error: "query required" });
|
||||
|
||||
const upperQuery = query.trim().toUpperCase();
|
||||
if (
|
||||
!allowWrite &&
|
||||
(upperQuery.startsWith("DROP") ||
|
||||
upperQuery.startsWith("TRUNCATE") ||
|
||||
upperQuery.startsWith("ALTER"))
|
||||
) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Destructive query blocked. Set allowWrite: true to override." });
|
||||
}
|
||||
|
||||
try {
|
||||
const docker = getDockerClient();
|
||||
const container = docker.getContainer("layonara-mariadb");
|
||||
|
||||
const exec = await container.exec({
|
||||
Cmd: [
|
||||
"mysql",
|
||||
"-u",
|
||||
"nwn",
|
||||
`-p${process.env.MYSQL_PASSWORD || "forge"}`,
|
||||
"nwn",
|
||||
"-e",
|
||||
query,
|
||||
],
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
});
|
||||
|
||||
const stream = await exec.start({});
|
||||
let output = "";
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
stream.on("data", (chunk: Buffer) => {
|
||||
output += chunk.toString();
|
||||
});
|
||||
stream.on("end", resolve);
|
||||
});
|
||||
|
||||
const lines = output
|
||||
.trim()
|
||||
.split("\n")
|
||||
.filter((l) => l.trim());
|
||||
if (lines.length === 0) {
|
||||
res.json({ columns: [], rows: [] });
|
||||
return;
|
||||
}
|
||||
|
||||
const columns = lines[0].split("\t");
|
||||
const rows = lines.slice(1).map((line) => {
|
||||
const values = line.split("\t");
|
||||
const row: Record<string, string> = {};
|
||||
columns.forEach((col, i) => {
|
||||
row[col] = values[i] || "";
|
||||
});
|
||||
return row;
|
||||
});
|
||||
|
||||
res.json({ columns, rows });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user