UNPKG

@itrocks/mysql-maintainer

Version:

Reactively maintains database structure by updating schema and retrying on MySQL errors

106 lines 4.77 kB
"use strict"; 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