@dbcube/schema-builder 1.0.8 → 1.0.10

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/dist/index.js CHANGED
@@ -51,7 +51,7 @@ var FileUtils = class {
51
51
  const fullPath = path.join(currentDir, entry.name);
52
52
  if (entry.isDirectory()) {
53
53
  recurse(fullPath);
54
- } else if (entry.isFile() && (entry.name.endsWith(suffix) || entry.name.includes(suffix))) {
54
+ } else if (entry.isFile() && entry.name.endsWith(suffix)) {
55
55
  cubeFiles.push(fullPath);
56
56
  }
57
57
  }
@@ -64,32 +64,189 @@ var FileUtils = class {
64
64
  });
65
65
  return cubeFiles;
66
66
  }
67
+ /**
68
+ * Extrae nombres de tablas reales de archivos .cube
69
+ * @param {string} filePath - String ruta del archivo .cube
70
+ * @returns {object} - Objeto que contiene el estado y el mensaje con el nombre de la tabla
71
+ */
72
+ static extracTableNameFromCube(filePath) {
73
+ try {
74
+ const content = fs.readFileSync(filePath, "utf8");
75
+ const metaMatch = content.match(/@meta\s*\(\s*\{\s*name\s*:\s*["']([^"']+)["']\s*;\s*[^}]*\}\s*\)/s);
76
+ if (metaMatch) {
77
+ return {
78
+ status: 200,
79
+ message: metaMatch[1]
80
+ };
81
+ }
82
+ throw new Error(`Error to execute this file ${filePath} because no exist a name of table.`);
83
+ } catch (error) {
84
+ if (error instanceof Error) {
85
+ return {
86
+ status: 500,
87
+ message: error.message
88
+ };
89
+ }
90
+ return {
91
+ status: 500,
92
+ message: String(error)
93
+ };
94
+ }
95
+ }
67
96
  };
68
97
  var FileUtils_default = FileUtils;
69
98
 
99
+ // src/lib/UIUtils.ts
100
+ import chalk from "chalk";
101
+ var UIUtils = class {
102
+ /**
103
+ * Shows animated progress for processing items
104
+ */
105
+ static async showItemProgress(itemName, current, total) {
106
+ const consoleWidth = process.stdout.columns || 80;
107
+ const prefix = `\u251C\u2500 ${itemName} `;
108
+ const suffix = ` \u2713 OK`;
109
+ const availableSpace = consoleWidth - prefix.length - suffix.length;
110
+ const maxDots = Math.max(10, availableSpace);
111
+ return new Promise((resolve2) => {
112
+ process.stdout.write(`${chalk.blue("\u251C\u2500")} ${chalk.cyan(itemName)} `);
113
+ let dotCount = 0;
114
+ const interval = setInterval(() => {
115
+ if (dotCount < maxDots) {
116
+ process.stdout.write(chalk.gray("."));
117
+ dotCount++;
118
+ } else {
119
+ clearInterval(interval);
120
+ resolve2();
121
+ }
122
+ }, 10);
123
+ });
124
+ }
125
+ /**
126
+ * Shows success for a processed item
127
+ */
128
+ static showItemSuccess(itemName) {
129
+ process.stdout.write(` ${chalk.green("\u2713")} ${chalk.gray("OK")}
130
+ `);
131
+ }
132
+ /**
133
+ * Shows error for an item
134
+ */
135
+ static showItemError(itemName, error) {
136
+ process.stdout.write(` ${chalk.red("\u2717")} ${chalk.red("ERROR")}
137
+ `);
138
+ console.log(`${chalk.red("\u2502 ")} ${chalk.gray("\u2514\u2500")} ${chalk.red(error)}`);
139
+ }
140
+ /**
141
+ * Shows operation header
142
+ */
143
+ static showOperationHeader(operationName, databaseName, icon = "\u{1F5D1}\uFE0F") {
144
+ console.log(`
145
+ ${chalk.cyan(icon)} ${chalk.bold.green(operationName.toUpperCase())}`);
146
+ console.log(chalk.gray("\u2500".repeat(60)));
147
+ console.log(`${chalk.blue("\u250C\u2500")} ${chalk.bold(`Database: ${databaseName}`)}`);
148
+ }
149
+ /**
150
+ * Shows comprehensive operation summary
151
+ */
152
+ static showOperationSummary(summary) {
153
+ const { startTime, totalProcessed, successCount, errorCount, processedItems, operationName, databaseName } = summary;
154
+ const totalTime = ((Date.now() - startTime) / 1e3).toFixed(1);
155
+ console.log(`
156
+ ${chalk.cyan("\u{1F4CA}")} ${chalk.bold.green(`SUMMARY OF ${operationName.toUpperCase()}`)}`);
157
+ console.log(chalk.gray("\u2500".repeat(60)));
158
+ if (successCount > 0) {
159
+ console.log(`${chalk.green("\u250C\u2500")} ${chalk.bold("Successful processing:")}`);
160
+ console.log(`${chalk.green("\u251C\u2500")} ${chalk.cyan(`Items processed: ${successCount}`)}`);
161
+ console.log(`${chalk.green("\u251C\u2500")} ${chalk.gray(`Database: ${databaseName}`)}`);
162
+ if (processedItems.length > 0) {
163
+ console.log(`${chalk.green("\u251C\u2500")} ${chalk.yellow("Items updated:")}`);
164
+ processedItems.forEach((item, index) => {
165
+ const isLast = index === processedItems.length - 1;
166
+ const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
167
+ console.log(`${chalk.green("\u2502 ")} ${chalk.gray(connector)} ${chalk.cyan(item)}`);
168
+ });
169
+ }
170
+ }
171
+ if (errorCount > 0) {
172
+ console.log(`${chalk.red("\u251C\u2500")} ${chalk.bold.red(`Errors: ${errorCount}`)}`);
173
+ }
174
+ console.log(`${chalk.blue("\u251C\u2500")} ${chalk.gray(`Total time: ${totalTime}s`)}`);
175
+ console.log(`${chalk.blue("\u2514\u2500")} ${chalk.bold(totalProcessed > 0 ? chalk.green("\u2705 Completed") : chalk.yellow("\u26A0\uFE0F No changes"))}`);
176
+ if (totalProcessed > 0) {
177
+ console.log(`
178
+ ${chalk.green("\u{1F389}")} ${chalk.bold(`${operationName} executed successfully!`)}`);
179
+ } else {
180
+ console.log(`
181
+ ${chalk.yellow("\u26A0\uFE0F ")} ${chalk.bold("No items were processed.")}`);
182
+ }
183
+ console.log("");
184
+ }
185
+ };
186
+
70
187
  // src/lib/Schema.ts
