fix(postgres): patch redbean-node for PostgreSQL dialect and bind handling, update service
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 10s
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 10s
This commit is contained in:
parent
a974249e6e
commit
fbff2e3fd9
6 changed files with 130 additions and 4 deletions
|
|
@ -48,7 +48,7 @@ jobs:
|
||||||
PORT=3002
|
PORT=3002
|
||||||
UPTIME_KUMA_PORT=3002
|
UPTIME_KUMA_PORT=3002
|
||||||
UPTIME_KUMA_DB_TYPE=postgres
|
UPTIME_KUMA_DB_TYPE=postgres
|
||||||
DB_HOST=16.113.106.152
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_USER=vignesh
|
DB_USER=vignesh
|
||||||
DB_PASSWORD=vignesh_secret_pass_2026
|
DB_PASSWORD=vignesh_secret_pass_2026
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
"lint:prod": "node --run lint:js-prod && node --run lint:style",
|
"lint:prod": "node --run lint:js-prod && node --run lint:style",
|
||||||
"dev": "concurrently -k -r \"wait-on tcp:3000 && node --run start-server-dev \" \"node --run start-frontend-dev\"",
|
"dev": "concurrently -k -r \"wait-on tcp:3000 && node --run start-server-dev \" \"node --run start-frontend-dev\"",
|
||||||
"start-frontend-dev": "cross-env NODE_ENV=development vite --host",
|
"start-frontend-dev": "cross-env NODE_ENV=development vite --host",
|
||||||
"start": "node --run start-server",
|
"start": "node --import=tsx server/server.js",
|
||||||
"start-server": "node --import=tsx server/server.js",
|
"start-server": "node --import=tsx server/server.js",
|
||||||
"start-server-dev": "cross-env NODE_ENV=development tsx server/server.js",
|
"start-server-dev": "cross-env NODE_ENV=development tsx server/server.js",
|
||||||
"start-server-dev:watch": "cross-env NODE_ENV=development tsx --watch server/server.js",
|
"start-server-dev:watch": "cross-env NODE_ENV=development tsx --watch server/server.js",
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ Environment=NODE_ENV=production
|
||||||
Environment=PORT=3002
|
Environment=PORT=3002
|
||||||
Environment=UPTIME_KUMA_PORT=3002
|
Environment=UPTIME_KUMA_PORT=3002
|
||||||
Environment=UPTIME_KUMA_DB_TYPE=postgres
|
Environment=UPTIME_KUMA_DB_TYPE=postgres
|
||||||
Environment=DB_HOST=16.113.106.152
|
Environment=DB_HOST=127.0.0.1
|
||||||
Environment=DB_PORT=5432
|
Environment=DB_PORT=5432
|
||||||
Environment=DB_USER=vignesh
|
Environment=DB_USER=vignesh
|
||||||
Environment=DB_PASSWORD=vignesh_secret_pass_2026
|
Environment=DB_PASSWORD=vignesh_secret_pass_2026
|
||||||
Environment=DB_NAME=ResourceManagement
|
Environment=DB_NAME=ResourceManagement
|
||||||
ExecStart=/usr/bin/npm start -- --port=3002
|
ExecStart=/usr/bin/node --import=tsx server/server.js --port=3002
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=10
|
RestartSec=10
|
||||||
StandardOutput=append:/home/ubuntu/resourcemanagement/logs/app.log
|
StandardOutput=append:/home/ubuntu/resourcemanagement/logs/app.log
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const fsAsync = fs.promises;
|
const fsAsync = fs.promises;
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
require("./utils/patch-redbean-postgres");
|
||||||
const { log, sleep, isDevEnv } = require("../src/util");
|
const { log, sleep, isDevEnv } = require("../src/util");
|
||||||
const knex = require("knex");
|
const knex = require("knex");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ const express = require("express");
|
||||||
const expressStaticGzip = require("express-static-gzip");
|
const expressStaticGzip = require("express-static-gzip");
|
||||||
log.debug("server", "Importing redbean-node");
|
log.debug("server", "Importing redbean-node");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
require("./utils/patch-redbean-postgres");
|
||||||
log.debug("server", "Importing http-graceful-shutdown");
|
log.debug("server", "Importing http-graceful-shutdown");
|
||||||
const gracefulShutdown = require("http-graceful-shutdown");
|
const gracefulShutdown = require("http-graceful-shutdown");
|
||||||
log.debug("server", "Importing prometheus-api-metrics");
|
log.debug("server", "Importing prometheus-api-metrics");
|
||||||
|
|
|
||||||
124
server/utils/patch-redbean-postgres.js
Normal file
124
server/utils/patch-redbean-postgres.js
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
|
||||||
|
function patchRedBeanPostgres() {
|
||||||
|
const RedBeanNode = R.constructor;
|
||||||
|
if (RedBeanNode.prototype._pgPatched) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RedBeanNode.prototype._pgPatched = true;
|
||||||
|
|
||||||
|
function cleanPgSql(sql) {
|
||||||
|
if (typeof sql === "string") {
|
||||||
|
return sql.replace(/`([^`]+)`/g, '"$1"');
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
const origNormalizeRawCore = RedBeanNode.prototype.normalizeRawCore;
|
||||||
|
RedBeanNode.prototype.normalizeRawCore = function (sql, data) {
|
||||||
|
if (this.dbType === "pg") {
|
||||||
|
sql = cleanPgSql(sql);
|
||||||
|
}
|
||||||
|
return origNormalizeRawCore.call(this, sql, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const origNormalizeRaw = RedBeanNode.prototype.normalizeRaw;
|
||||||
|
RedBeanNode.prototype.normalizeRaw = async function (sql, data) {
|
||||||
|
let result = await this.normalizeRawCore(sql, data);
|
||||||
|
this.queryLog(sql);
|
||||||
|
if (this.dbType === "mysql") {
|
||||||
|
result = result[0];
|
||||||
|
} else if (this.dbType === "pg" && result && result.rows) {
|
||||||
|
result = result.rows;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
RedBeanNode.prototype.getRow = async function (sql, data = [], autoLimit = false) {
|
||||||
|
if (autoLimit) {
|
||||||
|
if (this.dbType === "mssql") {
|
||||||
|
if (sql.trim().toLowerCase().startsWith("select ")) {
|
||||||
|
sql = sql.replace(/select/i, "$& TOP 1");
|
||||||
|
}
|
||||||
|
} else if (this.dbType === "pg") {
|
||||||
|
let limitTemplate = this.knex.limit(1).toSQL();
|
||||||
|
sql = cleanPgSql(sql) + limitTemplate.sql.replace("select *", "");
|
||||||
|
data = data.concat(limitTemplate.bindings);
|
||||||
|
} else {
|
||||||
|
let limitTemplate = this.knex.limit(1).toSQL().toNative();
|
||||||
|
sql = sql + limitTemplate.sql.replace("select *", "");
|
||||||
|
data = data.concat(limitTemplate.bindings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.queryLog(sql);
|
||||||
|
let result = await this.normalizeRaw(sql, data);
|
||||||
|
if (result && result.length > 0) {
|
||||||
|
return result[0];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const origFindCore = RedBeanNode.prototype.findCore;
|
||||||
|
RedBeanNode.prototype.findCore = function (type, clause, data = []) {
|
||||||
|
if (this.dbType === "pg") {
|
||||||
|
clause = cleanPgSql(clause);
|
||||||
|
}
|
||||||
|
return origFindCore.call(this, type, clause, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
RedBeanNode.prototype.findOne = async function (type, clause = "", data = []) {
|
||||||
|
if (this.dbType === "pg") {
|
||||||
|
clause = cleanPgSql(clause);
|
||||||
|
}
|
||||||
|
let queryPromise = this.knex.table(type).whereRaw(clause, data).first();
|
||||||
|
this.queryLog(queryPromise);
|
||||||
|
let obj;
|
||||||
|
try {
|
||||||
|
obj = await queryPromise;
|
||||||
|
} catch (error) {
|
||||||
|
this.checkAllowedError(error);
|
||||||
|
}
|
||||||
|
if (!obj) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.convertToBean(type, obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
const origCount = RedBeanNode.prototype.count;
|
||||||
|
RedBeanNode.prototype.count = async function (type, clause = "", data = [], autoLimit = true) {
|
||||||
|
if (this.dbType === "pg") {
|
||||||
|
clause = cleanPgSql(clause);
|
||||||
|
}
|
||||||
|
return origCount.call(this, type, clause, data, autoLimit);
|
||||||
|
};
|
||||||
|
|
||||||
|
const origStoreCore = RedBeanNode.prototype.storeCore;
|
||||||
|
RedBeanNode.prototype.storeCore = async function (bean, changedFieldsOnly = true) {
|
||||||
|
if (this.dbType === "pg" && !bean.id) {
|
||||||
|
this.devLog("Store PG insert", bean.beanMeta.type);
|
||||||
|
await bean.storeTypeBeanList();
|
||||||
|
if (typeof bean.onUpdate === "function") {
|
||||||
|
bean.onUpdate();
|
||||||
|
}
|
||||||
|
let obj = bean.export(false);
|
||||||
|
delete obj.id;
|
||||||
|
let queryPromise = this.knex(bean.getType()).insert(obj).returning("id");
|
||||||
|
this.queryLog(queryPromise);
|
||||||
|
let result = await queryPromise;
|
||||||
|
bean.id = result && result[0] ? (typeof result[0] === "object" ? result[0].id : result[0]) : null;
|
||||||
|
await bean.storeSharedList();
|
||||||
|
await bean.storeOwnList();
|
||||||
|
bean.beanMeta.old = {};
|
||||||
|
if (typeof bean.onAfterUpdate === "function") {
|
||||||
|
bean.onAfterUpdate();
|
||||||
|
}
|
||||||
|
return bean.id;
|
||||||
|
}
|
||||||
|
return origStoreCore.call(this, bean, changedFieldsOnly);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
patchRedBeanPostgres();
|
||||||
|
|
||||||
|
module.exports = { patchRedBeanPostgres };
|
||||||
Loading…
Reference in a new issue