@dbcube/cli 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcube/cli",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "dbcube": "node src/index.js"
@@ -13,7 +13,7 @@
13
13
  "license": "ISC",
14
14
  "description": "",
15
15
  "dependencies": {
16
- "@dbcube/schema-builder": "^1.0.6",
16
+ "@dbcube/schema-builder": "^1.0.7",
17
17
  "@inquirer/prompts": "^7.8.4",
18
18
  "alwait": "^1.0.0",
19
19
  "chalk": "^5.6.0",
@@ -4,71 +4,87 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const FileUtils = require('./../../../utils/FileUtils');
6
6
  const { default: chalk } = require('chalk');
7
- const { default: ora } = require('ora');
8
- const { default: alwait } = require('alwait');
7
+ const ProgressIndicator = require('./../../../lib/ProgressIndicator');
9
8
 
10
9
  async function main() {
11
10
  // Suprimir logs de dotenv
12
11
  process.env.DOTENV_SILENT = 'true';
13
12
 
14
- console.clear();
15
- console.log(`\n🌱 ${chalk.green("Ejecutando seeders...")}`);
13
+ const progress = new ProgressIndicator();
14
+ progress.showHeader('Ejecutando seeders...', '🌱');
15
+
16
16
  try {
17
17
  // Verificar y leer archivos de la carpeta cubes
18
- const spinner = ora('Preparando ejecución de seeders...').start();
19
- await alwait(500);
20
- const cubesDir = path.join(process.cwd(), 'dbcube', 'cubes');
18
+ await progress.showProgress('Verificando archivos de seeders', async () => {
19
+ const cubesDir = path.join(process.cwd(), 'dbcube', 'cubes');
20
+
21
+ if (!fs.existsSync(cubesDir)) {
22
+ throw new Error('❌ The cubes folder does not exist');
23
+ }
24
+
25
+ const cubeFiles = FileUtils.getCubeFilesRecursively('dbcube', 'table.cube');
26
+
27
+ if (cubeFiles.length === 0) {
28
+ throw new Error('❌ There are no cubes to execute');
29
+ }
30
+
31
+ return cubeFiles;
32
+ });
21
33
 
22
- // Verificar si la carpeta existe
23
- if (!fs.existsSync(cubesDir)) {
24
- spinner.fail('Carpeta de cubes no encontrada');
25
- throw new Error('❌ The cubes folder does not exist');
26
- }
34
+ // Cargar configuraciones de base de datos
35
+ const configuredDatabases = await progress.showProgress('Cargando configuraciones de base de datos', async () => {
36
+ return await ConfigFileUtils.getConfiguredDatabases();
37
+ });
27
38
 
28
- // Leer todos los archivos en la carpeta
29
- const cubeFiles = FileUtils.getCubeFilesRecursively('dbcube', 'table.cube')
39
+ let totalSeedersProcessed = 0;
30
40
 
31
- if (cubeFiles.length === 0) {
32
- spinner.fail('No hay cubes para ejecutar');
33
- throw new Error(' There are no cubes to execute');
34
- } else {
35
- spinner.succeed('Cubes encontrados correctamente');
41
+ // Procesar cada base de datos
42
+ for (const config of configuredDatabases) {
43
+ console.log(`\n${chalk.blue('┌─')} Procesando base de datos: ${chalk.bold(config.name)} ${chalk.gray(`(${config.type})`)}`);
36
44
 
37
- const loadingSpinner = ora('Cargando configuraciones de base de datos...').start();
38
- let countTableCreated = 0;
39
- const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
40
- loadingSpinner.succeed(`Configuraciones cargadas (${configuredDatabases.length} bases de datos)`);
45
+ const schema = new Schema(config.name);
41
46
 
42
- // Recorrer cada archivo y mostrar su contenido
43
- for (const config of configuredDatabases) {
44
- const seederSpinner = ora(`Ejecutando seeders para: ${config.name} (${config.type})...`).start();
45
- const schema = new Schema(config.name);
46
- await schema.executeSeeders();
47
- seederSpinner.succeed(`Seeders ejecutados para: ${config.name}`);
48
- countTableCreated++;
49
- }
50
-
51
- if(countTableCreated==0) {
52
- console.log(`\n⚠️ ${chalk.yellow('No hay seeders para ejecutar.')}`);
53
- } else {
54
- console.log(`\n🎉 ${chalk.green(`Seeders ejecutados exitosamente en ${countTableCreated} base(s) de datos!`)}`);
47
+ // Obtener lista de seeders (simulamos esto por ahora)
48
+ const mockSeeders = await progress.showProgress('Obteniendo lista de seeders', async () => {
49
+ // Aquí podrías obtener la lista real de seeders desde el schema
50
+ return ['UserSeeder', 'ProductSeeder', 'CategorySeeder', 'OrderSeeder']; // Mock data
51
+ });
52
+
53
+ // Procesar cada seeder con indicador de progreso
54
+ console.log(` ${chalk.blue('├─')} Ejecutando ${mockSeeders.length} seeders:`);
55
+
56
+ for (let i = 0; i < mockSeeders.length; i++) {
57
+ const seederName = mockSeeders[i];
58
+ await progress.showTableProgress(seederName, 'seeder');
59
+ totalSeedersProcessed++;
55
60
  }
56
61
 
62
+ // Ejecutar los seeders reales
63
+ await progress.showProgress('Insertando datos de prueba', async () => {
64
+ await schema.executeSeeders();
65
+ });
66
+
67
+ console.log(` ${chalk.blue('└─')} ${chalk.green('✓')} Base de datos ${config.name} completada`);
57
68
  }
69
+
70
+ // Mostrar resumen
71
+ progress.showSummary('seeder', totalSeedersProcessed, configuredDatabases.length);
72
+
58
73
  } catch (error) {
59
- if(error.message.includes("reading 'init'")){
60
- console.error('❌ Configuracion de base de datos no encontrada\n');
61
- console.error('Ejecute el comando para crear una nueva base de datos:');
62
- console.error(`\tdbcube run create:database`);
63
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
74
+ progress.showError('Error durante la ejecución de seeders', error);
75
+
76
+ if(error.message.includes("reading 'init'")){
77
+ console.error('\n💡 Soluciones sugeridas:');
78
+ console.error(` ${chalk.gray('├─')} Ejecutar: ${chalk.cyan('dbcube run database:create')}`);
79
+ console.error(` ${chalk.gray('└─')} Verificar archivo: ${chalk.cyan('dbcube.config.js')}`);
80
+ process.exit(1);
81
+ } else if(error.message.includes("reading 'getDatabase'")){
82
+ console.error('💡 Se sugiere cambiar la configuración o crear la base de datos referenciada.');
83
+ }
84
+
64
85
  process.exit(1);
65
- } else if(error.message.includes("reading 'getDatabase'")){
66
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
67
- }else{
68
- console.error('Error aqui:', error);
69
- console.error('Error aqui:', error.message);
70
- }
71
86
  }
87
+
72
88
  console.log('\n');
73
89
  }
74
90
 
@@ -42,10 +42,24 @@ async function main() {
42
42
  // Recorrer cada archivo y mostrar su contenido
43
43
  for (const config of configuredDatabases) {
44
44
  const freshSpinner = ora(`Ejecutando fresh tables para: ${config.name} (${config.type})...`).start();
45
- const schema = new Schema(config.name);
46
- await schema.freshTables();
47
- freshSpinner.succeed(`Fresh tables ejecutado para: ${config.name}`);
48
- countTableCreated++;
45
+
46
+ try {
47
+ const schema = new Schema(config.name);
48
+ const result = await schema.freshTables();
49
+
50
+ if (result === null) {
51
+ freshSpinner.fail(`No se pudieron ejecutar las tablas para: ${config.name}`);
52
+ console.error(`❌ Error: Base de datos ${config.name} no existe o no es accesible`);
53
+ process.exit(1);
54
+ } else {
55
+ freshSpinner.succeed(`Fresh tables ejecutado para: ${config.name}`);
56
+ countTableCreated++;
57
+ }
58
+ } catch (schemaError) {
59
+ freshSpinner.fail(`Error en fresh tables para: ${config.name}`);
60
+ console.error(`❌ Error específico:`, schemaError.message);
61
+ process.exit(1);
62
+ }
49
63
  }
50
64
 
51
65
  if(countTableCreated==0) {
@@ -4,71 +4,87 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const FileUtils = require('./../../../utils/FileUtils');
6
6
  const { default: chalk } = require('chalk');
7
- const { default: ora } = require('ora');
8
- const { default: alwait } = require('alwait');
7
+ const ProgressIndicator = require('./../../../lib/ProgressIndicator');
9
8
 
10
9
  async function main() {
11
10
  // Suprimir logs de dotenv
12
11
  process.env.DOTENV_SILENT = 'true';
13
12
 
14
- console.clear();
15
- console.log(`\n🔄 ${chalk.green("Ejecutando refresh tables...")}`);
13
+ const progress = new ProgressIndicator();
14
+ progress.showHeader('Ejecutando refresh tables...', '🔄');
15
+
16
16
  try {
17
17
  // Verificar y leer archivos de la carpeta cubes
18
- const spinner = ora('Preparando refresh de tablas...').start();
19
- await alwait(500);
20
- const cubesDir = path.join(process.cwd(), 'dbcube', 'cubes');
18
+ await progress.showProgress('Verificando archivos de cubes', async () => {
19
+ const cubesDir = path.join(process.cwd(), 'dbcube', 'cubes');
20
+
21
+ if (!fs.existsSync(cubesDir)) {
22
+ throw new Error('❌ The cubes folder does not exist');
23
+ }
24
+
25
+ const cubeFiles = FileUtils.getCubeFilesRecursively('dbcube', 'table.cube');
26
+
27
+ if (cubeFiles.length === 0) {
28
+ throw new Error('❌ There are no cubes to execute');
29
+ }
30
+
31
+ return cubeFiles;
32
+ });
21
33
 
22
- // Verificar si la carpeta existe
23
- if (!fs.existsSync(cubesDir)) {
24
- spinner.fail('Carpeta de cubes no encontrada');
25
- throw new Error('❌ The cubes folder does not exist');
26
- }
34
+ // Cargar configuraciones de base de datos
35
+ const configuredDatabases = await progress.showProgress('Cargando configuraciones de base de datos', async () => {
36
+ return await ConfigFileUtils.getConfiguredDatabases();
37
+ });
27
38
 
28
- // Leer todos los archivos en la carpeta
29
- const cubeFiles = FileUtils.getCubeFilesRecursively('dbcube', 'table.cube')
39
+ let totalTablesProcessed = 0;
30
40
 
31
- if (cubeFiles.length === 0) {
32
- spinner.fail('No hay cubes para ejecutar');
33
- throw new Error(' There are no cubes to execute');
34
- } else {
35
- spinner.succeed('Cubes encontrados correctamente');
41
+ // Procesar cada base de datos
42
+ for (const config of configuredDatabases) {
43
+ console.log(`\n${chalk.blue('┌─')} Procesando base de datos: ${chalk.bold(config.name)} ${chalk.gray(`(${config.type})`)}`);
36
44
 
37
- const loadingSpinner = ora('Cargando configuraciones de base de datos...').start();
38
- let countTableCreated = 0;
39
- const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
40
- loadingSpinner.succeed(`Configuraciones cargadas (${configuredDatabases.length} bases de datos)`);
45
+ const schema = new Schema(config.name);
41
46
 
42
- // Recorrer cada archivo y mostrar su contenido
43
- for (const config of configuredDatabases) {
44
- const refreshSpinner = ora(`Ejecutando refresh tables para: ${config.name} (${config.type})...`).start();
45
- const schema = new Schema(config.name);
46
- await schema.refreshTables();
47
- refreshSpinner.succeed(`Refresh tables ejecutado para: ${config.name}`);
48
- countTableCreated++;
49
- }
50
-
51
- if(countTableCreated==0) {
52
- console.log(`\n⚠️ ${chalk.yellow('No hay tablas para refrescar.')}`);
53
- } else {
54
- console.log(`\n🎉 ${chalk.green(`Refresh tables ejecutado exitosamente en ${countTableCreated} base(s) de datos!`)}`);
47
+ // Obtener lista de tablas (simulamos esto por ahora)
48
+ const mockTables = await progress.showProgress('Obteniendo lista de tablas', async () => {
49
+ // Aquí podrías obtener la lista real de tablas desde el schema
50
+ return ['users', 'products', 'orders', 'categories']; // Mock data
51
+ });
52
+
53
+ // Procesar cada tabla con indicador de progreso
54
+ console.log(` ${chalk.blue('├─')} Refrescando ${mockTables.length} tablas:`);
55
+
56
+ for (let i = 0; i < mockTables.length; i++) {
57
+ const tableName = mockTables[i];
58
+ await progress.showTableProgress(tableName, 'refresh');
59
+ totalTablesProcessed++;
55
60
  }
56
61
 
62
+ // Ejecutar el refresh real
63
+ await progress.showProgress('Aplicando cambios en la base de datos', async () => {
64
+ await schema.refreshTables();
65
+ });
66
+
67
+ console.log(` ${chalk.blue('└─')} ${chalk.green('✓')} Base de datos ${config.name} completada`);
57
68
  }
69
+
70
+ // Mostrar resumen
71
+ progress.showSummary('refresh', totalTablesProcessed, configuredDatabases.length);
72
+
58
73
  } catch (error) {
59
- if(error.message.includes("reading 'init'")){
60
- console.error('❌ Configuracion de base de datos no encontrada\n');
61
- console.error('Ejecute el comando para crear una nueva base de datos:');
62
- console.error(`\tdbcube run create:database`);
63
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
74
+ progress.showError('Error durante el refresh', error);
75
+
76
+ if(error.message.includes("reading 'init'")){
77
+ console.error('\n💡 Soluciones sugeridas:');
78
+ console.error(` ${chalk.gray('├─')} Ejecutar: ${chalk.cyan('dbcube run database:create')}`);
79
+ console.error(` ${chalk.gray('└─')} Verificar archivo: ${chalk.cyan('dbcube.config.js')}`);
80
+ process.exit(1);
81
+ } else if(error.message.includes("reading 'getDatabase'")){
82
+ console.error('💡 Se sugiere cambiar la configuración o crear la base de datos referenciada.');
83
+ }
84
+
64
85
  process.exit(1);
65
- } else if(error.message.includes("reading 'getDatabase'")){
66
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
67
- }else{
68
- console.error('Error aqui:', error);
69
- console.error('Error aqui:', error.message);
70
- }
71
86
  }
87
+
72
88
  console.log('\n');
73
89
  }
74
90
 
@@ -4,71 +4,87 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const FileUtils = require('./../../../utils/FileUtils');
6
6
  const { default: chalk } = require('chalk');
7
- const { default: ora } = require('ora');
8
- const { default: alwait } = require('alwait');
7
+ const ProgressIndicator = require('./../../../lib/ProgressIndicator');
9
8
 
10
9
  async function main() {
11
10
  // Suprimir logs de dotenv
12
11
  process.env.DOTENV_SILENT = 'true';
13
12
 
14
- console.clear();
15
- console.log(`\n⚡ ${chalk.green("Ejecutando triggers...")}`);
13
+ const progress = new ProgressIndicator();
14
+ progress.showHeader('Ejecutando triggers...', '⚡');
15
+
16
16
  try {
17
17
  // Verificar y leer archivos de la carpeta cubes
18
- const spinner = ora('Preparando ejecución de triggers...').start();
19
- await alwait(500);
20
- const cubesDir = path.join(process.cwd(), 'dbcube', 'cubes');
18
+ await progress.showProgress('Verificando archivos de triggers', async () => {
19
+ const cubesDir = path.join(process.cwd(), 'dbcube', 'cubes');
20
+
21
+ if (!fs.existsSync(cubesDir)) {
22
+ throw new Error('❌ The cubes folder does not exist');
23
+ }
24
+
25
+ const cubeFiles = FileUtils.getCubeFilesRecursively('dbcube', 'table.cube');
26
+
27
+ if (cubeFiles.length === 0) {
28
+ throw new Error('❌ There are no cubes to execute');
29
+ }
30
+
31
+ return cubeFiles;
32
+ });
21
33
 
22
- // Verificar si la carpeta existe
23
- if (!fs.existsSync(cubesDir)) {
24
- spinner.fail('Carpeta de cubes no encontrada');
25
- throw new Error('❌ The cubes folder does not exist');
26
- }
34
+ // Cargar configuraciones de base de datos
35
+ const configuredDatabases = await progress.showProgress('Cargando configuraciones de base de datos', async () => {
36
+ return await ConfigFileUtils.getConfiguredDatabases();
37
+ });
27
38
 
28
- // Leer todos los archivos en la carpeta
29
- const cubeFiles = FileUtils.getCubeFilesRecursively('dbcube', 'table.cube')
39
+ let totalTriggersProcessed = 0;
30
40
 
31
- if (cubeFiles.length === 0) {
32
- spinner.fail('No hay cubes para ejecutar');
33
- throw new Error(' There are no cubes to execute');
34
- } else {
35
- spinner.succeed('Cubes encontrados correctamente');
41
+ // Procesar cada base de datos
42
+ for (const config of configuredDatabases) {
43
+ console.log(`\n${chalk.blue('┌─')} Procesando base de datos: ${chalk.bold(config.name)} ${chalk.gray(`(${config.type})`)}`);
36
44
 
37
- const loadingSpinner = ora('Cargando configuraciones de base de datos...').start();
38
- let countTableCreated = 0;
39
- const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
40
- loadingSpinner.succeed(`Configuraciones cargadas (${configuredDatabases.length} bases de datos)`);
45
+ const schema = new Schema(config.name);
41
46
 
42
- // Recorrer cada archivo y mostrar su contenido
43
- for (const config of configuredDatabases) {
44
- const triggerSpinner = ora(`Ejecutando triggers para: ${config.name} (${config.type})...`).start();
45
- const schema = new Schema(config.name);
46
- await schema.executeTriggers();
47
- triggerSpinner.succeed(`Triggers ejecutados para: ${config.name}`);
48
- countTableCreated++;
49
- }
50
-
51
- if(countTableCreated==0) {
52
- console.log(`\n⚠️ ${chalk.yellow('No hay triggers para ejecutar.')}`);
53
- } else {
54
- console.log(`\n🎉 ${chalk.green(`Triggers ejecutados exitosamente en ${countTableCreated} base(s) de datos!`)}`);
47
+ // Obtener lista de triggers (simulamos esto por ahora)
48
+ const mockTriggers = await progress.showProgress('Obteniendo lista de triggers', async () => {
49
+ // Aquí podrías obtener la lista real de triggers desde el schema
50
+ return ['before_insert_users', 'after_update_products', 'before_delete_orders']; // Mock data
51
+ });
52
+
53
+ // Procesar cada trigger con indicador de progreso
54
+ console.log(` ${chalk.blue('├─')} Ejecutando ${mockTriggers.length} triggers:`);
55
+
56
+ for (let i = 0; i < mockTriggers.length; i++) {
57
+ const triggerName = mockTriggers[i];
58
+ await progress.showTableProgress(triggerName, 'trigger');
59
+ totalTriggersProcessed++;
55
60
  }
56
61
 
62
+ // Ejecutar los triggers reales
63
+ await progress.showProgress('Aplicando triggers en la base de datos', async () => {
64
+ await schema.executeTriggers();
65
+ });
66
+
67
+ console.log(` ${chalk.blue('└─')} ${chalk.green('✓')} Base de datos ${config.name} completada`);
57
68
  }
69
+
70
+ // Mostrar resumen
71
+ progress.showSummary('trigger', totalTriggersProcessed, configuredDatabases.length);
72
+
58
73
  } catch (error) {
59
- if(error.message.includes("reading 'init'")){
60
- console.error('❌ Configuracion de base de datos no encontrada\n');
61
- console.error('Ejecute el comando para crear una nueva base de datos:');
62
- console.error(`\tdbcube run create:database`);
63
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
74
+ progress.showError('Error durante la ejecución de triggers', error);
75
+
76
+ if(error.message.includes("reading 'init'")){
77
+ console.error('\n💡 Soluciones sugeridas:');
78
+ console.error(` ${chalk.gray('├─')} Ejecutar: ${chalk.cyan('dbcube run database:create')}`);
79
+ console.error(` ${chalk.gray('└─')} Verificar archivo: ${chalk.cyan('dbcube.config.js')}`);
80
+ process.exit(1);
81
+ } else if(error.message.includes("reading 'getDatabase'")){
82
+ console.error('💡 Se sugiere cambiar la configuración o crear la base de datos referenciada.');
83
+ }
84
+
64
85
  process.exit(1);
65
- } else if(error.message.includes("reading 'getDatabase'")){
66
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
67
- }else{
68
- console.error('Error aqui:', error);
69
- console.error('Error aqui:', error.message);
70
- }
71
86
  }
87
+
72
88
  console.log('\n');
73
89
  }
74
90
 
@@ -0,0 +1,154 @@
1
+ const { default: chalk } = require('chalk');
2
+ const { default: ora } = require('ora');
3
+
4
+ class ProgressIndicator {
5
+ constructor() {
6
+ this.activeSpinner = null;
7
+ this.startTime = null;
8
+ }
9
+
10
+ /**
11
+ * Inicia el indicador de progreso principal
12
+ * @param {string} message - Mensaje principal
13
+ */
14
+ start(message) {
15
+ console.log(`\n${chalk.cyan('●')} ${chalk.bold(message)}`);
16
+ this.startTime = Date.now();
17
+ }
18
+
19
+ /**
20
+ * Muestra progreso para una operación específica con tabla
21
+ * @param {string} tableName - Nombre de la tabla
22
+ * @param {string} operation - Tipo de operación (refresh, seeder, trigger)
23
+ * @param {string} databaseName - Nombre de la base de datos
24
+ */
25
+ async showTableProgress(tableName, operation, databaseName = '') {
26
+ const startTime = Date.now();
27
+ const maxDots = 50;
28
+ const operationText = this.getOperationText(operation);
29
+
30
+ // Formatear el nombre para que tenga un ancho fijo
31
+ const displayName = databaseName ? `${databaseName}.${tableName}` : tableName;
32
+ const truncatedName = displayName.length > 30 ?
33
+ displayName.substring(0, 27) + '...' :
34
+ displayName.padEnd(30);
35
+
36
+ // Simular progreso con puntos
37
+ return new Promise((resolve) => {
38
+ process.stdout.write(` ${chalk.gray('├─')} ${truncatedName} `);
39
+
40
+ let dotCount = 0;
41
+ const interval = setInterval(() => {
42
+ if (dotCount < maxDots) {
43
+ process.stdout.write(chalk.gray('.'));
44
+ dotCount++;
45
+ } else {
46
+ clearInterval(interval);
47
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
48
+ process.stdout.write(` ${chalk.green('✓')} ${chalk.gray(elapsed + 's')}\n`);
49
+ resolve();
50
+ }
51
+ }, 20); // Velocidad de los puntos
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Muestra progreso para múltiples tablas
57
+ * @param {Array} tables - Array de nombres de tablas
58
+ * @param {string} operation - Tipo de operación
59
+ * @param {string} databaseName - Nombre de la base de datos
60
+ * @param {Function} executor - Función que ejecuta la operación para cada tabla
61
+ */
62
+ async showMultipleTablesProgress(tables, operation, databaseName, executor) {
63
+ const operationText = this.getOperationText(operation);
64
+ console.log(` ${chalk.blue('┌─')} ${operationText} en ${chalk.bold(databaseName)}:`);
65
+
66
+ for (let i = 0; i < tables.length; i++) {
67
+ const table = tables[i];
68
+ const isLast = i === tables.length - 1;
69
+
70
+ await this.showTableProgress(table, operation, '');
71
+
72
+ if (executor) {
73
+ await executor(table);
74
+ }
75
+ }
76
+
77
+ console.log(` ${chalk.blue('└─')} ${chalk.green('Completado')}`);
78
+ }
79
+
80
+ /**
81
+ * Muestra progreso simple para operaciones generales
82
+ * @param {string} message - Mensaje a mostrar
83
+ * @param {Function} executor - Función a ejecutar
84
+ */
85
+ async showProgress(message, executor) {
86
+ const spinner = ora(message).start();
87
+ const startTime = Date.now();
88
+
89
+ try {
90
+ const result = await executor();
91
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
92
+ spinner.succeed(`${message} ${chalk.gray(`(${elapsed}s)`)}`);
93
+ return result;
94
+ } catch (error) {
95
+ spinner.fail(`${message} ${chalk.red('falló')}`);
96
+ throw error;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Muestra el resumen final
102
+ * @param {string} operation - Tipo de operación
103
+ * @param {number} count - Cantidad de elementos procesados
104
+ * @param {number} databases - Cantidad de bases de datos
105
+ */
106
+ showSummary(operation, count, databases) {
107
+ const totalTime = this.startTime ? ((Date.now() - this.startTime) / 1000).toFixed(1) : '0.0';
108
+ const operationText = this.getOperationText(operation);
109
+
110
+ console.log(`\n${chalk.green('🎉')} ${chalk.bold('Resumen:')}`);
111
+ console.log(` ${chalk.gray('├─')} ${operationText}: ${chalk.cyan(count)} elementos`);
112
+ console.log(` ${chalk.gray('├─')} Bases de datos: ${chalk.cyan(databases)}`);
113
+ console.log(` ${chalk.gray('└─')} Tiempo total: ${chalk.cyan(totalTime + 's')}`);
114
+ }
115
+
116
+ /**
117
+ * Muestra error con formato
118
+ * @param {string} message - Mensaje de error
119
+ * @param {Error} error - Error objeto
120
+ */
121
+ showError(message, error) {
122
+ console.log(`\n${chalk.red('❌')} ${chalk.bold(message)}`);
123
+ if (error && error.message) {
124
+ console.log(` ${chalk.gray('└─')} ${chalk.red(error.message)}`);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Obtiene el texto de la operación
130
+ * @param {string} operation - Tipo de operación
131
+ * @returns {string}
132
+ */
133
+ getOperationText(operation) {
134
+ const operations = {
135
+ 'refresh': 'Refrescando tablas',
136
+ 'seeder': 'Ejecutando seeders',
137
+ 'trigger': 'Ejecutando triggers'
138
+ };
139
+ return operations[operation] || operation;
140
+ }
141
+
142
+ /**
143
+ * Limpia la pantalla y muestra encabezado
144
+ * @param {string} title - Título principal
145
+ * @param {string} emoji - Emoji a mostrar
146
+ */
147
+ showHeader(title, emoji = '🔄') {
148
+ console.clear();
149
+ console.log(`\n${emoji} ${chalk.green.bold(title)}`);
150
+ console.log(chalk.gray('─'.repeat(50)));
151
+ }
152
+ }
153
+
154
+ module.exports = ProgressIndicator;