Port Node.js CRUD to MariaDB
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* server.js — Node.js CRUD (Express + MariaDB).
|
||||
*
|
||||
* Переменные окружения:
|
||||
* DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD
|
||||
* TABLE_NAME (по умолчанию crud_items)
|
||||
* PORT (по умолчанию 3000)
|
||||
*
|
||||
* При старте: CREATE TABLE IF NOT EXISTS.
|
||||
*/
|
||||
const express = require("express");
|
||||
const mysql = require("mysql2/promise");
|
||||
const path = require("path");
|
||||
|
||||
const VERSION = "1.0.0";
|
||||
const TABLE_NAME = process.env.TABLE_NAME || "crud_items";
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(TABLE_NAME)) {
|
||||
throw new Error("TABLE_NAME must be a simple SQL identifier");
|
||||
}
|
||||
const TABLE_SQL = `\`${TABLE_NAME}\``;
|
||||
// SERVICE_NAME — какое приложение добавило строку (колонка created_by).
|
||||
// Задаётся в json_env манифеста для каждого сервиса (flask / lucee / nodejs).
|
||||
const SERVICE_NAME = process.env.SERVICE_NAME || "nodejs";
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST || "127.0.0.1",
|
||||
port: Number.parseInt(process.env.DB_PORT || "3306", 10),
|
||||
database: process.env.DB_NAME || "maria",
|
||||
user: process.env.DB_USER || "",
|
||||
password: process.env.DB_PASSWORD || "",
|
||||
waitForConnections: true,
|
||||
connectionLimit: 5,
|
||||
queueLimit: 0,
|
||||
charset: "utf8mb4",
|
||||
});
|
||||
|
||||
const app = express();
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
app.set("view engine", "ejs");
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
|
||||
// --- Инициализация БД ---
|
||||
// Таблица выставочная: кроме id/value — две метки: created_at (когда добавлено)
|
||||
// и created_by (какое приложение добавило). ALTER ... IF NOT EXISTS досыпает
|
||||
// колонки в таблицу, созданную прошлой версией приложения, не теряя данные.
|
||||
async function initDB() {
|
||||
const client = await pool.getConnection();
|
||||
try {
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS ${TABLE_SQL} (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
\`value\` TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by VARCHAR(255) NOT NULL DEFAULT ''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`);
|
||||
await client.query(
|
||||
`ALTER TABLE ${TABLE_SQL} ADD COLUMN IF NOT EXISTS created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP`
|
||||
);
|
||||
await client.query(
|
||||
`ALTER TABLE ${TABLE_SQL} ADD COLUMN IF NOT EXISTS created_by VARCHAR(255) NOT NULL DEFAULT ''`
|
||||
);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Главная страница (GET + POST) ---
|
||||
app.get("/", async (req, res) => {
|
||||
try {
|
||||
let editRow = null;
|
||||
if (req.query.edit) {
|
||||
const [editRows] = await pool.execute(
|
||||
`SELECT id, \`value\`, created_at, created_by FROM ${TABLE_SQL} WHERE id = ?`,
|
||||
[parseInt(req.query.edit)]
|
||||
);
|
||||
if (editRows.length > 0) editRow = editRows[0];
|
||||
}
|
||||
|
||||
const [rows] = await pool.execute(
|
||||
`SELECT id, \`value\`, created_at, created_by FROM ${TABLE_SQL} ORDER BY id`
|
||||
);
|
||||
|
||||
res.render("index", {
|
||||
table_name: TABLE_NAME,
|
||||
rows,
|
||||
editRow,
|
||||
version: VERSION,
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).send(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/", async (req, res) => {
|
||||
try {
|
||||
const { action, value, id } = req.body;
|
||||
|
||||
if (action === "create") {
|
||||
// created_at ставит СУБД (DEFAULT now()), created_by — имя этого сервиса
|
||||
await pool.execute(
|
||||
`INSERT INTO ${TABLE_SQL} (\`value\`, created_by) VALUES (?, ?)`,
|
||||
[value || "", SERVICE_NAME]
|
||||
);
|
||||
} else if (action === "update") {
|
||||
await pool.execute(`UPDATE ${TABLE_SQL} SET \`value\` = ? WHERE id = ?`, [
|
||||
value || "",
|
||||
parseInt(id || 0),
|
||||
]);
|
||||
} else if (action === "delete") {
|
||||
await pool.execute(`DELETE FROM ${TABLE_SQL} WHERE id = ?`, [
|
||||
parseInt(id || 0),
|
||||
]);
|
||||
}
|
||||
|
||||
res.redirect("/");
|
||||
} catch (err) {
|
||||
res.status(500).send(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
// --- Старт ---
|
||||
// Сервер стартует всегда, даже если PG недоступен.
|
||||
// initDB — асинхронно, ошибка логируется но не роняет под.
|
||||
initDB()
|
||||
.then(() => console.log("DB ready"))
|
||||
.catch((err) => console.error("DB init failed:", err.message));
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Node.js CRUD v${VERSION} — http://0.0.0.0:${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user