From 3a20e4726d9f8fe063129e00792d9f3dfe3a5649 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Mon, 28 Oct 2024 00:42:25 +0800 Subject: [PATCH] WIP --- server/database.js | 12 ++++++-- .../utils/knex/lib/dialects/mysql2/index.js | 20 +++++++++++++ .../mysql2/schema/mysql2-columncompiler.js | 30 +++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 server/utils/knex/lib/dialects/mysql2/index.js create mode 100644 server/utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler.js diff --git a/server/database.js b/server/database.js index eb459435..4ba53bb8 100644 --- a/server/database.js +++ b/server/database.js @@ -190,6 +190,14 @@ class Database { fs.writeFileSync(path.join(Database.dataDir, "db-config.json"), JSON.stringify(dbConfig, null, 4)); } + /** + * Get the MySQL2 Knex client + * @returns {KumaMySQL2} MySQL2 Knex client + */ + static getMySQL2KnexClient() { + return require("./utils/knex/lib/dialects/mysql2/index"); + } + /** * Connect to the database * @param {boolean} testMode Should the connection be started in test mode? @@ -261,7 +269,7 @@ class Database { connection.end(); config = { - client: "mysql2", + client: Database.getMySQL2KnexClient(), connection: { host: dbConfig.hostname, port: dbConfig.port, @@ -284,7 +292,7 @@ class Database { await embeddedMariaDB.start(); log.info("mariadb", "Embedded MariaDB started"); config = { - client: "mysql2", + client: Database.getMySQL2KnexClient(), connection: { socketPath: embeddedMariaDB.socketPath, user: "node", diff --git a/server/utils/knex/lib/dialects/mysql2/index.js b/server/utils/knex/lib/dialects/mysql2/index.js new file mode 100644 index 00000000..bfdc3f8b --- /dev/null +++ b/server/utils/knex/lib/dialects/mysql2/index.js @@ -0,0 +1,20 @@ +const ClientMySQL2 = require("knex/lib/dialects/mysql2/index"); +const KumaColumnCompiler = require("./schema/mysql2-columncompiler"); + +/** + * Fixed MySQL2 client class. + * - Fix: Default value for TEXT fields is not supported. + */ +class KumaMySQL2 extends ClientMySQL2 { + + driverName = "mysql2"; + + /** + * + */ + columnCompiler() { + return new KumaColumnCompiler(this, ...arguments); + } +} + +module.exports = KumaMySQL2; diff --git a/server/utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler.js b/server/utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler.js new file mode 100644 index 00000000..b1cb2e1b --- /dev/null +++ b/server/utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler.js @@ -0,0 +1,30 @@ +const ColumnCompilerMySQL = require("knex/lib/dialects/mysql/schema/mysql-columncompiler"); +const { isObject } = require("knex/lib/util/is"); + +class KumaColumnCompiler extends ColumnCompilerMySQL { + /** + * Diff: Override defaultTo method to handle default value for TEXT fields + * @param {any} value Value + * @returns {string|void} Default value (Don't understand why it can return void or string, but it's the original code, lol) + */ + defaultTo(value) { + // MySQL defaults to null by default, but breaks down if you pass it explicitly + // Note that in MySQL versions up to 5.7, logic related to updating + // timestamps when no explicit value is passed is quite insane - https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp + if (value === null || value === undefined) { + return; + } + if ((this.type === "json" || this.type === "jsonb") && isObject(value)) { + // Default value for json will work only it is an expression + return `default ('${JSON.stringify(value)}')`; + } + const defaultVal = super.defaultTo.apply(this, arguments); + + // louislam deleted: (this.type !== "blob" && this.type.indexOf("text") === -1) + // Other code is the same as the original code + // See: https://github.com/louislam/uptime-kuma/pull/5048#discussion_r1818076626 + return defaultVal; + } +} + +module.exports = KumaColumnCompiler;