UNPKG

nestjs-reverse-engineering

Version:

A powerful TypeScript/NestJS library for database reverse engineering, entity generation, and CRUD operations

165 lines 6.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MySQLSchemaIntrospector = void 0; /* eslint-disable prettier/prettier */ const postgres_introspector_1 = require("./postgres-introspector"); const database_types_1 = require("../types/database.types"); class MySQLSchemaIntrospector extends postgres_introspector_1.BaseSchemaIntrospector { getDialect() { return database_types_1.DatabaseDialect.MYSQL; } async getAllTables() { const query = ` SELECT t.TABLE_NAME as table_name, t.TABLE_SCHEMA as table_schema, t.TABLE_COMMENT as table_comment FROM information_schema.TABLES t WHERE t.TABLE_TYPE = 'BASE TABLE' AND t.TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys') ORDER BY t.TABLE_SCHEMA, t.TABLE_NAME; `; const tables = await this.dataSource.query(query); const tableInfos = []; for (const table of tables) { const tableInfo = await this.getTableInfo(table.table_name, table.table_schema); tableInfos.push(tableInfo); } return tableInfos; } async getTableInfo(tableName, schema) { const databaseName = schema || await this.getCurrentDatabase(); const [columns, primaryKeys, foreignKeys, indexes] = await Promise.all([ this.getColumns(tableName, databaseName), this.getPrimaryKeys(tableName, databaseName), this.getForeignKeys(tableName, databaseName), this.getIndexes(tableName, databaseName) ]); const tableCommentQuery = ` SELECT TABLE_COMMENT as table_comment FROM information_schema.TABLES WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?; `; const commentResult = await this.dataSource.query(tableCommentQuery, [tableName, databaseName]); const tableComment = commentResult[0]?.table_comment; return { tableName, tableSchema: databaseName, tableComment, columns, primaryKeys, foreignKeys, indexes }; } async getCurrentDatabase() { const result = await this.dataSource.query('SELECT DATABASE() as current_db'); return result[0].current_db; } async getColumns(tableName, schema) { const query = ` SELECT c.COLUMN_NAME as column_name, c.DATA_TYPE as data_type, c.IS_NULLABLE as is_nullable, c.COLUMN_DEFAULT as column_default, c.CHARACTER_MAXIMUM_LENGTH as character_maximum_length, c.NUMERIC_PRECISION as numeric_precision, c.NUMERIC_SCALE as numeric_scale, c.ORDINAL_POSITION as ordinal_position, c.COLUMN_COMMENT as column_comment, c.EXTRA as extra, c.COLUMN_TYPE as column_type FROM information_schema.COLUMNS c WHERE c.TABLE_NAME = ? AND c.TABLE_SCHEMA = ? ORDER BY c.ORDINAL_POSITION; `; const columns = await this.dataSource.query(query, [tableName, schema]); return columns.map((col) => ({ columnName: col.column_name, dataType: col.data_type, isNullable: col.is_nullable === 'YES', defaultValue: col.column_default, characterMaximumLength: col.character_maximum_length, numericPrecision: col.numeric_precision, numericScale: col.numeric_scale, columnComment: col.column_comment, isAutoIncrement: col.extra && col.extra.toLowerCase().includes('auto_increment'), ordinalPosition: col.ordinal_position, enumValues: this.extractEnumValues(col.column_type) })); } extractEnumValues(columnType) { if (!columnType || !columnType.toLowerCase().startsWith('enum(')) { return undefined; } const match = columnType.match(/enum\((.*)\)/i); if (!match) return undefined; return match[1] .split(',') .map(value => value.trim().replace(/^'|'$/g, '')) .filter(value => value.length > 0); } async getPrimaryKeys(tableName, schema) { const query = ` SELECT COLUMN_NAME as column_name FROM information_schema.KEY_COLUMN_USAGE WHERE CONSTRAINT_NAME = 'PRIMARY' AND TABLE_NAME = ? AND TABLE_SCHEMA = ? ORDER BY ORDINAL_POSITION; `; const result = await this.dataSource.query(query, [tableName, schema]); return result.map((row) => row.column_name); } async getForeignKeys(tableName, schema) { const query = ` SELECT kcu.CONSTRAINT_NAME as constraint_name, kcu.COLUMN_NAME as column_name, kcu.REFERENCED_TABLE_SCHEMA as referenced_table_schema, kcu.REFERENCED_TABLE_NAME as referenced_table_name, kcu.REFERENCED_COLUMN_NAME as referenced_column_name, rc.DELETE_RULE as on_delete, rc.UPDATE_RULE as on_update FROM information_schema.KEY_COLUMN_USAGE kcu JOIN information_schema.REFERENTIAL_CONSTRAINTS rc ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME WHERE kcu.TABLE_NAME = ? AND kcu.TABLE_SCHEMA = ? AND kcu.REFERENCED_TABLE_NAME IS NOT NULL; `; const result = await this.dataSource.query(query, [tableName, schema]); return result.map((row) => ({ constraintName: row.constraint_name, columnName: row.column_name, referencedTableSchema: row.referenced_table_schema, referencedTableName: row.referenced_table_name, referencedColumnName: row.referenced_column_name, onDelete: row.on_delete, onUpdate: row.on_update })); } async getIndexes(tableName, schema) { const query = ` SELECT INDEX_NAME as index_name, GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) as column_names, NON_UNIQUE = 0 as is_unique, INDEX_NAME = 'PRIMARY' as is_primary FROM information_schema.STATISTICS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ? GROUP BY INDEX_NAME, NON_UNIQUE ORDER BY INDEX_NAME; `; const result = await this.dataSource.query(query, [tableName, schema]); return result.map((row) => ({ indexName: row.index_name, columnNames: row.column_names ? row.column_names.split(',') : [], isUnique: Boolean(row.is_unique), isPrimary: Boolean(row.is_primary) })); } } exports.MySQLSchemaIntrospector = MySQLSchemaIntrospector; //# sourceMappingURL=mysql-introspector.js.map