UNPKG

nestjs-reverse-engineering

Version:

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

289 lines 13.1 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReverseEngineeringService = void 0; /* eslint-disable prettier/prettier */ const common_1 = require("@nestjs/common"); const typeorm_1 = require("typeorm"); const introspector_factory_1 = require("./schema/introspector-factory"); const entity_builder_1 = require("./builders/entity-builder"); const path = require("path"); let ReverseEngineeringService = class ReverseEngineeringService { constructor(dataSource) { this.dataSource = dataSource; } /** * Generate TypeScript entities from database schema */ async generateEntities(options = {}) { const defaultOptions = { outputPath: path.join(process.cwd(), 'generated/entities'), generateInterfaces: false, generateRepositories: false, useDataTransferObjects: false, includeComments: true, namingConvention: 'camelCase', includeRelations: true, ...options }; console.log('Starting reverse engineering process...'); console.log(`Output path: ${defaultOptions.outputPath}`); // Get database schema const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(this.dataSource); const schema = await introspector.getDatabaseSchema(); console.log(`Found ${schema.tables.length} tables in ${schema.dialect} database`); // Generate entities const entityBuilder = new entity_builder_1.EntityBuilder(defaultOptions, schema.tables, schema.dialect); for (const table of schema.tables) { try { await entityBuilder.generateEntity(table); } catch (error) { console.error(`Failed to generate entity for table ${table.tableName}:`, error); } } console.log('Reverse engineering process completed!'); } /** * Analyze database schema and return metadata */ async analyzeSchema() { const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(this.dataSource); return await introspector.getDatabaseSchema(); } /** * Get basic table information */ async getTableList() { const schema = await this.analyzeSchema(); return schema.tables.map(table => ({ tableName: table.tableName, tableSchema: table.tableSchema, columnCount: table.columns.length })); } /** * Generate SQL scripts for schema recreation */ async generateSQLScripts(options) { const { SqlGenerator } = await Promise.resolve().then(() => require('./builders/sql-generator')); const { DatabaseDialect } = await Promise.resolve().then(() => require('./types/database.types')); const dialect = options?.dialect || introspector_factory_1.SchemaIntrospectorFactory.getDialectFromDataSource(this.dataSource); const sqlGenerator = new SqlGenerator({ dialect: dialect === 'postgres' ? DatabaseDialect.POSTGRES : DatabaseDialect.MYSQL, schemaName: options?.schemaName, includeDropIfExists: options?.includeDropIfExists || false, includeCreateIfNotExists: options?.includeCreateIfNotExists !== false, outputPath: options?.outputPath || path.join(process.cwd(), 'generated/sql') }); let result; if (options?.entitiesPath) { // Generate from entity files console.log(`🔍 Generating SQL from entity files in ${options.entitiesPath}...`); result = await sqlGenerator.generateFromEntityDirectory(options.entitiesPath); } else { // Generate from database schema (default) console.log('🔍 Generating SQL from database schema...'); const schema = await this.analyzeSchema(); result = sqlGenerator.generateCreateTableScripts(schema.tables); } // Save to file const outputPath = await sqlGenerator.saveSqlScript(result); return { sql: result.sql, tableCount: result.tableCount, outputPath }; } /** * Generate React/UI components */ async generateUIComponents() { // TODO: Implement UI component generation console.log('UI component generation not implemented yet'); } /** * Test database connection and compatibility */ async testConnection() { try { if (!this.dataSource.isInitialized) { await this.dataSource.initialize(); } const dialect = introspector_factory_1.SchemaIntrospectorFactory.getDialectFromDataSource(this.dataSource); // Get database version let version; try { switch (dialect) { case 'postgres': const pgResult = await this.dataSource.query('SELECT version()'); version = pgResult[0]?.version; break; case 'mysql': const mysqlResult = await this.dataSource.query('SELECT VERSION() as version'); version = mysqlResult[0]?.version; break; // Add other dialects as needed } } catch (versionError) { console.warn('Could not retrieve database version:', versionError); } return { connected: true, dialect, version }; } catch (error) { return { connected: false, dialect: 'unknown', error: error instanceof Error ? error.message : String(error) }; } } /** * Generate index.ts file for all entities */ async generateEntityIndex(entitiesPath) { const { EntityIndexGenerator } = await Promise.resolve().then(() => require('./builders/entity-index-generator')); const generator = new EntityIndexGenerator({ entitiesPath: entitiesPath || path.join(process.cwd(), 'generated/entities'), outputPath: path.join(entitiesPath || path.join(process.cwd(), 'generated/entities'), 'index.ts'), includeNamedExports: true, includeEntitiesArray: true, filePattern: '**/*.entity.ts' }); await generator.generateIndex(); } /** * Scan entity files and return information */ async scanEntityFiles(entitiesPath) { const { EntityIndexGenerator } = await Promise.resolve().then(() => require('./builders/entity-index-generator')); const generator = new EntityIndexGenerator({ entitiesPath: entitiesPath || path.join(process.cwd(), 'generated/entities') }); return await generator.scanEntityFiles(); } /** * Export table data as INSERT statements */ async exportTableData(options) { const { DataExporter } = await Promise.resolve().then(() => require('./builders/data-exporter')); const { DatabaseDialect } = await Promise.resolve().then(() => require('./types/database.types')); const dialect = introspector_factory_1.SchemaIntrospectorFactory.getDialectFromDataSource(this.dataSource); const dataExporter = new DataExporter(this.dataSource, { dialect: dialect === 'postgres' ? DatabaseDialect.POSTGRES : DatabaseDialect.MYSQL, batchSize: options?.batchSize || 1000, outputPath: options?.outputPath || path.join(process.cwd(), 'generated/sql/data'), prettyPrint: options?.prettyPrint !== false, alignValues: options?.alignValues !== false, nullHandling: options?.nullHandling || 'NULL', includeHeaders: true, includeTableComments: true, tables: options?.tables, excludeTables: options?.excludeTables, whereConditions: options?.whereConditions, dataMasking: { enabled: options?.dataMasking?.enabled || false, sensitiveFields: options?.dataMasking?.sensitiveFields || ['password', 'email', 'phone', 'mobile', 'ssn'], maskingPatterns: { email: { type: 'email', replacement: 'user{n}@example.com' }, password: { type: 'custom', replacement: '***MASKED***' }, phone: { type: 'phone', pattern: 'XXX-XXX-XXXX' }, mobile: { type: 'phone', pattern: 'XXX-XXX-XXXX' }, name: { type: 'name', replacement: 'User {n}' } } } }); try { const result = await dataExporter.exportAllTables(); return { success: true, tableCount: result.tableCount, totalRows: result.totalRows, fileCount: result.fileCount, outputPaths: result.outputPaths, statistics: result.statistics }; } catch (error) { console.error('Data export failed:', error); throw error; } } /** * Generate CRUD operations for all tables */ async generateCrudOperations(options) { try { const { CrudGenerator } = await Promise.resolve().then(() => require('./builders/crud-generator')); const { DatabaseDialect } = await Promise.resolve().then(() => require('./types/database.types')); const dialect = introspector_factory_1.SchemaIntrospectorFactory.getDialectFromDataSource(this.dataSource); // Get database schema const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(this.dataSource); const schema = await introspector.getDatabaseSchema(); // Filter tables if specified let tables = schema.tables; if (options?.tables) { tables = tables.filter(table => options.tables.includes(table.tableName)); } if (options?.excludeTables) { tables = tables.filter(table => !options.excludeTables.includes(table.tableName)); } const crudGenerator = new CrudGenerator({ outputPath: options?.outputPath || path.join(process.cwd(), 'generated/crud'), dialect: dialect === 'postgres' ? DatabaseDialect.POSTGRES : DatabaseDialect.MYSQL, framework: options?.framework || 'nestjs', includeValidation: options?.includeValidation !== false, includeSwagger: options?.includeSwagger !== false, includePagination: options?.includePagination !== false, includeFiltering: options?.includeFiltering !== false, includeSorting: options?.includeSorting !== false, includeRelations: options?.includeRelations !== false, generateTests: options?.generateTests || false, authGuards: options?.authGuards || false, useTypeORM: options?.useTypeORM !== false, useDTO: options?.useDTO !== false, }); const result = await crudGenerator.generateCrudForTables(tables); return { success: true, tablesProcessed: result.tablesProcessed, filesGenerated: result.filesGenerated, outputPaths: result.outputPaths, modules: result.modules }; } catch (error) { console.error('CRUD generation failed:', error); throw error; } } /** * Generate CRUD operations for specific tables */ async generateCrudForTables(tableNames, options) { return this.generateCrudOperations({ ...options, tables: tableNames }); } }; exports.ReverseEngineeringService = ReverseEngineeringService; exports.ReverseEngineeringService = ReverseEngineeringService = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", [typeorm_1.DataSource]) ], ReverseEngineeringService); //# sourceMappingURL=reverse-engineering.service.js.map