@itrocks/mysql-maintainer
Version:
Reactively maintains database structure by updating schema and retrying on MySQL errors
106 lines • 4.77 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MysqlMaintainer = exports.DEBUG = exports.Mysql = void 0;
const class_type_1 = require("@itrocks/class-type");
const mysql_1 = require("@itrocks/mysql");
const mysql_to_schema_1 = require("@itrocks/mysql-to-schema");
const reflect_to_schema_1 = require("@itrocks/reflect-to-schema");
const schema_diff_1 = require("@itrocks/schema-diff");
const schema_diff_mysql_1 = require("@itrocks/schema-diff-mysql");
const schema_to_mysql_1 = require("@itrocks/schema-to-mysql");
const store_1 = require("@itrocks/store");
var mysql_2 = require("./mysql");
Object.defineProperty(exports, "Mysql", { enumerable: true, get: function () { return mysql_2.Mysql; } });
exports.DEBUG = false;
const DELETION = false;
class MysqlMaintainer {
connection;
constructor(connection) {
this.connection = connection;
}
async createImplicitTable(type1, type2) {
const joinTable = this.implicitTableName(type1, type2);
const table1 = (0, store_1.storeOf)(type1);
const table2 = (0, store_1.storeOf)(type2);
const query = `CREATE TABLE \`${joinTable}\` (
${table1}_id int unsigned NOT NULL,
${table2}_id int unsigned NOT NULL,
PRIMARY KEY (${table1}_id, ${table2}_id),
CONSTRAINT \`${joinTable}.${table1}_id\` FOREIGN KEY (${table1}_id) REFERENCES \`${table1}\` (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT \`${joinTable}.${table2}_id\` FOREIGN KEY (${table2}_id) REFERENCES \`${table2}\` (id) ON DELETE CASCADE ON UPDATE CASCADE
)`;
await this.connection.query(query);
return true;
}
async createTable(type) {
const tableName = (0, store_1.storeOf)(type);
if (!tableName) {
throw 'No table name for type';
}
const tableSchema = new reflect_to_schema_1.ReflectToTable().convert(type);
const schemaToMysql = new schema_to_mysql_1.SchemaToMysql();
const sql = schemaToMysql.sql(tableSchema);
await this.connection.query(sql);
return true;
}
implicitTableName(type1, type2) {
const table1 = (0, store_1.storeOf)(type1);
const table2 = (0, store_1.storeOf)(type2);
if (!table1 || !table2) {
throw 'Collection objects are not stored';
}
return (0, mysql_1.joinTableName)(table1, table2);
}
async manageError(error, context, _sql, _values) {
if (exports.DEBUG)
console.log('MAINTAINER: manageError', error);
switch (error.code) {
case 'ER_BAD_FIELD_ERROR':
case 'ER_CANNOT_ADD_FOREIGN':
return this.updateContextTables(context);
case 'ER_NO_SUCH_TABLE':
const tableName = /Table '.*?\.(.*?)'/.exec(error.message)?.[1];
return this.updateContextTables(context, tableName);
}
return false;
}
async updateContextTables(context, tableName) {
let result = false;
const contexts = Array.isArray(context) ? context : [context];
for (const context of contexts) {
const type = (0, class_type_1.typeOf)(context);
const tableName = (0, store_1.storeOf)(type);
if (!tableName) {
throw 'No table name for type';
}
const exists = (await this.connection.query('SHOW TABLES LIKE ?', tableName));
result ||= await (exists.length ? this.updateTable(type) : this.createTable(type));
}
if ((contexts.length === 2) && (this.implicitTableName(contexts[0], contexts[1]) === tableName)) {
result ||= await this.createImplicitTable(contexts[0], contexts[1]);
}
return result;
}
async updateTable(type) {
const tableName = (0, store_1.storeOf)(type);
if (!tableName) {
throw 'No table name for type';
}
const classTable = new reflect_to_schema_1.ReflectToTable().convert(type);
new mysql_to_schema_1.MysqlToTable(this.connection).normalize(classTable);
const mysqlTable = await ((new mysql_to_schema_1.MysqlToTable(this.connection)).convert(tableName));
const schemaDiff = new schema_diff_1.TableDiff(mysqlTable, classTable);
if (!schemaDiff.additions.length
&& !schemaDiff.changes.length
&& (!schemaDiff.deletions.length || !DELETION)
&& !schemaDiff.tableChanges()) {
return false;
}
const schemaDiffMysql = new schema_diff_mysql_1.SchemaDiffMysql();
const sql = schemaDiffMysql.sql(schemaDiff, DELETION);
await this.connection.query(sql);
return true;
}
}
exports.MysqlMaintainer = MysqlMaintainer;
//# sourceMappingURL=mysql-maintainer.js.map