71
188
  var Schema = class {
72
189
  name;
73
190
  engine;
74
191
  constructor(name) {
75
192
  this.name = name;
76
- const engine = new Engine(name);
77
- this.engine = engine;
193
+ this.engine = new Engine(name);
78
194
  }
79
195
  async createDatabase() {
196
+ const startTime = Date.now();
80
197
  const rootPath = path2.resolve(process.cwd());
81
- const response = await this.engine.run("schema_engine", [
82
- "--action",
83
- "create_database",
84
- "--path",
85
- rootPath
86
- ]);
87
- if (response.status != 200) {
88
- returnFormattedError(response.status, response.message);
198
+ UIUtils.showOperationHeader("CREATING DATABASE", this.name, "\u{1F5C4}\uFE0F");
199
+ await UIUtils.showItemProgress("Database", 1, 1);
200
+ try {
201
+ const response = await this.engine.run("schema_engine", [
202
+ "--action",
203
+ "create_database",
204
+ "--path",
205
+ rootPath
206
+ ]);
207
+ if (response.status != 200) {
208
+ UIUtils.showItemError("Database", `Error creating: ${response.message}`);
209
+ const summary2 = {
210
+ startTime,
211
+ totalProcessed: 0,
212
+ successCount: 0,
213
+ errorCount: 1,
214
+ processedItems: [],
215
+ operationName: "create database",
216
+ databaseName: this.name
217
+ };
218
+ UIUtils.showOperationSummary(summary2);
219
+ returnFormattedError(response.status, response.message);
220
+ }
221
+ UIUtils.showItemSuccess("Database");
222
+ const summary = {
223
+ startTime,
224
+ totalProcessed: 1,
225
+ successCount: 1,
226
+ errorCount: 0,
227
+ processedItems: [this.name],
228
+ operationName: "create database",
229
+ databaseName: this.name
230
+ };
231
+ UIUtils.showOperationSummary(summary);
232
+ return response.data;
233
+ } catch (error) {
234
+ UIUtils.showItemError("Database", error.message);
235
+ const summary = {
236
+ startTime,
237
+ totalProcessed: 0,
238
+ successCount: 0,
239
+ errorCount: 1,
240
+ processedItems: [],
241
+ operationName: "create database",
242
+ databaseName: this.name
243
+ };
244
+ UIUtils.showOperationSummary(summary);
245
+ throw error;
89
246
  }
90
- return response.data;
91
247
  }
92
248
  async refreshTables() {
249
+ const startTime = Date.now();
93
250
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
94
251
  if (!fs2.existsSync(cubesDir)) {
95
252
  throw new Error("\u274C The cubes folder does not exist");
@@ -97,11 +254,21 @@ var Schema = class {
97
254
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "table.cube");
98
255
  if (cubeFiles.length === 0) {
99
256
  throw new Error("\u274C There are no cubes to execute");
100
- } else {
101
- for (const file of cubeFiles) {
102
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
103
- const stats = fs2.statSync(filePath);
104
- if (stats.isFile()) {
257
+ }
258
+ UIUtils.showOperationHeader("EXECUTING REFRESH TABLES", this.name, "\u{1F504}");
259
+ let totalTablesProcessed = 0;
260
+ let successCount = 0;
261
+ let errorCount = 0;
262
+ const processedTables = [];
263
+ for (let index = 0; index < cubeFiles.length; index++) {
264
+ const file = cubeFiles[index];
265
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
266
+ const stats = fs2.statSync(filePath);
267
+ if (stats.isFile()) {
268
+ const getTableName = FileUtils_default.extracTableNameFromCube(filePath);
269
+ const tableName = getTableName.status === 200 ? getTableName.message : path2.basename(file, ".table.cube");
270
+ await UIUtils.showItemProgress(tableName, index + 1, cubeFiles.length);
271
+ try {
105
272
  const dml = await this.engine.run("schema_engine", [
106
273
  "--action",
107
274
  "parse_table",
@@ -111,7 +278,9 @@ var Schema = class {
111
278
  filePath
112
279
  ]);
113
280
  if (dml.status != 200) {
114
- returnFormattedError(dml.status, dml.message);
281
+ UIUtils.showItemError(tableName, `Error parsing: ${dml.message}`);
282
+ errorCount++;
283
+ continue;
115
284
  }
116
285
  const parseJson = JSON.stringify(dml.data.actions).replace(/[\r\n\t]/g, "").replace(/\\[rnt]/g, "").replace(/\s{2,}/g, " ");
117
286
  const queries = await this.engine.run("schema_engine", [
@@ -123,7 +292,9 @@ var Schema = class {
123
292
  parseJson
124
293
  ]);
125
294
  if (queries.status != 200) {
126
- returnFormattedError(queries.status, queries.message);
295
+ UIUtils.showItemError(tableName, `Error generating queries: ${queries.message}`);
296
+ errorCount++;
297
+ continue;
127
298
  }
128
299
  delete queries.data.database_type;
129
300
  const parseJsonQueries = JSON.stringify(queries.data);
@@ -136,17 +307,36 @@ var Schema = class {
136
307
  parseJsonQueries
137
308
  ]);
138
309
  if (response.status != 200) {
139
- returnFormattedError(response.status, response.message);
310
+ UIUtils.showItemError(tableName, `Error executing: ${response.message}`);
311
+ errorCount++;
312
+ continue;
140
313
  }
141
314
  const createQuery = queries.data.regular_queries.filter((q) => q.includes("CREATE"))[0];
142
315
  await TableProcessor.saveQuery(dml.data.table, dml.data.database, createQuery);
143
- return response.data;
316
+ UIUtils.showItemSuccess(tableName);
317
+ successCount++;
318
+ processedTables.push(tableName);
319
+ totalTablesProcessed++;
320
+ } catch (error) {
321
+ UIUtils.showItemError(tableName, error.message);
322
+ errorCount++;
144
323
  }
145
324
  }
146
325
  }
147
- return null;
326
+ const summary = {
327
+ startTime,
328
+ totalProcessed: totalTablesProcessed,
329
+ successCount,
330
+ errorCount,
331
+ processedItems: processedTables,
332
+ operationName: "refresh tables",
333
+ databaseName: this.name
334
+ };
335
+ UIUtils.showOperationSummary(summary);
336
+ return totalTablesProcessed > 0 ? { processed: totalTablesProcessed, success: successCount, errors: errorCount } : null;
148
337
  }
149
338
  async freshTables() {
339
+ const startTime = Date.now();
150
340
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
151
341
  if (!fs2.existsSync(cubesDir)) {
152
342
  throw new Error("\u274C The cubes folder does not exist");
@@ -154,11 +344,21 @@ var Schema = class {
154
344
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "table.cube");
155
345
  if (cubeFiles.length === 0) {
156
346
  throw new Error("\u274C There are no cubes to execute");
157
- } else {
158
- for (const file of cubeFiles) {
159
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
160
- const stats = fs2.statSync(filePath);
161
- if (stats.isFile()) {
347
+ }
348
+ UIUtils.showOperationHeader("EXECUTING FRESH TABLES", this.name);
349
+ let totalTablesProcessed = 0;
350
+ let successCount = 0;
351
+ let errorCount = 0;
352
+ const processedTables = [];
353
+ for (let index = 0; index < cubeFiles.length; index++) {
354
+ const file = cubeFiles[index];
355
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
356
+ const stats = fs2.statSync(filePath);
357
+ if (stats.isFile()) {
358
+ const getTableName = FileUtils_default.extracTableNameFromCube(filePath);
359
+ const tableName = getTableName.status === 200 ? getTableName.message : path2.basename(file, ".table.cube");
360
+ await UIUtils.showItemProgress(tableName, index + 1, cubeFiles.length);
361
+ try {
162
362
  const dml = await this.engine.run("schema_engine", [
163
363
  "--action",
164
364
  "parse_table",
@@ -168,7 +368,9 @@ var Schema = class {
168
368
  "fresh"
169
369
  ]);
170
370
  if (dml.status != 200) {
171
- returnFormattedError(dml.status, dml.message);
371
+ UIUtils.showItemError(tableName, `Error parsing: ${dml.message}`);
372
+ errorCount++;
373
+ continue;
172
374
  }
173
375
  const parseJson = JSON.stringify(dml.data.actions).replace(/[\r\n\t]/g, "").replace(/\\[rnt]/g, "").replace(/\s{2,}/g, " ");
174
376
  const queries = await this.engine.run("schema_engine", [
@@ -178,7 +380,9 @@ var Schema = class {
178
380
  parseJson
179
381
  ]);
180
382
  if (queries.status != 200) {
181
- returnFormattedError(queries.status, queries.message);
383
+ UIUtils.showItemError(tableName, `Error generating queries: ${queries.message}`);
384
+ errorCount++;
385
+ continue;
182
386
  }
183
387
  delete queries.data._type;
184
388
  const createQuery = queries.data.regular_queries.filter((q) => q.includes("CREATE"))[0];
@@ -196,16 +400,35 @@ var Schema = class {
196
400
  parseJsonQueries
197
401
  ]);
198
402
  if (response.status != 200) {
199
- returnFormattedError(response.status, response.message);
403
+ UIUtils.showItemError(tableName, `Error executing: ${response.message}`);
404
+ errorCount++;
405
+ continue;
200
406
  }
201
407
  await TableProcessor.saveQuery(dml.data.table, dml.data.database, createQuery);
202
- return response.data;
408
+ UIUtils.showItemSuccess(tableName);
409
+ successCount++;
410
+ processedTables.push(tableName);
411
+ totalTablesProcessed++;
412
+ } catch (error) {
413
+ UIUtils.showItemError(tableName, error.message);
414
+ errorCount++;
203
415
  }
204
416
  }
205
417
  }
206
- return null;
418
+ const summary = {
419
+ startTime,
420
+ totalProcessed: totalTablesProcessed,
421
+ successCount,
422
+ errorCount,
423
+ processedItems: processedTables,
424
+ operationName: "fresh tables",
425
+ databaseName: this.name
426
+ };
427
+ UIUtils.showOperationSummary(summary);
428
+ return totalTablesProcessed > 0 ? { processed: totalTablesProcessed, success: successCount, errors: errorCount } : null;
207
429
  }
208
430
  async executeSeeders() {
431
+ const startTime = Date.now();
209
432
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
210
433
  if (!fs2.existsSync(cubesDir)) {
211
434
  throw new Error("\u274C The cubes folder does not exist");
@@ -213,11 +436,21 @@ var Schema = class {
213
436
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "seeder.cube");
214
437
  if (cubeFiles.length === 0) {
215
438
  throw new Error("\u274C There are no cubes to execute");
216
- } else {
217
- for (const file of cubeFiles) {
218
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
219
- const stats = fs2.statSync(filePath);
220
- if (stats.isFile()) {
439
+ }
440
+ UIUtils.showOperationHeader("EXECUTING SEEDERS", this.name, "\u{1F331}");
441
+ let totalSeedersProcessed = 0;
442
+ let successCount = 0;
443
+ let errorCount = 0;
444
+ const processedSeeders = [];
445
+ for (let index = 0; index < cubeFiles.length; index++) {
446
+ const file = cubeFiles[index];
447
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
448
+ const stats = fs2.statSync(filePath);
449
+ if (stats.isFile()) {
450
+ const getSeederName = FileUtils_default.extracTableNameFromCube(filePath);
451
+ const seederName = getSeederName.status === 200 ? getSeederName.message : path2.basename(file, ".seeder.cube");
452
+ await UIUtils.showItemProgress(seederName, index + 1, cubeFiles.length);
453
+ try {
221
454
  const response = await this.engine.run("schema_engine", [
222
455
  "--action",
223
456
  "seeder",
@@ -225,15 +458,34 @@ var Schema = class {
225
458
  filePath
226
459
  ]);
227
460
  if (response.status != 200) {
228
- returnFormattedError(response.status, response.message);
461
+ UIUtils.showItemError(seederName, `Error executing: ${response.message}`);
462
+ errorCount++;
463
+ continue;
229
464
  }
230
- return response.data;
465
+ UIUtils.showItemSuccess(seederName);
466
+ successCount++;
467
+ processedSeeders.push(seederName);
468
+ totalSeedersProcessed++;
469
+ } catch (error) {
470
+ UIUtils.showItemError(seederName, error.message);
471
+ errorCount++;
231
472
  }
232
473
  }
233
474
  }
234
- return null;
475
+ const summary = {
476
+ startTime,
477
+ totalProcessed: totalSeedersProcessed,
478
+ successCount,
479
+ errorCount,
480
+ processedItems: processedSeeders,
481
+ operationName: "seeders",
482
+ databaseName: this.name
483
+ };
484
+ UIUtils.showOperationSummary(summary);
485
+ return totalSeedersProcessed > 0 ? { processed: totalSeedersProcessed, success: successCount, errors: errorCount } : null;
235
486
  }
236
487
  async executeTriggers() {
488
+ const startTime = Date.now();
237
489
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
238
490
  const triggersDirExit = path2.join(process.cwd(), "dbcube", "triggers");
239
491
  if (!fs2.existsSync(cubesDir)) {
@@ -242,11 +494,21 @@ var Schema = class {
242
494
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "trigger.cube");
243
495
  if (cubeFiles.length === 0) {
244
496
  throw new Error("\u274C There are no cubes to execute");
245
- } else {
246
- for (const file of cubeFiles) {
247
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
248
- const stats = fs2.statSync(filePath);
249
- if (stats.isFile()) {
497
+ }
498
+ UIUtils.showOperationHeader("EXECUTING TRIGGERS", this.name, "\u26A1");
499
+ let totalTriggersProcessed = 0;
500
+ let successCount = 0;
501
+ let errorCount = 0;
502
+ const processedTriggers = [];
503
+ for (let index = 0; index < cubeFiles.length; index++) {
504
+ const file = cubeFiles[index];
505
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
506
+ const stats = fs2.statSync(filePath);
507
+ if (stats.isFile()) {
508
+ const getTriggerName = FileUtils_default.extracTableNameFromCube(filePath);
509
+ const triggerName = getTriggerName.status === 200 ? getTriggerName.message : path2.basename(file, ".trigger.cube");
510
+ await UIUtils.showItemProgress(triggerName, index + 1, cubeFiles.length);
511
+ try {
250
512
  const response = await this.engine.run("schema_engine", [
251
513
  "--action",
252
514
  "trigger",
@@ -256,13 +518,31 @@ var Schema = class {
256
518
  filePath
257
519
  ]);
258
520
  if (response.status != 200) {
259
- returnFormattedError(response.status, response.message);
521
+ UIUtils.showItemError(triggerName, `Error executing: ${response.message}`);
522
+ errorCount++;
523
+ continue;
260
524
  }
261
- return response.data;
525
+ UIUtils.showItemSuccess(triggerName);
526
+ successCount++;
527
+ processedTriggers.push(triggerName);
528
+ totalTriggersProcessed++;
529
+ } catch (error) {
530
+ UIUtils.showItemError(triggerName, error.message);
531
+ errorCount++;
262
532
  }
263
533
  }
264
534
  }
265
- return null;
535
+ const summary = {
536
+ startTime,
537
+ totalProcessed: totalTriggersProcessed,
538
+ successCount,
539
+ errorCount,
540
+ processedItems: processedTriggers,
541
+ operationName: "triggers",
542
+ databaseName: this.name
543
+ };
544
+ UIUtils.showOperationSummary(summary);
545
+ return totalTriggersProcessed > 0 ? { processed: totalTriggersProcessed, success: successCount, errors: errorCount } : null;
266
546
  }
267
547
  };
268
548
  function returnFormattedError(status, message) {