UNPKG

nestjs-reverse-engineering

Version:

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

350 lines 15.6 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 crud_generator_new_1 = require("./builders/crud-generator-new"); const sql_generator_1 = require("./builders/sql-generator"); const data_exporter_1 = require("./builders/data-exporter"); const entity_index_generator_1 = require("./builders/entity-index-generator"); const default_config_1 = require("./config/default.config"); const path = require("path"); let ReverseEngineeringService = class ReverseEngineeringService { constructor(dataSource) { this.dataSource = dataSource; } /** * Initialize the service with configuration */ initialize(configInput) { this.config = (0, default_config_1.createConfig)(configInput); console.log('🔧 Reverse Engineering Service initialized with configuration'); } /** * Get configuration (create default if not initialized) */ getConfig() { if (!this.config) { throw new Error('Service not initialized. Call initialize() with configuration first.'); } return this.config; } /** * Create a database connection from configuration */ async createDataSource(dbConfig) { const { DataSource } = await Promise.resolve().then(() => require('typeorm')); // Ensure password is a string const sanitizedConfig = { ...dbConfig, password: String(dbConfig.password || ''), port: Number(dbConfig.port) || 5432 }; console.log(`🔌 Connecting to ${sanitizedConfig.type}://${sanitizedConfig.username}@${sanitizedConfig.host}:${sanitizedConfig.port}/${sanitizedConfig.database}`); return new DataSource({ type: sanitizedConfig.type, host: sanitizedConfig.host, port: sanitizedConfig.port, username: sanitizedConfig.username, password: sanitizedConfig.password, database: sanitizedConfig.database, schema: sanitizedConfig.schema, ssl: sanitizedConfig.ssl, entities: [], synchronize: false, }); } /** * Generate TypeScript entities from database schema */ async generateEntities(configOverride) { const config = configOverride ? (0, default_config_1.createConfig)({ ...this.getConfig(), ...configOverride }) : this.getConfig(); if (!config.features.entities) { console.log('⏭️ Entity generation disabled in configuration'); return; } console.log('🔄 Starting entity generation process...'); console.log(`📁 Output path: ${config.paths.entities}`); // Create or use existing data source const dataSource = this.dataSource || await this.createDataSource(config.database); if (!dataSource.isInitialized) { await dataSource.initialize(); } try { // Get database schema const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(dataSource); const schema = await introspector.getDatabaseSchema(); console.log(`🗄️ Found ${schema.tables.length} tables in ${schema.dialect} database`); // Filter tables based on configuration let filteredTables = schema.tables; if (config.entities.includedTables && config.entities.includedTables.length > 0) { filteredTables = filteredTables.filter(table => config.entities.includedTables.includes(table.tableName)); } if (config.entities.excludedTables && config.entities.excludedTables.length > 0) { filteredTables = filteredTables.filter(table => !config.entities.excludedTables.includes(table.tableName)); } console.log(`📊 Processing ${filteredTables.length} tables after filtering`); // Generate entities const entityOptions = { outputPath: config.paths.entities, generateInterfaces: false, generateRepositories: false, useDataTransferObjects: false, includeComments: true, namingConvention: 'camelCase', includeRelations: config.entities.useTypeORM, }; const entityBuilder = new entity_builder_1.EntityBuilder(entityOptions, filteredTables, schema.dialect); for (const table of filteredTables) { try { await entityBuilder.generateEntity(table); console.log(` ✅ Generated entity for ${table.tableName}`); } catch (error) { console.error(` ❌ Failed to generate entity for table ${table.tableName}:`, error); } } // Generate index file if enabled if (config.features.generateIndex) { const indexGenerator = new entity_index_generator_1.EntityIndexGenerator({ entitiesPath: config.paths.entities, outputPath: path.join(config.paths.entities, 'index.ts') }); await indexGenerator.generateIndex(); console.log(` 📄 Generated index file`); } console.log('✅ Entity generation process completed!'); } finally { // Only destroy if we created the connection if (!this.dataSource && dataSource.isInitialized) { await dataSource.destroy(); } } } /** * Generate CRUD operations for tables */ async generateCrud(configOverride) { const config = configOverride ? (0, default_config_1.createConfig)({ ...this.getConfig(), ...configOverride }) : this.getConfig(); if (!config.features.crud) { console.log('⏭️ CRUD generation disabled in configuration'); return; } console.log('🔄 Starting CRUD generation process...'); // Create or use existing data source const dataSource = this.dataSource || await this.createDataSource(config.database); if (!dataSource.isInitialized) { await dataSource.initialize(); } try { // Get database schema const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(dataSource); const schema = await introspector.getDatabaseSchema(); console.log(`🗄️ Found ${schema.tables.length} tables in ${schema.dialect} database`); // Generate CRUD operations const crudGenerator = new crud_generator_new_1.CrudGenerator(config); const result = await crudGenerator.generateCrudForTables(schema.tables); console.log(`✅ CRUD generation completed!`); console.log(`📊 ${result.tablesProcessed} tables processed`); console.log(`📁 ${result.filesGenerated} files generated`); console.log(`📋 App module: ${result.appModulePath}`); } finally { // Only destroy if we created the connection if (!this.dataSource && dataSource.isInitialized) { await dataSource.destroy(); } } } /** * Generate SQL scripts */ async generateSql(configOverride) { const config = configOverride ? (0, default_config_1.createConfig)({ ...this.getConfig(), ...configOverride }) : this.getConfig(); if (!config.features.sql) { console.log('⏭️ SQL generation disabled in configuration'); return; } console.log('🔄 Starting SQL generation process...'); console.log(`📁 Output path: ${config.paths.sql}`); // Create or use existing data source const dataSource = this.dataSource || await this.createDataSource(config.database); if (!dataSource.isInitialized) { await dataSource.initialize(); } try { // Get database schema const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(dataSource); const schema = await introspector.getDatabaseSchema(); // Generate SQL scripts const sqlGenerator = new sql_generator_1.SqlGenerator(); const result = await sqlGenerator.generateCreateTableScripts(schema.tables); // Create output directory const fs = await Promise.resolve().then(() => require('fs')); const path = await Promise.resolve().then(() => require('path')); if (!fs.existsSync(config.paths.sql)) { fs.mkdirSync(config.paths.sql, { recursive: true }); } // Write CREATE TABLE scripts const createTablesFile = path.join(config.paths.sql, 'create-tables.sql'); fs.writeFileSync(createTablesFile, result.sql); console.log(`📄 Created: ${createTablesFile}`); console.log(`✅ SQL generation completed!`); console.log(`📁 Generated ${result.tableCount} table scripts in ${config.paths.sql}`); } finally { if (!this.dataSource && dataSource.isInitialized) { await dataSource.destroy(); } } } /** * Export data with optional masking */ async exportData(configOverride) { const config = configOverride ? (0, default_config_1.createConfig)({ ...this.getConfig(), ...configOverride }) : this.getConfig(); if (!config.features.dataExport) { console.log('⏭️ Data export disabled in configuration'); return; } console.log('🔄 Starting data export process...'); // Create or use existing data source const dataSource = this.dataSource || await this.createDataSource(config.database); if (!dataSource.isInitialized) { await dataSource.initialize(); } try { // Get database schema const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(dataSource); const schema = await introspector.getDatabaseSchema(); // Export data const dataExporter = new data_exporter_1.DataExporter(dataSource, { dialect: config.database.type, outputPath: config.paths.dataExport, batchSize: config.dataExport.batchSize, dataMasking: { enabled: config.dataExport.enableMasking, sensitiveFields: config.dataExport.maskedFields, maskingPatterns: {} } }); const tableNames = schema.tables.map(t => t.tableName); const result = await dataExporter.exportTables(tableNames); console.log(`✅ Data export completed!`); console.log(`📊 ${result.tableCount} tables processed`); console.log(`📁 ${result.fileCount} files generated`); } finally { if (!this.dataSource && dataSource.isInitialized) { await dataSource.destroy(); } } } /** * Complete reverse engineering process (entities + CRUD + SQL + data export) */ async generateAll(configOverride) { const config = configOverride ? (0, default_config_1.createConfig)({ ...this.getConfig(), ...configOverride }) : this.getConfig(); console.log('🚀 Starting complete reverse engineering process...'); if (config.features.entities) { await this.generateEntities(configOverride); } if (config.features.crud) { await this.generateCrud(configOverride); } if (config.features.sql) { await this.generateSql(configOverride); } if (config.features.dataExport) { await this.exportData(configOverride); } console.log('🎉 Complete reverse engineering process finished!'); } /** * Test database connection */ async testConnection(dbConfig) { const config = dbConfig || this.getConfig().database; console.log('🔌 Testing database connection...'); try { const dataSource = await this.createDataSource(config); await dataSource.initialize(); console.log('✅ Database connection successful!'); await dataSource.destroy(); return true; } catch (error) { console.error('❌ Database connection failed:', error.message); return false; } } /** * Get database schema information */ async getSchema(dbConfig) { const config = dbConfig || this.getConfig().database; const dataSource = await this.createDataSource(config); await dataSource.initialize(); try { const introspector = introspector_factory_1.SchemaIntrospectorFactory.create(dataSource); return await introspector.getDatabaseSchema(); } finally { await dataSource.destroy(); } } /** * Get list of tables */ async getTables(dbConfig) { const schema = await this.getSchema(dbConfig); return schema.tables; } /** * Validate configuration */ validateConfig(configInput) { try { const config = (0, default_config_1.createConfig)(configInput); // Validate database configuration if (!config.database.host || !config.database.database) { throw new Error('Database host and database name are required'); } // Validate paths if (!config.paths.baseOutput) { throw new Error('Base output path is required'); } console.log('✅ Configuration is valid'); return true; } catch (error) { console.error('❌ Configuration validation failed:', error.message); return false; } } /** * Get current configuration */ getConfiguration() { return this.config || null; } }; exports.ReverseEngineeringService = ReverseEngineeringService; exports.ReverseEngineeringService = ReverseEngineeringService = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", [typeorm_1.DataSource]) ], ReverseEngineeringService); //# sourceMappingURL=reverse-engineering-service-new.js.map