Fix multiple MySQL issues

The first issue is an invalid option to the MySQL connector in the form
of the table prefix. It instead gets set as a private prop on the
storage class and then removed from the options object.

The second and more important issue is that the field to store the
duplication check data ended up being too small too quickly, causing it
to quickly fail to write a full JSON string and leading to an error
while retrieving the poll. An `ALTER` statement during init is used to
make sure the datatype is now a `MEDIUMTEXT`. With 16MB it should fill
up way less quickly than previously.
This commit is contained in:
Wolvan 2022-02-04 20:34:21 +01:00
parent 2f4cacf5d0
commit 8bf0155142

View file

@ -7,7 +7,8 @@ import { BackendPoll as Poll } from "./Poll";
export default class MySQLStorage extends Storage { export default class MySQLStorage extends Storage {
#db: mysql.Connection; #db: mysql.Connection;
#options: mysql.ConnectionOptions & { tablePrefix?: string }; #options: mysql.ConnectionOptions;
#tablePrefix: string;
#createConnection(mysqlInstance?: mysql.Connection): void { #createConnection(mysqlInstance?: mysql.Connection): void {
if (!mysqlInstance) this.#db = mysql.createConnection(this.#options); if (!mysqlInstance) this.#db = mysql.createConnection(this.#options);
this.#db.on("error", (err: mysql.QueryError) => { this.#db.on("error", (err: mysql.QueryError) => {
@ -17,6 +18,9 @@ export default class MySQLStorage extends Storage {
constructor(options: mysql.ConnectionOptions & { tablePrefix?: string }) { constructor(options: mysql.ConnectionOptions & { tablePrefix?: string }) {
super(); super();
options = Object.assign({}, options);
this.#tablePrefix = options.tablePrefix || "";
delete options["tablePrefix"];
this.#options = options; this.#options = options;
console.debug("Initiating MySQLStorage."); console.debug("Initiating MySQLStorage.");
this.#db = mysql.createConnection(this.#options); this.#db = mysql.createConnection(this.#options);
@ -25,7 +29,7 @@ export default class MySQLStorage extends Storage {
async init(): Promise<this> { async init(): Promise<this> {
await this.#db.promise().query(` await this.#db.promise().query(`
CREATE TABLE IF NOT EXISTS ${ this.#options.tablePrefix || "" }polls ( CREATE TABLE IF NOT EXISTS ${ this.#tablePrefix || "" }polls (
id_str VARCHAR(32) NOT NULL PRIMARY KEY, id_str VARCHAR(32) NOT NULL PRIMARY KEY,
title VARCHAR(${MAX_CHARACTER_LENGTH}) NOT NULL DEFAULT '', title VARCHAR(${MAX_CHARACTER_LENGTH}) NOT NULL DEFAULT '',
dupe_check_mode ENUM('none', 'ip', 'cookie') NOT NULL DEFAULT 'ip', dupe_check_mode ENUM('none', 'ip', 'cookie') NOT NULL DEFAULT 'ip',
@ -38,11 +42,14 @@ export default class MySQLStorage extends Storage {
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=INNODB; ) ENGINE=INNODB;
`); `);
await this.#db.promise().query(`
ALTER TABLE ${ this.#tablePrefix || "" }polls CHANGE dupe_data dupe_data MEDIUMTEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL;
`);
return this; return this;
} }
async getItem(key: string): Promise<Poll|null> { async getItem(key: string): Promise<Poll|null> {
const [rows] = await this.#db.promise().execute(`SELECT * FROM ${ this.#options.tablePrefix || "" }polls WHERE id_str = ? AND deleted_at IS NULL;`, [key]); const [rows] = await this.#db.promise().execute(`SELECT * FROM ${ this.#tablePrefix || "" }polls WHERE id_str = ? AND deleted_at IS NULL;`, [key]);
if (!rows || !Array.isArray(rows) || !rows.length) return null; if (!rows || !Array.isArray(rows) || !rows.length) return null;
const row = rows[0] as { const row = rows[0] as {
id_str: string, id_str: string,
@ -68,7 +75,7 @@ export default class MySQLStorage extends Storage {
async setItem(key: string, value: Poll): Promise<void> { async setItem(key: string, value: Poll): Promise<void> {
await this.#db.promise().execute(` await this.#db.promise().execute(`
INSERT INTO ${ this.#options.tablePrefix || "" }polls INSERT INTO ${ this.#tablePrefix || "" }polls
(id_str, title, dupe_check_mode, multi_select, captcha, dupe_data, options, creation_time) (id_str, title, dupe_check_mode, multi_select, captcha, dupe_data, options, creation_time)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE